From b58a71636eb07843032e644211285b282a307d97 Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Sun, 22 Mar 2020 21:20:47 +0100 Subject: New upstream version 4.0 --- .clang-format | 7 + .mailmap | 1 + .travis.yml | 2 +- AUTHORS | 6 +- COPYING | 2 +- acinclude.m4 | 14 +- audacious.desktop | 2 +- config.h.in | 7 + configure | 688 +++++++++--- configure.ac | 7 +- contrib/macpack/Audacious.app/Contents/Info.plist | 34 +- .../macpack/Audacious.app/Contents/MacOS/audacious | 1 + contrib/macpack/Audacious.app/Contents/PkgInfo | 2 +- .../macpack/Audacious.app/Contents/version.plist | 16 - images/README-svg | 19 + images/about-logo.svg | 2 +- images/application-exit.svg | 2 +- images/applications-graphics.svg | 2 +- images/applications-internet.svg | 2 +- images/applications-system.svg | 2 +- images/audacious.svg | 2 +- images/audio-card.svg | 2 +- images/audio-volume-high.svg | 2 +- images/audio-volume-low.svg | 2 +- images/audio-volume-medium.svg | 2 +- images/audio-volume-muted.svg | 2 +- images/audio-x-generic.svg | 2 +- images/dialog-question.svg | 2 +- images/dialog-warning.svg | 2 +- images/document-new.svg | 2 +- images/document-open-recent.svg | 2 +- images/document-open.svg | 2 +- images/document-save.svg | 2 +- images/edit-clear.svg | 2 +- images/edit-cut.svg | 2 +- images/edit-delete.svg | 2 +- images/edit-find.svg | 2 +- images/edit-paste.svg | 2 +- images/face-smile.svg | 2 +- images/folder-remote.svg | 2 +- images/go-down.svg | 2 +- images/go-next.svg | 2 +- images/go-previous.svg | 2 +- images/go-up.svg | 2 +- images/help-about.svg | 2 +- images/insert-text.svg | 2 +- images/media-optical.svg | 2 +- images/media-playlist-repeat.svg | 2 +- images/media-playlist-shuffle.svg | 2 +- images/meson.build | 2 + images/preferences-desktop-font.svg | 1 + images/preferences-system.svg | 2 +- images/process-stop.svg | 2 +- images/system-run.svg | 2 +- images/text-x-generic.svg | 2 +- images/user-desktop.svg | 2 +- images/user-trash.svg | 2 +- images/view-refresh.svg | 2 +- images/view-sort-ascending.svg | 2 +- images/view-sort-descending.svg | 2 +- images/window-close.svg | 2 +- man/audtool.1.in | 11 +- man/meson.build | 9 + meson.build | 154 +++ meson_options.txt | 4 + po/LINGUAS | 46 + po/bg.po | 22 +- po/cs.po | 36 +- po/da.po | 10 +- po/de.po | 5 +- po/el.po | 60 +- po/en_GB.po | 22 +- po/fr.po | 16 +- po/id_ID.po | 8 +- po/ja.po | 22 +- po/meson.build | 15 + po/pl.po | 32 +- po/pt_BR.po | 33 +- po/pt_PT.po | 7 +- po/ru.po | 4 +- po/sv.po | 12 +- po/tr.po | 48 +- po/uk.po | 188 ++-- src/audacious/Makefile | 4 +- src/audacious/dbus-server.cc | 48 +- src/audacious/main.cc | 14 +- src/audacious/meson.build | 24 + src/audacious/signals.cc | 9 +- src/audtool/audtool.h | 4 +- src/audtool/handlers_general.c | 2 +- src/audtool/handlers_playback.c | 2 +- src/audtool/handlers_playlist.c | 12 +- src/audtool/handlers_playqueue.c | 2 +- src/audtool/handlers_vitals.c | 2 +- src/audtool/main.c | 6 +- src/audtool/meson.build | 23 + src/audtool/report.c | 2 +- src/config.h.meson | 21 + src/dbus/aud-dbus.xml | 6 + src/dbus/meson.build | 29 + src/libaudcore/Makefile | 3 +- src/libaudcore/adder.cc | 464 ++++---- src/libaudcore/art-search.cc | 119 +- src/libaudcore/art.cc | 193 ++-- src/libaudcore/audio.cc | 430 +++++--- src/libaudcore/audstrings.cc | 756 ++++++------- src/libaudcore/audstrings.h | 137 +-- src/libaudcore/charset.cc | 148 ++- src/libaudcore/config.cc | 340 +++--- src/libaudcore/cue-cache.cc | 59 +- src/libaudcore/cue-cache.h | 6 +- src/libaudcore/drct.cc | 206 ++-- src/libaudcore/drct.h | 72 +- src/libaudcore/effect.cc | 157 ++- src/libaudcore/equalizer-preset.cc | 153 +-- src/libaudcore/equalizer.cc | 150 ++- src/libaudcore/equalizer.h | 28 +- src/libaudcore/eventqueue.cc | 68 +- src/libaudcore/export.h | 12 +- src/libaudcore/fft.cc | 55 +- src/libaudcore/history.cc | 30 +- src/libaudcore/hook.cc | 104 +- src/libaudcore/hook.h | 106 +- src/libaudcore/i18n.h | 19 +- src/libaudcore/index.cc | 165 +-- src/libaudcore/index.h | 223 ++-- src/libaudcore/inifile.cc | 60 +- src/libaudcore/inifile.h | 16 +- src/libaudcore/interface.cc | 157 ++- src/libaudcore/interface.h | 36 +- src/libaudcore/internal.h | 137 +-- src/libaudcore/list.cc | 8 +- src/libaudcore/list.h | 61 +- src/libaudcore/logger.cc | 77 +- src/libaudcore/mainloop.cc | 204 ++-- src/libaudcore/mainloop.h | 28 +- src/libaudcore/meson.build | 126 +++ src/libaudcore/multihash.cc | 98 +- src/libaudcore/multihash.h | 206 ++-- src/libaudcore/objects.h | 201 ++-- src/libaudcore/output.cc | 775 +++++++------ src/libaudcore/output.h | 42 +- src/libaudcore/parse.cc | 23 +- src/libaudcore/parse.h | 15 +- src/libaudcore/playback.cc | 547 +++++----- src/libaudcore/playlist-cache.cc | 65 +- src/libaudcore/playlist-data.cc | 1008 +++++++++-------- src/libaudcore/playlist-data.h | 182 ++-- src/libaudcore/playlist-files.cc | 115 +- src/libaudcore/playlist-internal.h | 45 +- src/libaudcore/playlist-utils.cc | 383 ++++--- src/libaudcore/playlist.cc | 1149 ++++++++++---------- src/libaudcore/playlist.h | 254 +++-- src/libaudcore/plugin-init.cc | 312 +++--- src/libaudcore/plugin-load.cc | 112 +- src/libaudcore/plugin-registry.cc | 547 +++++----- src/libaudcore/plugin.h | 308 +++--- src/libaudcore/plugins-internal.h | 55 +- src/libaudcore/plugins.h | 45 +- src/libaudcore/preferences.cc | 74 +- src/libaudcore/preferences.h | 424 +++++--- src/libaudcore/probe-buffer.cc | 80 +- src/libaudcore/probe-buffer.h | 29 +- src/libaudcore/probe.cc | 176 +-- src/libaudcore/probe.h | 49 +- src/libaudcore/ringbuf.cc | 117 +- src/libaudcore/ringbuf.h | 180 +-- src/libaudcore/runtime.cc | 316 +++--- src/libaudcore/runtime.h | 181 ++- src/libaudcore/scanner.cc | 80 +- src/libaudcore/scanner.h | 18 +- src/libaudcore/stringbuf.cc | 134 +-- src/libaudcore/strpool.cc | 125 ++- src/libaudcore/templates.h | 327 +++--- src/libaudcore/tests/test-mainloop.cc | 21 +- src/libaudcore/threads.h | 100 ++ src/libaudcore/timer.cc | 80 +- src/libaudcore/tinylock.cc | 38 +- src/libaudcore/tinylock.h | 43 + src/libaudcore/tinylock.h.in | 56 - src/libaudcore/tuple-compiler.cc | 286 ++--- src/libaudcore/tuple-compiler.h | 10 +- src/libaudcore/tuple.cc | 560 +++++----- src/libaudcore/tuple.h | 188 ++-- src/libaudcore/util.cc | 141 ++- src/libaudcore/vfs.cc | 253 +++-- src/libaudcore/vfs.h | 138 +-- src/libaudcore/vfs_async.cc | 76 +- src/libaudcore/vfs_async.h | 13 +- src/libaudcore/vfs_local.cc | 219 ++-- src/libaudcore/vfs_local.h | 15 +- src/libaudcore/vis-runner.cc | 130 +-- src/libaudcore/visualization.cc | 104 +- src/libaudcore/visualizer.h | 19 +- src/libaudgui/Makefile | 6 +- src/libaudgui/eq-preset.cc | 69 +- src/libaudgui/equalizer.cc | 6 +- src/libaudgui/images.gresource.xml | 1 + src/libaudgui/infopopup.cc | 26 +- src/libaudgui/infowin.cc | 51 +- src/libaudgui/init.cc | 2 + src/libaudgui/libaudgui-gtk.h | 4 + src/libaudgui/playlists.cc | 2 +- src/libaudgui/prefs-widget.cc | 2 +- src/libaudgui/prefs-window.cc | 26 +- src/libaudgui/preset-browser.cc | 76 +- src/libaudgui/preset-browser.h | 7 +- src/libaudgui/url-opener.cc | 2 +- src/libaudgui/util.cc | 93 +- src/libaudqt/Makefile | 17 +- src/libaudqt/about-qt.cc | 84 +- src/libaudqt/art-qt.cc | 57 +- src/libaudqt/audqt.cc | 212 ++-- src/libaudqt/colorbutton.cc | 62 ++ src/libaudqt/colorbutton.h | 52 + src/libaudqt/eq-preset-qt.cc | 414 +++++++ src/libaudqt/equalizer-qt.cc | 197 ++-- src/libaudqt/export.h | 12 +- src/libaudqt/file-entry.cc | 128 +++ src/libaudqt/fileopener.cc | 160 ++- src/libaudqt/font-entry.cc | 167 +++ src/libaudqt/iface.h | 48 +- src/libaudqt/images.qrc | 1 + src/libaudqt/info-widget.cc | 392 +++++-- src/libaudqt/info-widget.h | 25 +- src/libaudqt/infopopup-qt.cc | 197 ++-- src/libaudqt/infowin-qt.cc | 279 +++-- src/libaudqt/libaudqt-internal.h | 19 +- src/libaudqt/libaudqt.h | 155 ++- src/libaudqt/log-inspector.cc | 239 ++-- src/libaudqt/menu-qt.cc | 79 +- src/libaudqt/menu.h | 81 +- src/libaudqt/meson.build | 58 + src/libaudqt/playlist-management.cc | 120 +- src/libaudqt/plugin-menu-qt.cc | 51 +- src/libaudqt/prefs-builder.cc | 112 +- src/libaudqt/prefs-plugin.cc | 93 +- src/libaudqt/prefs-pluginlist-model.cc | 122 ++- src/libaudqt/prefs-pluginlist-model.h | 28 +- src/libaudqt/prefs-widget-qt.cc | 347 +++--- src/libaudqt/prefs-widget.h | 135 ++- src/libaudqt/prefs-window-qt.cc | 883 ++++++++------- src/libaudqt/queue-manager-qt.cc | 173 ++- src/libaudqt/treeview.cc | 77 ++ src/libaudqt/treeview.h | 49 + src/libaudqt/url-opener-qt.cc | 117 +- src/libaudqt/util-qt.cc | 70 +- src/libaudqt/volumebutton.cc | 171 +-- src/libaudtag/Makefile | 4 +- src/libaudtag/ape/ape.cc | 22 +- src/libaudtag/builtin.h | 2 +- src/libaudtag/id3/id3v22.cc | 2 +- src/libaudtag/id3/id3v24.cc | 2 + src/libaudtag/meson.build | 27 + src/libguess/meson.build | 15 + src/meson.build | 36 + win32/merge.sh | 2 + win32/notes.html | 101 +- win32/patches/gtk-parentheses.diff | 67 ++ win32/patches/lame-3.99.diff | 61 -- win32/patches/libbs2b-makefile.am.diff | 11 - win32/patches/libcdio-0.83.diff | 40 - win32/patches/libcue-install-dll.diff | 11 - win32/patches/libfaad-decoder.c.diff | 13 + win32/patches/libfaad-main.c.diff | 10 - win32/patches/libfaad-makefile.am.diff | 11 - win32/patches/libmp3lame.sym.diff | 8 + 267 files changed, 14144 insertions(+), 10630 deletions(-) create mode 100644 .clang-format create mode 100644 .mailmap create mode 120000 contrib/macpack/Audacious.app/Contents/MacOS/audacious delete mode 100644 contrib/macpack/Audacious.app/Contents/version.plist create mode 100644 images/README-svg create mode 100644 images/meson.build create mode 100644 images/preferences-desktop-font.svg create mode 100644 man/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 po/LINGUAS create mode 100644 po/meson.build create mode 100644 src/audacious/meson.build create mode 100644 src/audtool/meson.build create mode 100644 src/config.h.meson create mode 100644 src/dbus/meson.build create mode 100644 src/libaudcore/meson.build create mode 100644 src/libaudcore/threads.h create mode 100644 src/libaudcore/tinylock.h delete mode 100644 src/libaudcore/tinylock.h.in create mode 100644 src/libaudqt/colorbutton.cc create mode 100644 src/libaudqt/colorbutton.h create mode 100644 src/libaudqt/eq-preset-qt.cc create mode 100644 src/libaudqt/file-entry.cc create mode 100644 src/libaudqt/font-entry.cc create mode 100644 src/libaudqt/meson.build create mode 100644 src/libaudqt/treeview.cc create mode 100644 src/libaudqt/treeview.h create mode 100644 src/libaudtag/meson.build create mode 100644 src/libguess/meson.build create mode 100644 src/meson.build mode change 100644 => 100755 win32/notes.html create mode 100644 win32/patches/gtk-parentheses.diff delete mode 100644 win32/patches/lame-3.99.diff delete mode 100644 win32/patches/libbs2b-makefile.am.diff delete mode 100644 win32/patches/libcdio-0.83.diff delete mode 100644 win32/patches/libcue-install-dll.diff create mode 100644 win32/patches/libfaad-decoder.c.diff delete mode 100644 win32/patches/libfaad-main.c.diff delete mode 100644 win32/patches/libfaad-makefile.am.diff create mode 100644 win32/patches/libmp3lame.sym.diff diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9c546c4 --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +AccessModifierOffset: -4 +BreakBeforeBraces: Allman +PointerAlignment: Middle +SpaceAfterTemplateKeyword: false +AlwaysBreakTemplateDeclarations: Yes diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..28c0689 --- /dev/null +++ b/.mailmap @@ -0,0 +1 @@ +Ariadne Conill diff --git a/.travis.yml b/.travis.yml index ea5e23b..fea03d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - sudo apt-get install libgtk2.0-dev qtbase5-dev script: - ./autogen.sh - - ./configure --prefix=/opt/aud --enable-qt + - ./configure --prefix=/opt/aud --enable-gtk - make - cd src/libaudcore/tests - make test diff --git a/AUTHORS b/AUTHORS index 67b67f1..b02f864 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,8 +4,8 @@ Audacious was originally based on the X Multimedia System (“XMMS”) via its GTK+ 2.x port Beep Media Player (“BMP”). Audacious has changed quite a bit since its first release, however, and little XMMS/BMP code remains. -The Audacious project began in 2005 under the leadership of William Pitcock -(“nenolod”). Many people have made contributions, both large and small, since +The Audacious project began in 2005 under the leadership of Ariadne Conill +(“kaniini”). Many people have made contributions, both large and small, since that time. At present, the project is led by John Lindgren and Michał Lipski (“tallica”), with help from a few others. Special thanks go to Michał Lipski for setting up and maintaining the current website, and to Thomas Lange for @@ -29,6 +29,7 @@ Audacious was written by: Daniel Barkalow René Bertin Christian Birchinger + Ariadne Conill Ralf Ertzinger Michael Färber Matti Hämäläinen @@ -41,7 +42,6 @@ Audacious was written by: Giacomo Lozito Mikael Magnusson Tomasz Moń - William Pitcock Paula Stanciu Ben Tucker Tony Vroon diff --git a/COPYING b/COPYING index ac6c59e..ff618fb 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ LICENSE -Copyright © 2001-2018 Audacious developers and others +Copyright © 2001-2020 Audacious developers and others (A list of the copyright holders is provided in the AUTHORS file.) diff --git a/acinclude.m4 b/acinclude.m4 index 401f335..5e25b37 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -177,16 +177,18 @@ dnl ======================= PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32) PKG_CHECK_MODULES(GMODULE, gmodule-2.0 >= 2.32) +AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_32], [target GLib 2.32]) + dnl GTK+ support dnl ============= AC_ARG_ENABLE(gtk, - AS_HELP_STRING(--disable-gtk, [Disable GTK+ support (default=enabled)]), - USE_GTK=$enableval, USE_GTK=yes) + AS_HELP_STRING(--enable-gtk, [Enable GTK+ support (default=disabled)]), + USE_GTK=$enableval, USE_GTK=no) if test $USE_GTK = yes ; then PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.24) - AC_DEFINE(USE_GTK, 1, [Define if GTK+ support enabled]) + AC_DEFINE([USE_GTK], [1], [Define if GTK+ support enabled]) fi AC_SUBST(USE_GTK) @@ -210,14 +212,14 @@ dnl Qt support dnl ========== AC_ARG_ENABLE(qt, - AS_HELP_STRING(--enable-qt, [Enable Qt support (default=disabled)]), - USE_QT=$enableval, USE_QT=no) + AS_HELP_STRING(--disable-qt, [Disable Qt support (default=enabled)]), + USE_QT=$enableval, USE_QT=yes) if test $USE_QT = yes ; then PKG_CHECK_MODULES([QTCORE], [Qt5Core >= 5.2]) PKG_CHECK_VAR([QTBINPATH], [Qt5Core >= 5.2], [host_bins]) PKG_CHECK_MODULES([QT], [Qt5Core Qt5Gui Qt5Widgets >= 5.2]) - AC_DEFINE(USE_QT, 1, [Define if Qt support enabled]) + AC_DEFINE([USE_QT], [1], [Define if Qt support enabled]) # needed if Qt was built with -reduce-relocations QTCORE_CFLAGS="$QTCORE_CFLAGS -fPIC" diff --git a/audacious.desktop b/audacious.desktop index fe29e70..1ecd8c9 100644 --- a/audacious.desktop +++ b/audacious.desktop @@ -10,7 +10,7 @@ Exec=audacious %U TryExec=audacious StartupNotify=true Terminal=false -MimeType=application/ogg;application/x-cue;application/x-ogg;application/xspf+xml;audio/midi;audio/mp3;audio/mp4;audio/mpeg;audio/mpegurl;audio/ogg;audio/prs.sid;audio/x-flac;audio/x-it;audio/x-mod;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-asx;audio/x-ms-wma;audio/x-musepack;audio/x-s3m;audio/x-scpls;audio/x-stm;audio/x-vorbis+ogg;audio/x-wav;audio/x-wavpack;audio/x-xm;x-content/audio-cdda; +MimeType=application/ogg;application/x-cue;application/x-ogg;application/xspf+xml;audio/aac;audio/flac;audio/midi;audio/mp3;audio/mp4;audio/mpeg;audio/mpegurl;audio/ogg;audio/prs.sid;audio/wav;audio/x-flac;audio/x-it;audio/x-mod;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-asx;audio/x-ms-wma;audio/x-musepack;audio/x-s3m;audio/x-scpls;audio/x-stm;audio/x-vorbis+ogg;audio/x-wav;audio/x-wavpack;audio/x-xm;x-content/audio-cdda; Comment[ar]=استمع إلى الموسيقى Comment[be]=Слухайце музыку diff --git a/config.h.in b/config.h.in index 52da6ba..7b294bd 100644 --- a/config.h.in +++ b/config.h.in @@ -16,10 +16,17 @@ /* Define to compiler syntax for public symbols */ #undef EXPORT +/* target GLib 2.32 */ +#undef GLIB_VERSION_MIN_REQUIRED + /* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ #undef HAVE_CFLOCALECOPYCURRENT +/* Define to 1 if you have the Mac OS X function + CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */ +#undef HAVE_CFLOCALECOPYPREFERREDLANGUAGES + /* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE diff --git a/configure b/configure index 0be2fa4..024d177 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for audacious 3.10.1. +# Generated by GNU Autoconf 2.69 for audacious 4.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -9,7 +9,7 @@ # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # -# Copyright (C) 2001-2018 Audacious developers and others +# Copyright (C) 2001-2020 Audacious developers and others ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## @@ -579,8 +579,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='audacious' PACKAGE_TARNAME='audacious' -PACKAGE_VERSION='3.10.1' -PACKAGE_STRING='audacious 3.10.1' +PACKAGE_VERSION='4.0' +PACKAGE_STRING='audacious 4.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -648,11 +648,11 @@ LIBINTL INTLLIBS INTL_MACOSX_LIBS XGETTEXT_EXTRA_OPTIONS +MSGMERGE_FOR_MSGFMT_OPTION MSGMERGE XGETTEXT_015 XGETTEXT GMSGFMT_015 -MSGFMT_015 GMSGFMT MSGFMT GETTEXT_MACRO_VERSION @@ -1369,7 +1369,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures audacious 3.10.1 to adapt to many kinds of systems. +\`configure' configures audacious 4.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1435,7 +1435,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of audacious 3.10.1:";; + short | recursive ) echo "Configuration of audacious 4.0:";; esac cat <<\_ACEOF @@ -1444,8 +1444,8 @@ Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-largefile omit support for large files - --disable-gtk Disable GTK+ support (default=enabled) - --enable-qt Enable Qt support (default=disabled) + --enable-gtk Enable GTK+ support (default=disabled) + --disable-qt Disable Qt support (default=enabled) --disable-rpath do not hardcode runtime library paths --disable-nls do not use Native Language Support --disable-dbus Disable D-Bus support (default=enabled) @@ -1568,14 +1568,14 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -audacious configure 3.10.1 +audacious configure 4.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. -Copyright (C) 2001-2018 Audacious developers and others +Copyright (C) 2001-2020 Audacious developers and others _ACEOF exit fi @@ -2036,7 +2036,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by audacious $as_me 3.10.1, which was +It was created by audacious $as_me 4.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2398,7 +2398,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF -COPYRIGHT="Copyright (C) 2001-2018 Audacious developers and others" +COPYRIGHT="Copyright (C) 2001-2020 Audacious developers and others" cat >>confdefs.h <<_ACEOF #define COPYRIGHT "$COPYRIGHT" @@ -6389,11 +6389,15 @@ $as_echo "yes" >&6; } fi +$as_echo "#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32" >>confdefs.h + + + # Check whether --enable-gtk was given. if test "${enable_gtk+set}" = set; then : enableval=$enable_gtk; USE_GTK=$enableval else - USE_GTK=yes + USE_GTK=no fi @@ -6696,7 +6700,7 @@ fi if test "${enable_qt+set}" = set; then : enableval=$enable_qt; USE_QT=$enableval else - USE_QT=no + USE_QT=yes fi @@ -7115,38 +7119,12 @@ if test "${PATH_SEPARATOR+set}" != set; then } fi -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld" >&5 +$as_echo_n "checking for ld... " >&6; } +elif test "$GCC" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` - while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } @@ -7154,44 +7132,129 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi -if ${acl_cv_path_LD+:} false; then : +if test -n "$LD"; then + # Let the user override the test with a path. + : +else + if ${acl_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else - if test -z "$LD"; then - acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$acl_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$acl_cv_path_LD" -v 2>&1 &5 | tr -d '\015'` ;; + *) + acl_output=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $acl_output in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + acl_output=`echo "$acl_output" | sed 's%\\\\%/%g'` + while echo "$acl_output" | grep "$re_direlt" > /dev/null 2>&1; do + acl_output=`echo $acl_output | sed "s%$re_direlt%/%"` + done + # Got the pathname. No search in PATH is needed. + acl_cv_path_LD="$acl_output" + ac_prog= + ;; + "") + # If it fails, then pretend we aren't using GCC. + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; esac fi - done - IFS="$acl_save_ifs" + if test -n "$ac_prog"; then + # Search for $ac_prog in $PATH. + acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$acl_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 conftest.$ac_ext +/* end confdefs.h. */ +#if defined __powerpc64__ || defined _ARCH_PPC64 + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # The compiler produces 64-bit code. Add option '-b64' so that the + # linker groks 64-bit object files. + case "$acl_cv_path_LD " in + *" -b64 "*) ;; + *) acl_cv_path_LD="$acl_cv_path_LD -b64" ;; + esac + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + sparc64-*-netbsd*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined __sparcv9 || defined __arch64__ + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + else - acl_cv_path_LD="$LD" # Let the user override the test with a path. + # The compiler produces 32-bit code. Add option '-m elf32_sparc' + # so that the linker groks 32-bit object files. + case "$acl_cv_path_LD " in + *" -m elf32_sparc "*) ;; + *) acl_cv_path_LD="$acl_cv_path_LD -m elf32_sparc" ;; + esac + fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + esac + fi -LD="$acl_cv_path_LD" + LD="$acl_cv_path_LD" +fi if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } + as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${acl_cv_prog_gnu_ld+:} false; then : @@ -7248,67 +7311,324 @@ fi - acl_libdirstem=lib - acl_libdirstem2= + { $as_echo "$as_me:${as_lineno-$LINENO}: checking 32-bit host C ABI" >&5 +$as_echo_n "checking 32-bit host C ABI... " >&6; } +if ${gl_cv_host_cpu_c_abi_32bit+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$gl_cv_host_cpu_c_abi"; then + case "$gl_cv_host_cpu_c_abi" in + i386 | x86_64-x32 | arm | armhf | arm64-ilp32 | hppa | ia64-ilp32 | mips | mipsn32 | powerpc | riscv*-ilp32* | s390 | sparc) + gl_cv_host_cpu_c_abi_32bit=yes ;; + *) + gl_cv_host_cpu_c_abi_32bit=no ;; + esac + else + case "$host_cpu" in + + i[4567]86 ) + gl_cv_host_cpu_c_abi_32bit=yes + ;; + + x86_64 ) + # On x86_64 systems, the C compiler may be generating code in one of + # these ABIs: + # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64. + # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64 + # with native Windows (mingw, MSVC). + # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32. + # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if (defined __x86_64__ || defined __amd64__ \ + || defined _M_X64 || defined _M_AMD64) \ + && !(defined __ILP32__ || defined _ILP32) + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + arm* | aarch64 ) + # Assume arm with EABI. + # On arm64 systems, the C compiler may be generating code in one of + # these ABIs: + # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64. + # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32. + # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined __aarch64__ && !(defined __ILP32__ || defined _ILP32) + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + hppa1.0 | hppa1.1 | hppa2.0* | hppa64 ) + # On hppa, the C compiler may be generating 32-bit code or 64-bit + # code. In the latter case, it defines _LP64 and __LP64__. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __LP64__ + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + ia64* ) + # On ia64 on HP-UX, the C compiler may be generating 64-bit code or + # 32-bit code. In the latter case, it defines _ILP32. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef _ILP32 + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=yes +else + gl_cv_host_cpu_c_abi_32bit=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + mips* ) + # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this + # at 32. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64) + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + powerpc* ) + # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD. + # No need to distinguish them here; the caller may distinguish + # them based on the OS. + # On powerpc64 systems, the C compiler may still be generating + # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may + # be generating 64-bit code. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined __powerpc64__ || defined _ARCH_PPC64 + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + rs6000 ) + gl_cv_host_cpu_c_abi_32bit=yes + ;; + + riscv32 | riscv64 ) + # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d. + # Size of 'long' and 'void *': + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined __LP64__ + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + s390* ) + # On s390x, the C compiler may be generating 64-bit (= s390x) code + # or 31-bit (= s390) code. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined __LP64__ || defined __s390x__ + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + sparc | sparc64 ) + # UltraSPARCs running Linux have `uname -m` = "sparc64", but the + # C compiler still generates 32-bit code. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined __sparcv9 || defined __arch64__ + int ok; + #else + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_host_cpu_c_abi_32bit=no +else + gl_cv_host_cpu_c_abi_32bit=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + + *) + gl_cv_host_cpu_c_abi_32bit=no + ;; + esac + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_host_cpu_c_abi_32bit" >&5 +$as_echo "$gl_cv_host_cpu_c_abi_32bit" >&6; } + + HOST_CPU_C_ABI_32BIT="$gl_cv_host_cpu_c_abi_32bit" + + + + + case "$host_os" in solaris*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5 $as_echo_n "checking for 64-bit host... " >&6; } if ${gl_cv_solaris_64bit+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #ifdef _LP64 -sixtyfour bits -#endif + int ok; + #else + error fail + #endif _ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "sixtyfour bits" >/dev/null 2>&1; then : +if ac_fn_c_try_compile "$LINENO"; then : gl_cv_solaris_64bit=yes else gl_cv_solaris_64bit=no fi -rm -f conftest* - +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_solaris_64bit" >&5 -$as_echo "$gl_cv_solaris_64bit" >&6; } - if test $gl_cv_solaris_64bit = yes; then - acl_libdirstem=lib/64 - case "$host_cpu" in - sparc*) acl_libdirstem2=lib/sparcv9 ;; - i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; - esac - fi - ;; - *) - searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` - if test -n "$searchpath"; then - acl_save_IFS="${IFS= }"; IFS=":" - for searchdir in $searchpath; do - if test -d "$searchdir"; then - case "$searchdir" in - */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; - */../ | */.. ) - # Better ignore directories of this form. They are misleading. - ;; - *) searchdir=`cd "$searchdir" && pwd` - case "$searchdir" in - */lib64 ) acl_libdirstem=lib64 ;; - esac ;; - esac - fi - done - IFS="$acl_save_IFS" - fi - ;; +$as_echo "$gl_cv_solaris_64bit" >&6; };; esac - test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the common suffixes of directories in the library search path" >&5 +$as_echo_n "checking for the common suffixes of directories in the library search path... " >&6; } +if ${acl_cv_libdirstems+:} false; then : + $as_echo_n "(cached) " >&6 +else + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + if test "$HOST_CPU_C_ABI_32BIT" != yes; then + searchpath=`(if test -f /usr/bin/gcc \ + && LC_ALL=C /usr/bin/gcc -print-search-dirs >/dev/null 2>/dev/null; then \ + LC_ALL=C /usr/bin/gcc -print-search-dirs; \ + else \ + LC_ALL=C $CC -print-search-dirs; \ + fi) 2>/dev/null \ + | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" + acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libdirstems" >&5 +$as_echo "$acl_cv_libdirstems" >&6; } + # Decompose acl_cv_libdirstems into acl_libdirstem and acl_libdirstem2. + acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'` + acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e '/,/s/.*,//'` @@ -7357,7 +7677,7 @@ if test "${with_libiconv_prefix+set}" = set; then : additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" if test "$acl_libdirstem2" != "$acl_libdirstem" \ - && ! test -d "$withval/$acl_libdirstem"; then + && test ! -d "$withval/$acl_libdirstem"; then additional_libdir="$withval/$acl_libdirstem2" fi fi @@ -7779,7 +8099,6 @@ fi - am_save_CPPFLAGS="$CPPFLAGS" for element in $INCICONV; do @@ -7980,15 +8299,27 @@ int result = 0; #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ - if (/* Try standardized names. */ - iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) - /* Try IRIX, OSF/1 names. */ - && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) - /* Try AIX names. */ - && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) - /* Try HP-UX names. */ - && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) - result |= 16; + { + /* Try standardized names. */ + iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP"); + /* Try IRIX, OSF/1 names. */ + iconv_t cd2 = iconv_open ("UTF-8", "eucJP"); + /* Try AIX names. */ + iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP"); + /* Try HP-UX names. */ + iconv_t cd4 = iconv_open ("utf8", "eucJP"); + if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1) + && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1)) + result |= 16; + if (cd1 != (iconv_t)(-1)) + iconv_close (cd1); + if (cd2 != (iconv_t)(-1)) + iconv_close (cd2); + if (cd3 != (iconv_t)(-1)) + iconv_close (cd3); + if (cd4 != (iconv_t)(-1)) + iconv_close (cd4); + } return result; ; @@ -8078,13 +8409,15 @@ fi $am_cv_proto_iconv" >&5 $as_echo " $am_cv_proto_iconv" >&6; } + else + am_cv_proto_iconv_arg1="" + fi cat >>confdefs.h <<_ACEOF #define ICONV_CONST $am_cv_proto_iconv_arg1 _ACEOF - fi LIBS="$LIBS $LIBICONV" @@ -8339,7 +8672,7 @@ $as_echo "$USE_NLS" >&6; } - GETTEXT_MACRO_VERSION=0.19 + GETTEXT_MACRO_VERSION=0.20 @@ -8454,12 +8787,7 @@ fi - case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; - *) MSGFMT_015=$MSGFMT ;; - esac - - case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; *) GMSGFMT_015=$GMSGFMT ;; esac @@ -8611,7 +8939,15 @@ $as_echo "no" >&6; } fi - test -n "$localedir" || localedir='${datadir}/locale' + if LC_ALL=C $MSGMERGE --help | grep ' --for-msgfmt ' >/dev/null; then + MSGMERGE_FOR_MSGFMT_OPTION='--for-msgfmt' + else + if LC_ALL=C $MSGMERGE --help | grep ' --no-fuzzy-matching ' >/dev/null; then + MSGMERGE_FOR_MSGFMT_OPTION='--no-fuzzy-matching --no-location --quiet' + else + MSGMERGE_FOR_MSGFMT_OPTION='--no-location --quiet' + fi + fi test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= @@ -8641,7 +8977,6 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 @@ -8711,9 +9046,45 @@ $as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } $as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyPreferredLanguages" >&5 +$as_echo_n "checking for CFLocaleCopyPreferredLanguages... " >&6; } +if ${gt_cv_func_CFLocaleCopyPreferredLanguages+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFLocaleCopyPreferredLanguages(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gt_cv_func_CFLocaleCopyPreferredLanguages=yes +else + gt_cv_func_CFLocaleCopyPreferredLanguages=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyPreferredLanguages" >&5 +$as_echo "$gt_cv_func_CFLocaleCopyPreferredLanguages" >&6; } + if test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then + +$as_echo "#define HAVE_CFLOCALECOPYPREFERREDLANGUAGES 1" >>confdefs.h + fi INTL_MACOSX_LIBS= - if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + if test $gt_cv_func_CFPreferencesCopyAppValue = yes \ + || test $gt_cv_func_CFLocaleCopyCurrent = yes \ + || test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi @@ -9001,15 +9372,27 @@ int result = 0; #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ - if (/* Try standardized names. */ - iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) - /* Try IRIX, OSF/1 names. */ - && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) - /* Try AIX names. */ - && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) - /* Try HP-UX names. */ - && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) - result |= 16; + { + /* Try standardized names. */ + iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP"); + /* Try IRIX, OSF/1 names. */ + iconv_t cd2 = iconv_open ("UTF-8", "eucJP"); + /* Try AIX names. */ + iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP"); + /* Try HP-UX names. */ + iconv_t cd4 = iconv_open ("utf8", "eucJP"); + if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1) + && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1)) + result |= 16; + if (cd1 != (iconv_t)(-1)) + iconv_close (cd1); + if (cd2 != (iconv_t)(-1)) + iconv_close (cd2); + if (cd3 != (iconv_t)(-1)) + iconv_close (cd3); + if (cd4 != (iconv_t)(-1)) + iconv_close (cd4); + } return result; ; @@ -9062,7 +9445,6 @@ $as_echo "$LIBICONV" >&6; } - use_additional=yes acl_save_prefix="$prefix" @@ -9100,7 +9482,7 @@ if test "${with_libintl_prefix+set}" = set; then : additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" if test "$acl_libdirstem2" != "$acl_libdirstem" \ - && ! test -d "$withval/$acl_libdirstem"; then + && test ! -d "$withval/$acl_libdirstem"; then additional_libdir="$withval/$acl_libdirstem2" fi fi @@ -9516,7 +9898,6 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 $as_echo_n "checking for GNU gettext in libintl... " >&6; } if eval \${$gt_func_gnugettext_libintl+:} false; then : @@ -9825,10 +10206,10 @@ CPPFLAGS="$CPPFLAGS -include config.h" ### --------------------------------------------------------------------------- -GENERATED_FILES="audacious.pc buildsys.mk extra.mk man/audtool.1 man/audacious.1 src/libaudcore/audio.h src/libaudcore/tinylock.h win32/audacious.nsi win32/override/README.txt" +GENERATED_FILES="audacious.pc buildsys.mk extra.mk man/audtool.1 man/audacious.1 src/libaudcore/audio.h win32/audacious.nsi win32/override/README.txt" -ac_config_files="$ac_config_files audacious.pc buildsys.mk extra.mk man/audtool.1 man/audacious.1 src/libaudcore/audio.h src/libaudcore/tinylock.h win32/audacious.nsi win32/override/README.txt" +ac_config_files="$ac_config_files audacious.pc buildsys.mk extra.mk man/audtool.1 man/audacious.1 src/libaudcore/audio.h win32/audacious.nsi win32/override/README.txt" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -10470,7 +10851,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by audacious $as_me 3.10.1, which was +This file was extended by audacious $as_me 4.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10536,7 +10917,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -audacious config.status 3.10.1 +audacious config.status 4.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -10655,9 +11036,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # INIT-COMMANDS # # Capture the value of obsolete ALL_LINGUAS because we need it to compute - # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it - # from automake < 1.5. - eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. + OBSOLETE_ALL_LINGUAS="$ALL_LINGUAS" # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" @@ -10678,7 +11058,6 @@ do "man/audtool.1") CONFIG_FILES="$CONFIG_FILES man/audtool.1" ;; "man/audacious.1") CONFIG_FILES="$CONFIG_FILES man/audacious.1" ;; "src/libaudcore/audio.h") CONFIG_FILES="$CONFIG_FILES src/libaudcore/audio.h" ;; - "src/libaudcore/tinylock.h") CONFIG_FILES="$CONFIG_FILES src/libaudcore/tinylock.h" ;; "win32/audacious.nsi") CONFIG_FILES="$CONFIG_FILES win32/audacious.nsi" ;; "win32/override/README.txt") CONFIG_FILES="$CONFIG_FILES win32/override/README.txt" ;; @@ -11279,14 +11658,11 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi - ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` - # Hide the ALL_LINGUAS assignment from automake < 1.5. - eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + ALL_LINGUAS=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. - # Hide the ALL_LINGUAS assignment from automake < 1.5. - eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + ALL_LINGUAS=$OBSOLETE_ALL_LINGUAS fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) diff --git a/configure.ac b/configure.ac index 2bf0c32..f1cbddd 100644 --- a/configure.ac +++ b/configure.ac @@ -6,13 +6,13 @@ dnl Initialize dnl ========== AC_PREREQ([2.59]) -AC_INIT([audacious], [3.10.1]) -AC_COPYRIGHT([Copyright (C) 2001-2018 Audacious developers and others]) +AC_INIT([audacious], [4.0]) +AC_COPYRIGHT([Copyright (C) 2001-2020 Audacious developers and others]) AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE_NAME", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$PACKAGE_VERSION", [Version number of package]) -COPYRIGHT="Copyright (C) 2001-2018 Audacious developers and others" +COPYRIGHT="Copyright (C) 2001-2020 Audacious developers and others" AC_DEFINE_UNQUOTED(COPYRIGHT, "$COPYRIGHT", [Copyright]) AC_SUBST(COPYRIGHT) @@ -114,7 +114,6 @@ define(GENERATED_FILES, man/audtool.1 man/audacious.1 src/libaudcore/audio.h - src/libaudcore/tinylock.h win32/audacious.nsi win32/override/README.txt) diff --git a/contrib/macpack/Audacious.app/Contents/Info.plist b/contrib/macpack/Audacious.app/Contents/Info.plist index 7898402..77e2fbd 100644 --- a/contrib/macpack/Audacious.app/Contents/Info.plist +++ b/contrib/macpack/Audacious.app/Contents/Info.plist @@ -1,24 +1,30 @@ - + - CFBundleDevelopmentRegion - English - CFBundleDisplayName - Audacious - CFBundleExecutable + CFBundleName Audacious - CFBundleIconFile - Audacious.icns CFBundleIdentifier org.audacious-media-player - CFBundleInfoDictionaryVersion - 3.6-devel - CFBundleName + CFBundleDisplayName Audacious - CFBundleShortVersionString - 3.6 + CFBundleIconFile + Audacious + CFBundleVersion + 3.11.0 + CFBundlePackageType + APPL + CFBundleSignature + Auda + CFBundleExecutable + audacious + LSMultipleInstancesProhibited + + NSHighResolutionCapable + + NSHighResolutionMagnifyAllowed + NSHumanReadableCopyright - Copyright © 2001-2014 Audacious developers and others + Copyright © 2001-2018 Audacious developers and others diff --git a/contrib/macpack/Audacious.app/Contents/MacOS/audacious b/contrib/macpack/Audacious.app/Contents/MacOS/audacious new file mode 120000 index 0000000..16ec655 --- /dev/null +++ b/contrib/macpack/Audacious.app/Contents/MacOS/audacious @@ -0,0 +1 @@ +/usr/local/bin/audacious \ No newline at end of file diff --git a/contrib/macpack/Audacious.app/Contents/PkgInfo b/contrib/macpack/Audacious.app/Contents/PkgInfo index 36500fb..7b9a4f2 100644 --- a/contrib/macpack/Audacious.app/Contents/PkgInfo +++ b/contrib/macpack/Audacious.app/Contents/PkgInfo @@ -1 +1 @@ -Audacious \ No newline at end of file +APPLAuda \ No newline at end of file diff --git a/contrib/macpack/Audacious.app/Contents/version.plist b/contrib/macpack/Audacious.app/Contents/version.plist deleted file mode 100644 index 207b6c4..0000000 --- a/contrib/macpack/Audacious.app/Contents/version.plist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - BuildVersion - 12 - CFBundleShortVersionString - 1.4 - CFBundleVersion - 220 - ProjectName - Audacious - SourceVersion - 1337 - - diff --git a/images/README-svg b/images/README-svg new file mode 100644 index 0000000..4cda348 --- /dev/null +++ b/images/README-svg @@ -0,0 +1,19 @@ +These SVG files have been un-optimized to work around the following librsvg bug: + https://bugzilla.gnome.org/show_bug.cgi?id=620923 + +Basically, older versions of librsvg can't parse an optimized path like +".123.456", they need it spelled out as "0.123 0.456". + +An SVG file can be un-optimized by the following regex replacements: + +Replace once: + ([^0-9])\. + \10\. + +Replace until no longer found: + ([0-9]+)\.([0-9]+)\.([0-9|\.|-]+) + \1\.\2 0\.\3 + +Replace once: + www0 + www diff --git a/images/about-logo.svg b/images/about-logo.svg index 65843a9..a3d3dda 100644 --- a/images/about-logo.svg +++ b/images/about-logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/application-exit.svg b/images/application-exit.svg index c34ae18..29ffab7 100644 --- a/images/application-exit.svg +++ b/images/application-exit.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/applications-graphics.svg b/images/applications-graphics.svg index 394d0ba..d7da760 100644 --- a/images/applications-graphics.svg +++ b/images/applications-graphics.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/applications-internet.svg b/images/applications-internet.svg index 05c7709..33fd294 100644 --- a/images/applications-internet.svg +++ b/images/applications-internet.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/applications-system.svg b/images/applications-system.svg index e43d7cc..fce52ef 100644 --- a/images/applications-system.svg +++ b/images/applications-system.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audacious.svg b/images/audacious.svg index 5b712f5..4951a6e 100644 --- a/images/audacious.svg +++ b/images/audacious.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audio-card.svg b/images/audio-card.svg index 4aec807..7d19bad 100644 --- a/images/audio-card.svg +++ b/images/audio-card.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audio-volume-high.svg b/images/audio-volume-high.svg index 4799c83..4eb32fd 100644 --- a/images/audio-volume-high.svg +++ b/images/audio-volume-high.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audio-volume-low.svg b/images/audio-volume-low.svg index e24ea40..ec1f44d 100644 --- a/images/audio-volume-low.svg +++ b/images/audio-volume-low.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audio-volume-medium.svg b/images/audio-volume-medium.svg index 126763f..03eed1f 100644 --- a/images/audio-volume-medium.svg +++ b/images/audio-volume-medium.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audio-volume-muted.svg b/images/audio-volume-muted.svg index 09224d9..ac33bdf 100644 --- a/images/audio-volume-muted.svg +++ b/images/audio-volume-muted.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/audio-x-generic.svg b/images/audio-x-generic.svg index 4661eed..c85e674 100644 --- a/images/audio-x-generic.svg +++ b/images/audio-x-generic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/dialog-question.svg b/images/dialog-question.svg index db8c479..749ef63 100644 --- a/images/dialog-question.svg +++ b/images/dialog-question.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/dialog-warning.svg b/images/dialog-warning.svg index 04bf09f..ba1bb83 100644 --- a/images/dialog-warning.svg +++ b/images/dialog-warning.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/document-new.svg b/images/document-new.svg index 7e89a4a..d9d9fbc 100644 --- a/images/document-new.svg +++ b/images/document-new.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/document-open-recent.svg b/images/document-open-recent.svg index cf53e98..a2fcb23 100644 --- a/images/document-open-recent.svg +++ b/images/document-open-recent.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/document-open.svg b/images/document-open.svg index b0ac18d..bbc81b5 100644 --- a/images/document-open.svg +++ b/images/document-open.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/document-save.svg b/images/document-save.svg index 72e1af9..5f5ce5d 100644 --- a/images/document-save.svg +++ b/images/document-save.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/edit-clear.svg b/images/edit-clear.svg index ff3b91e..f582873 100644 --- a/images/edit-clear.svg +++ b/images/edit-clear.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/edit-cut.svg b/images/edit-cut.svg index 063876d..33ab7c2 100644 --- a/images/edit-cut.svg +++ b/images/edit-cut.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/edit-delete.svg b/images/edit-delete.svg index 586437e..4535069 100644 --- a/images/edit-delete.svg +++ b/images/edit-delete.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/edit-find.svg b/images/edit-find.svg index 5e964c0..02a68a2 100644 --- a/images/edit-find.svg +++ b/images/edit-find.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/edit-paste.svg b/images/edit-paste.svg index 5637bcc..5857a74 100644 --- a/images/edit-paste.svg +++ b/images/edit-paste.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/face-smile.svg b/images/face-smile.svg index bef6576..e49c792 100644 --- a/images/face-smile.svg +++ b/images/face-smile.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/folder-remote.svg b/images/folder-remote.svg index dcf6794..ff3dccf 100644 --- a/images/folder-remote.svg +++ b/images/folder-remote.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/go-down.svg b/images/go-down.svg index 7a1cabc..9eb6700 100644 --- a/images/go-down.svg +++ b/images/go-down.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/go-next.svg b/images/go-next.svg index ac1e41b..dbf6a2c 100644 --- a/images/go-next.svg +++ b/images/go-next.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/go-previous.svg b/images/go-previous.svg index a9f46b1..b027aec 100644 --- a/images/go-previous.svg +++ b/images/go-previous.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/go-up.svg b/images/go-up.svg index fbb8780..b36eef2 100644 --- a/images/go-up.svg +++ b/images/go-up.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/help-about.svg b/images/help-about.svg index afcfcb4..91c078a 100644 --- a/images/help-about.svg +++ b/images/help-about.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/insert-text.svg b/images/insert-text.svg index a4d48b1..37a1852 100644 --- a/images/insert-text.svg +++ b/images/insert-text.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/media-optical.svg b/images/media-optical.svg index bb93d2f..4e6505e 100644 --- a/images/media-optical.svg +++ b/images/media-optical.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/media-playlist-repeat.svg b/images/media-playlist-repeat.svg index d98c082..f0d3992 100644 --- a/images/media-playlist-repeat.svg +++ b/images/media-playlist-repeat.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/media-playlist-shuffle.svg b/images/media-playlist-shuffle.svg index a4fb9ad..31e0100 100644 --- a/images/media-playlist-shuffle.svg +++ b/images/media-playlist-shuffle.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/meson.build b/images/meson.build new file mode 100644 index 0000000..3076150 --- /dev/null +++ b/images/meson.build @@ -0,0 +1,2 @@ +install_data('audacious.png', install_dir: install_unscalable_iconpath) +install_data('audacious.svg', install_dir: install_scalable_iconpath) diff --git a/images/preferences-desktop-font.svg b/images/preferences-desktop-font.svg new file mode 100644 index 0000000..7a92811 --- /dev/null +++ b/images/preferences-desktop-font.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/preferences-system.svg b/images/preferences-system.svg index c18f12f..8965825 100644 --- a/images/preferences-system.svg +++ b/images/preferences-system.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/process-stop.svg b/images/process-stop.svg index ece8f92..e2415ed 100644 --- a/images/process-stop.svg +++ b/images/process-stop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/system-run.svg b/images/system-run.svg index 677aad9..611169d 100644 --- a/images/system-run.svg +++ b/images/system-run.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/text-x-generic.svg b/images/text-x-generic.svg index 13c8af1..2459a41 100644 --- a/images/text-x-generic.svg +++ b/images/text-x-generic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/user-desktop.svg b/images/user-desktop.svg index c4905c5..898963a 100644 --- a/images/user-desktop.svg +++ b/images/user-desktop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/user-trash.svg b/images/user-trash.svg index 9e262bb..7c3cf22 100644 --- a/images/user-trash.svg +++ b/images/user-trash.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/view-refresh.svg b/images/view-refresh.svg index 9e06b76..65cdc39 100644 --- a/images/view-refresh.svg +++ b/images/view-refresh.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/view-sort-ascending.svg b/images/view-sort-ascending.svg index 10fc675..f041e7d 100644 --- a/images/view-sort-ascending.svg +++ b/images/view-sort-ascending.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/view-sort-descending.svg b/images/view-sort-descending.svg index 5a73a24..488c65e 100644 --- a/images/view-sort-descending.svg +++ b/images/view-sort-descending.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/images/window-close.svg b/images/window-close.svg index 03b1b9d..5a6f04e 100644 --- a/images/window-close.svg +++ b/images/window-close.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/man/audtool.1.in b/man/audtool.1.in index 048a22b..a1ca8b6 100644 --- a/man/audtool.1.in +++ b/man/audtool.1.in @@ -370,13 +370,14 @@ them at \fIhttps://redmine.audacious-media-player.org/projects/audacious\fR. .SH AUTHORS .B audtool -was written by George Averill and William -Pitcock . +was written by George Averill and Ariadne +Conill . .PP This manual page was written by Adam Cecile and Kiyoshi -Aman . Some additional tweaks were done by William Pitcock - and Tony Vroon . The manual page was -updated for Audacious 3.7 and later by John Lindgren . +Aman . Some additional tweaks were done by Ariadne Conill + and Tony Vroon . The manual +page was updated for Audacious 3.7 and later by John Lindgren +. .PP This work is licensed under a Creative Commons Attribution 3.0 Unported License . diff --git a/man/meson.build b/man/meson.build new file mode 100644 index 0000000..d65eca2 --- /dev/null +++ b/man/meson.build @@ -0,0 +1,9 @@ +mans = ['audtool.1', 'audacious.1'] + +foreach man : mans + configure_file(input: '@0@.in'.format(man), + output: man, + configuration: conf, + install: true, + install_dir: join_paths(get_option('mandir'), 'man1')) +endforeach diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..450277d --- /dev/null +++ b/meson.build @@ -0,0 +1,154 @@ +project('audacious', 'c', 'cpp', + version: '4.0-devel', + meson_version: '>= 0.50') + + +copyright = 'Copyright (C) 2001-2020 Audacious developers and others' + + +qt5 = import('qt5') +gnome = import('gnome') + + +glib_req = '>= 2.32' +glib_dep = dependency('glib-2.0', version: glib_req, required: true) +gmodule_dep = dependency('gmodule-2.0', version: glib_req, required: true) + + +if get_option('qt') + qt_req = '>= 5.2' + qt_dep = dependency('qt5', version: qt_req, required: true, modules: ['Core', 'Widgets', 'Gui']) +endif + + +cc = meson.get_compiler('c') +cxx = meson.get_compiler('cpp') + + +if cc.get_id() == 'gcc' or cc.get_id() == 'clang' + common_flags = [ + '-pipe', + '-ffast-math', + '-Wall', + '-Wtype-limits', + '-Wno-stringop-truncation' + ] + + cxx_flags = [ + '-Wno-non-virtual-dtor', + '-Woverloaded-virtual' + ] + + check_cflags = ['-std=gnu99'] + common_flags + check_cxxflags = ['-std=gnu++11'] + common_flags + cxx_flags + + foreach arg : check_cflags + if cc.has_argument(arg) + add_project_arguments(arg, language: 'c') + endif + endforeach + + foreach arg : check_cxxflags + if cxx.has_argument(arg) + add_project_arguments(arg, language: 'cpp') + endif + endforeach +endif + + +conf = configuration_data() +conf.set_quoted('BUILDSTAMP', '???') +conf.set_quoted('COPYRIGHT', copyright) +conf.set_quoted('PACKAGE', meson.project_name()) +conf.set_quoted('VERSION', meson.project_version()) +conf.set('PACKAGE_VERSION', meson.project_version()) +if host_machine.endian() == 'big' + conf.set10('WORDS_BIGENDIAN', true) + conf.set10('BIGENDIAN', true) +else + conf.set10('BIGENDIAN', false) +endif + + +# XXX - investigate to see if we can do better +conf.set_quoted('PLUGIN_SUFFIX', '.so') +if host_machine.system() == 'windows' + conf.set_quoted('PLUGIN_SUFFIX', '.dll') +elif host_machine.system() == 'darwin' + conf.set_quoted('PLUGIN_SUFFIX', '.dylib') +endif + + +if host_machine.system() == 'windows' + conf.set('EXPORT', '__declspec(dllexport)') + conf.set_quoted('PLUGIN_SUFFIX', '.dll') +elif cc.get_id() == 'gcc' or cc.get_id() == 'clang' + add_project_arguments('-fvisibility=hidden', language: 'c') + add_project_arguments('-fvisibility=hidden', language: 'cpp') + conf.set('EXPORT', '__attribute__((visibility("default")))') +endif + + +install_bindir = get_option('bindir') +install_datadir = join_paths(get_option('datadir'), 'audacious') +install_plugindir = join_paths(get_option('libdir'), 'audacious') +install_localedir = get_option('localedir') +install_desktoppath = join_paths(get_option('datadir'), 'applications') +install_desktopfile = join_paths(install_desktoppath, 'audacious.desktop') +install_iconpath = join_paths(get_option('datadir'), 'icons') +install_unscalable_iconpath = join_paths(install_iconpath, 'hicolor', '48x48', 'apps') +install_scalable_iconpath = join_paths(install_iconpath, 'hicolor', 'scalable', 'apps') +install_iconfile = join_paths(install_unscalable_iconpath, 'audacious.png') + + +conf.set_quoted('INSTALL_BINDIR', join_paths(get_option('prefix'), install_bindir)) +conf.set_quoted('INSTALL_DATADIR', join_paths(get_option('prefix'), install_datadir)) +conf.set_quoted('INSTALL_PLUGINDIR', join_paths(get_option('prefix'), install_plugindir)) +conf.set_quoted('INSTALL_LOCALEDIR', join_paths(get_option('prefix'), install_localedir)) +conf.set_quoted('INSTALL_DESKTOPFILE', join_paths(get_option('prefix'), install_desktopfile)) +conf.set_quoted('INSTALL_ICONFILE', join_paths(get_option('prefix'), install_iconfile)) +conf.set('plugindir', install_plugindir) +conf.set('datarootdir', get_option('datadir')) + + +if get_option('dbus') + conf.set10('USE_DBUS', true) +endif + + +if get_option('qt') + conf.set10('USE_QT', true) +endif + + +subdir('src') +subdir('po') +subdir('man') +subdir('images') + + +install_data('AUTHORS', 'COPYING') + + +install_data('audacious.desktop', install_dir: install_desktoppath) + + +pkg = import('pkgconfig') + +# When Meson fixes the utter disappointment that is +# https://github.com/mesonbuild/meson/issues/5836, +# use libaudcore_lib as base dependency here. +pkg.generate( + libraries: ['-L${libdir} -laudcore'], + variables: [ + 'plugin_dir=${libdir}/audacious', + + # Appease broken third-party plugin build systems. + 'audacious_include_dir=${includedir}', + 'include_dir=${includedir}', + 'lib_dir=${libdir}' + ], + description: 'versatile and handy multi platform media player', + name: 'audacious', + url: 'https://audacious-media-player.org' +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..6942ba6 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,4 @@ +option('dbus', type: 'boolean', value: true, + description: 'Whether DBus support is enabled') +option('qt', type: 'boolean', value: true, + description: 'Whether Qt support is enabled') diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..587c36f --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,46 @@ +ar +be +bg +ca +cmn +cs +da +de +el +en_GB +es_AR +es_MX +es +et +eu +fa_IR +fi +fr +gl +hu +id_ID +it +ja +ko +ky +lt +lv +ml_IN +ms +nl +pl +pt_BR +pt_PT +ro +ru +si +sk +sr +sr_RS +sv +ta +tr +uk +zh_CN +zh_TW + diff --git a/po/bg.po b/po/bg.po index f1feada..0e4c2c7 100644 --- a/po/bg.po +++ b/po/bg.po @@ -7,7 +7,7 @@ # Elusiv_man , 2014 # Ivailo Monev , 2014 # Kiril Kirilov (Cybercop) , 2012 -# Kiril Kirilov , 2014-2015,2018 +# Kiril Kirilov , 2014-2015 # Myselus, 2016-2017 # Pandi3a , 2012 # Pandi3a , 2012 @@ -20,8 +20,8 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: Kiril Kirilov \n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: Радослав Иванов \n" "Language-Team: Bulgarian (http://www.transifex.com/audacious/audacious/" "language/bg/)\n" "Language: bg\n" @@ -847,7 +847,7 @@ msgstr "Разширения" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Разширени" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -1132,11 +1132,11 @@ msgstr "Показване на часовете отделно (1:30:00 с/у 9 #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Изнасяне" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "Използване на алтернативни пътища, когато е възможно" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1189,15 +1189,15 @@ msgstr "Знакът „\\“ да се тълкува като разделит #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Списък" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Рекурсивно добавяне на папки" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Добавяне на папки, включени в списъци за изпълнение" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1338,7 +1338,7 @@ msgstr "Информация" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Запазване в историята" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1350,7 +1350,7 @@ msgstr "Добавяне на интернет адрес" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "_Изчистване на историята" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" diff --git a/po/cs.po b/po/cs.po index dc88fe2..6e34933 100644 --- a/po/cs.po +++ b/po/cs.po @@ -18,14 +18,14 @@ # fri, 2012 # Petr Písař , 2007-2012 # Petr Šimáček , 2014,2017 -# Roman Horník , 2016,2018 +# Roman Horník , 2016 msgid "" msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: Roman Horník \n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: John Lindgren \n" "Language-Team: Czech (http://www.transifex.com/audacious/audacious/language/" "cs/)\n" "Language: cs\n" @@ -818,7 +818,7 @@ msgstr "_Nastavení" #: src/libaudgui/prefs-window.cc:742 src/libaudqt/prefs-window-qt.cc:596 #: src/libaudqt/prefs-window-qt.cc:599 msgid "_About" -msgstr "_O programu" +msgstr "_O Programu" #: src/libaudgui/prefs-widget.cc:277 msgid "Choose File" @@ -852,7 +852,7 @@ msgstr "Moduly" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Pokročilé" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -1020,7 +1020,7 @@ msgstr "ms" #: src/libaudgui/prefs-window.cc:218 src/libaudqt/prefs-window-qt.cc:248 msgid "Soft clipping" -msgstr "Měkké oříznutí" +msgstr "Měké oříznutí" #: src/libaudgui/prefs-window.cc:220 src/libaudqt/prefs-window-qt.cc:250 msgid "Use software volume control (not recommended)" @@ -1084,7 +1084,7 @@ msgstr "Používat proxy" #: src/libaudgui/prefs-window.cc:268 src/libaudqt/prefs-window-qt.cc:298 msgid "Use authentication with proxy" -msgstr "Použít ověřování pomocí proxy serveru" +msgstr "Autentizovat se na proxy" #: src/libaudgui/prefs-window.cc:275 src/libaudqt/prefs-window-qt.cc:305 msgid "Auto character encoding detector for:" @@ -1112,7 +1112,7 @@ msgstr "Přejít dál, když současná skladba je smazána" #: src/libaudgui/prefs-window.cc:294 src/libaudqt/prefs-window-qt.cc:324 msgid "Clear the playlist when opening files" -msgstr "Při otevírání souborů vyprázdnit seznam skladeb" +msgstr "Při otvírání souborů vyprázdnit seznam skladeb" #: src/libaudgui/prefs-window.cc:296 src/libaudqt/prefs-window-qt.cc:326 msgid "Open files in a temporary playlist" @@ -1136,11 +1136,11 @@ msgstr "Zobrazit hodiny odděleně (1:30:00 oproti 90:00)" #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Exportovat" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "Použít relativní cesty kdykoliv je to možné" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1156,7 +1156,7 @@ msgstr "Vyloučit obrázky vyhovují těmto slovům (oddělené čárkou):" #: src/libaudgui/prefs-window.cc:317 src/libaudqt/prefs-window-qt.cc:347 msgid "Search for images matching song file name" -msgstr "Hledat obrázky odpovídající názvu hudebního souboru" +msgstr "Hledat obrázky odpovídající názevu hudebního souboru" #: src/libaudgui/prefs-window.cc:319 src/libaudqt/prefs-window-qt.cc:349 msgid "Search recursively" @@ -1172,7 +1172,7 @@ msgstr "Vyskakovací okno s podrobnostmi" #: src/libaudgui/prefs-window.cc:326 src/libaudqt/prefs-window-qt.cc:356 msgid "Show popup information" -msgstr "Zobrazit informace ve vyskakovacím oknu" +msgstr "Zobrazit popup informace" #: src/libaudgui/prefs-window.cc:328 src/libaudqt/prefs-window-qt.cc:358 msgid "Popup delay (tenths of a second):" @@ -1188,19 +1188,19 @@ msgstr "Kompatibilita" #: src/libaudgui/prefs-window.cc:339 src/libaudqt/prefs-window-qt.cc:369 msgid "Interpret \\ (backward slash) as a folder delimiter" -msgstr "Interpretovat \\ (zpětné lomítko) jako oddělovač složek" +msgstr "Interpret \\ (zpětné lomítko) jako oddělovač složky" #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Playlist" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Přidat složky rekurzivně" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Přidat složky vnořené do souborů playlistu" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1341,7 +1341,7 @@ msgstr "Informace" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Uložit do historie" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1353,7 +1353,7 @@ msgstr "Přidat URL" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "_Vyčistit historii" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" diff --git a/po/da.po b/po/da.po index ac19a49..4fefca4 100644 --- a/po/da.po +++ b/po/da.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-07-03 21:07+0000\n" "Last-Translator: scootergrisen\n" "Language-Team: Danish (http://www.transifex.com/audacious/audacious/language/" "da/)\n" @@ -280,7 +280,7 @@ msgstr "Om Audacious" #: src/libaudqt/playlist-management.cc:75 src/libaudqt/prefs-plugin.cc:131 #: src/libaudqt/url-opener-qt.cc:79 msgid "_Cancel" -msgstr "_Annuller" +msgstr "_Afbryd" #: src/libaudgui/confirm.cc:51 src/libaudqt/playlist-management.cc:73 msgid "_Don’t ask again" @@ -494,7 +494,7 @@ msgstr "Kvalitet:" #: src/libaudgui/infowin.cc:52 msgid "Bitrate:" -msgstr "Bithastighed:" +msgstr "Bitfrekvens:" #: src/libaudgui/infowin.cc:86 msgid "Acid Jazz" @@ -1265,7 +1265,7 @@ msgstr "Indstillinger for Audacious" #: src/libaudgui/preset-browser.cc:50 src/libaudgui/util.cc:172 msgid "Cancel" -msgstr "Annuller" +msgstr "Afbryd" #: src/libaudgui/preset-browser.cc:51 msgid "Save" @@ -1394,7 +1394,7 @@ msgstr "Teknisk" #: src/libaudqt/info-widget.cc:58 msgid "Bitrate" -msgstr "Bithastighed" +msgstr "Bitfrekvens" #: src/libaudqt/log-inspector.cc:137 msgid "Level" diff --git a/po/de.po b/po/de.po index eedd2da..5cc7e25 100644 --- a/po/de.po +++ b/po/de.po @@ -18,7 +18,7 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-08-04 20:29+0200\n" "Last-Translator: Thomas Lange\n" "Language-Team: German (http://www.transifex.com/audacious/audacious/language/" "de/)\n" @@ -1451,6 +1451,3 @@ msgstr "Dienste" #: src/libaudqt/util-qt.cc:80 msgid "Copy" msgstr "Kopieren" - -#~ msgid "Plugins ..." -#~ msgstr "Plugins ..." diff --git a/po/el.po b/po/el.po index 66d7b0b..bf214da 100644 --- a/po/el.po +++ b/po/el.po @@ -20,8 +20,8 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: Ioannis LM\n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: Γιάννης Ανθυμίδης\n" "Language-Team: Greek (http://www.transifex.com/audacious/audacious/language/" "el/)\n" "Language: el\n" @@ -533,7 +533,7 @@ msgstr "Bluegrass" #: src/libaudgui/infowin.cc:91 msgid "Blues" -msgstr "Blues" +msgstr "Μπλουζ" #: src/libaudgui/infowin.cc:92 msgid "Chamber Music" @@ -545,7 +545,7 @@ msgstr "Κλασική Μουσική" #: src/libaudgui/infowin.cc:94 msgid "Country" -msgstr "Country" +msgstr "Κάντρι" #: src/libaudgui/infowin.cc:95 msgid "Death Metal" @@ -553,7 +553,7 @@ msgstr "Death Metal" #: src/libaudgui/infowin.cc:96 msgid "Disco" -msgstr "Disco" +msgstr "Ντίσκο" #: src/libaudgui/infowin.cc:97 msgid "Easy Listening" @@ -561,11 +561,11 @@ msgstr "Easy Listening" #: src/libaudgui/infowin.cc:98 msgid "Folk" -msgstr "Folk" +msgstr "Φολκ" #: src/libaudgui/infowin.cc:99 msgid "Funk" -msgstr "Funk" +msgstr "Φανκ" #: src/libaudgui/infowin.cc:100 msgid "Gangsta Rap" @@ -589,7 +589,7 @@ msgstr "Heavy Metal" #: src/libaudgui/infowin.cc:105 msgid "Hip-hop" -msgstr "Hip-hop" +msgstr "Χιπ χοπ" #: src/libaudgui/infowin.cc:106 msgid "House" @@ -597,7 +597,7 @@ msgstr "House" #: src/libaudgui/infowin.cc:107 msgid "Jazz" -msgstr "Jazz" +msgstr "Τζαζ" #: src/libaudgui/infowin.cc:108 msgid "Jungle" @@ -605,7 +605,7 @@ msgstr "Jungle" #: src/libaudgui/infowin.cc:109 msgid "Metal" -msgstr "Metal" +msgstr "Μέταλ" #: src/libaudgui/infowin.cc:110 msgid "New Age" @@ -621,7 +621,7 @@ msgstr "Noise" #: src/libaudgui/infowin.cc:113 msgid "Pop" -msgstr "Pop" +msgstr "Ποπ" #: src/libaudgui/infowin.cc:114 msgid "Punk Rock" @@ -629,15 +629,15 @@ msgstr "Punk Rock" #: src/libaudgui/infowin.cc:115 msgid "Rap" -msgstr "Rap" +msgstr "Ραπ" #: src/libaudgui/infowin.cc:116 msgid "Reggae" -msgstr "Reggae" +msgstr "Ρέγκε" #: src/libaudgui/infowin.cc:117 msgid "Rock" -msgstr "Rock" +msgstr "Ροκ" #: src/libaudgui/infowin.cc:118 msgid "Rock and Roll" @@ -657,11 +657,11 @@ msgstr "Soul" #: src/libaudgui/infowin.cc:122 msgid "Swing" -msgstr "Swing" +msgstr "Σουίνγκ" #: src/libaudgui/infowin.cc:123 msgid "Techno" -msgstr "Techno" +msgstr "Τέκνο" #: src/libaudgui/infowin.cc:124 msgid "Trip-hop" @@ -827,7 +827,7 @@ msgstr "Επιλογή αρχείου" #: src/libaudgui/prefs-widget.cc:281 msgid "Choose Folder" -msgstr "Επιλογή φακέλου" +msgstr "Επιλογή Φακέλου" #: src/libaudgui/prefs-window.cc:82 src/libaudqt/prefs-window-qt.cc:136 msgid "Appearance" @@ -853,7 +853,7 @@ msgstr "Πρόσθετα" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Προχωρημένα" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -1037,7 +1037,7 @@ msgstr "Καταγραφή ροής:" #: src/libaudgui/prefs-window.cc:229 src/libaudqt/prefs-window-qt.cc:259 msgid "ReplayGain" -msgstr "ReplayGain (ομαλοποίηση έντασης)" +msgstr "ReplayGain" #: src/libaudgui/prefs-window.cc:230 src/libaudqt/prefs-window-qt.cc:260 msgid "Enable ReplayGain" @@ -1137,11 +1137,11 @@ msgstr "Εμφάνιση της ώρας χωριστά (1:30:00 αντί 90:00) #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Εξαγωγή" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "Χρήση των σχετικών διαδρομών, όταν είναι δυνατόν" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1150,12 +1150,12 @@ msgstr "Άλμπουμ" #: src/libaudgui/prefs-window.cc:313 src/libaudqt/prefs-window-qt.cc:343 msgid "Search for images matching these words (comma-separated):" msgstr "" -"Αναζήτηση εικόνων που ταιριάζουν με τις λέξεις (διαχωρισμένες με κόμμα):" +"Αναζήτηση εικόνων που ταιριάζουν με αυτά τα λόγια (διαχωρισμένα με κόμμα):" #: src/libaudgui/prefs-window.cc:315 src/libaudqt/prefs-window-qt.cc:345 msgid "Exclude images matching these words (comma-separated):" msgstr "" -"Εξαίρεση εικόνων που ταιριάζουν με τις λέξεις (διαχωρισμένες με κόμμα):" +"Εξαίρεση εικόνων που ταιριάζουν με αυτά τα λόγια (διαχωρισμένα με κόμμα):" #: src/libaudgui/prefs-window.cc:317 src/libaudqt/prefs-window-qt.cc:347 msgid "Search for images matching song file name" @@ -1163,7 +1163,7 @@ msgstr "Αναζήτηση εικόνων που ταιριάζουν με το #: src/libaudgui/prefs-window.cc:319 src/libaudqt/prefs-window-qt.cc:349 msgid "Search recursively" -msgstr "Αναδρομική αναζήτηση" +msgstr "Αναζήτηση αναδρομικά" #: src/libaudgui/prefs-window.cc:321 src/libaudqt/prefs-window-qt.cc:351 msgid "Search depth:" @@ -1195,15 +1195,15 @@ msgstr "Εξήγηση με \\\\ (αντιπλάγια μπάρα) ως διαχ #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Λίστα αναπαραγωγής" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Αναδρομική προσθήκη φακέλων" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Προσθήκη των ενσωματωμένων φακέλων στα αρχεία της λίστας αναπαραγωγής" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1316,7 +1316,7 @@ msgstr "Αποθήκευση αρχείου EQF" #: src/libaudgui/preset-browser.cc:127 msgid ".eqf" -msgstr ".eqf" +msgstr "<όνομα>.eqf" #: src/libaudgui/preset-browser.cc:141 msgid "Import Winamp Presets" @@ -1344,7 +1344,7 @@ msgstr "Πληροφόρηση" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Αποθήκευση" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1356,7 +1356,7 @@ msgstr "Προσθήκη διεύθυνσης URL" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "_Καθαρισμός ιστορικού" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" diff --git a/po/en_GB.po b/po/en_GB.po index a4bf379..d6cd915 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -3,13 +3,13 @@ # This file is distributed under the same license as the Audacious package. # # Translators: -# Andi Chandler , 2013,2015-2018 +# Andi Chandler , 2013,2015-2017 msgid "" msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/audacious/" "audacious/language/en_GB/)\n" @@ -835,7 +835,7 @@ msgstr "Plug-ins" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Advanced" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -1119,11 +1119,11 @@ msgstr "Show hours separately (1:30:00 vs. 90:00)" #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Export" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "Use relative paths when possible" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1175,15 +1175,15 @@ msgstr "Interpret \\ (backward slash) as a folder delimiter" #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Playlist" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Add folders recursively" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Add folders nested within playlist files" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1324,7 +1324,7 @@ msgstr "Information" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Save to history" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1336,7 +1336,7 @@ msgstr "Add URL" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "C_lear history" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" @@ -1437,7 +1437,7 @@ msgstr "Services" #: src/libaudqt/util-qt.cc:80 msgid "Copy" -msgstr "Copy" +msgstr "" #~ msgid "Plugins ..." #~ msgstr "Plugins ..." diff --git a/po/fr.po b/po/fr.po index 5c6c362..e79fda9 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3,23 +3,23 @@ # This file is distributed under the same license as the Audacious package. # # Translators: -# AO , 2012-2013 -# AO , 2017-2018 -# AO , 2016 -# AO , 2016 +# French language coordinator , 2012-2013 +# French language coordinator , 2017-2018 +# French language coordinator , 2016 +# French language coordinator , 2016 # Oxayotl , 2013-2014 # Oxayotl , 2011-2012 # Oxayotl , 2011 # Oxayotl , 2011,2013 -# AO , 2015 -# AO , 2013-2015 +# French language coordinator , 2015 +# French language coordinator , 2013-2015 msgid "" msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: AO \n" +"PO-Revision-Date: 2018-07-04 21:45+0000\n" +"Last-Translator: French language coordinator \n" "Language-Team: French (http://www.transifex.com/audacious/audacious/language/" "fr/)\n" "Language: fr\n" diff --git a/po/id_ID.po b/po/id_ID.po index c2bfe0d..d6dfd9f 100644 --- a/po/id_ID.po +++ b/po/id_ID.po @@ -24,15 +24,15 @@ # , 2012 # , 2012 # se7entime , 2012 -# Adrianus Yoza Aprilio , 2012 -# Adrianus Yoza Aprilio , 2012 -# Adrianus Yoza Aprilio , 2012 +# Yoza Aprilio , 2012 +# Yoza Aprilio , 2012 +# Yoza Aprilio , 2012 msgid "" msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" "Last-Translator: Rahman Yusri Aftian \n" "Language-Team: Indonesian (Indonesia) (http://www.transifex.com/audacious/" "audacious/language/id_ID/)\n" diff --git a/po/ja.po b/po/ja.po index 3a05e6d..1dcfc41 100644 --- a/po/ja.po +++ b/po/ja.po @@ -4,7 +4,7 @@ # # Translators: # ABE Tsunehiko, 2013 -# ABE Tsunehiko, 2015-2018 +# ABE Tsunehiko, 2015-2017 # natird zoto , 2012 # ABE Tsunehiko, 2013 # Nastuko Toda , 2012 @@ -21,8 +21,8 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: ABE Tsunehiko\n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: TAKAHASHI Shuuji \n" "Language-Team: Japanese (http://www.transifex.com/audacious/audacious/" "language/ja/)\n" "Language: ja\n" @@ -845,7 +845,7 @@ msgstr "プラグイン" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "高度" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -1129,11 +1129,11 @@ msgstr "時分秒表示を使う (例 1:30:00)" #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "エクスポート" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "可能な限り相対パスを使う" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1185,15 +1185,15 @@ msgstr "\\ (バックスラッシュ) をフォルダーの区切り文字とし #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "プレイリスト" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "再帰的にフォルダーを追加する" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "プレイリスト内に入れ子にされたフォルダーを追加する" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1334,7 +1334,7 @@ msgstr "情報" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "履歴に追加 (_S)" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1346,7 +1346,7 @@ msgstr "URL を追加" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "履歴を削除 (_L)" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 0000000..e05db57 --- /dev/null +++ b/po/meson.build @@ -0,0 +1,15 @@ +i18n = import('i18n') + + +i18n.gettext('audacious', + args: [ + '--default-domain=audacious', + '--language=C', + '--keyword=_', + '--keyword=N_', + '--from-code=UTF-8', + '--msgid-bugs-address="https://redmine.audacious-media-player.org/"', + '--directory=%0%'.format(meson.source_root()), + '--files-from=POTFILES.in' + ] +) diff --git a/po/pl.po b/po/pl.po index 54752d8..1482e68 100644 --- a/po/pl.po +++ b/po/pl.po @@ -27,7 +27,7 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-07-02 06:30+0000\n" "Last-Translator: No Ne\n" "Language-Team: Polish (http://www.transifex.com/audacious/audacious/language/" "pl/)\n" @@ -85,7 +85,7 @@ msgstr "Wyświetl główne okno programu" #: src/audacious/main.cc:76 msgid "Display the jump-to-song window" -msgstr "Wyświetla okno przejścia do piosenki" +msgstr "Wyświetla okno \"Przejdź do ścieżki\"" #: src/audacious/main.cc:77 msgid "Start without a graphical interface" @@ -231,7 +231,7 @@ msgstr "Błąd wczytywania wtyczki" #: src/libaudcore/probe.cc:171 msgid "Seek error" -msgstr "Błąd wyszukiwania" +msgstr "Znajdź błąd" #: src/libaudcore/probe.cc:179 msgid "File format not recognized" @@ -500,7 +500,7 @@ msgstr "Rok wydania" #: src/libaudgui/infopopup.cc:210 src/libaudgui/prefs-window.cc:147 #: src/libaudqt/infopopup-qt.cc:126 src/libaudqt/prefs-window-qt.cc:192 msgid "Track" -msgstr "Ścieżka" +msgstr "Utwór" #: src/libaudgui/infopopup.cc:211 src/libaudqt/infopopup-qt.cc:128 #: src/libaudqt/info-widget.cc:55 @@ -686,11 +686,11 @@ msgstr "Błąd zapisu" #: src/libaudgui/infowin.cc:306 src/libaudgui/prefs-window.cc:86 #: src/libaudqt/infowin-qt.cc:123 src/libaudqt/prefs-window-qt.cc:140 msgid "Song Info" -msgstr "Informacje o piosence" +msgstr "Informacje o nagraniu" #: src/libaudgui/infowin.cc:360 src/libaudqt/info-widget.cc:47 msgid "Album Artist" -msgstr "Wykonawca albumu" +msgstr "Artysta albumu" #: src/libaudgui/infowin.cc:363 src/libaudgui/prefs-window.cc:111 #: src/libaudqt/info-widget.cc:46 src/libaudqt/prefs-window-qt.cc:156 @@ -699,11 +699,11 @@ msgstr "Komentarz" #: src/libaudgui/infowin.cc:373 src/libaudqt/info-widget.cc:44 msgid "Track Number" -msgstr "Numer ścieżki" +msgstr "Numer nagrania" #: src/libaudgui/infowin.cc:380 msgid "Clea_r fields when moving to next song" -msgstr "Czyść pola podczas p_rzechodzenia do następnej piosenki" +msgstr "Czyść pola podczas p_rzechodzenia do następnego utworu" #: src/libaudgui/infowin.cc:394 src/libaudqt/infowin-qt.cc:148 msgid "_Save" @@ -745,7 +745,7 @@ msgstr "U_suń z kolejki" #: src/libaudgui/jump-to-track.cc:240 msgid "Jump to Song" -msgstr "Przejdź do piosenki" +msgstr "Przejdź do ścieżki" #: src/libaudgui/jump-to-track.cc:265 msgid "Filter: " @@ -884,7 +884,7 @@ msgstr "Transport" #: src/libaudgui/prefs-window.cc:103 src/libaudqt/prefs-window-qt.cc:148 msgid "Album artist" -msgstr "Wykonawca albumu" +msgstr "Artysta albumu" #: src/libaudgui/prefs-window.cc:105 src/libaudqt/prefs-window-qt.cc:150 msgid "Track number" @@ -1116,7 +1116,7 @@ msgstr "Wstrzymaj zamiast natychmiastowego wznowienia" #: src/libaudgui/prefs-window.cc:292 src/libaudqt/prefs-window-qt.cc:322 msgid "Advance when the current song is deleted" -msgstr "Przejdź do następnej, gdy usunę odtwarzaną piosenkę" +msgstr "Przejdź do następnej gdy usunę odtwarzaną ścieżkę" #: src/libaudgui/prefs-window.cc:294 src/libaudqt/prefs-window-qt.cc:324 msgid "Clear the playlist when opening files" @@ -1128,11 +1128,11 @@ msgstr "Dodaj pliki do tymczasowej listy odtwarzania" #: src/libaudgui/prefs-window.cc:298 src/libaudqt/prefs-window-qt.cc:328 msgid "Song Display" -msgstr "Wyświetlanie piosenki" +msgstr "Wyświetlanie ścieżki" #: src/libaudgui/prefs-window.cc:299 src/libaudqt/prefs-window-qt.cc:329 msgid "Show song numbers" -msgstr "Pokaż numery piosenek" +msgstr "Numery ścieżek" #: src/libaudgui/prefs-window.cc:301 src/libaudqt/prefs-window-qt.cc:331 msgid "Show leading zeroes (02:00 vs. 2:00)" @@ -1164,7 +1164,7 @@ msgstr "Wyklucz obrazy pasujące do tych słów (oddzielone przecinkiem):" #: src/libaudgui/prefs-window.cc:317 src/libaudqt/prefs-window-qt.cc:347 msgid "Search for images matching song file name" -msgstr "Wyszukaj obrazy pasujące do nazwy pliku piosenki" +msgstr "Wyszukaj obrazy pasujące do nazwy pliku utworu" #: src/libaudgui/prefs-window.cc:319 src/libaudqt/prefs-window-qt.cc:349 msgid "Search recursively" @@ -1188,7 +1188,7 @@ msgstr "Opóźnij wyskakujące komunikaty (dziesiąte sekundy):" #: src/libaudgui/prefs-window.cc:332 src/libaudqt/prefs-window-qt.cc:362 msgid "Show time scale for current song" -msgstr "Pokaż skalę czasową dla bieżącej piosenki" +msgstr "Pokaż skalę czasową dla bieżącej ścieżki" #: src/libaudgui/prefs-window.cc:338 src/libaudqt/prefs-window-qt.cc:368 msgid "Compatibility" @@ -1220,7 +1220,7 @@ msgstr "Odgadnij brakujące metadane ze ścieżki pliku" #: src/libaudgui/prefs-window.cc:350 src/libaudqt/prefs-window-qt.cc:380 msgid "Do not load metadata for songs until played" -msgstr "Opóźnij wczytywanie metadanych piosenek do czasu odtworzenia" +msgstr "Opóźnij wczytywanie metadanych ścieżek do czasu odtworzenia" #: src/libaudgui/prefs-window.cc:352 src/libaudqt/prefs-window-qt.cc:382 msgid "Probe content of files with no recognized file name extension" diff --git a/po/pt_BR.po b/po/pt_BR.po index 9f19e7c..3d93fab 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -4,7 +4,6 @@ # # Translators: # Alexandro Casanova , 2012-2014 -# Bruno Lima , 2018 # Cleber de Souza Corrêa , 2014 # Cleiton Lima , 2011 # Cleiton Lima , 2011 @@ -23,7 +22,6 @@ # Rodrigo de Araujo , 2016 # Rodrigo de Araujo , 2016 # Rodrigo de Almeida Sottomaior Macedo , 2012 -# Rui , 2018 # Alexandro Casanova , 2012-2013 # Alexandro Casanova , 2012 # vitorgatti , 2012 @@ -33,8 +31,9 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: Rui \n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: Rodrigo de Almeida Sottomaior Macedo " +"\n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/audacious/" "audacious/language/pt_BR/)\n" "Language: pt_BR\n" @@ -151,7 +150,7 @@ msgstr "" #: src/libaudcore/adder.cc:445 msgid "No files found." -msgstr "Nenhum arquivo encontrado." +msgstr "Nenum arquivo encontrado." #: src/libaudcore/adder.cc:467 src/libaudcore/playlist.cc:88 msgid "New Playlist" @@ -546,7 +545,7 @@ msgstr "Blues" #: src/libaudgui/infowin.cc:92 msgid "Chamber Music" -msgstr "Chamber Music" +msgstr "Música de cámara" #: src/libaudgui/infowin.cc:93 msgid "Classical" @@ -566,7 +565,7 @@ msgstr "Disco" #: src/libaudgui/infowin.cc:97 msgid "Easy Listening" -msgstr "Easy Listening" +msgstr "Fácil de escutar" #: src/libaudgui/infowin.cc:98 msgid "Folk" @@ -618,15 +617,15 @@ msgstr "Metal" #: src/libaudgui/infowin.cc:110 msgid "New Age" -msgstr "New Age" +msgstr "New age" #: src/libaudgui/infowin.cc:111 msgid "New Wave" -msgstr "New Wave" +msgstr "New wave" #: src/libaudgui/infowin.cc:112 msgid "Noise" -msgstr "Noise" +msgstr "Ruído" #: src/libaudgui/infowin.cc:113 msgid "Pop" @@ -862,7 +861,7 @@ msgstr "Plugins" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Avançado" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -1146,11 +1145,11 @@ msgstr "Mostrar horas separadamente (1:30:00 vs. 90:00)" #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Exportar" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "Use caminhos relativos quando possível" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1204,11 +1203,11 @@ msgstr "" #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Lista de Reprodução" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Adicionar pastas recursivamente" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" @@ -1354,7 +1353,7 @@ msgstr "Informação " #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Adicionar ao histórico" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1366,7 +1365,7 @@ msgstr "Adicionar URL" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "_Limpar histórico" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" diff --git a/po/pt_PT.po b/po/pt_PT.po index 16b4f3d..8935797 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -6,7 +6,6 @@ # Alexandro Casanova , 2012 # Pitxyoki , 2010 # Pitxyoki , 2010 -# Rui , 2018 # Alexandro Casanova , 2012 # Sérgio Marques , 2012-2018 # Alexandro Casanova , 2012 @@ -16,8 +15,8 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: Rui \n" +"PO-Revision-Date: 2018-07-05 23:06+0000\n" +"Last-Translator: Sérgio Marques \n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/audacious/" "audacious/language/pt_PT/)\n" "Language: pt_PT\n" @@ -1190,7 +1189,7 @@ msgstr "Adicionar pastas recursivamente" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Adicionar pastas dentro de ficheiros de listas de reprodução" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" diff --git a/po/ru.po b/po/ru.po index 355eec2..de89566 100644 --- a/po/ru.po +++ b/po/ru.po @@ -7,7 +7,7 @@ # Денис , 2014 # michurin , 2011 # Andrei Stepanov, 2014,2016 -# Andrei Stepanov , 2014,2016 +# Andrei Stepanov, 2014,2016 # Ilyas B Arinov , 2014 # Danila E , 2018 # dartraiden, 2018 @@ -45,7 +45,7 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-07-29 18:16+0000\n" "Last-Translator: dartraiden\n" "Language-Team: Russian (http://www.transifex.com/audacious/audacious/" "language/ru/)\n" diff --git a/po/sv.po b/po/sv.po index 0d1403f..8ce125e 100644 --- a/po/sv.po +++ b/po/sv.po @@ -19,7 +19,7 @@ msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" +"PO-Revision-Date: 2018-07-31 15:57+0000\n" "Last-Translator: Jonatan Nyberg\n" "Language-Team: Swedish (http://www.transifex.com/audacious/audacious/" "language/sv/)\n" @@ -402,7 +402,7 @@ msgstr "16 kHz" #: src/libaudgui/equalizer.cc:129 src/libaudqt/equalizer-qt.cc:142 msgid "Equalizer" -msgstr "Equalizer" +msgstr "Equalisation" #: src/libaudgui/equalizer.cc:143 msgid "Presets ..." @@ -599,7 +599,7 @@ msgstr "Jungle" #: src/libaudgui/infowin.cc:109 msgid "Metal" -msgstr "Metal" +msgstr "Metall" #: src/libaudgui/infowin.cc:110 msgid "New Age" @@ -1161,15 +1161,15 @@ msgstr "Sökdjup:" #: src/libaudgui/prefs-window.cc:325 src/libaudqt/prefs-window-qt.cc:355 msgid "Popup Information" -msgstr "Poppupp-information" +msgstr "Popup-information" #: src/libaudgui/prefs-window.cc:326 src/libaudqt/prefs-window-qt.cc:356 msgid "Show popup information" -msgstr "Visa poppupp-information" +msgstr "Visa popup-information" #: src/libaudgui/prefs-window.cc:328 src/libaudqt/prefs-window-qt.cc:358 msgid "Popup delay (tenths of a second):" -msgstr "Poppupp-fördröjning (tiondelar av en sekund):" +msgstr "Popup-fördröjning (tiondelar av en sekund):" #: src/libaudgui/prefs-window.cc:332 src/libaudqt/prefs-window-qt.cc:362 msgid "Show time scale for current song" diff --git a/po/tr.po b/po/tr.po index 5272030..5e6276a 100644 --- a/po/tr.po +++ b/po/tr.po @@ -9,8 +9,7 @@ # Imnune , 2012 # Ali Orhun Akkirman , 2013 # hsngrms , 2012 -# Dragon Blogger , 2018 -# Dragon Blogger , 2016 +# Dragon xarax , 2016 # Emre FIRAT , 2013 # Emin Tufan , 2016 # Emre FIRAT , 2013 @@ -28,15 +27,14 @@ # M. Tayyip Yel , 2013 # tarkan255 , 2012 # Volkan Gezer , 2014-2015 -# yaşar çiv , 2018 # Zekeriya Cihan , 2013 msgid "" msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: yaşar çiv \n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: Akferzan \n" "Language-Team: Turkish (http://www.transifex.com/audacious/audacious/" "language/tr/)\n" "Language: tr\n" @@ -129,7 +127,7 @@ msgstr "" #: src/audacious/main.cc:185 msgid "Select instance to run/control" -msgstr "Çalıştırılacak/kontrol edilecek örneği seçin" +msgstr "" #: src/audacious/main.cc:367 src/libaudqt/audqt.cc:63 msgid "Audacious" @@ -175,7 +173,7 @@ msgstr "(karakter kodlama hatası)" #: src/libaudcore/drct.cc:96 msgid "" "Stream recording must be configured in Audio Settings before it can be used." -msgstr "Akış kaydı, kullanılmadan önce Ses Ayarları'nda yapılandırılmalıdır." +msgstr "" #: src/libaudcore/output.cc:195 msgid "Error opening output stream" @@ -183,7 +181,7 @@ msgstr "Çıktı akışı açılırken hata" #: src/libaudcore/output.cc:248 msgid "Error recording output stream" -msgstr "Çıkış akışı kaydedilirken hata oluştu" +msgstr "" #: src/libaudcore/playback.cc:373 #, c-format @@ -860,7 +858,7 @@ msgstr "Eklentiler" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Gelişmiş" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -974,7 +972,7 @@ msgstr "Çözüldüğü gibi" #: src/libaudgui/prefs-window.cc:141 src/libaudqt/prefs-window-qt.cc:186 msgid "After applying ReplayGain" -msgstr "ReplayGain'i uyguladıktan sonra" +msgstr "" #: src/libaudgui/prefs-window.cc:142 src/libaudqt/prefs-window-qt.cc:187 msgid "After applying effects" @@ -986,11 +984,11 @@ msgstr "Dengeleme uygulandıktan sonra" #: src/libaudgui/prefs-window.cc:149 src/libaudqt/prefs-window-qt.cc:194 msgid "Based on shuffle" -msgstr "Karıştırmaya dayalı" +msgstr "" #: src/libaudgui/prefs-window.cc:161 src/libaudqt/prefs-window-qt.cc:206 msgid "Interface:" -msgstr "Arayüz:" +msgstr "" #: src/libaudgui/prefs-window.cc:180 src/libaudqt/prefs-window-qt.cc:216 msgid "Output plugin:" @@ -1044,7 +1042,7 @@ msgstr "Akışı kaydet:" #: src/libaudgui/prefs-window.cc:229 src/libaudqt/prefs-window-qt.cc:259 msgid "ReplayGain" -msgstr "ReplayGain" +msgstr "" #: src/libaudgui/prefs-window.cc:230 src/libaudqt/prefs-window-qt.cc:260 msgid "Enable ReplayGain" @@ -1052,7 +1050,7 @@ msgstr "ReplayGain'i etkinleştir" #: src/libaudgui/prefs-window.cc:232 src/libaudqt/prefs-window-qt.cc:262 msgid "Mode:" -msgstr "Mod:" +msgstr "" #: src/libaudgui/prefs-window.cc:236 src/libaudqt/prefs-window-qt.cc:266 msgid "Prevent clipping (recommended)" @@ -1144,11 +1142,11 @@ msgstr "Saatleri ayrı ayrı göster (1:30:00'a karşı 90:00)" #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Dışa1Dışa aktar" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "Mümkün olduğunda göreli yollar kullanın" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1200,15 +1198,15 @@ msgstr "Geriye yatık taksimi ( \\ ) klasör sınırlayıcı olarak yorumla" #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Oynatma Liistesi" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Dizinleri tekrarlı olarak ekle" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Oynatma listesi dosyalarında yuvalanmış dizinler ekle" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1277,7 +1275,7 @@ msgstr "Özel metin:" #: src/libaudgui/prefs-window.cc:756 src/libaudqt/prefs-window-qt.cc:719 #, c-format msgid "Enable audio stream recording with %s" -msgstr "%s ile ses akışı kaydını etkinleştir " +msgstr "" #: src/libaudgui/prefs-window.cc:765 src/libaudqt/prefs-window-qt.cc:730 msgid "No audio recording plugin available" @@ -1313,7 +1311,7 @@ msgstr "Önayar Dosyasını Kaydet" #: src/libaudgui/preset-browser.cc:109 msgid ".preset" -msgstr ".preset" +msgstr "" #: src/libaudgui/preset-browser.cc:127 msgid "Save EQF File" @@ -1321,7 +1319,7 @@ msgstr "EQF Dosyasını Kaydet" #: src/libaudgui/preset-browser.cc:127 msgid ".eqf" -msgstr ".eqf" +msgstr "" #: src/libaudgui/preset-browser.cc:141 msgid "Import Winamp Presets" @@ -1349,7 +1347,7 @@ msgstr "Bilgi" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Geçmişe kaydet" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1361,7 +1359,7 @@ msgstr "URL Ekle" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "Geçmişi temiz_le" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" @@ -1450,7 +1448,7 @@ msgstr "Uyarı" #: src/libaudqt/log-inspector.cc:219 msgid "Cl_ear" -msgstr "Temizl_e" +msgstr "" #: src/libaudqt/log-inspector.cc:232 msgid "Log Level:" diff --git a/po/uk.po b/po/uk.po index 8fff92c..ff9af36 100644 --- a/po/uk.po +++ b/po/uk.po @@ -16,15 +16,15 @@ # Rustam Tsurik , 2013 # Rustam Tsurik , 2013 # Oleg , 2012 -# Taras Holyj, 2017-2018 +# Taras Shevchenko, 2017 # Yaroslav Yenkala , 2016 msgid "" msgstr "" "Project-Id-Version: Audacious\n" "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n" "POT-Creation-Date: 2018-08-04 20:34+0200\n" -"PO-Revision-Date: 2018-12-26 05:38+0000\n" -"Last-Translator: Taras Holyj\n" +"PO-Revision-Date: 2018-07-02 04:50+0000\n" +"Last-Translator: Rax Garfield \n" "Language-Team: Ukrainian (http://www.transifex.com/audacious/audacious/" "language/uk/)\n" "Language: uk\n" @@ -98,7 +98,7 @@ msgstr "Виводити налагоджувальні повідомлення #: src/audacious/main.cc:81 msgid "Run in Qt mode" -msgstr "Запуск у режимі Qt" +msgstr "Запуск в режимі Qt" #: src/audacious/main.cc:138 #, c-format @@ -154,12 +154,12 @@ msgstr "Новий список відтворення" #: src/libaudcore/audstrings.cc:659 src/libaudcore/tuple.cc:520 msgid "Standard input" -msgstr "Стандартний ввід" +msgstr "Стандартний вхід" #: src/libaudcore/audstrings.cc:661 #, c-format msgid "Audio CD, track %s" -msgstr "Авдіодиск, стежка %s" +msgstr "Аудіодиск, доріжка %s" #: src/libaudcore/audstrings.cc:665 src/libaudcore/tuple.cc:496 msgid "(character encoding error)" @@ -189,7 +189,7 @@ msgstr "" #: src/libaudcore/playback.cc:505 msgid "Invalid audio format" -msgstr "Хибний авдіоформат" +msgstr "Хибний формат аудіо" #: src/libaudcore/playlist.cc:89 msgid "Now Playing" @@ -222,7 +222,7 @@ msgstr "Неможливо зберегти %s: непідтримуване р #: src/libaudcore/probe.cc:54 msgid "Error loading plugin" -msgstr "Помилка завантаження втулку" +msgstr "Помилка завантаження модуля" #: src/libaudcore/probe.cc:171 msgid "Seek error" @@ -255,12 +255,12 @@ msgstr[3] "%d каналів" #: src/libaudcore/tuple.cc:768 msgid "Audio CD" -msgstr "Авдіодиск" +msgstr "Аудіодиск" #: src/libaudcore/tuple.cc:850 #, c-format msgid "Track %d" -msgstr "Стежка %d" +msgstr "Доріжка %d" #: src/libaudcore/tuple.cc:855 msgid "(unknown title)" @@ -268,7 +268,7 @@ msgstr "(невідома назва)" #: src/libaudcore/vfs.cc:79 msgid "Unknown URI scheme" -msgstr "Невідома схема ланки" +msgstr "Невідома схема посилання" #: src/libaudcore/vfs_local.cc:85 src/libaudcore/vfs_local.cc:330 #: src/libaudcore/vfs_local.cc:385 @@ -307,15 +307,15 @@ msgstr "_Більше не питати" #: src/libaudgui/confirm.cc:70 src/libaudqt/playlist-management.cc:79 #, c-format msgid "Do you want to permanently remove “%s”?" -msgstr "Чи ви хочете усунути “%s”?" +msgstr "Ви хочете видалити “%s”?" #: src/libaudgui/confirm.cc:73 src/libaudqt/playlist-management.cc:74 msgid "_Remove" -msgstr "_Усунути" +msgstr "_Видалити" #: src/libaudgui/confirm.cc:76 src/libaudqt/playlist-management.cc:78 msgid "Remove Playlist" -msgstr "Усунення списку відтворення" +msgstr "Видалення списку відтворення" #: src/libaudgui/confirm.cc:95 src/libaudqt/playlist-management.cc:40 msgid "What would you like to call this playlist?" @@ -323,19 +323,19 @@ msgstr "Як би Ви хотіли назвати цей список відт #: src/libaudgui/confirm.cc:96 src/libaudqt/playlist-management.cc:42 msgid "_Rename" -msgstr "_Змінити назву" +msgstr "_Перейменувати" #: src/libaudgui/confirm.cc:97 src/libaudqt/playlist-management.cc:62 msgid "Rename Playlist" -msgstr "Зміна назви списку відтворення" +msgstr "Перейменування списку відтворення" #: src/libaudgui/eq-preset.cc:208 src/libaudgui/eq-preset.cc:215 msgid "Preset File ..." -msgstr "Файл пресетів ..." +msgstr "Файл налаштувань ..." #: src/libaudgui/eq-preset.cc:209 src/libaudgui/eq-preset.cc:216 msgid "EQF File ..." -msgstr "Файл налаштувань еквалайзеру ..." +msgstr "Файл налаштувань еквалайзера ..." #: src/libaudgui/eq-preset.cc:211 msgid "Winamp Presets ..." @@ -343,15 +343,15 @@ msgstr "Файл налаштувань Winamp ..." #: src/libaudgui/eq-preset.cc:220 src/libaudqt/fileopener.cc:70 msgid "Import" -msgstr "Імпортування" +msgstr "Імпорт" #: src/libaudgui/eq-preset.cc:221 src/libaudqt/fileopener.cc:71 msgid "Export" -msgstr "Експортування" +msgstr "Експорт" #: src/libaudgui/eq-preset.cc:236 msgid "Equalizer Presets" -msgstr "Налаштування еквалайзеру" +msgstr "Налаштування еквалайзера" #: src/libaudgui/eq-preset.cc:258 msgid "Save Preset" @@ -423,7 +423,9 @@ msgstr "Скинути на нуль" #: src/libaudgui/equalizer.cc:154 src/libaudqt/equalizer-qt.cc:123 msgid "Preamp" -msgstr "Попереднє підсилення" +msgstr "" +"Попереднє\n" +"підсилення" #: src/libaudgui/file-opener.cc:78 src/libaudqt/fileopener.cc:57 msgid "Open Files" @@ -484,7 +486,7 @@ msgstr "Альбом" #: src/libaudgui/prefs-window.cc:106 src/libaudqt/infopopup-qt.cc:122 #: src/libaudqt/info-widget.cc:45 src/libaudqt/prefs-window-qt.cc:151 msgid "Genre" -msgstr "Напрямок" +msgstr "Жанр" #: src/libaudgui/infopopup.cc:209 src/libaudgui/infowin.cc:370 #: src/libaudgui/prefs-window.cc:110 src/libaudqt/infopopup-qt.cc:124 @@ -495,7 +497,7 @@ msgstr "Рік" #: src/libaudgui/infopopup.cc:210 src/libaudgui/prefs-window.cc:147 #: src/libaudqt/infopopup-qt.cc:126 src/libaudqt/prefs-window-qt.cc:192 msgid "Track" -msgstr "Стежка" +msgstr "Доріжка" #: src/libaudgui/infopopup.cc:211 src/libaudqt/infopopup-qt.cc:128 #: src/libaudqt/info-widget.cc:55 @@ -516,159 +518,159 @@ msgstr "Бітрейт:" #: src/libaudgui/infowin.cc:86 msgid "Acid Jazz" -msgstr "Ейсид-джаз" +msgstr "Acid Jazz" #: src/libaudgui/infowin.cc:87 msgid "Acid Rock" -msgstr "Ейсид-рок" +msgstr "Acid Rock" #: src/libaudgui/infowin.cc:88 msgid "Ambient" -msgstr "Ембієнт" +msgstr "Ambient" #: src/libaudgui/infowin.cc:89 msgid "Bebop" -msgstr "Бібоп" +msgstr "Bebop" #: src/libaudgui/infowin.cc:90 msgid "Bluegrass" -msgstr "Блуґрас" +msgstr "Bluegrass" #: src/libaudgui/infowin.cc:91 msgid "Blues" -msgstr "Блюз" +msgstr "Blues" #: src/libaudgui/infowin.cc:92 msgid "Chamber Music" -msgstr "Камерна музика" +msgstr "Chamber Music" #: src/libaudgui/infowin.cc:93 msgid "Classical" -msgstr "Класична музика" +msgstr "Classical" #: src/libaudgui/infowin.cc:94 msgid "Country" -msgstr "Кантрі" +msgstr "Country" #: src/libaudgui/infowin.cc:95 msgid "Death Metal" -msgstr "Дет-метал" +msgstr "Death Metal" #: src/libaudgui/infowin.cc:96 msgid "Disco" -msgstr "Диско" +msgstr "Disco" #: src/libaudgui/infowin.cc:97 msgid "Easy Listening" -msgstr "Легка музика" +msgstr "Easy Listening" #: src/libaudgui/infowin.cc:98 msgid "Folk" -msgstr "Народна музика" +msgstr "Folk" #: src/libaudgui/infowin.cc:99 msgid "Funk" -msgstr "Фанк" +msgstr "Funk" #: src/libaudgui/infowin.cc:100 msgid "Gangsta Rap" -msgstr "Ґанґста-реп" +msgstr "Gangsta Rap" #: src/libaudgui/infowin.cc:101 msgid "Gospel" -msgstr "Ґоспел" +msgstr "Gospel" #: src/libaudgui/infowin.cc:102 msgid "Grunge" -msgstr "Ґрандж" +msgstr "Grunge" #: src/libaudgui/infowin.cc:103 msgid "Hard Rock" -msgstr "Гардрок" +msgstr "Hard Rock" #: src/libaudgui/infowin.cc:104 msgid "Heavy Metal" -msgstr "Гевіметал " +msgstr "Heavy Metal" #: src/libaudgui/infowin.cc:105 msgid "Hip-hop" -msgstr "Гіп-гоп" +msgstr "Hip-hop" #: src/libaudgui/infowin.cc:106 msgid "House" -msgstr "Гавз" +msgstr "House" #: src/libaudgui/infowin.cc:107 msgid "Jazz" -msgstr "Джаз" +msgstr "Jazz" #: src/libaudgui/infowin.cc:108 msgid "Jungle" -msgstr "Джанґл" +msgstr "Jungle" #: src/libaudgui/infowin.cc:109 msgid "Metal" -msgstr "Метал" +msgstr "Metal" #: src/libaudgui/infowin.cc:110 msgid "New Age" -msgstr "Ню-ейдж" +msgstr "New Age" #: src/libaudgui/infowin.cc:111 msgid "New Wave" -msgstr "Нова хвиля" +msgstr "New Wave" #: src/libaudgui/infowin.cc:112 msgid "Noise" -msgstr "Нойз" +msgstr "Noise" #: src/libaudgui/infowin.cc:113 msgid "Pop" -msgstr "Поп-музика" +msgstr "Pop" #: src/libaudgui/infowin.cc:114 msgid "Punk Rock" -msgstr "Панк-рок" +msgstr "Punk Rock" #: src/libaudgui/infowin.cc:115 msgid "Rap" -msgstr "Реп" +msgstr "Rap" #: src/libaudgui/infowin.cc:116 msgid "Reggae" -msgstr "Реґей" +msgstr "Reggae" #: src/libaudgui/infowin.cc:117 msgid "Rock" -msgstr "Рок" +msgstr "Rock" #: src/libaudgui/infowin.cc:118 msgid "Rock and Roll" -msgstr "Рок-н-рол" +msgstr "Rock and Roll" #: src/libaudgui/infowin.cc:119 msgid "Rhythm and Blues" -msgstr "Ритм-енд-блюз" +msgstr "Rhythm and Blues" #: src/libaudgui/infowin.cc:120 msgid "Ska" -msgstr "Ска" +msgstr "Ska" #: src/libaudgui/infowin.cc:121 msgid "Soul" -msgstr "Совл" +msgstr "Soul" #: src/libaudgui/infowin.cc:122 msgid "Swing" -msgstr "Свінг" +msgstr "Swing" #: src/libaudgui/infowin.cc:123 msgid "Techno" -msgstr "Техно" +msgstr "Techno" #: src/libaudgui/infowin.cc:124 msgid "Trip-hop" -msgstr "Трип-гоп" +msgstr "Trip-hop" #: src/libaudgui/infowin.cc:217 msgid "Save successful" @@ -694,7 +696,7 @@ msgstr "Коментар" #: src/libaudgui/infowin.cc:373 src/libaudqt/info-widget.cc:44 msgid "Track Number" -msgstr "Номер стежки" +msgstr "Номер пісні" #: src/libaudgui/infowin.cc:380 msgid "Clea_r fields when moving to next song" @@ -736,7 +738,7 @@ msgstr "_Додати до черги" #: src/libaudgui/jump-to-track.cc:101 msgid "Un_queue" -msgstr "В_илучити з черги" +msgstr "В_илучити із черги" #: src/libaudgui/jump-to-track.cc:240 msgid "Jump to Song" @@ -794,7 +796,7 @@ msgstr "_Імпортувати" #: src/libaudgui/plugin-menu.cc:40 src/libaudqt/plugin-menu-qt.cc:45 msgid "_Plugins ..." -msgstr "_Втулки ..." +msgstr "_Модулі ..." #: src/libaudgui/plugin-prefs.cc:109 src/libaudqt/prefs-plugin.cc:56 #, c-format @@ -850,11 +852,11 @@ msgstr "Списки відтворення" #: src/libaudgui/prefs-window.cc:87 src/libaudqt/prefs-window-qt.cc:141 msgid "Plugins" -msgstr "Втулки" +msgstr "Модулі" #: src/libaudgui/prefs-window.cc:88 src/libaudqt/prefs-window-qt.cc:142 msgid "Advanced" -msgstr "Розширені" +msgstr "" #: src/libaudgui/prefs-window.cc:92 src/libaudqt/prefs-pluginlist-model.cc:37 msgid "General" @@ -870,7 +872,7 @@ msgstr "Візуалізація" #: src/libaudgui/prefs-window.cc:95 src/libaudqt/prefs-pluginlist-model.cc:40 msgid "Input" -msgstr "Ввід" +msgstr "Вхід" #: src/libaudgui/prefs-window.cc:97 src/libaudqt/prefs-pluginlist-model.cc:42 msgid "Transport" @@ -882,15 +884,15 @@ msgstr "Виконавець альбому" #: src/libaudgui/prefs-window.cc:105 src/libaudqt/prefs-window-qt.cc:150 msgid "Track number" -msgstr "Номер стежки" +msgstr "Номер доріжки" #: src/libaudgui/prefs-window.cc:107 src/libaudqt/prefs-window-qt.cc:152 msgid "File name" -msgstr "Назва файлу" +msgstr "Ім’я файлу" #: src/libaudgui/prefs-window.cc:108 src/libaudqt/prefs-window-qt.cc:153 msgid "File path" -msgstr "Шлях до файлу" +msgstr "Путь до файлу" #: src/libaudgui/prefs-window.cc:109 src/libaudqt/prefs-window-qt.cc:154 msgid "Date" @@ -988,7 +990,7 @@ msgstr "Вигляд:" #: src/libaudgui/prefs-window.cc:180 src/libaudqt/prefs-window-qt.cc:216 msgid "Output plugin:" -msgstr "Втулок виведення:" +msgstr "Модуль виведення:" #: src/libaudgui/prefs-window.cc:201 src/libaudqt/prefs-window-qt.cc:231 msgid "Amplify all files:" @@ -1001,7 +1003,7 @@ msgstr "дБ" #: src/libaudgui/prefs-window.cc:204 src/libaudqt/prefs-window-qt.cc:234 msgid "Amplify untagged files:" -msgstr "Підсилювати непомічені файли:" +msgstr "Підсилювати непозначені файли:" #: src/libaudgui/prefs-window.cc:210 src/libaudqt/prefs-window-qt.cc:240 msgid "Output Settings" @@ -1014,7 +1016,7 @@ msgstr "Амплітудна розрядність:" #: src/libaudgui/prefs-window.cc:215 src/libaudgui/prefs-window.cc:260 #: src/libaudqt/prefs-window-qt.cc:245 src/libaudqt/prefs-window-qt.cc:290 msgid "Buffer size:" -msgstr "Розмір буферу:" +msgstr "Розмір буфера:" #: src/libaudgui/prefs-window.cc:217 src/libaudqt/prefs-window-qt.cc:247 msgid "ms" @@ -1054,7 +1056,7 @@ msgstr "Запобігати відсіканню (рекомендовано)" #: src/libaudgui/prefs-window.cc:244 src/libaudqt/prefs-window-qt.cc:274 msgid "Proxy hostname:" -msgstr "Адреса проксі-серверу:" +msgstr "Адреса проксі-сервера:" #: src/libaudgui/prefs-window.cc:246 src/libaudqt/prefs-window-qt.cc:276 msgid "Proxy port:" @@ -1066,7 +1068,7 @@ msgstr "Ім'я користувача:" #: src/libaudgui/prefs-window.cc:253 src/libaudqt/prefs-window-qt.cc:283 msgid "Proxy password:" -msgstr "Гасло:" +msgstr "Пароль:" #: src/libaudgui/prefs-window.cc:259 src/libaudqt/prefs-window-qt.cc:289 msgid "Network Settings" @@ -1138,11 +1140,11 @@ msgstr "Показувати розряд годин (1:30:00 замість 90: #: src/libaudgui/prefs-window.cc:306 src/libaudqt/prefs-window-qt.cc:336 msgid "Export" -msgstr "Експортування" +msgstr "" #: src/libaudgui/prefs-window.cc:307 src/libaudqt/prefs-window-qt.cc:337 msgid "Use relative paths when possible" -msgstr "За можливістю використовувати схожі шляхи" +msgstr "" #: src/libaudgui/prefs-window.cc:312 src/libaudqt/prefs-window-qt.cc:342 msgid "Album Art" @@ -1194,15 +1196,15 @@ msgstr "Вважати \\ (обернену косу риску) розділю #: src/libaudgui/prefs-window.cc:342 src/libaudqt/prefs-window-qt.cc:372 msgid "Playlist" -msgstr "Список відтворення" +msgstr "" #: src/libaudgui/prefs-window.cc:343 src/libaudqt/prefs-window-qt.cc:373 msgid "Add folders recursively" -msgstr "Додавати теки рекурсивно" +msgstr "" #: src/libaudgui/prefs-window.cc:345 src/libaudqt/prefs-window-qt.cc:375 msgid "Add folders nested within playlist files" -msgstr "Додати теки, які вкладені поміж списків відтворення" +msgstr "" #: src/libaudgui/prefs-window.cc:347 src/libaudqt/prefs-window-qt.cc:377 msgid "Metadata" @@ -1218,7 +1220,7 @@ msgstr "Не завантажувати метадані доріжок до в #: src/libaudgui/prefs-window.cc:352 src/libaudqt/prefs-window-qt.cc:382 msgid "Probe content of files with no recognized file name extension" -msgstr "Сканувати вміст файлів з невпізнаним розширенням" +msgstr "Сканувати вміст файлу із невпізнаним розширенням" #: src/libaudgui/prefs-window.cc:370 src/libaudqt/prefs-window-qt.cc:400 msgid "TITLE" @@ -1242,11 +1244,11 @@ msgstr "ВИКОНАВЕЦЬ - АЛЬБОМ - НАЗВА" #: src/libaudgui/prefs-window.cc:375 src/libaudqt/prefs-window-qt.cc:405 msgid "ARTIST - ALBUM - TRACK. TITLE" -msgstr "ВИКОНАВЕЦЬ - АЛЬБОМ - СТЕЖКА. НАЗВА" +msgstr "ВИКОНАВЕЦЬ - АЛЬБОМ - ДОРІЖКА. НАЗВА" #: src/libaudgui/prefs-window.cc:376 src/libaudqt/prefs-window-qt.cc:406 msgid "ARTIST [ ALBUM ] - TRACK. TITLE" -msgstr "ВИКОНАВЕЦЬ [ АЛЬБОМ ] СТЕЖКА. НАЗВА" +msgstr "ВИКОНАВЕЦЬ [ АЛЬБОМ ] ДОРІЖКА. НАЗВА" #: src/libaudgui/prefs-window.cc:377 src/libaudqt/prefs-window-qt.cc:407 msgid "ALBUM - TITLE" @@ -1275,7 +1277,7 @@ msgstr "Увімкнено записування потоку з %s" #: src/libaudgui/prefs-window.cc:765 src/libaudqt/prefs-window-qt.cc:730 msgid "No audio recording plugin available" -msgstr "Немає втулків для запису авдіо" +msgstr "Немає модулів для запису аудіо" #: src/libaudgui/prefs-window.cc:825 src/libaudqt/prefs-window-qt.cc:607 msgid "Audacious Settings" @@ -1299,7 +1301,7 @@ msgstr "Завантажити файл налаштувань" #: src/libaudgui/preset-browser.cc:94 msgid "Load EQF File" -msgstr "Завантажити файл налаштувань еквалайзеру" +msgstr "Завантажити файл налаштувань еквалайзера" #: src/libaudgui/preset-browser.cc:109 msgid "Save Preset File" @@ -1307,15 +1309,15 @@ msgstr "Зберегти файл налаштувань" #: src/libaudgui/preset-browser.cc:109 msgid ".preset" -msgstr ".пресет" +msgstr "<ім'я>.preset" #: src/libaudgui/preset-browser.cc:127 msgid "Save EQF File" -msgstr "Зберегти файл налаштувань еквалайзеру" +msgstr "Зберегти файл налаштувань еквалайзера" #: src/libaudgui/preset-browser.cc:127 msgid ".eqf" -msgstr ".eqf" +msgstr "<>.eqf" #: src/libaudgui/preset-browser.cc:141 msgid "Import Winamp Presets" @@ -1343,7 +1345,7 @@ msgstr "Інформація" #: src/libaudgui/url-opener.cc:55 src/libaudqt/url-opener-qt.cc:39 msgid "_Save to history" -msgstr "_Зберегти до історії" +msgstr "" #: src/libaudgui/url-opener.cc:63 src/libaudqt/url-opener-qt.cc:47 msgid "Open URL" @@ -1355,7 +1357,7 @@ msgstr "Додати адресу" #: src/libaudgui/url-opener.cc:92 src/libaudqt/url-opener-qt.cc:68 msgid "C_lear history" -msgstr "О_чистити історію" +msgstr "" #: src/libaudgui/url-opener.cc:104 src/libaudqt/url-opener-qt.cc:62 msgid "Enter URL:" @@ -1459,4 +1461,4 @@ msgid "Copy" msgstr "Копіювати" #~ msgid "Plugins ..." -#~ msgstr "Втулки ..." +#~ msgstr "Модулі ..." diff --git a/src/audacious/Makefile b/src/audacious/Makefile index e4678ba..79e86cd 100644 --- a/src/audacious/Makefile +++ b/src/audacious/Makefile @@ -28,7 +28,9 @@ CPPFLAGS := -I.. -I../.. \ ${CPPFLAGS} \ ${GLIB_CFLAGS} -LIBS := -L../libaudcore -laudcore \ +LDFLAGS := -L../libaudcore $(LDFLAGS) + +LIBS := -laudcore \ ${LIBS} -lm \ ${LIBINTL} \ ${GLIB_LIBS} diff --git a/src/audacious/dbus-server.cc b/src/audacious/dbus-server.cc index 20a6c58..10f3bba 100644 --- a/src/audacious/dbus-server.cc +++ b/src/audacious/dbus-server.cc @@ -86,14 +86,21 @@ static gboolean do_add_url (Obj * obj, Invoc * invoc, const char * url) static gboolean do_advance (Obj * obj, Invoc * invoc) { - CURRENT.next_song (aud_get_bool (nullptr, "repeat")); + CURRENT.next_song (aud_get_bool ("repeat")); FINISH (advance); return true; } +static gboolean do_advance_album (Obj * obj, Invoc * invoc) +{ + CURRENT.next_album (aud_get_bool ("repeat")); + FINISH (advance_album); + return true; +} + static gboolean do_auto_advance (Obj * obj, Invoc * invoc) { - FINISH2 (auto_advance, ! aud_get_bool (nullptr, "no_playlist_advance")); + FINISH2 (auto_advance, ! aud_get_bool ("no_playlist_advance")); return true; } @@ -150,7 +157,7 @@ static gboolean do_eject (Obj * obj, Invoc * invoc) static gboolean do_equalizer_activate (Obj * obj, Invoc * invoc, gboolean active) { - aud_set_bool (nullptr, "equalizer_active", active); + aud_set_bool ("equalizer_active", active); FINISH (equalizer_activate); return true; } @@ -170,7 +177,7 @@ static gboolean do_get_active_playlist_name (Obj * obj, Invoc * invoc) static gboolean do_get_eq (Obj * obj, Invoc * invoc) { - double preamp = aud_get_double (nullptr, "equalizer_preamp"); + double preamp = aud_get_double ("equalizer_preamp"); double bands[AUD_EQ_NBANDS]; aud_eq_get_bands (bands); @@ -188,7 +195,7 @@ static gboolean do_get_eq_band (Obj * obj, Invoc * invoc, int band) static gboolean do_get_eq_preamp (Obj * obj, Invoc * invoc) { - FINISH2 (get_eq_preamp, aud_get_double (nullptr, "equalizer_preamp")); + FINISH2 (get_eq_preamp, aud_get_double ("equalizer_preamp")); return true; } @@ -423,7 +430,7 @@ static gboolean do_quit (Obj * obj, Invoc * invoc) static gboolean do_record (Obj * obj, Invoc * invoc) { if (aud_drct_get_record_enabled ()) - aud_set_bool (nullptr, "record", ! aud_get_bool (nullptr, "record")); + aud_set_bool ("record", ! aud_get_bool ("record")); FINISH (record); return true; @@ -433,7 +440,7 @@ static gboolean do_recording (Obj * obj, Invoc * invoc) { bool recording = false; if (aud_drct_get_record_enabled ()) - recording = aud_get_bool (nullptr, "record"); + recording = aud_get_bool ("record"); FINISH2 (recording, recording); return true; @@ -441,7 +448,7 @@ static gboolean do_recording (Obj * obj, Invoc * invoc) static gboolean do_repeat (Obj * obj, Invoc * invoc) { - FINISH2 (repeat, aud_get_bool (nullptr, "repeat")); + FINISH2 (repeat, aud_get_bool ("repeat")); return true; } @@ -452,6 +459,13 @@ static gboolean do_reverse (Obj * obj, Invoc * invoc) return true; } +static gboolean do_reverse_album (Obj * obj, Invoc * invoc) +{ + CURRENT.prev_album (); + FINISH (reverse_album); + return true; +} + static gboolean do_seek (Obj * obj, Invoc * invoc, unsigned pos) { aud_drct_seek (pos); @@ -504,7 +518,7 @@ static gboolean do_set_eq (Obj * obj, Invoc * invoc, double preamp, GVariant * v if (nbands != AUD_EQ_NBANDS) return false; - aud_set_double (nullptr, "equalizer_preamp", preamp); + aud_set_double ("equalizer_preamp", preamp); aud_eq_set_bands (bands); FINISH (set_eq); return true; @@ -519,7 +533,7 @@ static gboolean do_set_eq_band (Obj * obj, Invoc * invoc, int band, double value static gboolean do_set_eq_preamp (Obj * obj, Invoc * invoc, double preamp) { - aud_set_double (nullptr, "equalizer_preamp", preamp); + aud_set_double ("equalizer_preamp", preamp); FINISH (set_eq_preamp); return true; } @@ -598,7 +612,7 @@ static gboolean do_show_prefs_box (Obj * obj, Invoc * invoc, gboolean show) static gboolean do_shuffle (Obj * obj, Invoc * invoc) { - FINISH2 (shuffle, aud_get_bool (nullptr, "shuffle")); + FINISH2 (shuffle, aud_get_bool ("shuffle")); return true; } @@ -689,7 +703,7 @@ static gboolean do_stop (Obj * obj, Invoc * invoc) static gboolean do_stop_after (Obj * obj, Invoc * invoc) { - FINISH2 (stop_after, aud_get_bool (nullptr, "stop_after_current_song")); + FINISH2 (stop_after, aud_get_bool ("stop_after_current_song")); return true; } @@ -707,28 +721,28 @@ static gboolean do_time (Obj * obj, Invoc * invoc) static gboolean do_toggle_auto_advance (Obj * obj, Invoc * invoc) { - aud_toggle_bool (nullptr, "no_playlist_advance"); + aud_toggle_bool ("no_playlist_advance"); FINISH (toggle_auto_advance); return true; } static gboolean do_toggle_repeat (Obj * obj, Invoc * invoc) { - aud_toggle_bool (nullptr, "repeat"); + aud_toggle_bool ("repeat"); FINISH (toggle_repeat); return true; } static gboolean do_toggle_shuffle (Obj * obj, Invoc * invoc) { - aud_toggle_bool (nullptr, "shuffle"); + aud_toggle_bool ("shuffle"); FINISH (toggle_shuffle); return true; } static gboolean do_toggle_stop_after (Obj * obj, Invoc * invoc) { - aud_toggle_bool (nullptr, "stop_after_current_song"); + aud_toggle_bool ("stop_after_current_song"); FINISH (toggle_stop_after); return true; } @@ -757,6 +771,7 @@ handlers[] = {"handle-add-list", (GCallback) do_add_list}, {"handle-add-url", (GCallback) do_add_url}, {"handle-advance", (GCallback) do_advance}, + {"handle-advance-album", (GCallback) do_advance_album}, {"handle-auto-advance", (GCallback) do_auto_advance}, {"handle-balance", (GCallback) do_balance}, {"handle-clear", (GCallback) do_clear}, @@ -805,6 +820,7 @@ handlers[] = {"handle-record", (GCallback) do_record}, {"handle-repeat", (GCallback) do_repeat}, {"handle-reverse", (GCallback) do_reverse}, + {"handle-reverse-album", (GCallback) do_reverse_album}, {"handle-seek", (GCallback) do_seek}, {"handle-select-displayed-playlist", (GCallback) do_select_displayed_playlist}, {"handle-select-playing-playlist", (GCallback) do_select_playing_playlist}, diff --git a/src/audacious/main.cc b/src/audacious/main.cc index 52ad234..1213a95 100644 --- a/src/audacious/main.cc +++ b/src/audacious/main.cc @@ -1,6 +1,6 @@ /* * main.c - * Copyright 2007-2013 William Pitcock and John Lindgren + * Copyright 2007-2013 Ariadne Conill and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -50,7 +50,7 @@ static struct { int mainwin, show_jump_box; int headless, quit_after_play; int verbose; - int qt; + int gtk; } options; static bool initted = false; @@ -78,7 +78,7 @@ static const struct { {"quit-after-play", 'q', & options.quit_after_play, N_("Quit on playback stop")}, {"verbose", 'V', & options.verbose, N_("Print debugging messages (may be used twice)")}, #if defined(USE_QT) && defined(USE_GTK) - {"qt", 'Q', & options.qt, N_("Run in Qt mode")}, + {"gtk", 'G', & options.gtk, N_("Run in GTK mode")}, #endif }; @@ -171,8 +171,8 @@ static bool parse_options (int argc, char * * argv) else if (options.verbose) audlog::set_stderr_level (audlog::Info); - if (options.qt) - aud_set_mainloop_type (MainloopType::Qt); + if (options.gtk) + aud_set_mainloop_type (MainloopType::GLib); return true; } @@ -199,9 +199,7 @@ static void do_remote () ObjAudacious * obj = nullptr; GError * error = nullptr; -#if ! GLIB_CHECK_VERSION (2, 36, 0) g_type_init (); -#endif /* check whether the selected instance is running */ if (dbus_server_init () != StartupType::Client) @@ -270,7 +268,7 @@ static void do_remote () static void do_commands () { - bool resume = aud_get_bool (nullptr, "resume_playback_on_startup"); + bool resume = aud_get_bool ("resume_playback_on_startup"); if (filenames.len ()) { diff --git a/src/audacious/meson.build b/src/audacious/meson.build new file mode 100644 index 0000000..d91ba79 --- /dev/null +++ b/src/audacious/meson.build @@ -0,0 +1,24 @@ +audacious_deps = [glib_dep] +audacious_libs = [libaudcore_lib] + +audacious_sources = [ + 'main.cc', + 'signals.cc', + 'util.cc' +] + + +if get_option('dbus') + audacious_sources += ['dbus-server.cc'] + audacious_libs += [aud_dbus_lib] + audacious_deps += [aud_dbus_deps] +endif + + +audacious_exe = executable('audacious', + audacious_sources, + include_directories: [src_inc, aud_dbus_inc], + dependencies: audacious_deps, + link_with: audacious_libs, + install: true +) diff --git a/src/audacious/signals.cc b/src/audacious/signals.cc index 35c1011..8ed1fec 100644 --- a/src/audacious/signals.cc +++ b/src/audacious/signals.cc @@ -19,23 +19,21 @@ #ifdef HAVE_SIGWAIT -#include #include #include +#include #include "main.h" static sigset_t signal_set; -static void * signal_thread (void * data) +static void signal_thread () { int signal; while (! sigwait (& signal_set, & signal)) event_queue ("quit", nullptr); - - return nullptr; } /* Must be called before any threads are created. */ @@ -52,8 +50,7 @@ void signals_init_one () void signals_init_two () { - pthread_t thread; - pthread_create (& thread, nullptr, signal_thread, nullptr); + std::thread (signal_thread).detach (); } #endif /* HAVE_SIGWAIT */ diff --git a/src/audtool/audtool.h b/src/audtool/audtool.h index b3aa711..7a1e3a9 100644 --- a/src/audtool/audtool.h +++ b/src/audtool/audtool.h @@ -1,6 +1,6 @@ /* * audtool.h - * Copyright 2005-2011 William Pitcock, George Averill, Giacomo Lozito, + * Copyright 2005-2011 Ariadne Conill, George Averill, Giacomo Lozito, * Yoshiki Yazawa, Matti Hämäläinen, and John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -63,9 +63,11 @@ void select_displayed (int, char * *); void select_playing (int, char * *); void playlist_position (int, char * *); void playlist_advance (int, char * *); +void playlist_advance_album (int, char * *); void playlist_auto_advance_status (int, char * *); void playlist_auto_advance_toggle (int, char * *); void playlist_reverse (int, char * *); +void playlist_reverse_album (int, char * *); void playlist_length (int, char * *); void playlist_song (int, char * *); void playlist_song_filename (int, char * *); diff --git a/src/audtool/handlers_general.c b/src/audtool/handlers_general.c index 886e7ac..d03c63b 100644 --- a/src/audtool/handlers_general.c +++ b/src/audtool/handlers_general.c @@ -1,6 +1,6 @@ /* * handlers_general.c - * Copyright 2005-2013 George Averill, William Pitcock, Giacomo Lozito, + * Copyright 2005-2013 George Averill, Ariadne Conill, Giacomo Lozito, * Matti Hämäläinen, and John Lindgren * * Redistribution and use in source and binary forms, with or without diff --git a/src/audtool/handlers_playback.c b/src/audtool/handlers_playback.c index 8a812b7..c9ba722 100644 --- a/src/audtool/handlers_playback.c +++ b/src/audtool/handlers_playback.c @@ -1,6 +1,6 @@ /* * handlers_playback.c - * Copyright 2005-2013 George Averill, William Pitcock, Matti Hämäläinen, and + * Copyright 2005-2013 George Averill, Ariadne Conill, Matti Hämäläinen, and * John Lindgren * * Redistribution and use in source and binary forms, with or without diff --git a/src/audtool/handlers_playlist.c b/src/audtool/handlers_playlist.c index e2362c9..e97d794 100644 --- a/src/audtool/handlers_playlist.c +++ b/src/audtool/handlers_playlist.c @@ -1,6 +1,6 @@ /* * handlers_playlist.c - * Copyright 2005-2013 George Averill, William Pitcock, Yoshiki Yazawa, + * Copyright 2005-2013 George Averill, Ariadne Conill, Yoshiki Yazawa, * Matti Hämäläinen, and John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -39,11 +39,21 @@ void playlist_reverse (int argc, char * * argv) obj_audacious_call_reverse_sync (dbus_proxy, NULL, NULL); } +void playlist_reverse_album (int argc, char * * argv) +{ + obj_audacious_call_reverse_album_sync (dbus_proxy, NULL, NULL); +} + void playlist_advance (int argc, char * * argv) { obj_audacious_call_advance_sync (dbus_proxy, NULL, NULL); } +void playlist_advance_album (int argc, char * * argv) +{ + obj_audacious_call_advance_album_sync (dbus_proxy, NULL, NULL); +} + void playlist_auto_advance_status (int argc, char * * argv) { gboolean advance = FALSE; diff --git a/src/audtool/handlers_playqueue.c b/src/audtool/handlers_playqueue.c index 1efdb37..56f5196 100644 --- a/src/audtool/handlers_playqueue.c +++ b/src/audtool/handlers_playqueue.c @@ -1,6 +1,6 @@ /* * handlers_playqueue.c - * Copyright 2005-2013 George Averill, William Pitcock, Yoshiki Yazawa, + * Copyright 2005-2013 George Averill, Ariadne Conill, Yoshiki Yazawa, * Matti Hämäläinen, and John Lindgren * * Redistribution and use in source and binary forms, with or without diff --git a/src/audtool/handlers_vitals.c b/src/audtool/handlers_vitals.c index 68918dc..76f0eb3 100644 --- a/src/audtool/handlers_vitals.c +++ b/src/audtool/handlers_vitals.c @@ -1,6 +1,6 @@ /* * handlers_vitals.c - * Copyright 2005-2013 George Averill, William Pitcock, and John Lindgren + * Copyright 2005-2013 George Averill, Ariadne Conill, and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/audtool/main.c b/src/audtool/main.c index a09c6b8..5584ed3 100644 --- a/src/audtool/main.c +++ b/src/audtool/main.c @@ -1,6 +1,6 @@ /* * main.c - * Copyright 2005-2013 George Averill, William Pitcock, Yoshiki Yazawa, and + * Copyright 2005-2013 George Averill, Ariadne Conill, Yoshiki Yazawa, and * John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,9 @@ const struct commandhandler handlers[] = {"select-displayed", select_displayed, "apply commands to displayed playlist", 0}, {"select-playing", select_playing, "apply commands to playing playlist", 0}, {"playlist-advance", playlist_advance, "skip to next song", 0}, + {"playlist-advance-album", playlist_advance_album, "skip to next album", 0}, {"playlist-reverse", playlist_reverse, "skip to previous song", 0}, + {"playlist-reverse-album", playlist_reverse_album, "skip to beginning of the previous album", 0}, {"playlist-addurl", playlist_add_url_string, "add URI at end of playlist", 1}, {"playlist-insurl", playlist_ins_url_string, "insert URI at given position", 2}, {"playlist-addurl-to-new-playlist", playlist_enqueue_to_temp, "open URI in \"Now Playing\" playlist", 1}, @@ -222,9 +224,7 @@ int main (int argc, char * * argv) setlocale (LC_CTYPE, ""); -#if ! GLIB_CHECK_VERSION (2, 36, 0) g_type_init(); -#endif #ifdef _WIN32 g_set_print_handler (print_utf8); diff --git a/src/audtool/meson.build b/src/audtool/meson.build new file mode 100644 index 0000000..df7539f --- /dev/null +++ b/src/audtool/meson.build @@ -0,0 +1,23 @@ +audtool_sources = [ + 'main.c', + 'handlers_general.c', + 'handlers_playback.c', + 'handlers_playlist.c', + 'handlers_playqueue.c', + 'handlers_vitals.c', + 'handlers_equalizer.c', + 'report.c', + 'wrappers.c' +] + + +audtool_deps = aud_dbus_deps + + +audtool_exe = executable('audtool', + audtool_sources, + link_with: aud_dbus_lib, + dependencies: audtool_deps, + include_directories: aud_dbus_inc, + install: true +) diff --git a/src/audtool/report.c b/src/audtool/report.c index 2bc0298..0628756 100644 --- a/src/audtool/report.c +++ b/src/audtool/report.c @@ -1,6 +1,6 @@ /* * report.c - * Copyright 2007-2008 William Pitcock and Matti Hämäläinen + * Copyright 2007-2008 Ariadne Conill and Matti Hämäläinen * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/config.h.meson b/src/config.h.meson new file mode 100644 index 0000000..51b89ff --- /dev/null +++ b/src/config.h.meson @@ -0,0 +1,21 @@ +#mesondefine PACKAGE +#mesondefine BUILDSTAMP +#mesondefine VERSION +#mesondefine COPYRIGHT +#mesondefine EXPORT +#mesondefine PLUGIN_SUFFIX + +#define PACKAGE_VERSION VERSION +#define ICONV_CONST + +#mesondefine INSTALL_BINDIR +#mesondefine INSTALL_DATADIR +#mesondefine INSTALL_PLUGINDIR +#mesondefine INSTALL_LOCALEDIR +#mesondefine INSTALL_DESKTOPFILE +#mesondefine INSTALL_ICONFILE + +#mesondefine USE_DBUS +#mesondefine USE_QT + +#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32 diff --git a/src/dbus/aud-dbus.xml b/src/dbus/aud-dbus.xml index 960c910..b240d90 100644 --- a/src/dbus/aud-dbus.xml +++ b/src/dbus/aud-dbus.xml @@ -249,9 +249,15 @@ + + + + + + diff --git a/src/dbus/meson.build b/src/dbus/meson.build new file mode 100644 index 0000000..d1bbdf0 --- /dev/null +++ b/src/dbus/meson.build @@ -0,0 +1,29 @@ +gnome = import('gnome') + + +gio_dep = dependency('gio-2.0', required: true) +aud_dbus_deps = [gio_dep] + + +if host_machine.system() != 'windows' + gio_unix_dep = dependency('gio-unix-2.0', required: true) + aud_dbus_deps += [gio_unix_dep] +endif + + +aud_dbus_src = gnome.gdbus_codegen('aud-dbus', + sources: 'aud-dbus.xml', + interface_prefix: 'org.atheme.', + namespace: 'Obj' +) +aud_dbus_deps += declare_dependency(sources: aud_dbus_src) + + +aud_dbus_lib = static_library('aud-dbus', + aud_dbus_src, + dependencies: aud_dbus_deps, + pic: true +) + + +aud_dbus_inc = include_directories('.') diff --git a/src/libaudcore/Makefile b/src/libaudcore/Makefile index e969f93..4b1c383 100644 --- a/src/libaudcore/Makefile +++ b/src/libaudcore/Makefile @@ -1,6 +1,6 @@ SHARED_LIB = ${LIB_PREFIX}audcore${LIB_SUFFIX} LIB_MAJOR = 5 -LIB_MINOR = 1 +LIB_MINOR = 2 SRCS = adder.cc \ art.cc \ @@ -78,6 +78,7 @@ INCLUDES = audio.h \ runtime.h \ templates.h \ tinylock.h \ + threads.h \ tuple.h \ visualizer.h \ vfs.h \ diff --git a/src/libaudcore/adder.cc b/src/libaudcore/adder.cc index 888b321..8ee3bb9 100644 --- a/src/libaudcore/adder.cc +++ b/src/libaudcore/adder.cc @@ -17,33 +17,37 @@ * the use of this software. */ -#include "playlist-internal.h" #include "internal.h" +#include "playlist-internal.h" -#include #include #include #include "audstrings.h" #include "hook.h" #include "i18n.h" +#include "interface.h" #include "list.h" #include "mainloop.h" #include "plugins-internal.h" #include "probe.h" #include "runtime.h" +#include "threads.h" #include "tuple.h" -#include "interface.h" #include "vfs.h" // regrettably, strcmp_nocase can't be used directly as a // callback for Index::sort due to taking a third argument; // strcmp also triggers -Wnoexcept-type with GCC 7 -static int filename_compare (const char * a, const char * b) +static int filename_compare(const char * a, const char * b) #ifdef _WIN32 - { return strcmp_nocase (a, b); } +{ + return strcmp_nocase(a, b); +} #else - { return strcmp (a, b); } +{ + return strcmp(a, b); +} #endif struct AddTask : public ListNode @@ -66,16 +70,15 @@ struct AddResult : public ListNode bool saw_folder, filtered; }; -static void * add_worker (void * unused); +static void add_worker(); static List add_tasks; static List add_results; static Playlist current_playlist; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static bool add_thread_started = false; +static aud::mutex mutex; +static std::thread add_thread; static bool add_thread_exited = false; -static pthread_t add_thread; static QueuedFunc queued_add; static QueuedFunc status_timer; @@ -83,63 +86,61 @@ static char status_path[512]; static int status_count; static bool status_shown = false; -static void status_cb (void * unused) +static void status_cb(void * unused) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); char scratch[128]; - snprintf (scratch, sizeof scratch, dngettext (PACKAGE, "%d file found", - "%d files found", status_count), status_count); + snprintf( + scratch, sizeof scratch, + dngettext(PACKAGE, "%d file found", "%d files found", status_count), + status_count); - if (aud_get_headless_mode ()) + if (aud_get_headless_mode()) { - printf ("Searching, %s ...\r", scratch); - fflush (stdout); + printf("Searching, %s ...\r", scratch); + fflush(stdout); } else { - hook_call ("ui show progress", status_path); - hook_call ("ui show progress 2", scratch); + hook_call("ui show progress", status_path); + hook_call("ui show progress 2", scratch); } status_shown = true; - - pthread_mutex_unlock (& mutex); } -static void status_update (const char * filename, int found) +static void status_update(const char * filename, int found) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - snprintf (status_path, sizeof status_path, "%s", filename); + snprintf(status_path, sizeof status_path, "%s", filename); status_count = found; - if (! status_timer.running ()) - status_timer.start (250, status_cb, nullptr); - - pthread_mutex_unlock (& mutex); + if (!status_timer.running()) + status_timer.start(250, status_cb, nullptr); } -static void status_done_locked () +static void status_done_locked() { - status_timer.stop (); + status_timer.stop(); if (status_shown) { - if (aud_get_headless_mode ()) - printf ("\n"); + if (aud_get_headless_mode()) + printf("\n"); else - hook_call ("ui hide progress", nullptr); + hook_call("ui hide progress", nullptr); status_shown = false; } } -static void add_file (PlaylistAddItem && item, Playlist::FilterFunc filter, - void * user, AddResult * result, bool skip_invalid) +static void add_file(PlaylistAddItem && item, Playlist::FilterFunc filter, + void * user, AddResult * result, bool skip_invalid) { - AUDINFO ("Adding file: %s\n", (const char *) item.filename); - status_update (item.filename, result->items.len ()); + AUDINFO("Adding file: %s\n", (const char *)item.filename); + status_update(item.filename, result->items.len()); /* * If possible, we'll wait until the file is added to the playlist to probe @@ -153,20 +154,22 @@ static void add_file (PlaylistAddItem && item, Playlist::FilterFunc filter, * If we already have metadata, or the file is itself a subtune, then * neither of these reasons apply. */ - if (! item.tuple.valid () && ! is_subtune (item.filename)) + if (!item.tuple.valid() && !is_subtune(item.filename)) { /* If we open the file to identify the decoder, we can re-use the same * handle to read metadata. */ VFSFile file; - if (! item.decoder) + if (!item.decoder) { - if (aud_get_bool (nullptr, "slow_probe")) + if (aud_get_bool("slow_probe")) { /* The slow path. User settings dictate that we should try to - * find a decoder even if we don't recognize the file extension. */ - item.decoder = aud_file_find_decoder (item.filename, false, file); - if (skip_invalid && ! item.decoder) + * find a decoder even if we don't recognize the file extension. + */ + item.decoder = + aud_file_find_decoder(item.filename, false, file); + if (skip_invalid && !item.decoder) return; } else @@ -174,8 +177,8 @@ static void add_file (PlaylistAddItem && item, Playlist::FilterFunc filter, /* The fast path. First see whether any plugins recognize the * file extension. Note that it's possible for multiple plugins * to recognize the same extension (.ogg, for example). */ - int flags = probe_by_filename (item.filename); - if (skip_invalid && ! (flags & PROBE_FLAG_HAS_DECODER)) + int flags = probe_by_filename(item.filename); + if (skip_invalid && !(flags & PROBE_FLAG_HAS_DECODER)) return; if ((flags & PROBE_FLAG_MIGHT_HAVE_SUBTUNES)) @@ -183,8 +186,9 @@ static void add_file (PlaylistAddItem && item, Playlist::FilterFunc filter, /* At least one plugin recognized the file extension and * indicated that there might be subtunes. Figure out for * sure which decoder we need to use for this file. */ - item.decoder = aud_file_find_decoder (item.filename, true, file); - if (skip_invalid && ! item.decoder) + item.decoder = + aud_file_find_decoder(item.filename, true, file); + if (skip_invalid && !item.decoder) return; } } @@ -193,176 +197,186 @@ static void add_file (PlaylistAddItem && item, Playlist::FilterFunc filter, /* At this point we've either identified the decoder or determined that * the file doesn't have any subtunes. If the former, read the tag so * so we can expand any subtunes we find. */ - if (item.decoder && input_plugin_has_subtunes (item.decoder)) - aud_file_read_tag (item.filename, item.decoder, file, item.tuple); + if (item.decoder && input_plugin_has_subtunes(item.decoder)) + aud_file_read_tag(item.filename, item.decoder, file, item.tuple); } - int n_subtunes = item.tuple.get_n_subtunes (); + int n_subtunes = item.tuple.get_n_subtunes(); if (n_subtunes) { - for (int sub = 0; sub < n_subtunes; sub ++) + for (int sub = 0; sub < n_subtunes; sub++) { - StringBuf subname = str_printf ("%s?%d", - (const char *) item.filename, item.tuple.get_nth_subtune (sub)); + StringBuf subname = str_printf("%s?%d", (const char *)item.filename, + item.tuple.get_nth_subtune(sub)); - if (! filter || filter (subname, user)) - add_file ({String (subname), Tuple (), item.decoder}, filter, user, result, false); + if (!filter || filter(subname, user)) + add_file({String(subname), Tuple(), item.decoder}, filter, user, + result, false); else result->filtered = true; } } else - result->items.append (std::move (item)); + result->items.append(std::move(item)); } /* To prevent infinite recursion, we currently allow adding a folder from within * a playlist, but not a playlist from within a folder, nor a second playlist * from within a playlist (this last rule is enforced by setting * to true from within add_playlist()). */ -static void add_generic (PlaylistAddItem && item, Playlist::FilterFunc filter, - void * user, AddResult * result, bool save_title, bool from_playlist); +static void add_generic(PlaylistAddItem && item, Playlist::FilterFunc filter, + void * user, AddResult * result, bool save_title, + bool from_playlist); -static void add_playlist (const char * filename, Playlist::FilterFunc filter, - void * user, AddResult * result, bool save_title) +static void add_playlist(const char * filename, Playlist::FilterFunc filter, + void * user, AddResult * result, bool save_title) { - AUDINFO ("Adding playlist: %s\n", filename); - status_update (filename, result->items.len ()); + AUDINFO("Adding playlist: %s\n", filename); + status_update(filename, result->items.len()); String title; Index items; - if (! playlist_load (filename, title, items)) + if (!playlist_load(filename, title, items)) return; if (save_title) result->title = title; for (auto & item : items) - add_generic (std::move (item), filter, user, result, false, true); + add_generic(std::move(item), filter, user, result, false, true); } -static void add_cuesheets (Index & files, Playlist::FilterFunc filter, - void * user, AddResult * result) +static void add_cuesheets(Index & files, Playlist::FilterFunc filter, + void * user, AddResult * result) { Index cuesheets; - for (int i = 0; i < files.len ();) + for (int i = 0; i < files.len();) { - if (str_has_suffix_nocase (files[i], ".cue")) - cuesheets.move_from (files, i, -1, 1, true, true); + if (str_has_suffix_nocase(files[i], ".cue")) + cuesheets.move_from(files, i, -1, 1, true, true); else - i ++; + i++; } - if (! cuesheets.len ()) + if (!cuesheets.len()) return; // sort cuesheet list in natural order - cuesheets.sort (str_compare_encoded); + cuesheets.sort(str_compare_encoded); // sort file list in system-dependent order for duplicate removal - files.sort (filename_compare); + files.sort(filename_compare); for (String & cuesheet : cuesheets) { - AUDINFO ("Adding cuesheet: %s\n", (const char *) cuesheet); - status_update (cuesheet, result->items.len ()); + AUDINFO("Adding cuesheet: %s\n", (const char *)cuesheet); + status_update(cuesheet, result->items.len()); String title; // ignored Index items; - if (! playlist_load (cuesheet, title, items)) + if (!playlist_load(cuesheet, title, items)) continue; String prev_filename; for (auto & item : items) { - String filename = item.tuple.get_str (Tuple::AudioFile); - if (! filename) + String filename = item.tuple.get_str(Tuple::AudioFile); + if (!filename) continue; // shouldn't happen - if (! filter || filter (item.filename, user)) - add_file (std::move (item), filter, user, result, false); + if (!filter || filter(item.filename, user)) + add_file(std::move(item), filter, user, result, false); else result->filtered = true; // remove duplicates from file list - if (prev_filename && ! filename_compare (filename, prev_filename)) + if (prev_filename && !filename_compare(filename, prev_filename)) continue; - int idx = files.bsearch ((const char *) filename, filename_compare); + int idx = files.bsearch((const char *)filename, filename_compare); if (idx >= 0) - files.remove (idx, 1); + files.remove(idx, 1); - prev_filename = std::move (filename); + prev_filename = std::move(filename); } } } -static void add_folder (const char * filename, Playlist::FilterFunc filter, - void * user, AddResult * result, bool save_title) +static void add_folder(const char * filename, Playlist::FilterFunc filter, + void * user, AddResult * result, bool save_title) { - AUDINFO ("Adding folder: %s\n", filename); - status_update (filename, result->items.len ()); + AUDINFO("Adding folder: %s\n", filename); + status_update(filename, result->items.len()); String error; - Index files = VFSFile::read_folder (filename, error); + Index files = VFSFile::read_folder(filename, error); + Index folders; if (error) - aud_ui_show_error (str_printf (_("Error reading %s:\n%s"), filename, (const char *) error)); + aud_ui_show_error(str_printf(_("Error reading %s:\n%s"), filename, + (const char *)error)); - if (! files.len ()) + if (!files.len()) return; if (save_title) { - const char * slash = strrchr (filename, '/'); + const char * slash = strrchr(filename, '/'); if (slash) - result->title = String (str_decode_percent (slash + 1)); + result->title = String(str_decode_percent(slash + 1)); } - add_cuesheets (files, filter, user, result); + add_cuesheets(files, filter, user, result); // sort file list in natural order (must come after add_cuesheets) - files.sort (str_compare_encoded); + files.sort(str_compare_encoded); - for (const char * file : files) + for (const String & file : files) { - if (filter && ! filter (file, user)) + if (filter && !filter(file, user)) { result->filtered = true; continue; } String error; - VFSFileTest mode = VFSFile::test_file (file, - VFSFileTest (VFS_IS_REGULAR | VFS_IS_SYMLINK | VFS_IS_DIR), error); + VFSFileTest mode = VFSFile::test_file( + file, VFSFileTest(VFS_IS_REGULAR | VFS_IS_SYMLINK | VFS_IS_DIR), + error); if (error) - AUDERR ("%s: %s\n", file, (const char *) error); + AUDERR("%s: %s\n", (const char *)file, (const char *)error); if (mode & VFS_IS_SYMLINK) continue; if (mode & VFS_IS_REGULAR) - add_file ({String (file)}, filter, user, result, true); - else if ((mode & VFS_IS_DIR) && aud_get_bool (nullptr, "recurse_folders")) - add_folder (file, filter, user, result, false); + add_file({file}, filter, user, result, true); + else if ((mode & VFS_IS_DIR) && aud_get_bool("recurse_folders")) + folders.append(file); } + + // add folders after files + for (const String & folder : folders) + add_folder(folder, filter, user, result, false); } -static void add_generic (PlaylistAddItem && item, Playlist::FilterFunc filter, - void * user, AddResult * result, bool save_title, bool from_playlist) +static void add_generic(PlaylistAddItem && item, Playlist::FilterFunc filter, + void * user, AddResult * result, bool save_title, + bool from_playlist) { - if (! strstr (item.filename, "://")) + if (!strstr(item.filename, "://")) { /* Let's not add random junk to the playlist. */ - AUDERR ("Invalid URI: %s\n", (const char *) item.filename); + AUDERR("Invalid URI: %s\n", (const char *)item.filename); return; } - if (filter && ! filter (item.filename, user)) + if (filter && !filter(item.filename, user)) { result->filtered = true; return; @@ -370,263 +384,237 @@ static void add_generic (PlaylistAddItem && item, Playlist::FilterFunc filter, /* If the item has a valid tuple or known decoder, or it's a subtune, then * assume it's a playable file and skip some checks. */ - if (item.tuple.valid () || item.decoder || is_subtune (item.filename)) - add_file (std::move (item), filter, user, result, false); + if (item.tuple.valid() || item.decoder || is_subtune(item.filename)) + add_file(std::move(item), filter, user, result, false); else { int tests = 0; - if (! from_playlist) + if (!from_playlist) tests |= VFS_NO_ACCESS; - if (! from_playlist || aud_get_bool (nullptr, "folders_in_playlist")) + if (!from_playlist || aud_get_bool("folders_in_playlist")) tests |= VFS_IS_DIR; String error; - VFSFileTest mode = VFSFile::test_file (item.filename, (VFSFileTest) tests, error); + VFSFileTest mode = + VFSFile::test_file(item.filename, (VFSFileTest)tests, error); if ((mode & VFS_NO_ACCESS)) - aud_ui_show_error (str_printf (_("Error reading %s:\n%s"), - (const char *) item.filename, (const char *) error)); + aud_ui_show_error(str_printf(_("Error reading %s:\n%s"), + (const char *)item.filename, + (const char *)error)); else if (mode & VFS_IS_DIR) { - add_folder (item.filename, filter, user, result, save_title); + add_folder(item.filename, filter, user, result, save_title); result->saw_folder = true; } - else if ((! from_playlist) && Playlist::filename_is_playlist (item.filename)) - add_playlist (item.filename, filter, user, result, save_title); + else if ((!from_playlist) && + Playlist::filename_is_playlist(item.filename)) + add_playlist(item.filename, filter, user, result, save_title); else - add_file (std::move (item), filter, user, result, false); + add_file(std::move(item), filter, user, result, false); } } -static void start_thread_locked () +static void start_thread_locked() { if (add_thread_exited) { - pthread_mutex_unlock (& mutex); - pthread_join (add_thread, nullptr); - pthread_mutex_lock (& mutex); + mutex.unlock(); + add_thread.join(); + mutex.lock(); } - if (! add_thread_started || add_thread_exited) + if (!add_thread.joinable()) { - pthread_create (& add_thread, nullptr, add_worker, nullptr); - add_thread_started = true; + add_thread = std::thread(add_worker); add_thread_exited = false; } } -static void stop_thread_locked () +static void stop_thread_locked() { - if (add_thread_started) + if (add_thread.joinable()) { - pthread_mutex_unlock (& mutex); - pthread_join (add_thread, nullptr); - pthread_mutex_lock (& mutex); - add_thread_started = false; + mutex.unlock(); + add_thread.join(); + mutex.lock(); add_thread_exited = false; } } -static void add_finish (void * unused) +static void add_finish(void * unused) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - AddResult * result; - while ((result = add_results.head ())) + for (SmartPtr result; result.capture(add_results.pop_head());) { - add_results.remove (result); - - PlaylistEx playlist; - int count; - - if (! result->items.len ()) + if (!result->items.len()) { - if (result->saw_folder && ! result->filtered) - aud_ui_show_error (_("No files found.")); - goto FREE; + if (result->saw_folder && !result->filtered) + aud_ui_show_error(_("No files found.")); + continue; } - playlist = result->playlist; - if (! playlist.exists ()) /* playlist deleted */ - goto FREE; + PlaylistEx playlist = result->playlist; + if (!playlist.exists()) /* playlist deleted */ + continue; if (result->play) { - if (aud_get_bool (nullptr, "clear_playlist")) - playlist.remove_all_entries (); + if (aud_get_bool("clear_playlist")) + playlist.remove_all_entries(); else - playlist.queue_remove_all (); + playlist.queue_remove_all(); } - count = playlist.n_entries (); + int count = playlist.n_entries(); if (result->at < 0 || result->at > count) result->at = count; - if (result->title && ! count) + if (result->title && !count) { - if (! strcmp (playlist.get_title (), _("New Playlist"))) - playlist.set_title (result->title); + if (!strcmp(playlist.get_title(), _("New Playlist"))) + playlist.set_title(result->title); } /* temporarily disable scanning this playlist; the intent is to avoid * scanning until the currently playing entry is known, at which time it * can be scanned more efficiently (album art read in the same pass). */ - playlist_enable_scan (false); - playlist.insert_flat_items (result->at, std::move (result->items)); + playlist_enable_scan(false); + playlist.insert_flat_items(result->at, std::move(result->items)); if (result->play) { - if (! aud_get_bool (0, "shuffle")) - playlist.set_position (result->at); + if (!aud_get_bool("shuffle")) + playlist.set_position(result->at); - playlist.start_playback (); + playlist.start_playback(); } - playlist_enable_scan (true); - - FREE: - delete result; + playlist_enable_scan(true); } if (add_thread_exited) { - stop_thread_locked (); - status_done_locked (); + stop_thread_locked(); + status_done_locked(); } - pthread_mutex_unlock (& mutex); + mh.unlock(); // before calling hook - hook_call ("playlist add complete", nullptr); + hook_call("playlist add complete", nullptr); } -static void * add_worker (void * unused) +static void add_worker() { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - AddTask * task; - while ((task = add_tasks.head ())) + for (SmartPtr task; task.capture(add_tasks.pop_head());) { - add_tasks.remove (task); - current_playlist = task->playlist; - pthread_mutex_unlock (& mutex); + mh.unlock(); - playlist_cache_load (task->items); + playlist_cache_load(task->items); - AddResult * result = new AddResult (); + AddResult * result = new AddResult(); result->playlist = task->playlist; result->at = task->at; result->play = task->play; - bool save_title = (task->items.len () == 1); + bool save_title = (task->items.len() == 1); for (auto & item : task->items) - add_generic (std::move (item), task->filter, task->user, result, save_title, false); + add_generic(std::move(item), task->filter, task->user, result, + save_title, false); - delete task; + mh.lock(); + current_playlist = Playlist(); - pthread_mutex_lock (& mutex); - current_playlist = Playlist (); + if (!add_results.head()) + queued_add.queue(add_finish, nullptr); - if (! add_results.head ()) - queued_add.queue (add_finish, nullptr); - - add_results.append (result); + add_results.append(result); } add_thread_exited = true; - pthread_mutex_unlock (& mutex); - return nullptr; } -void adder_cleanup () +void adder_cleanup() { - pthread_mutex_lock (& mutex); - - add_tasks.clear (); + auto mh = mutex.take(); - stop_thread_locked (); - status_done_locked (); + add_tasks.clear(); - add_results.clear (); + stop_thread_locked(); + status_done_locked(); - queued_add.stop (); + add_results.clear(); - pthread_mutex_unlock (& mutex); + queued_add.stop(); } -EXPORT void Playlist::insert_entry (int at, - const char * filename, Tuple && tuple, bool play) const +EXPORT void Playlist::insert_entry(int at, const char * filename, + Tuple && tuple, bool play) const { Index items; - items.append (String (filename), std::move (tuple)); + items.append(String(filename), std::move(tuple)); - insert_items (at, std::move (items), play); + insert_items(at, std::move(items), play); } -EXPORT void Playlist::insert_items (int at, - Index && items, bool play) const +EXPORT void Playlist::insert_items(int at, Index && items, + bool play) const { - insert_filtered (at, std::move (items), nullptr, nullptr, play); + insert_filtered(at, std::move(items), nullptr, nullptr, play); } -EXPORT void Playlist::insert_filtered (int at, - Index && items, Playlist::FilterFunc filter, void * user, - bool play) const +EXPORT void Playlist::insert_filtered(int at, Index && items, + Playlist::FilterFunc filter, void * user, + bool play) const { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - AddTask * task = new AddTask (); + AddTask * task = new AddTask(); - task->playlist = * this; + task->playlist = *this; task->at = at; task->play = play; - task->items = std::move (items); + task->items = std::move(items); task->filter = filter; task->user = user; - add_tasks.append (task); - start_thread_locked (); - - pthread_mutex_unlock (& mutex); + add_tasks.append(task); + start_thread_locked(); } -EXPORT bool Playlist::add_in_progress () const +EXPORT bool Playlist::add_in_progress() const { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - for (AddTask * task = add_tasks.head (); task; task = add_tasks.next (task)) + for (AddTask * task = add_tasks.head(); task; task = add_tasks.next(task)) { - if (task->playlist == * this) - goto YES; + if (task->playlist == *this) + return true; } - if (current_playlist == * this) - goto YES; + if (current_playlist == *this) + return true; - for (AddResult * result = add_results.head (); result; result = add_results.next (result)) + for (AddResult * result = add_results.head(); result; + result = add_results.next(result)) { - if (result->playlist == * this) - goto YES; + if (result->playlist == *this) + return true; } - pthread_mutex_unlock (& mutex); return false; - -YES: - pthread_mutex_unlock (& mutex); - return true; } -EXPORT bool Playlist::add_in_progress_any () +EXPORT bool Playlist::add_in_progress_any() { - pthread_mutex_lock (& mutex); - - bool in_progress = (add_tasks.head () || - current_playlist != Playlist () || - add_results.head ()); + auto mh = mutex.take(); - pthread_mutex_unlock (& mutex); - return in_progress; + return (add_tasks.head() || current_playlist != Playlist() || + add_results.head()); } diff --git a/src/libaudcore/art-search.cc b/src/libaudcore/art-search.cc index 0fe71e9..05f9723 100644 --- a/src/libaudcore/art-search.cc +++ b/src/libaudcore/art-search.cc @@ -21,132 +21,133 @@ #include -#include /* for g_dir_open, g_file_test */ +#include /* for g_dir_open, g_file_test */ #include "audstrings.h" #include "index.h" #include "runtime.h" -struct SearchParams { +struct SearchParams +{ String filename; Index include, exclude; }; -static bool has_front_cover_extension (const char * name) +static bool has_front_cover_extension(const char * name) { - const char * ext = strrchr (name, '.'); - if (! ext) + const char * ext = strrchr(name, '.'); + if (!ext) return false; - return ! strcmp_nocase (ext, ".jpg") || ! strcmp_nocase (ext, ".jpeg") || - ! strcmp_nocase (ext, ".png"); + return !strcmp_nocase(ext, ".jpg") || !strcmp_nocase(ext, ".jpeg") || + !strcmp_nocase(ext, ".png"); } -static bool cover_name_filter (const char * name, - const Index & keywords, bool ret_on_empty) +static bool cover_name_filter(const char * name, const Index & keywords, + bool ret_on_empty) { - if (! keywords.len ()) + if (!keywords.len()) return ret_on_empty; for (const String & keyword : keywords) { - if (strstr_nocase (name, keyword)) + if (strstr_nocase(name, keyword)) return true; } return false; } -static String fileinfo_recursive_get_image (const char * path, - const SearchParams * params, int depth) +static String fileinfo_recursive_get_image(const char * path, + const SearchParams * params, + int depth) { - GDir * d = g_dir_open (path, 0, nullptr); - if (! d) - return String (); + GDir * d = g_dir_open(path, 0, nullptr); + if (!d) + return String(); const char * name; - if (aud_get_bool (nullptr, "use_file_cover") && ! depth) + if (aud_get_bool("use_file_cover") && !depth) { /* Look for images matching file name */ - while ((name = g_dir_read_name (d))) + while ((name = g_dir_read_name(d))) { - StringBuf newpath = filename_build ({path, name}); + StringBuf newpath = filename_build({path, name}); - if (! g_file_test (newpath, G_FILE_TEST_IS_DIR) && - has_front_cover_extension (name) && - same_basename (name, params->filename)) + if (has_front_cover_extension(name) && + same_basename(name, params->filename) && + !g_file_test(newpath, G_FILE_TEST_IS_DIR)) { - g_dir_close (d); - return String (newpath); + g_dir_close(d); + return String(newpath); } } - g_dir_rewind (d); + g_dir_rewind(d); } /* Search for files using filter */ - while ((name = g_dir_read_name (d))) + while ((name = g_dir_read_name(d))) { - StringBuf newpath = filename_build ({path, name}); + StringBuf newpath = filename_build({path, name}); - if (! g_file_test (newpath, G_FILE_TEST_IS_DIR) && - has_front_cover_extension (name) && - cover_name_filter (name, params->include, true) && - ! cover_name_filter (name, params->exclude, false)) + if (has_front_cover_extension(name) && + cover_name_filter(name, params->include, true) && + !cover_name_filter(name, params->exclude, false) && + !g_file_test(newpath, G_FILE_TEST_IS_DIR)) { - g_dir_close (d); - return String (newpath); + g_dir_close(d); + return String(newpath); } } - g_dir_rewind (d); + g_dir_rewind(d); - if (aud_get_bool (nullptr, "recurse_for_cover") && depth < aud_get_int (nullptr, "recurse_for_cover_depth")) + if (aud_get_bool("recurse_for_cover") && + depth < aud_get_int("recurse_for_cover_depth")) { /* Descend into directories recursively. */ - while ((name = g_dir_read_name (d))) + while ((name = g_dir_read_name(d))) { - StringBuf newpath = filename_build ({path, name}); + StringBuf newpath = filename_build({path, name}); - if (g_file_test (newpath, G_FILE_TEST_IS_DIR)) + if (g_file_test(newpath, G_FILE_TEST_IS_DIR)) { - String tmp = fileinfo_recursive_get_image (newpath, params, depth + 1); + String tmp = + fileinfo_recursive_get_image(newpath, params, depth + 1); if (tmp) { - g_dir_close (d); + g_dir_close(d); return tmp; } } } } - g_dir_close (d); - return String (); + g_dir_close(d); + return String(); } -String art_search (const char * filename) +String art_search(const char * filename) { - StringBuf local = uri_to_filename (filename); - if (! local) - return String (); + StringBuf local = uri_to_filename(filename); + if (!local) + return String(); - const char * elem = last_path_element (local); - if (! elem) - return String (); + const char * elem = last_path_element(local); + if (!elem) + return String(); - String include = aud_get_str (nullptr, "cover_name_include"); - String exclude = aud_get_str (nullptr, "cover_name_exclude"); + String include = aud_get_str("cover_name_include"); + String exclude = aud_get_str("cover_name_exclude"); - SearchParams params = { - String (elem), - str_list_to_index (include, ", "), - str_list_to_index (exclude, ", ") - }; + SearchParams params = {String(elem), str_list_to_index(include, ", "), + str_list_to_index(exclude, ", ")}; - cut_path_element (local, elem - local); + cut_path_element(local, elem - local); - String image_local = fileinfo_recursive_get_image (local, & params, 0); - return image_local ? String (filename_to_uri (image_local)) : String (); + String image_local = fileinfo_recursive_get_image(local, ¶ms, 0); + return image_local ? String(filename_to_uri(image_local)) : String(); } diff --git a/src/libaudcore/art.cc b/src/libaudcore/art.cc index e406eec..a0ea230 100644 --- a/src/libaudcore/art.cc +++ b/src/libaudcore/art.cc @@ -17,12 +17,11 @@ * the use of this software. */ -#include "probe.h" #include "internal.h" +#include "probe.h" #include #include -#include #include #include #include @@ -35,12 +34,14 @@ #include "multihash.h" #include "runtime.h" #include "scanner.h" +#include "threads.h" #include "vfs.h" #define FLAG_DONE 1 #define FLAG_SENT 2 -struct AudArtItem { +struct AudArtItem +{ String filename; int refcount; int flag; @@ -53,228 +54,222 @@ struct AudArtItem { bool is_temp; }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - +static aud::mutex mutex; static SimpleHash art_items; static AudArtItem * current_item; static QueuedFunc queued_requests; -static Index get_queued () +static Index get_queued() { + auto mh = mutex.take(); Index queued; - pthread_mutex_lock (& mutex); - art_items.iterate ([&] (const String &, AudArtItem & item) - { + art_items.iterate([&](const String &, AudArtItem & item) { if (item.flag == FLAG_DONE) { - queued.append (& item); + queued.append(&item); item.flag = FLAG_SENT; } }); - queued_requests.stop (); + queued_requests.stop(); - pthread_mutex_unlock (& mutex); return queued; } -static void send_requests (void *) +static void send_requests(void *) { - auto queued = get_queued (); + auto queued = get_queued(); for (AudArtItem * item : queued) { - hook_call ("art ready", (void *) (const char *) item->filename); - aud_art_unref (item); /* release temporary reference */ + hook_call("art ready", (void *)(const char *)item->filename); + aud_art_unref(item); /* release temporary reference */ } } -static void finish_item_locked (AudArtItem * item, Index && data, String && art_file) +static void finish_item(aud::mutex::holder &, AudArtItem * item, + Index && data, String && art_file) { /* already finished? */ if (item->flag) return; - item->data = std::move (data); - item->art_file = std::move (art_file); + item->data = std::move(data); + item->art_file = std::move(art_file); item->flag = FLAG_DONE; - queued_requests.queue (send_requests, nullptr); + queued_requests.queue(send_requests, nullptr); } -static void request_callback (ScanRequest * request) +static void request_callback(ScanRequest * request) { - pthread_mutex_lock (& mutex); - - AudArtItem * item = art_items.lookup (request->filename); + auto mh = mutex.take(); + AudArtItem * item = art_items.lookup(request->filename); if (item) - finish_item_locked (item, std::move (request->image_data), std::move (request->image_file)); - - pthread_mutex_unlock (& mutex); + finish_item(mh, item, std::move(request->image_data), + std::move(request->image_file)); } -static AudArtItem * art_item_get_locked (const String & filename, bool * queued) +static AudArtItem * art_item_get(aud::mutex::holder &, const String & filename, + bool * queued) { if (queued) - * queued = false; + *queued = false; // blacklist stdin - if (! strncmp (filename, "stdin://", 8)) + if (!strncmp(filename, "stdin://", 8)) return nullptr; - AudArtItem * item = art_items.lookup (filename); + AudArtItem * item = art_items.lookup(filename); if (item && item->flag) { - item->refcount ++; + item->refcount++; return item; } - if (! item) + if (!item) { - item = art_items.add (filename, AudArtItem ()); + item = art_items.add(filename, AudArtItem()); item->filename = filename; item->refcount = 1; /* temporary reference */ - scanner_request (new ScanRequest (filename, SCAN_IMAGE, request_callback)); + scanner_request( + new ScanRequest(filename, SCAN_IMAGE, request_callback)); } if (queued) - * queued = true; + *queued = true; return nullptr; } -static void art_item_unref_locked (AudArtItem * item) +static void art_item_unref(aud::mutex::holder &, AudArtItem * item) { - if (! -- item->refcount) + if (!--item->refcount) { /* delete temporary file */ if (item->art_file && item->is_temp) { - StringBuf local = uri_to_filename (item->art_file); + StringBuf local = uri_to_filename(item->art_file); if (local) - g_unlink (local); + g_unlink(local); } - art_items.remove (item->filename); + art_items.remove(item->filename); } } -static void clear_current_locked () +static void clear_current(aud::mutex::holder & mh) { if (current_item) { - art_item_unref_locked (current_item); + art_item_unref(mh, current_item); current_item = nullptr; } } -void art_cache_current (const String & filename, Index && data, String && art_file) +void art_cache_current(const String & filename, Index && data, + String && art_file) { - pthread_mutex_lock (& mutex); - - clear_current_locked (); + auto mh = mutex.take(); + clear_current(mh); - AudArtItem * item = art_items.lookup (filename); + AudArtItem * item = art_items.lookup(filename); - if (! item) + if (!item) { - item = art_items.add (filename, AudArtItem ()); + item = art_items.add(filename, AudArtItem()); item->filename = filename; item->refcount = 1; /* temporary reference */ } - finish_item_locked (item, std::move (data), std::move (art_file)); + finish_item(mh, item, std::move(data), std::move(art_file)); - item->refcount ++; + item->refcount++; current_item = item; - - pthread_mutex_unlock (& mutex); } -void art_clear_current () +void art_clear_current() { - pthread_mutex_lock (& mutex); - clear_current_locked (); - pthread_mutex_unlock (& mutex); + auto mh = mutex.take(); + clear_current(mh); } -void art_cleanup () +void art_cleanup() { - auto queued = get_queued (); + auto queued = get_queued(); for (AudArtItem * item : queued) - aud_art_unref (item); /* release temporary reference */ + aud_art_unref(item); /* release temporary reference */ /* playback should already be stopped */ - assert (! current_item); + assert(!current_item); - if (art_items.n_items ()) - AUDWARN ("Album art reference count not zero at exit!\n"); + if (art_items.n_items()) + AUDWARN("Album art reference count not zero at exit!\n"); } -EXPORT AudArtPtr aud_art_request (const char * file, int format, bool * queued) +EXPORT AudArtPtr aud_art_request(const char * file, int format, bool * queued) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); + AudArtItem * item = art_item_get(mh, String(file), queued); - String key (file); - AudArtItem * item = art_item_get_locked (key, queued); - bool good = true; - - if (! item) - goto UNLOCK; + if (!item) + return AudArtPtr(); if (format & AUD_ART_DATA) { /* load data from external image file */ - if (! item->data.len () && item->art_file) + if (!item->data.len() && item->art_file) { - VFSFile file (item->art_file, "r"); + VFSFile file(item->art_file, "r"); if (file) - item->data = file.read_all (); + item->data = file.read_all(); } - if (! item->data.len ()) - good = false; + if (!item->data.len()) + { + art_item_unref(mh, item); + return AudArtPtr(); + } } if (format & AUD_ART_FILE) { /* save data to temporary file */ - if (item->data.len () && ! item->art_file) + if (item->data.len() && !item->art_file) { - String local = write_temp_file (item->data.begin (), item->data.len ()); + String local = + write_temp_file(item->data.begin(), item->data.len()); if (local) { - item->art_file = String (filename_to_uri (local)); + item->art_file = String(filename_to_uri(local)); item->is_temp = true; } } - if (! item->art_file) - good = false; - } - - if (! good) - { - art_item_unref_locked (item); - item = nullptr; + if (!item->art_file) + { + art_item_unref(mh, item); + return AudArtPtr(); + } } -UNLOCK: - pthread_mutex_unlock (& mutex); - return AudArtPtr (item); + return AudArtPtr(item); } -EXPORT const Index * aud_art_data (const AudArtItem * item) - { return & item->data; } -EXPORT const char * aud_art_file (const AudArtItem * item) - { return item->art_file; } +EXPORT const Index * aud_art_data(const AudArtItem * item) +{ + return &item->data; +} +EXPORT const char * aud_art_file(const AudArtItem * item) +{ + return item->art_file; +} -EXPORT void aud_art_unref (AudArtItem * item) +EXPORT void aud_art_unref(AudArtItem * item) { - pthread_mutex_lock (& mutex); - art_item_unref_locked (item); - pthread_mutex_unlock (& mutex); + auto mh = mutex.take(); + art_item_unref(mh, item); } diff --git a/src/libaudcore/audio.cc b/src/libaudcore/audio.cc index b553864..524ae7f 100644 --- a/src/libaudcore/audio.cc +++ b/src/libaudcore/audio.cc @@ -27,106 +27,129 @@ #define SW_VOLUME_RANGE 40 /* decibels */ -struct packed24_t { uint8_t b[3]; }; -static_assert (sizeof (packed24_t) == 3, "invalid packed 24-bit type"); +struct packed24_t +{ + uint8_t b[3]; +}; +static_assert(sizeof(packed24_t) == 3, "invalid packed 24-bit type"); template -void interlace_loop (const void * const * in, int channels, void * out, int frames) +void interlace_loop(const void * const * in, int channels, void * out, + int frames) { - for (int c = 0; c < channels; c ++) + for (int c = 0; c < channels; c++) { - auto get = (const Word *) in[c]; + auto get = (const Word *)in[c]; auto end = get + frames; - auto set = (Word *) out + c; + auto set = (Word *)out + c; while (get < end) { - * set = * get ++; + *set = *get++; set += channels; } } } template -void deinterlace_loop (const void * in, int channels, void * const * out, int frames) +void deinterlace_loop(const void * in, int channels, void * const * out, + int frames) { - for (int c = 0; c < channels; c ++) + for (int c = 0; c < channels; c++) { - auto get = (const Word *) in + c; - auto set = (Word *) out[c]; + auto get = (const Word *)in + c; + auto set = (Word *)out[c]; auto end = set + frames; while (set < end) { - * set ++ = * get; + *set++ = *get; get += channels; } } } -EXPORT void audio_interlace (const void * const * in, int format, int channels, - void * out, int frames) +EXPORT void audio_interlace(const void * const * in, int format, int channels, + void * out, int frames) { switch (format) { case FMT_FLOAT: - interlace_loop (in, channels, out, frames); + interlace_loop(in, channels, out, frames); break; - case FMT_S8: case FMT_U8: - interlace_loop (in, channels, out, frames); + case FMT_S8: + case FMT_U8: + interlace_loop(in, channels, out, frames); break; - case FMT_S16_LE: case FMT_S16_BE: - case FMT_U16_LE: case FMT_U16_BE: - interlace_loop (in, channels, out, frames); + case FMT_S16_LE: + case FMT_S16_BE: + case FMT_U16_LE: + case FMT_U16_BE: + interlace_loop(in, channels, out, frames); break; - case FMT_S24_LE: case FMT_S24_BE: - case FMT_U24_LE: case FMT_U24_BE: - case FMT_S32_LE: case FMT_S32_BE: - case FMT_U32_LE: case FMT_U32_BE: - interlace_loop (in, channels, out, frames); + case FMT_S24_LE: + case FMT_S24_BE: + case FMT_U24_LE: + case FMT_U24_BE: + case FMT_S32_LE: + case FMT_S32_BE: + case FMT_U32_LE: + case FMT_U32_BE: + interlace_loop(in, channels, out, frames); break; - case FMT_S24_3LE: case FMT_S24_3BE: - case FMT_U24_3LE: case FMT_U24_3BE: - interlace_loop (in, channels, out, frames); + case FMT_S24_3LE: + case FMT_S24_3BE: + case FMT_U24_3LE: + case FMT_U24_3BE: + interlace_loop(in, channels, out, frames); break; } } -EXPORT void audio_deinterlace (const void * in, int format, int channels, - void * const * out, int frames) +EXPORT void audio_deinterlace(const void * in, int format, int channels, + void * const * out, int frames) { switch (format) { case FMT_FLOAT: - deinterlace_loop (in, channels, out, frames); + deinterlace_loop(in, channels, out, frames); break; - case FMT_S8: case FMT_U8: - deinterlace_loop (in, channels, out, frames); + case FMT_S8: + case FMT_U8: + deinterlace_loop(in, channels, out, frames); break; - case FMT_S16_LE: case FMT_S16_BE: - case FMT_U16_LE: case FMT_U16_BE: - deinterlace_loop (in, channels, out, frames); + case FMT_S16_LE: + case FMT_S16_BE: + case FMT_U16_LE: + case FMT_U16_BE: + deinterlace_loop(in, channels, out, frames); break; - case FMT_S24_LE: case FMT_S24_BE: - case FMT_U24_LE: case FMT_U24_BE: - case FMT_S32_LE: case FMT_S32_BE: - case FMT_U32_LE: case FMT_U32_BE: - deinterlace_loop (in, channels, out, frames); + case FMT_S24_LE: + case FMT_S24_BE: + case FMT_U24_LE: + case FMT_U24_BE: + case FMT_S32_LE: + case FMT_S32_BE: + case FMT_U32_LE: + case FMT_U32_BE: + deinterlace_loop(in, channels, out, frames); break; - case FMT_S24_3LE: case FMT_S24_3BE: - case FMT_U24_3LE: case FMT_U24_3BE: - deinterlace_loop (in, channels, out, frames); + case FMT_S24_3LE: + case FMT_S24_3BE: + case FMT_U24_3LE: + case FMT_U24_3BE: + deinterlace_loop(in, channels, out, frames); break; } } -static constexpr bool is_le (int format) +static constexpr bool is_le(int format) { return format == FMT_S16_LE || format == FMT_U16_LE || format == FMT_S24_LE || format == FMT_U24_LE || @@ -134,33 +157,48 @@ static constexpr bool is_le (int format) format == FMT_S24_3LE || format == FMT_U24_3LE; } -static constexpr bool is_signed (int format) +static constexpr bool is_signed(int format) { - return (format == FMT_S8 || - format == FMT_S16_LE || format == FMT_S16_BE || + return (format == FMT_S8 || format == FMT_S16_LE || format == FMT_S16_BE || format == FMT_S24_LE || format == FMT_S24_BE || format == FMT_S32_LE || format == FMT_S32_BE || format == FMT_S24_3LE || format == FMT_S24_3BE); } -static constexpr unsigned neg_range (int format) +static constexpr unsigned neg_range(int format) { - return (format >= FMT_S32_LE && format < FMT_S24_3LE) ? 0x80000000 : - (format >= FMT_S24_LE) ? 0x800000 : - (format >= FMT_S16_LE) ? 0x8000 : 0x80; + return (format >= FMT_S32_LE && format < FMT_S24_3LE) + ? 0x80000000 + : (format >= FMT_S24_LE) + ? 0x800000 + : (format >= FMT_S16_LE) ? 0x8000 : 0x80; } // 0x7fffff80 = largest representable floating-point value before 2^31 -static constexpr unsigned pos_range (int format) +static constexpr unsigned pos_range(int format) { - return (format >= FMT_S32_LE && format < FMT_S24_3LE) ? 0x7fffff80 : - (format >= FMT_S24_LE) ? 0x7fffff : - (format >= FMT_S16_LE) ? 0x7fff : 0x7f; + return (format >= FMT_S32_LE && format < FMT_S24_3LE) + ? 0x7fffff80 + : (format >= FMT_S24_LE) + ? 0x7fffff + : (format >= FMT_S16_LE) ? 0x7fff : 0x7f; } -template T do_swap (T value) { return value; } -template<> int16_t do_swap (int16_t value) { return bswap16 (value); } -template<> int32_t do_swap (int32_t value) { return bswap32 (value); } +template +T do_swap(T value) +{ + return value; +} +template<> +int16_t do_swap(int16_t value) +{ + return bswap16(value); +} +template<> +int32_t do_swap(int32_t value) +{ + return bswap32(value); +} template struct Convert @@ -171,26 +209,26 @@ struct Convert static constexpr bool native_le = true; #endif - static Int to_int (Word value) + static Int to_int(Word value) { - if (is_le (format) ^ native_le) - value = do_swap (value); - if (is_signed (format)) - value += neg_range (format); + if (is_le(format) ^ native_le) + value = do_swap(value); + if (is_signed(format)) + value += neg_range(format); if (format >= FMT_S24_LE && format <= FMT_U24_BE) value &= 0xffffff; /* ignore high byte */ - return value - neg_range (format); + return value - neg_range(format); } - static Word to_word (Int value) + static Word to_word(Int value) { - if (! is_signed (format)) - value += neg_range (format); + if (!is_signed(format)) + value += neg_range(format); if (format >= FMT_S24_LE && format <= FMT_U24_BE) value &= 0xffffff; /* zero high byte */ - if (is_le (format) ^ native_le) - value = do_swap (value); + if (is_le(format) ^ native_le) + value = do_swap(value); return value; } @@ -199,31 +237,30 @@ struct Convert template struct Convert { - static int32_t to_int (packed24_t value) + static int32_t to_int(packed24_t value) { uint8_t hi, mid, lo; - if (is_le (format)) + if (is_le(format)) hi = value.b[2], mid = value.b[1], lo = value.b[0]; else hi = value.b[0], mid = value.b[1], lo = value.b[2]; - if (! is_signed (format)) + if (!is_signed(format)) hi -= 0x80; - return (int8_t (hi) << 16) | (mid << 8) | lo; + return (int8_t(hi) << 16) | (mid << 8) | lo; } - static packed24_t to_word (int32_t value) + static packed24_t to_word(int32_t value) { - auto hi = uint8_t (value >> 16), - mid = uint8_t (value >> 8), - lo = uint8_t (value); + auto hi = uint8_t(value >> 16), mid = uint8_t(value >> 8), + lo = uint8_t(value); - if (! is_signed (format)) + if (!is_signed(format)) hi += 0x80; - if (is_le (format)) + if (is_le(format)) return {{lo, mid, hi}}; else return {{hi, mid, lo}}; @@ -231,109 +268,184 @@ struct Convert }; template -void from_int_loop (const void * in_, float * out, int samples) +void from_int_loop(const void * in_, float * out, int samples) { - auto in = (const Word *) in_; + auto in = (const Word *)in_; auto end = in + samples; while (in < end) { - Int value = Convert::to_int (* in ++); - * out ++ = value * (1.0f / neg_range (format)); + Int value = Convert::to_int(*in++); + *out++ = value * (1.0f / neg_range(format)); } } template -void to_int_loop (const float * in, void * out_, int samples) +void to_int_loop(const float * in, void * out_, int samples) { auto end = in + samples; - auto out = (Word *) out_; + auto out = (Word *)out_; while (in < end) { - float f = (* in ++) * neg_range (format); - f = aud::clamp (f, -(float) neg_range (format), (float) pos_range (format)); - * out ++ = Convert::to_word (lrintf (f)); + float f = (*in++) * neg_range(format); + f = aud::clamp(f, -(float)neg_range(format), (float)pos_range(format)); + *out++ = Convert::to_word(lrintf(f)); } } -EXPORT void audio_from_int (const void * in, int format, float * out, int samples) +EXPORT void audio_from_int(const void * in, int format, float * out, + int samples) { switch (format) { - case FMT_S8: from_int_loop (in, out, samples); break; - case FMT_U8: from_int_loop (in, out, samples); break; - - case FMT_S16_LE: from_int_loop (in, out, samples); break; - case FMT_S16_BE: from_int_loop (in, out, samples); break; - case FMT_U16_LE: from_int_loop (in, out, samples); break; - case FMT_U16_BE: from_int_loop (in, out, samples); break; - - case FMT_S24_LE: from_int_loop (in, out, samples); break; - case FMT_S24_BE: from_int_loop (in, out, samples); break; - case FMT_U24_LE: from_int_loop (in, out, samples); break; - case FMT_U24_BE: from_int_loop (in, out, samples); break; - - case FMT_S32_LE: from_int_loop (in, out, samples); break; - case FMT_S32_BE: from_int_loop (in, out, samples); break; - case FMT_U32_LE: from_int_loop (in, out, samples); break; - case FMT_U32_BE: from_int_loop (in, out, samples); break; - - case FMT_S24_3LE: from_int_loop (in, out, samples); break; - case FMT_S24_3BE: from_int_loop (in, out, samples); break; - case FMT_U24_3LE: from_int_loop (in, out, samples); break; - case FMT_U24_3BE: from_int_loop (in, out, samples); break; + case FMT_S8: + from_int_loop(in, out, samples); + break; + case FMT_U8: + from_int_loop(in, out, samples); + break; + + case FMT_S16_LE: + from_int_loop(in, out, samples); + break; + case FMT_S16_BE: + from_int_loop(in, out, samples); + break; + case FMT_U16_LE: + from_int_loop(in, out, samples); + break; + case FMT_U16_BE: + from_int_loop(in, out, samples); + break; + + case FMT_S24_LE: + from_int_loop(in, out, samples); + break; + case FMT_S24_BE: + from_int_loop(in, out, samples); + break; + case FMT_U24_LE: + from_int_loop(in, out, samples); + break; + case FMT_U24_BE: + from_int_loop(in, out, samples); + break; + + case FMT_S32_LE: + from_int_loop(in, out, samples); + break; + case FMT_S32_BE: + from_int_loop(in, out, samples); + break; + case FMT_U32_LE: + from_int_loop(in, out, samples); + break; + case FMT_U32_BE: + from_int_loop(in, out, samples); + break; + + case FMT_S24_3LE: + from_int_loop(in, out, samples); + break; + case FMT_S24_3BE: + from_int_loop(in, out, samples); + break; + case FMT_U24_3LE: + from_int_loop(in, out, samples); + break; + case FMT_U24_3BE: + from_int_loop(in, out, samples); + break; } } -EXPORT void audio_to_int (const float * in, void * out, int format, int samples) +EXPORT void audio_to_int(const float * in, void * out, int format, int samples) { - int save = fegetround (); - fesetround (FE_TONEAREST); + int save = fegetround(); + fesetround(FE_TONEAREST); switch (format) { - case FMT_S8: to_int_loop (in, out, samples); break; - case FMT_U8: to_int_loop (in, out, samples); break; - - case FMT_S16_LE: to_int_loop (in, out, samples); break; - case FMT_S16_BE: to_int_loop (in, out, samples); break; - case FMT_U16_LE: to_int_loop (in, out, samples); break; - case FMT_U16_BE: to_int_loop (in, out, samples); break; - - case FMT_S24_LE: to_int_loop (in, out, samples); break; - case FMT_S24_BE: to_int_loop (in, out, samples); break; - case FMT_U24_LE: to_int_loop (in, out, samples); break; - case FMT_U24_BE: to_int_loop (in, out, samples); break; - - case FMT_S32_LE: to_int_loop (in, out, samples); break; - case FMT_S32_BE: to_int_loop (in, out, samples); break; - case FMT_U32_LE: to_int_loop (in, out, samples); break; - case FMT_U32_BE: to_int_loop (in, out, samples); break; - - case FMT_S24_3LE: to_int_loop (in, out, samples); break; - case FMT_S24_3BE: to_int_loop (in, out, samples); break; - case FMT_U24_3LE: to_int_loop (in, out, samples); break; - case FMT_U24_3BE: to_int_loop (in, out, samples); break; + case FMT_S8: + to_int_loop(in, out, samples); + break; + case FMT_U8: + to_int_loop(in, out, samples); + break; + + case FMT_S16_LE: + to_int_loop(in, out, samples); + break; + case FMT_S16_BE: + to_int_loop(in, out, samples); + break; + case FMT_U16_LE: + to_int_loop(in, out, samples); + break; + case FMT_U16_BE: + to_int_loop(in, out, samples); + break; + + case FMT_S24_LE: + to_int_loop(in, out, samples); + break; + case FMT_S24_BE: + to_int_loop(in, out, samples); + break; + case FMT_U24_LE: + to_int_loop(in, out, samples); + break; + case FMT_U24_BE: + to_int_loop(in, out, samples); + break; + + case FMT_S32_LE: + to_int_loop(in, out, samples); + break; + case FMT_S32_BE: + to_int_loop(in, out, samples); + break; + case FMT_U32_LE: + to_int_loop(in, out, samples); + break; + case FMT_U32_BE: + to_int_loop(in, out, samples); + break; + + case FMT_S24_3LE: + to_int_loop(in, out, samples); + break; + case FMT_S24_3BE: + to_int_loop(in, out, samples); + break; + case FMT_U24_3LE: + to_int_loop(in, out, samples); + break; + case FMT_U24_3BE: + to_int_loop(in, out, samples); + break; } - fesetround (save); + fesetround(save); } -EXPORT void audio_amplify (float * data, int channels, int frames, const float * factors) +EXPORT void audio_amplify(float * data, int channels, int frames, + const float * factors) { float * end = data + channels * frames; int channel; while (data < end) { - for (channel = 0; channel < channels; channel ++) + for (channel = 0; channel < channels; channel++) { - * data = * data * factors[channel]; - data ++; + *data = *data * factors[channel]; + data++; } } } -EXPORT void audio_amplify (float * data, int channels, int frames, StereoVolume volume) +EXPORT void audio_amplify(float * data, int channels, int frames, + StereoVolume volume) { if (channels < 1 || channels > AUD_MAX_CHANNELS) return; @@ -345,9 +457,11 @@ EXPORT void audio_amplify (float * data, int channels, int frames, StereoVolume float factors[AUD_MAX_CHANNELS]; if (volume.left > 0) - lfactor = powf (10, (float) SW_VOLUME_RANGE * (volume.left - 100) / 100 / 20); + lfactor = + powf(10, (float)SW_VOLUME_RANGE * (volume.left - 100) / 100 / 20); if (volume.right > 0) - rfactor = powf (10, (float) SW_VOLUME_RANGE * (volume.right - 100) / 100 / 20); + rfactor = + powf(10, (float)SW_VOLUME_RANGE * (volume.right - 100) / 100 / 20); if (channels == 2) { @@ -356,37 +470,37 @@ EXPORT void audio_amplify (float * data, int channels, int frames, StereoVolume } else { - for (int c = 0; c < channels; c ++) - factors[c] = aud::max (lfactor, rfactor); + for (int c = 0; c < channels; c++) + factors[c] = aud::max(lfactor, rfactor); } - audio_amplify (data, channels, frames, factors); + audio_amplify(data, channels, frames, factors); } /* linear approximation of y = sin(x) */ /* contributed by Anders Johansson */ -EXPORT void audio_soft_clip (float * data, int samples) +EXPORT void audio_soft_clip(float * data, int samples) { float * end = data + samples; while (data < end) { - float x = * data; - float y = fabsf (x); + float x = *data; + float y = fabsf(x); if (y <= 0.4) - ; /* (0, 0.4) -> (0, 0.4) */ + ; /* (0, 0.4) -> (0, 0.4) */ else if (y <= 0.7) - y = 0.8 * y + 0.08; /* (0.4, 0.7) -> (0.4, 0.64) */ + y = 0.8 * y + 0.08; /* (0.4, 0.7) -> (0.4, 0.64) */ else if (y <= 1.0) - y = 0.7 * y + 0.15; /* (0.7, 1) -> (0.64, 0.85) */ + y = 0.7 * y + 0.15; /* (0.7, 1) -> (0.64, 0.85) */ else if (y <= 1.3) - y = 0.4 * y + 0.45; /* (1, 1.3) -> (0.85, 0.97) */ + y = 0.4 * y + 0.45; /* (1, 1.3) -> (0.85, 0.97) */ else if (y <= 1.5) - y = 0.15 * y + 0.775; /* (1.3, 1.5) -> (0.97, 1) */ + y = 0.15 * y + 0.775; /* (1.3, 1.5) -> (0.97, 1) */ else - y = 1.0; /* (1.5, inf) -> 1 */ + y = 1.0; /* (1.5, inf) -> 1 */ - * data ++ = (x > 0) ? y : -y; + *data++ = (x > 0) ? y : -y; } } diff --git a/src/libaudcore/audstrings.cc b/src/libaudcore/audstrings.cc index a53f8e7..d0f2264 100644 --- a/src/libaudcore/audstrings.cc +++ b/src/libaudcore/audstrings.cc @@ -1,6 +1,6 @@ /* * audstrings.c - * Copyright 2009-2012 John Lindgren and William Pitcock + * Copyright 2009-2012 John Lindgren and Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,8 +34,8 @@ #include "runtime.h" #define MAX_POW10 9 -static const unsigned int_pow10[MAX_POW10 + 1] = - {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; +static const unsigned int_pow10[MAX_POW10 + 1] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; static const char ascii_to_hex[256] = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" @@ -47,20 +47,19 @@ static const char ascii_to_hex[256] = "\x0\xa\xb\xc\xd\xe\xf\x0\x0\x0\x0\x0\x0\x0\x0\x0" "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0"; -static const char hex_to_ascii[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' -}; +static const char hex_to_ascii[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; static const char uri_legal_table[256] = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" - "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x1\x1" // '-' '.' '/' + "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x1\x1" // '-' '.' '/' #ifdef _WIN32 /* We assume ':' is used with a "reserved purpose" (i.e. drive letter). * This assumption might need to be reconsidered for non-file URIs. */ - "\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x0\x0\x0\x0\x0" // 0-9 ':' + "\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x0\x0\x0\x0\x0" // 0-9 ':' #else - "\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x0\x0\x0\x0\x0\x0" // 0-9 + "\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x0\x0\x0\x0\x0\x0" // 0-9 #endif "\x0\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1" // A-O "\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x0\x0\x0\x0\x1" // P-Z '_' @@ -73,10 +72,10 @@ static const char swap_case[256] = "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" "\0ABCDEFGHIJKLMNOPQRSTUVWXYZ\0\0\0\0\0"; -#define FROM_HEX(c) (ascii_to_hex[(unsigned char) (c)]) -#define TO_HEX(i) (hex_to_ascii[(i) & 15]) -#define IS_LEGAL(c) (uri_legal_table[(unsigned char) (c)]) -#define SWAP_CASE(c) (swap_case[(unsigned char) (c)]) +#define FROM_HEX(c) (ascii_to_hex[(unsigned char)(c)]) +#define TO_HEX(i) (hex_to_ascii[(i)&15]) +#define IS_LEGAL(c) (uri_legal_table[(unsigned char)(c)]) +#define SWAP_CASE(c) (swap_case[(unsigned char)(c)]) #ifdef _WIN32 #define IS_SEP(c) ((c) == '/' || (c) == '\\') @@ -85,119 +84,120 @@ static const char swap_case[256] = #endif /* strcmp() that handles nullptr safely */ -EXPORT int strcmp_safe (const char * a, const char * b, int len) +EXPORT int strcmp_safe(const char * a, const char * b, int len) { - if (! a) + if (!a) return b ? -1 : 0; - if (! b) + if (!b) return 1; - return len < 0 ? strcmp (a, b) : strncmp (a, b, len); + return len < 0 ? strcmp(a, b) : strncmp(a, b, len); } /* ASCII version of strcasecmp, also handles nullptr safely */ -EXPORT int strcmp_nocase (const char * a, const char * b, int len) +EXPORT int strcmp_nocase(const char * a, const char * b, int len) { - if (! a) + if (!a) return b ? -1 : 0; - if (! b) + if (!b) return 1; - return len < 0 ? g_ascii_strcasecmp (a, b) : g_ascii_strncasecmp (a, b, len); + return len < 0 ? g_ascii_strcasecmp(a, b) : g_ascii_strncasecmp(a, b, len); } /* strlen() if is negative, otherwise strnlen() */ -EXPORT int strlen_bounded (const char * s, int len) +EXPORT int strlen_bounded(const char * s, int len) { if (len < 0) - return strlen (s); + return strlen(s); - const char * nul = (const char *) memchr (s, 0, len); + const char * nul = (const char *)memchr(s, 0, len); if (nul) return nul - s; return len; } -EXPORT StringBuf str_copy (const char * s, int len) +EXPORT StringBuf str_copy(const char * s, int len) { if (len < 0) - len = strlen (s); + len = strlen(s); - StringBuf str (len); - memcpy (str, s, len); + StringBuf str(len); + memcpy(str, s, len); return str; } -EXPORT StringBuf str_concat (const std::initializer_list & strings) +EXPORT StringBuf str_concat(const std::initializer_list & strings) { - StringBuf str (-1); + StringBuf str(-1); char * set = str; - int left = str.len (); + int left = str.len(); for (const char * s : strings) { - int len = strlen (s); + int len = strlen(s); if (len > left) - throw std::bad_alloc (); + throw std::bad_alloc(); - memcpy (set, s, len); + memcpy(set, s, len); set += len; left -= len; } - str.resize (set - str); + str.resize(set - str); return str; } -EXPORT StringBuf str_printf (const char * format, ...) +EXPORT StringBuf str_printf(const char * format, ...) { va_list args; - va_start (args, format); - StringBuf str = str_vprintf (format, args); - va_end (args); + va_start(args, format); + StringBuf str = str_vprintf(format, args); + va_end(args); return str; } -EXPORT void str_append_printf (StringBuf & str, const char * format, ...) +EXPORT void str_append_printf(StringBuf & str, const char * format, ...) { va_list args; - va_start (args, format); - str_append_vprintf (str, format, args); - va_end (args); + va_start(args, format); + str_append_vprintf(str, format, args); + va_end(args); } -EXPORT StringBuf str_vprintf (const char * format, va_list args) +EXPORT StringBuf str_vprintf(const char * format, va_list args) { - StringBuf str (-1); - int len = vsnprintf (str, str.len (), format, args); - str.resize (len); + StringBuf str(-1); + int len = vsnprintf(str, str.len(), format, args); + str.resize(len); return str; } -EXPORT void str_append_vprintf (StringBuf & str, const char * format, va_list args) +EXPORT void str_append_vprintf(StringBuf & str, const char * format, + va_list args) { - int len0 = str.len (); - str.resize (-1); - int len1 = vsnprintf (str + len0, str.len () - len0, format, args); - str.resize (len0 + len1); + int len0 = str.len(); + str.resize(-1); + int len1 = vsnprintf(str + len0, str.len() - len0, format, args); + str.resize(len0 + len1); } -EXPORT bool str_has_prefix_nocase (const char * str, const char * prefix) +EXPORT bool str_has_prefix_nocase(const char * str, const char * prefix) { - return ! g_ascii_strncasecmp (str, prefix, strlen (prefix)); + return !g_ascii_strncasecmp(str, prefix, strlen(prefix)); } -EXPORT bool str_has_suffix_nocase (const char * str, const char * suffix) +EXPORT bool str_has_suffix_nocase(const char * str, const char * suffix) { - int len1 = strlen (str); - int len2 = strlen (suffix); + int len1 = strlen(str); + int len2 = strlen(suffix); if (len2 > len1) return false; - return ! g_ascii_strcasecmp (str + len1 - len2, suffix); + return !g_ascii_strcasecmp(str + len1 - len2, suffix); } /* Bernstein's hash function (unrolled version): @@ -207,23 +207,18 @@ EXPORT bool str_has_suffix_nocase (const char * str, const char * suffix) * This function is more than twice as fast as g_str_hash (a simpler version of * Bernstein's hash) and even slightly faster than Murmur 3. */ -EXPORT unsigned str_calc_hash (const char * s) +EXPORT unsigned str_calc_hash(const char * s) { unsigned h = 5381; - int len = strlen (s); + int len = strlen(s); while (len >= 8) { - h = h * 1954312449 + - (unsigned) s[0] * 3963737313 + - (unsigned) s[1] * 1291467969 + - (unsigned) s[2] * 39135393 + - (unsigned) s[3] * 1185921 + - (unsigned) s[4] * 35937 + - (unsigned) s[5] * 1089 + - (unsigned) s[6] * 33 + - s[7]; + h = h * 1954312449 + (unsigned)s[0] * 3963737313 + + (unsigned)s[1] * 1291467969 + (unsigned)s[2] * 39135393 + + (unsigned)s[3] * 1185921 + (unsigned)s[4] * 35937 + + (unsigned)s[5] * 1089 + (unsigned)s[6] * 33 + s[7]; s += 8; len -= 8; @@ -231,11 +226,8 @@ EXPORT unsigned str_calc_hash (const char * s) if (len >= 4) { - h = h * 1185921 + - (unsigned) s[0] * 35937 + - (unsigned) s[1] * 1089 + - (unsigned) s[2] * 33 + - s[3]; + h = h * 1185921 + (unsigned)s[0] * 35937 + (unsigned)s[1] * 1089 + + (unsigned)s[2] * 33 + s[3]; s += 4; len -= 4; @@ -243,15 +235,18 @@ EXPORT unsigned str_calc_hash (const char * s) switch (len) { - case 3: h = h * 33 + (* s ++); - case 2: h = h * 33 + (* s ++); - case 1: h = h * 33 + (* s ++); + case 3: + h = h * 33 + (*s++); + case 2: + h = h * 33 + (*s++); + case 1: + h = h * 33 + (*s++); } return h; } -EXPORT const char * strstr_nocase (const char * haystack, const char * needle) +EXPORT const char * strstr_nocase(const char * haystack, const char * needle) { while (1) { @@ -260,23 +255,24 @@ EXPORT const char * strstr_nocase (const char * haystack, const char * needle) while (1) { - char a = * ap ++; - char b = * bp ++; + char a = *ap++; + char b = *bp++; - if (! b) /* all of needle matched */ - return (char *) haystack; - if (! a) /* end of haystack reached */ + if (!b) /* all of needle matched */ + return (char *)haystack; + if (!a) /* end of haystack reached */ return nullptr; - if (a != b && a != SWAP_CASE (b)) + if (a != b && a != SWAP_CASE(b)) break; } - haystack ++; + haystack++; } } -EXPORT const char * strstr_nocase_utf8 (const char * haystack, const char * needle) +EXPORT const char * strstr_nocase_utf8(const char * haystack, + const char * needle) { while (1) { @@ -285,112 +281,114 @@ EXPORT const char * strstr_nocase_utf8 (const char * haystack, const char * need while (1) { - gunichar a = g_utf8_get_char (ap); - gunichar b = g_utf8_get_char (bp); + gunichar a = g_utf8_get_char(ap); + gunichar b = g_utf8_get_char(bp); - if (! b) /* all of needle matched */ - return (char *) haystack; - if (! a) /* end of haystack reached */ + if (!b) /* all of needle matched */ + return (char *)haystack; + if (!a) /* end of haystack reached */ return nullptr; - if (a != b && (a < 128 ? (gunichar) SWAP_CASE (a) != b : - g_unichar_tolower (a) != g_unichar_tolower (b))) + if (a != b && + (a < 128 ? (gunichar)SWAP_CASE(a) != b + : g_unichar_tolower(a) != g_unichar_tolower(b))) break; - ap = g_utf8_next_char (ap); - bp = g_utf8_next_char (bp); + ap = g_utf8_next_char(ap); + bp = g_utf8_next_char(bp); } - haystack = g_utf8_next_char (haystack); + haystack = g_utf8_next_char(haystack); } } -EXPORT StringBuf str_tolower (const char * str) +EXPORT StringBuf str_tolower(const char * str) { - StringBuf buf (strlen (str)); + StringBuf buf(strlen(str)); char * set = buf; - while (* str) - * set ++ = g_ascii_tolower (* str ++); + while (*str) + *set++ = g_ascii_tolower(*str++); return buf; } -EXPORT StringBuf str_tolower_utf8 (const char * str) +EXPORT StringBuf str_tolower_utf8(const char * str) { - StringBuf buf (6 * strlen (str)); + StringBuf buf(6 * strlen(str)); char * set = buf; gunichar c; - while ((c = g_utf8_get_char (str))) + while ((c = g_utf8_get_char(str))) { if (c < 128) - * set ++ = g_ascii_tolower (c); + *set++ = g_ascii_tolower(c); else - set += g_unichar_to_utf8 (g_unichar_tolower (c), set); + set += g_unichar_to_utf8(g_unichar_tolower(c), set); - str = g_utf8_next_char (str); + str = g_utf8_next_char(str); } - buf.resize (set - buf); + buf.resize(set - buf); return buf; } -EXPORT StringBuf str_toupper (const char * str) +EXPORT StringBuf str_toupper(const char * str) { - StringBuf buf (strlen (str)); + StringBuf buf(strlen(str)); char * set = buf; - while (* str) - * set ++ = g_ascii_toupper (* str ++); + while (*str) + *set++ = g_ascii_toupper(*str++); return buf; } -EXPORT StringBuf str_toupper_utf8 (const char * str) +EXPORT StringBuf str_toupper_utf8(const char * str) { - StringBuf buf (6 * strlen (str)); + StringBuf buf(6 * strlen(str)); char * set = buf; gunichar c; - while ((c = g_utf8_get_char (str))) + while ((c = g_utf8_get_char(str))) { if (c < 128) - * set ++ = g_ascii_toupper (c); + *set++ = g_ascii_toupper(c); else - set += g_unichar_to_utf8 (g_unichar_toupper (c), set); + set += g_unichar_to_utf8(g_unichar_toupper(c), set); - str = g_utf8_next_char (str); + str = g_utf8_next_char(str); } - buf.resize (set - buf); + buf.resize(set - buf); return buf; } -EXPORT void str_replace_char (char * string, char old_c, char new_c) +EXPORT void str_replace_char(char * string, char old_c, char new_c) { - while ((string = strchr (string, old_c))) - * string ++ = new_c; + while ((string = strchr(string, old_c))) + *string++ = new_c; } -/* Percent-decodes bytes of . If is negative, decodes all of . */ +/* Percent-decodes bytes of . If is negative, decodes all of + * . */ -EXPORT StringBuf str_decode_percent (const char * str, int len) +EXPORT StringBuf str_decode_percent(const char * str, int len) { if (len < 0) - len = strlen (str); + len = strlen(str); - StringBuf buf (len); + StringBuf buf(len); char * out = buf; while (1) { - const char * p = (const char *) memchr (str, '%', len); - if (! p) + const char * p = (const char *)memchr(str, '%', len); + if (!p) break; int block = p - str; - memcpy (out, str, block); + memcpy(out, str, block); str += block; out += block; @@ -399,181 +397,187 @@ EXPORT StringBuf str_decode_percent (const char * str, int len) if (len < 3) break; - * out ++ = (FROM_HEX (str[1]) << 4) | FROM_HEX (str[2]); + *out++ = (FROM_HEX(str[1]) << 4) | FROM_HEX(str[2]); str += 3; len -= 3; } - memcpy (out, str, len); - buf.resize (out + len - buf); + memcpy(out, str, len); + buf.resize(out + len - buf); return buf; } -/* Percent-encodes bytes of . If is negative, encodes all of . */ +/* Percent-encodes bytes of . If is negative, encodes all of + * . */ -EXPORT StringBuf str_encode_percent (const char * str, int len) +EXPORT StringBuf str_encode_percent(const char * str, int len) { if (len < 0) - len = strlen (str); + len = strlen(str); - StringBuf buf (3 * len); + StringBuf buf(3 * len); char * out = buf; - while (len --) + while (len--) { - char c = * str ++; + char c = *str++; - if (IS_LEGAL (c)) - * out ++ = c; + if (IS_LEGAL(c)) + *out++ = c; else { - * out ++ = '%'; - * out ++ = TO_HEX ((unsigned char) c >> 4); - * out ++ = TO_HEX (c & 0xF); + *out++ = '%'; + *out++ = TO_HEX((unsigned char)c >> 4); + *out++ = TO_HEX(c & 0xF); } } - buf.resize (out - buf); + buf.resize(out - buf); return buf; } -EXPORT StringBuf filename_normalize (StringBuf && filename) +EXPORT StringBuf filename_normalize(StringBuf && filename) { int len; char * s; #ifdef _WIN32 /* convert slash to backslash on Windows */ - str_replace_char (filename, '/', '\\'); + str_replace_char(filename, '/', '\\'); #endif /* remove current directory (".") elements */ - while ((len = filename.len ()) >= 2 && - (! strcmp ((s = filename + len - 2), G_DIR_SEPARATOR_S ".") || - (s = strstr (filename, G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S)))) - filename.remove (s + 1 - filename, aud::min (s + 3, filename + len) - (s + 1)); + while ((len = filename.len()) >= 2 && + (!strcmp((s = filename + len - 2), G_DIR_SEPARATOR_S ".") || + (s = strstr(filename, G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S)))) + filename.remove(s + 1 - filename, + aud::min(s + 3, filename + len) - (s + 1)); /* remove parent directory ("..") elements */ - while ((len = filename.len ()) >= 3 && - (! strcmp ((s = filename + len - 3), G_DIR_SEPARATOR_S "..") || - (s = strstr (filename, G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S)))) + while ((len = filename.len()) >= 3 && + (!strcmp((s = filename + len - 3), G_DIR_SEPARATOR_S "..") || + (s = strstr(filename, G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S)))) { - * s = 0; - char * s2 = strrchr (filename, G_DIR_SEPARATOR); - if (! s2) - * (s2 = s) = G_DIR_SEPARATOR; + *s = 0; + char * s2 = strrchr(filename, G_DIR_SEPARATOR); + if (!s2) + *(s2 = s) = G_DIR_SEPARATOR; - filename.remove (s2 + 1 - filename, aud::min (s + 4, filename + len) - (s2 + 1)); + filename.remove(s2 + 1 - filename, + aud::min(s + 4, filename + len) - (s2 + 1)); } /* remove trailing slash */ #ifdef _WIN32 - if ((len = filename.len ()) > 3 && filename[len - 1] == '\\') /* leave "C:\" */ + if ((len = filename.len()) > 3 && + filename[len - 1] == '\\') /* leave "C:\" */ #else - if ((len = filename.len ()) > 1 && filename[len - 1] == '/') /* leave leading "/" */ + if ((len = filename.len()) > 1 && + filename[len - 1] == '/') /* leave leading "/" */ #endif - filename.resize (len - 1); + filename.resize(len - 1); - return std::move (filename); + return std::move(filename); } /* note #1: recommended order is filename_contract(filename_normalize(f)) */ /* note #2: currently assumes filename is UTF-8 (intended for display) */ -EXPORT StringBuf filename_contract (StringBuf && filename) +EXPORT StringBuf filename_contract(StringBuf && filename) { /* replace home folder with '~' */ - const char * home = get_home_utf8 (); - int homelen = home ? strlen (home) : 0; + const char * home = get_home_utf8(); + int homelen = home ? strlen(home) : 0; - if (homelen && ! strncmp (filename, home, homelen) && - (! filename[homelen] || IS_SEP (filename[homelen]))) + if (homelen && !strncmp(filename, home, homelen) && + (!filename[homelen] || IS_SEP(filename[homelen]))) { filename[0] = '~'; - filename.remove (1, homelen - 1); + filename.remove(1, homelen - 1); } - return std::move (filename); + return std::move(filename); } /* note #1: recommended order is filename_normalize(filename_expand(f)) */ /* note #2: currently assumes filename is UTF-8 (intended for display) */ -EXPORT StringBuf filename_expand (StringBuf && filename) +EXPORT StringBuf filename_expand(StringBuf && filename) { /* expand leading '~' */ - if (filename[0] == '~' && (! filename[1] || IS_SEP(filename[1]))) + if (filename[0] == '~' && (!filename[1] || IS_SEP(filename[1]))) { - const char * home = get_home_utf8 (); + const char * home = get_home_utf8(); if (home && home[0]) { filename[0] = home[0]; - filename.insert (1, home + 1, -1); + filename.insert(1, home + 1, -1); } } - return std::move (filename); + return std::move(filename); } -EXPORT StringBuf filename_get_parent (const char * filename) +EXPORT StringBuf filename_get_parent(const char * filename) { - StringBuf buf = filename_normalize (str_copy (filename)); - const char * base = last_path_element (buf); + StringBuf buf = filename_normalize(str_copy(filename)); + const char * base = last_path_element(buf); - if (! base) - return StringBuf (); + if (!base) + return StringBuf(); #ifdef _WIN32 if (base - buf > 3) /* leave "C:\" */ #else - if (base - buf > 1) /* leave leading "/" */ + if (base - buf > 1) /* leave leading "/" */ #endif - buf.resize (base - buf - 1); + buf.resize(base - buf - 1); else - buf.resize (base - buf); + buf.resize(base - buf); return buf; } -EXPORT StringBuf filename_get_base (const char * filename) +EXPORT StringBuf filename_get_base(const char * filename) { - StringBuf buf = filename_normalize (str_copy (filename)); - const char * base = last_path_element (buf); + StringBuf buf = filename_normalize(str_copy(filename)); + const char * base = last_path_element(buf); if (base) - buf.remove (0, base - buf); + buf.remove(0, base - buf); return buf; } -EXPORT StringBuf filename_build (const std::initializer_list & elems) +EXPORT StringBuf +filename_build(const std::initializer_list & elems) { - StringBuf str (-1); + StringBuf str(-1); char * set = str; - int left = str.len (); + int left = str.len(); for (const char * s : elems) { - if (set > str && ! IS_SEP (set[-1])) + if (set > str && !IS_SEP(set[-1])) { - if (! left) - throw std::bad_alloc (); + if (!left) + throw std::bad_alloc(); - * set ++ = G_DIR_SEPARATOR; - left --; + *set++ = G_DIR_SEPARATOR; + left--; } - int len = strlen (s); + int len = strlen(s); if (len > left) - throw std::bad_alloc (); + throw std::bad_alloc(); - memcpy (set, s, len); + memcpy(set, s, len); set += len; left -= len; } - str.resize (set - str); + str.resize(set - str); return str; } @@ -589,24 +593,24 @@ EXPORT StringBuf filename_build (const std::initializer_list & ele * UTF-8 before percent-encoding (except on Windows, where filenames are assumed * to be UTF-8). On Windows, replaces '\' with '/' and adds a leading '/'. */ -EXPORT StringBuf filename_to_uri (const char * name) +EXPORT StringBuf filename_to_uri(const char * name) { #ifdef _WIN32 - StringBuf buf = str_copy (name); - str_replace_char (buf, '\\', '/'); + StringBuf buf = str_copy(name); + str_replace_char(buf, '\\', '/'); #else StringBuf buf; /* convert from locale if: * 1) system locale is not UTF-8, and * 2) filename is not already valid UTF-8 */ - if (! g_get_charset (nullptr) && ! g_utf8_validate (name, -1, nullptr)) - buf = str_from_locale (name); + if (!g_get_charset(nullptr) && !g_utf8_validate(name, -1, nullptr)) + buf = str_from_locale(name); #endif - buf = str_encode_percent (buf ? buf : name); - buf.insert (0, URI_PREFIX); - return buf.settle (); + buf = str_encode_percent(buf ? buf : name); + buf.insert(0, URI_PREFIX); + return buf.settle(); } /* Like g_filename_from_uri, but optionally converts the filename from UTF-8 to @@ -615,59 +619,60 @@ EXPORT StringBuf filename_to_uri (const char * name) * '/' with '\'. If the input is not a valid URI, it is assumed to be a local * filename already and is not percent-decoded. */ -EXPORT StringBuf uri_to_filename (const char * uri, bool use_locale) +EXPORT StringBuf uri_to_filename(const char * uri, bool use_locale) { StringBuf buf; - if (! strncmp (uri, URI_PREFIX, URI_PREFIX_LEN)) - buf = str_decode_percent (uri + URI_PREFIX_LEN); - else if (! strstr (uri, "://")) /* already a local filename? */ - buf = str_copy (uri); + if (!strncmp(uri, URI_PREFIX, URI_PREFIX_LEN)) + buf = str_decode_percent(uri + URI_PREFIX_LEN); + else if (!strstr(uri, "://")) /* already a local filename? */ + buf = str_copy(uri); else - return StringBuf (); + return StringBuf(); #ifndef _WIN32 /* convert to locale if: * 1) use_locale flag was not set to false, and * 2) system locale is not UTF-8, and * 3) decoded URI is valid UTF-8 */ - if (use_locale && ! g_get_charset (nullptr) && g_utf8_validate (buf, buf.len (), nullptr)) + if (use_locale && !g_get_charset(nullptr) && + g_utf8_validate(buf, buf.len(), nullptr)) { - StringBuf locale = str_to_locale (buf); + StringBuf locale = str_to_locale(buf); if (locale) - buf = std::move (locale); + buf = std::move(locale); } #endif /* if UTF-8 was requested, make sure the result is valid */ - if (! use_locale) + if (!use_locale) { - buf = str_to_utf8 (std::move (buf)); - if (! buf) - return StringBuf (); + buf = str_to_utf8(std::move(buf)); + if (!buf) + return StringBuf(); } - return filename_normalize (buf.settle ()); + return filename_normalize(buf.settle()); } /* Formats a URI for human-readable display. Percent-decodes and, for file:// * URI's, converts to filename format, but in UTF-8. */ -EXPORT StringBuf uri_to_display (const char * uri) +EXPORT StringBuf uri_to_display(const char * uri) { - if (! strncmp (uri, "stdin://", 8)) - return str_copy (_("Standard input")); - if (! strncmp (uri, "cdda://?", 8)) - return str_printf (_("Audio CD, track %s"), uri + 8); + if (!strncmp(uri, "stdin://", 8)) + return str_copy(_("Standard input")); + if (!strncmp(uri, "cdda://?", 8)) + return str_printf(_("Audio CD, track %s"), uri + 8); - StringBuf buf = str_to_utf8 (str_decode_percent (uri)); - if (! buf) - return str_copy (_("(character encoding error)")); + StringBuf buf = str_to_utf8(str_decode_percent(uri)); + if (!buf) + return str_copy(_("(character encoding error)")); - if (! strncmp (buf, URI_PREFIX, URI_PREFIX_LEN)) + if (!strncmp(buf, URI_PREFIX, URI_PREFIX_LEN)) { - buf.remove (0, URI_PREFIX_LEN); - return filename_contract (filename_normalize (std::move (buf))); + buf.remove(0, URI_PREFIX_LEN); + return filename_contract(filename_normalize(std::move(buf))); } return buf; @@ -676,58 +681,69 @@ EXPORT StringBuf uri_to_display (const char * uri) #undef URI_PREFIX #undef URI_PREFIX_LEN -EXPORT void uri_parse (const char * uri, const char * * base_p, const char * * ext_p, - const char * * sub_p, int * isub_p) +EXPORT void uri_parse(const char * uri, const char ** base_p, + const char ** ext_p, const char ** sub_p, int * isub_p) { - const char * end = uri + strlen (uri); - const char * base, * ext, * sub, * c; + const char * end = uri + strlen(uri); + const char *base, *ext, *sub, *c; int isub = 0; char junk; - if ((c = strrchr (uri, '/'))) + if ((c = strrchr(uri, '/'))) base = c + 1; else base = end; - if ((c = strrchr (base, '?')) && sscanf (c + 1, "%d%c", & isub, & junk) == 1) + if ((c = strrchr(base, '?')) && sscanf(c + 1, "%d%c", &isub, &junk) == 1) sub = c; else sub = end; - if ((c = strrchr (base, '.')) && c < sub) + if ((c = strrchr(base, '.')) && c < sub) ext = c; else ext = sub; if (base_p) - * base_p = base; + *base_p = base; if (ext_p) - * ext_p = ext; + *ext_p = ext; if (sub_p) - * sub_p = sub; + *sub_p = sub; if (isub_p) - * isub_p = isub; + *isub_p = isub; } -EXPORT StringBuf uri_get_scheme (const char * uri) +EXPORT StringBuf uri_get_scheme(const char * uri) { - const char * delim = strstr (uri, "://"); - return delim ? str_copy (uri, delim - uri) : StringBuf (); + const char * delim = strstr(uri, "://"); + return delim ? str_copy(uri, delim - uri) : StringBuf(); } -EXPORT StringBuf uri_get_extension (const char * uri) +EXPORT StringBuf uri_get_extension(const char * uri) { const char * ext; - uri_parse (uri, nullptr, & ext, nullptr, nullptr); + uri_parse(uri, nullptr, &ext, nullptr, nullptr); if (ext[0] != '.') - return StringBuf (); + return StringBuf(); - ext ++; // skip period + ext++; // skip period // remove subtunes and HTTP query strings - const char * qmark = strchr (ext, '?'); - return str_copy (ext, qmark ? qmark - ext : -1); + const char * qmark = strchr(ext, '?'); + return str_copy(ext, qmark ? qmark - ext : -1); +} + +EXPORT StringBuf uri_get_display_base(const char * uri) +{ + const char *base, *ext; + uri_parse(uri, &base, &ext, nullptr, nullptr); + + if (ext > base) + return str_to_utf8(str_decode_percent(base, ext - base)); + + return StringBuf(); } /* Constructs a full URI given: @@ -737,35 +753,35 @@ EXPORT StringBuf uri_get_extension (const char * uri) * c. a relative path (character set detected according to user settings) * 2. reference: the full URI of the playlist containing */ -EXPORT StringBuf uri_construct (const char * path, const char * reference) +EXPORT StringBuf uri_construct(const char * path, const char * reference) { /* URI */ - if (strstr (path, "://")) - return str_copy (path); + if (strstr(path, "://")) + return str_copy(path); - /* absolute filename */ + /* absolute filename */ #ifdef _WIN32 - if (path[0] && path[1] == ':' && IS_SEP (path[2])) + if (path[0] && path[1] == ':' && IS_SEP(path[2])) #else if (path[0] == '/') #endif - return filename_to_uri (path); + return filename_to_uri(path); /* relative path */ - const char * slash = strrchr (reference, '/'); - if (! slash) - return StringBuf (); + const char * slash = strrchr(reference, '/'); + if (!slash) + return StringBuf(); - StringBuf buf = str_to_utf8 (path, -1); - if (! buf) - return StringBuf (); + StringBuf buf = str_to_utf8(path, -1); + if (!buf) + return StringBuf(); - if (aud_get_bool (nullptr, "convert_backslash")) - str_replace_char (buf, '\\', '/'); + if (aud_get_bool("convert_backslash")) + str_replace_char(buf, '\\', '/'); - buf = str_encode_percent (buf); - buf.insert (0, reference, slash + 1 - reference); - return buf.settle (); + buf = str_encode_percent(buf); + buf.insert(0, reference, slash + 1 - reference); + return buf.settle(); } /* Basically the reverse of uri_construct(). @@ -779,39 +795,40 @@ EXPORT StringBuf uri_construct (const char * path, const char * reference) * 1. uri: the full URI of a song file * 2. reference: the full URI of the playlist being written */ -EXPORT StringBuf uri_deconstruct (const char * uri, const char * reference) +EXPORT StringBuf uri_deconstruct(const char * uri, const char * reference) { - if (aud_get_bool (nullptr, "export_relative_paths")) + if (aud_get_bool("export_relative_paths")) { - const char * slash = strrchr (reference, '/'); - if (slash && ! strncmp (uri, reference, slash + 1 - reference)) + const char * slash = strrchr(reference, '/'); + if (slash && !strncmp(uri, reference, slash + 1 - reference)) { - StringBuf path = str_to_utf8 (str_decode_percent (uri + (slash + 1 - reference))); + StringBuf path = + str_to_utf8(str_decode_percent(uri + (slash + 1 - reference))); if (path) return path; } } - StringBuf filename = uri_to_filename (uri, false); + StringBuf filename = uri_to_filename(uri, false); if (filename) return filename; - return str_copy (uri); + return str_copy(uri); } /* Like strcasecmp, but orders numbers correctly (2 before 10). */ /* Non-ASCII characters are treated exactly as is. */ /* Handles nullptr gracefully. */ -EXPORT int str_compare (const char * ap, const char * bp) +EXPORT int str_compare(const char * ap, const char * bp) { - if (! ap) + if (!ap) return bp ? -1 : 0; - if (! bp) + if (!bp) return 1; - unsigned char a = * ap ++, b = * bp ++; - for (; a || b; a = * ap ++, b = * bp ++) + unsigned char a = *ap++, b = *bp++; + for (; a || b; a = *ap++, b = *bp++) { if (a > '9' || b > '9' || a < '0' || b < '0') { @@ -828,11 +845,11 @@ EXPORT int str_compare (const char * ap, const char * bp) else { int x = a - '0'; - for (; (a = * ap) <= '9' && a >= '0'; ap ++) + for (; (a = *ap) <= '9' && a >= '0'; ap++) x = 10 * x + (a - '0'); int y = b - '0'; - for (; (b = * bp) >= '0' && b <= '9'; bp ++) + for (; (b = *bp) >= '0' && b <= '9'; bp++) y = 10 * y + (b - '0'); if (x > y) @@ -845,26 +862,26 @@ EXPORT int str_compare (const char * ap, const char * bp) return 0; } -/* Decodes percent-encoded strings, then compares then with str_compare. */ +/* Decodes percent-encoded strings, then compares them with str_compare. */ -EXPORT int str_compare_encoded (const char * ap, const char * bp) +EXPORT int str_compare_encoded(const char * ap, const char * bp) { - if (! ap) + if (!ap) return bp ? -1 : 0; - if (! bp) + if (!bp) return 1; - unsigned char a = * ap ++, b = * bp ++; - for (; a || b; a = * ap ++, b = * bp ++) + unsigned char a = *ap++, b = *bp++; + for (; a || b; a = *ap++, b = *bp++) { if (a == '%' && ap[0] && ap[1]) { - a = (FROM_HEX (ap[0]) << 4) | FROM_HEX (ap[1]); + a = (FROM_HEX(ap[0]) << 4) | FROM_HEX(ap[1]); ap += 2; } if (b == '%' && bp[0] && bp[1]) { - b = (FROM_HEX (bp[0]) << 4) | FROM_HEX (bp[1]); + b = (FROM_HEX(bp[0]) << 4) | FROM_HEX(bp[1]); bp += 2; } @@ -883,11 +900,11 @@ EXPORT int str_compare_encoded (const char * ap, const char * bp) else { int x = a - '0'; - for (; (a = * ap) <= '9' && a >= '0'; ap ++) + for (; (a = *ap) <= '9' && a >= '0'; ap++) x = 10 * x + (a - '0'); int y = b - '0'; - for (; (b = * bp) >= '0' && b <= '9'; bp ++) + for (; (b = *bp) >= '0' && b <= '9'; bp++) y = 10 * y + (b - '0'); if (x > y) @@ -900,29 +917,29 @@ EXPORT int str_compare_encoded (const char * ap, const char * bp) return 0; } -EXPORT Index str_list_to_index (const char * list, const char * delims) +EXPORT Index str_list_to_index(const char * list, const char * delims) { char dmap[256] = {0}; - for (; * delims; delims ++) - dmap[(unsigned char) (* delims)] = 1; + for (; *delims; delims++) + dmap[(unsigned char)(*delims)] = 1; Index index; const char * word = nullptr; - for (; * list; list ++) + for (; *list; list++) { - if (dmap[(unsigned char) (* list)]) + if (dmap[(unsigned char)(*list)]) { if (word) { - index.append (String (str_copy (word, list - word))); + index.append(String(str_copy(word, list - word))); word = nullptr; } } else { - if (! word) + if (!word) { word = list; } @@ -930,39 +947,40 @@ EXPORT Index str_list_to_index (const char * list, const char * delims) } if (word) - index.append (String (word)); + index.append(String(word)); return index; } -EXPORT StringBuf index_to_str_list (const Index & index, const char * sep) +EXPORT StringBuf index_to_str_list(const Index & index, + const char * sep) { - StringBuf str (-1); + StringBuf str(-1); char * set = str; - int left = str.len (); - int seplen = strlen (sep); + int left = str.len(); + int seplen = strlen(sep); for (const String & s : index) { - int len = strlen (s); + int len = strlen(s); if (len + seplen > left) - throw std::bad_alloc (); + throw std::bad_alloc(); if (set > str) { - memcpy (set, sep, seplen); + memcpy(set, sep, seplen); set += seplen; left -= seplen; } - memcpy (set, s, len); + memcpy(set, s, len); set += len; left -= len; } - str.resize (set - str); + str.resize(set - str); return str; } @@ -981,178 +999,178 @@ EXPORT StringBuf index_to_str_list (const Index & index, const char * se * have an accuracy of 6 decimal places. */ -static unsigned str_to_uint (const char * string, const char * * end = nullptr, - const char * stop = nullptr) +static unsigned str_to_uint(const char * string, const char ** end = nullptr, + const char * stop = nullptr) { unsigned val = 0; - for (char c; string != stop && (c = * string) >= '0' && c <= '9'; string ++) + for (char c; string != stop && (c = *string) >= '0' && c <= '9'; string++) val = val * 10 + (c - '0'); if (end) - * end = string; + *end = string; return val; } -static int digits_for (unsigned val) +static int digits_for(unsigned val) { int digits = 1; for (; val >= 1000; val /= 1000) digits += 3; for (; val >= 10; val /= 10) - digits ++; + digits++; return digits; } -static void uint_to_str (unsigned val, char * buf, int digits) +static void uint_to_str(unsigned val, char * buf, int digits) { for (char * rev = buf + digits; rev > buf; val /= 10) - * (-- rev) = '0' + val % 10; + *(--rev) = '0' + val % 10; } -EXPORT int str_to_int (const char * string) +EXPORT int str_to_int(const char * string) { bool neg = (string[0] == '-'); if (neg || string[0] == '+') - string ++; + string++; - unsigned val = str_to_uint (string); + unsigned val = str_to_uint(string); return neg ? -val : val; } -EXPORT double str_to_double (const char * string) +EXPORT double str_to_double(const char * string) { bool neg = (string[0] == '-'); if (neg || string[0] == '+') - string ++; + string++; const char * p; - double val = str_to_uint (string, & p); + double val = str_to_uint(string, &p); - if (* (p ++) == '.') + if (*(p++) == '.') { const char * end; - double decimal = str_to_uint (p, & end, p + MAX_POW10); + double decimal = str_to_uint(p, &end, p + MAX_POW10); val += decimal / int_pow10[end - p]; } return neg ? -val : val; } -EXPORT void str_insert_int (StringBuf & string, int pos, int val) +EXPORT void str_insert_int(StringBuf & string, int pos, int val) { bool neg = (val < 0); unsigned absval = neg ? -val : val; - int digits = digits_for (absval); + int digits = digits_for(absval); int len = (neg ? 1 : 0) + digits; - char * set = string.insert (pos, nullptr, len); + char * set = string.insert(pos, nullptr, len); if (neg) - * (set ++) = '-'; + *(set++) = '-'; - uint_to_str (absval, set, digits); + uint_to_str(absval, set, digits); } -EXPORT void str_insert_double (StringBuf & string, int pos, double val) +EXPORT void str_insert_double(StringBuf & string, int pos, double val) { bool neg = (val < 0); if (neg) val = -val; - unsigned i = floor (val); - unsigned f = round ((val - i) * 1000000); + unsigned i = floor(val); + unsigned f = round((val - i) * 1000000); if (f == 1000000) { - i ++; + i++; f = 0; } int decimals = f ? 6 : 0; - for (; decimals && ! (f % 10); f /= 10) - decimals --; + for (; decimals && !(f % 10); f /= 10) + decimals--; - int digits = digits_for (i); + int digits = digits_for(i); int len = (neg ? 1 : 0) + digits + (decimals ? 1 : 0) + decimals; - char * set = string.insert (pos, nullptr, len); + char * set = string.insert(pos, nullptr, len); if (neg) - * (set ++) = '-'; + *(set++) = '-'; - uint_to_str (i, set, digits); + uint_to_str(i, set, digits); if (decimals) { set += digits; - * (set ++) = '.'; - uint_to_str (f, set, decimals); + *(set++) = '.'; + uint_to_str(f, set, decimals); } } -EXPORT StringBuf int_to_str (int val) +EXPORT StringBuf int_to_str(int val) { StringBuf buf; - str_insert_int (buf, 0, val); + str_insert_int(buf, 0, val); return buf; } -EXPORT StringBuf double_to_str (double val) +EXPORT StringBuf double_to_str(double val) { StringBuf buf; - str_insert_double (buf, 0, val); + str_insert_double(buf, 0, val); return buf; } -EXPORT bool str_to_int_array (const char * string, int * array, int count) +EXPORT bool str_to_int_array(const char * string, int * array, int count) { - Index index = str_list_to_index (string, ", "); + Index index = str_list_to_index(string, ", "); - if (index.len () != count) + if (index.len() != count) return false; - for (int i = 0; i < count; i ++) - array[i] = str_to_int (index[i]); + for (int i = 0; i < count; i++) + array[i] = str_to_int(index[i]); return true; } -EXPORT StringBuf int_array_to_str (const int * array, int count) +EXPORT StringBuf int_array_to_str(const int * array, int count) { Index index; - for (int i = 0; i < count; i ++) - index.append (String (int_to_str (array[i]))); + for (int i = 0; i < count; i++) + index.append(String(int_to_str(array[i]))); - return index_to_str_list (index, ","); + return index_to_str_list(index, ","); } -EXPORT bool str_to_double_array (const char * string, double * array, int count) +EXPORT bool str_to_double_array(const char * string, double * array, int count) { - Index index = str_list_to_index (string, ", "); + Index index = str_list_to_index(string, ", "); - if (index.len () != count) + if (index.len() != count) return false; - for (int i = 0; i < count; i ++) - array[i] = str_to_double (index[i]); + for (int i = 0; i < count; i++) + array[i] = str_to_double(index[i]); return true; } -EXPORT StringBuf double_array_to_str (const double * array, int count) +EXPORT StringBuf double_array_to_str(const double * array, int count) { Index index; - for (int i = 0; i < count; i ++) - index.append (String (double_to_str (array[i]))); + for (int i = 0; i < count; i++) + index.append(String(double_to_str(array[i]))); - return index_to_str_list (index, ","); + return index_to_str_list(index, ","); } -EXPORT StringBuf str_format_time (int64_t milliseconds) +EXPORT StringBuf str_format_time(int64_t milliseconds) { bool neg = milliseconds < 0; @@ -1163,11 +1181,13 @@ EXPORT StringBuf str_format_time (int64_t milliseconds) int minutes = milliseconds / 60000; int seconds = (milliseconds / 1000) % 60; - if (hours && aud_get_bool (nullptr, "show_hours")) - return str_printf ("%s%d:%02d:%02d", neg ? "- " : "", hours, minutes % 60, seconds); + if (hours && aud_get_bool("show_hours")) + return str_printf("%s%d:%02d:%02d", neg ? "- " : "", hours, + minutes % 60, seconds); else { - bool zero = aud_get_bool (nullptr, "leading_zero"); - return str_printf (zero ? "%s%02d:%02d" : "%s%d:%02d", neg ? "- " : "", minutes, seconds); + bool zero = aud_get_bool("leading_zero"); + return str_printf(zero ? "%s%02d:%02d" : "%s%d:%02d", neg ? "- " : "", + minutes, seconds); } } diff --git a/src/libaudcore/audstrings.h b/src/libaudcore/audstrings.h index e32f00a..ccd0439 100644 --- a/src/libaudcore/audstrings.h +++ b/src/libaudcore/audstrings.h @@ -1,6 +1,6 @@ /* * audstrings.h - * Copyright 2009-2012 John Lindgren and William Pitcock + * Copyright 2009-2012 John Lindgren and Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,92 +28,103 @@ #include #include -int strcmp_safe (const char * a, const char * b, int len = -1); -int strcmp_nocase (const char * a, const char * b, int len = -1); -int strlen_bounded (const char * s, int len = -1); +int strcmp_safe(const char * a, const char * b, int len = -1); +int strcmp_nocase(const char * a, const char * b, int len = -1); +int strlen_bounded(const char * s, int len = -1); -StringBuf str_copy (const char * s, int len = -1); -StringBuf str_concat (const std::initializer_list & strings); +StringBuf str_copy(const char * s, int len = -1); +StringBuf str_concat(const std::initializer_list & strings); #ifdef _WIN32 -StringBuf str_printf (const char * format, ...) __attribute__ ((__format__ (gnu_printf, 1, 2))); -void str_append_printf (StringBuf & str, const char * format, ...) __attribute__ ((__format__ (gnu_printf, 2, 3))); +StringBuf str_printf(const char * format, ...) + __attribute__((__format__(gnu_printf, 1, 2))); +void str_append_printf(StringBuf & str, const char * format, ...) + __attribute__((__format__(gnu_printf, 2, 3))); #else -StringBuf str_printf (const char * format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -void str_append_printf (StringBuf & str, const char * format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +StringBuf str_printf(const char * format, ...) + __attribute__((__format__(__printf__, 1, 2))); +void str_append_printf(StringBuf & str, const char * format, ...) + __attribute__((__format__(__printf__, 2, 3))); #endif -StringBuf str_vprintf (const char * format, va_list args); -void str_append_vprintf (StringBuf & str, const char * format, va_list args); +StringBuf str_vprintf(const char * format, va_list args); +void str_append_vprintf(StringBuf & str, const char * format, va_list args); -bool str_has_prefix_nocase (const char * str, const char * prefix); -bool str_has_suffix_nocase (const char * str, const char * suffix); +bool str_has_prefix_nocase(const char * str, const char * prefix); +bool str_has_suffix_nocase(const char * str, const char * suffix); -unsigned str_calc_hash (const char * str); +unsigned str_calc_hash(const char * str); -const char * strstr_nocase (const char * haystack, const char * needle); -const char * strstr_nocase_utf8 (const char * haystack, const char * needle); +const char * strstr_nocase(const char * haystack, const char * needle); +const char * strstr_nocase_utf8(const char * haystack, const char * needle); -static inline char * strstr_nocase (char * haystack, const char * needle) - { return (char *) strstr_nocase ((const char *) haystack, needle); } -static inline char * strstr_nocase_utf8 (char * haystack, const char * needle) - { return (char *) strstr_nocase_utf8 ((const char *) haystack, needle); } +static inline char * strstr_nocase(char * haystack, const char * needle) +{ + return (char *)strstr_nocase((const char *)haystack, needle); +} +static inline char * strstr_nocase_utf8(char * haystack, const char * needle) +{ + return (char *)strstr_nocase_utf8((const char *)haystack, needle); +} -StringBuf str_tolower (const char * str); -StringBuf str_tolower_utf8 (const char * str); -StringBuf str_toupper (const char * str); -StringBuf str_toupper_utf8 (const char * str); +StringBuf str_tolower(const char * str); +StringBuf str_tolower_utf8(const char * str); +StringBuf str_toupper(const char * str); +StringBuf str_toupper_utf8(const char * str); -void str_replace_char (char * string, char old_c, char new_c); +void str_replace_char(char * string, char old_c, char new_c); -StringBuf str_decode_percent (const char * str, int len = -1); -StringBuf str_encode_percent (const char * str, int len = -1); +StringBuf str_decode_percent(const char * str, int len = -1); +StringBuf str_encode_percent(const char * str, int len = -1); -StringBuf str_convert (const char * str, int len, const char * from_charset, const char * to_charset); -StringBuf str_from_locale (const char * str, int len = -1); -StringBuf str_to_locale (const char * str, int len = -1); +StringBuf str_convert(const char * str, int len, const char * from_charset, + const char * to_charset); +StringBuf str_from_locale(const char * str, int len = -1); +StringBuf str_to_locale(const char * str, int len = -1); /* Requires: aud_init() */ -StringBuf str_to_utf8 (const char * str, int len); // no "len = -1" to avoid ambiguity -StringBuf str_to_utf8 (StringBuf && str); +StringBuf str_to_utf8(const char * str, + int len); // no "len = -1" to avoid ambiguity +StringBuf str_to_utf8(StringBuf && str); -StringBuf filename_normalize (StringBuf && filename); -StringBuf filename_contract (StringBuf && filename); -StringBuf filename_expand (StringBuf && filename); -StringBuf filename_get_parent (const char * filename); -StringBuf filename_get_base (const char * filename); -StringBuf filename_build (const std::initializer_list & elems); -StringBuf filename_to_uri (const char * filename); -StringBuf uri_to_filename (const char * uri, bool use_locale = true); -StringBuf uri_to_display (const char * uri); +StringBuf filename_normalize(StringBuf && filename); +StringBuf filename_contract(StringBuf && filename); +StringBuf filename_expand(StringBuf && filename); +StringBuf filename_get_parent(const char * filename); +StringBuf filename_get_base(const char * filename); +StringBuf filename_build(const std::initializer_list & elems); +StringBuf filename_to_uri(const char * filename); +StringBuf uri_to_filename(const char * uri, bool use_locale = true); -void uri_parse (const char * uri, const char * * base_p, const char * * ext_p, - const char * * sub_p, int * isub_p); +void uri_parse(const char * uri, const char ** base_p, const char ** ext_p, + const char ** sub_p, int * isub_p); -StringBuf uri_get_scheme (const char * uri); -StringBuf uri_get_extension (const char * uri); +StringBuf uri_get_scheme(const char * uri); +StringBuf uri_get_extension(const char * uri); /* Requires: aud_init() */ -StringBuf uri_construct (const char * path, const char * reference); -StringBuf uri_deconstruct (const char * uri, const char * reference); +StringBuf uri_to_display(const char * uri); +StringBuf uri_get_display_base(const char * uri); +StringBuf uri_construct(const char * path, const char * reference); +StringBuf uri_deconstruct(const char * uri, const char * reference); -int str_compare (const char * a, const char * b); -int str_compare_encoded (const char * a, const char * b); +int str_compare(const char * a, const char * b); +int str_compare_encoded(const char * a, const char * b); -Index str_list_to_index (const char * list, const char * delims); -StringBuf index_to_str_list (const Index & index, const char * sep); +Index str_list_to_index(const char * list, const char * delims); +StringBuf index_to_str_list(const Index & index, const char * sep); -int str_to_int (const char * string); -double str_to_double (const char * string); -void str_insert_int (StringBuf & string, int pos, int val); -void str_insert_double (StringBuf & string, int pos, double val); -StringBuf int_to_str (int val); -StringBuf double_to_str (double val); +int str_to_int(const char * string); +double str_to_double(const char * string); +void str_insert_int(StringBuf & string, int pos, int val); +void str_insert_double(StringBuf & string, int pos, double val); +StringBuf int_to_str(int val); +StringBuf double_to_str(double val); -bool str_to_int_array (const char * string, int * array, int count); -StringBuf int_array_to_str (const int * array, int count); -bool str_to_double_array (const char * string, double * array, int count); -StringBuf double_array_to_str (const double * array, int count); +bool str_to_int_array(const char * string, int * array, int count); +StringBuf int_array_to_str(const int * array, int count); +bool str_to_double_array(const char * string, double * array, int count); +StringBuf double_array_to_str(const double * array, int count); /* Requires: aud_init() */ -StringBuf str_format_time (int64_t milliseconds); +StringBuf str_format_time(int64_t milliseconds); #endif /* LIBAUDCORE_STRINGS_H */ diff --git a/src/libaudcore/charset.cc b/src/libaudcore/charset.cc index d77d38f..542225f 100644 --- a/src/libaudcore/charset.cc +++ b/src/libaudcore/charset.cc @@ -33,122 +33,125 @@ #include "hook.h" #include "index.h" #include "runtime.h" -#include "tinylock.h" +#include "threads.h" -EXPORT StringBuf str_convert (const char * str, int len, const char * from_charset, - const char * to_charset) +EXPORT StringBuf str_convert(const char * str, int len, + const char * from_charset, const char * to_charset) { - iconv_t conv = iconv_open (to_charset, from_charset); - if (conv == (iconv_t) -1) - return StringBuf (); + iconv_t conv = iconv_open(to_charset, from_charset); + if (conv == (iconv_t)-1) + return StringBuf(); if (len < 0) - len = strlen (str); + len = strlen(str); - StringBuf buf (-1); + StringBuf buf(-1); size_t inbytesleft = len; - size_t outbytesleft = buf.len (); - ICONV_CONST char * in = (ICONV_CONST char *) str; + size_t outbytesleft = buf.len(); + ICONV_CONST char * in = (ICONV_CONST char *)str; char * out = buf; errno = 0; - size_t ret = iconv (conv, & in, & inbytesleft, & out, & outbytesleft); + size_t ret = iconv(conv, &in, &inbytesleft, &out, &outbytesleft); - if (ret == (size_t) -1 && errno == E2BIG) - throw std::bad_alloc (); + if (ret == (size_t)-1 && errno == E2BIG) + throw std::bad_alloc(); - iconv_close (conv); + iconv_close(conv); - if (ret == (size_t) -1 || inbytesleft) - return StringBuf (); + if (ret == (size_t)-1 || inbytesleft) + return StringBuf(); - buf.resize (buf.len () - outbytesleft); + buf.resize(buf.len() - outbytesleft); return buf; } -static void whine_locale (const char * str, int len, const char * dir, const char * charset) +static void whine_locale(const char * str, int len, const char * dir, + const char * charset) { if (len < 0) - AUDWARN ("Cannot convert %s locale (%s): %s\n", dir, charset, str); + AUDWARN("Cannot convert %s locale (%s): %s\n", dir, charset, str); else - AUDWARN ("Cannot convert %s locale (%s): %.*s\n", dir, charset, len, str); + AUDWARN("Cannot convert %s locale (%s): %.*s\n", dir, charset, len, + str); } -EXPORT StringBuf str_from_locale (const char * str, int len) +EXPORT StringBuf str_from_locale(const char * str, int len) { const char * charset; - if (g_get_charset (& charset)) + if (g_get_charset(&charset)) { /* locale is UTF-8 */ - if (! g_utf8_validate (str, len, nullptr)) + if (!g_utf8_validate(str, len, nullptr)) { - whine_locale (str, len, "from", "UTF-8"); - return StringBuf (); + whine_locale(str, len, "from", "UTF-8"); + return StringBuf(); } - return str_copy (str, len); + return str_copy(str, len); } else { - StringBuf utf8 = str_convert (str, len, charset, "UTF-8"); - if (! utf8) - whine_locale (str, len, "from", charset); + StringBuf utf8 = str_convert(str, len, charset, "UTF-8"); + if (!utf8) + whine_locale(str, len, "from", charset); return utf8; } } -EXPORT StringBuf str_to_locale (const char * str, int len) +EXPORT StringBuf str_to_locale(const char * str, int len) { const char * charset; - if (g_get_charset (& charset)) + if (g_get_charset(&charset)) { /* locale is UTF-8 */ - return str_copy (str, len); + return str_copy(str, len); } else { - StringBuf local = str_convert (str, len, "UTF-8", charset); - if (! local) - whine_locale (str, len, "to", charset); + StringBuf local = str_convert(str, len, "UTF-8", charset); + if (!local) + whine_locale(str, len, "to", charset); return local; } } -static TinyRWLock settings_lock; +static aud::spinlock_rw settings_lock; static String detect_region; static Index fallback_charsets; -static void set_charsets (const char * region, const char * fallbacks) +static void set_charsets(const char * region, const char * fallbacks) { - tiny_lock_write (& settings_lock); + auto wr = settings_lock.write(); - detect_region = String (region); + detect_region = String(region); if (fallbacks) - fallback_charsets = str_list_to_index (fallbacks, ", "); + fallback_charsets = str_list_to_index(fallbacks, ", "); else - fallback_charsets.clear (); - - tiny_unlock_write (& settings_lock); + fallback_charsets.clear(); } -static StringBuf convert_to_utf8_locked (const char * str, int len) +static StringBuf convert_to_utf8(const char * str, int len) { + auto rd = settings_lock.read(); + if (len < 0) - len = strlen (str); + len = strlen(str); if (detect_region) { /* prefer libguess-detected charset */ - const char * detected = libguess_determine_encoding (str, len, detect_region); + const char * detected = + libguess_determine_encoding(str, len, detect_region); if (detected) { - StringBuf utf8 = str_convert (str, len, detected, "UTF-8"); + StringBuf utf8 = str_convert(str, len, detected, "UTF-8"); if (utf8) return utf8; } @@ -157,59 +160,54 @@ static StringBuf convert_to_utf8_locked (const char * str, int len) /* try user-configured fallbacks */ for (const String & fallback : fallback_charsets) { - StringBuf utf8 = str_convert (str, len, fallback, "UTF-8"); + StringBuf utf8 = str_convert(str, len, fallback, "UTF-8"); if (utf8) return utf8; } /* try system locale last (this one will print a warning if it fails) */ - return str_from_locale (str, len); + return str_from_locale(str, len); } -EXPORT StringBuf str_to_utf8 (const char * str, int len) +EXPORT StringBuf str_to_utf8(const char * str, int len) { /* check whether already UTF-8 */ - if (g_utf8_validate (str, len, nullptr)) - return str_copy (str, len); + if (g_utf8_validate(str, len, nullptr)) + return str_copy(str, len); - tiny_lock_read (& settings_lock); - StringBuf utf8 = convert_to_utf8_locked (str, len); - tiny_unlock_read (& settings_lock); - return utf8; + return convert_to_utf8(str, len); } -EXPORT StringBuf str_to_utf8 (StringBuf && str) +EXPORT StringBuf str_to_utf8(StringBuf && str) { /* check whether already UTF-8 */ - if (g_utf8_validate (str, str.len (), nullptr)) - return std::move (str); + if (g_utf8_validate(str, str.len(), nullptr)) + return std::move(str); - tiny_lock_read (& settings_lock); - str = convert_to_utf8_locked (str, str.len ()); - tiny_unlock_read (& settings_lock); - return str.settle (); + str = convert_to_utf8(str, str.len()); + return str.settle(); } -static void chardet_update (void * = nullptr, void * = nullptr) +static void chardet_update(void * = nullptr, void * = nullptr) { - String region = aud_get_str (nullptr, "chardet_detector"); - String fallbacks = aud_get_str (nullptr, "chardet_fallback"); + String region = aud_get_str("chardet_detector"); + String fallbacks = aud_get_str("chardet_fallback"); - set_charsets (region[0] ? (const char *) region : nullptr, fallbacks); + set_charsets(region[0] ? (const char *)region : nullptr, fallbacks); } -void chardet_init () +void chardet_init() { - chardet_update (); + chardet_update(); - hook_associate ("set chardet_detector", chardet_update, nullptr); - hook_associate ("set chardet_fallback", chardet_update, nullptr); + hook_associate("set chardet_detector", chardet_update, nullptr); + hook_associate("set chardet_fallback", chardet_update, nullptr); } -void chardet_cleanup () +void chardet_cleanup() { - hook_dissociate ("set chardet_detector", chardet_update); - hook_dissociate ("set chardet_fallback", chardet_update); + hook_dissociate("set chardet_detector", chardet_update); + hook_dissociate("set chardet_fallback", chardet_update); - set_charsets (nullptr, nullptr); + set_charsets(nullptr, nullptr); } diff --git a/src/libaudcore/config.cc b/src/libaudcore/config.cc index 5046914..e39b4d5 100644 --- a/src/libaudcore/config.cc +++ b/src/libaudcore/config.cc @@ -17,8 +17,8 @@ * the use of this software. */ -#include "runtime.h" #include "internal.h" +#include "runtime.h" #include #include @@ -33,81 +33,86 @@ #define DEFAULT_SECTION "audacious" static const char * const core_defaults[] = { - - /* general */ - "advance_on_delete", "FALSE", - "always_resume_paused", "TRUE", - "clear_playlist", "TRUE", - "open_to_temporary", "TRUE", - "recurse_folders", "TRUE", - "resume_playback_on_startup", "TRUE", - "show_interface", "TRUE", - - /* equalizer */ - "eqpreset_default_file", "", - "eqpreset_extension", "", - "equalizer_active", "FALSE", - "equalizer_bands", "0,0,0,0,0,0,0,0,0,0", - "equalizer_preamp", "0", - - /* info popup / info window */ - "cover_name_exclude", "back", - "cover_name_include", "album,cover,front,folder", - "filepopup_delay", "5", - "filepopup_showprogressbar", "FALSE", - "recurse_for_cover", "FALSE", - "recurse_for_cover_depth", "0", - "show_filepopup_for_tuple", "TRUE", - "use_file_cover", "FALSE", - - /* network */ - "net_buffer_kb", "128", - "save_url_history", "TRUE", - "use_proxy", "FALSE", - "use_proxy_auth", "FALSE", - - /* output */ - "default_gain", "0", - "enable_replay_gain", "TRUE", - "enable_clipping_prevention", "TRUE", - "output_bit_depth", "-1", - "output_buffer_size", "500", - "record", "FALSE", - "record_stream", aud::numeric_string<(int) OutputStream::AfterReplayGain>::str, - "replay_gain_mode", aud::numeric_string<(int) ReplayGainMode::Track>::str, - "replay_gain_preamp", "0", - "soft_clipping", "FALSE", - "software_volume_control", "FALSE", - "sw_volume_left", "100", - "sw_volume_right", "100", - - /* playback */ - "album_shuffle", "FALSE", - "no_playlist_advance", "FALSE", - "repeat", "FALSE", - "shuffle", "FALSE", - "stop_after_current_song", "FALSE", - - /* playlist */ - "chardet_fallback", "ISO-8859-1", + /* clang-format off */ + /* general */ + "advance_on_delete", "FALSE", + "always_resume_paused", "TRUE", + "clear_playlist", "TRUE", + "open_to_temporary", "TRUE", + "recurse_folders", "TRUE", + "resume_playback_on_startup", "TRUE", + "show_interface", "TRUE", + + /* equalizer */ + "eqpreset_default_file", "", + "eqpreset_extension", "", + "equalizer_active", "FALSE", + "equalizer_bands", "0,0,0,0,0,0,0,0,0,0", + "equalizer_preamp", "0", + + /* info popup / info window */ + "cover_name_exclude", "back", + "cover_name_include", "album,cover,front,folder", + "filepopup_delay", "5", + "filepopup_showprogressbar", "FALSE", + "recurse_for_cover", "FALSE", + "recurse_for_cover_depth", "0", + "show_filepopup_for_tuple", "TRUE", + "use_file_cover", "FALSE", + + /* network */ + "net_buffer_kb", "128", + "save_url_history", "TRUE", + "socks_proxy", "FALSE", + "socks_type", "0", + "use_proxy", "FALSE", + "use_proxy_auth", "FALSE", + + /* output */ + "default_gain", "0", + "enable_replay_gain", "TRUE", + "enable_clipping_prevention", "TRUE", + "output_bit_depth", "-1", + "output_buffer_size", "500", + "record", "FALSE", + "record_stream", aud::numeric_string<(int) OutputStream::AfterReplayGain>::str, + "replay_gain_mode", aud::numeric_string<(int) ReplayGainMode::Track>::str, + "replay_gain_preamp", "0", + "soft_clipping", "FALSE", + "software_volume_control", "FALSE", + "sw_volume_left", "100", + "sw_volume_right", "100", + "volume_delta", "5", + + /* playback */ + "album_shuffle", "FALSE", + "no_playlist_advance", "FALSE", + "repeat", "FALSE", + "shuffle", "FALSE", + "step_size", "5", + "stop_after_current_song", "FALSE", + + /* playlist */ + "chardet_fallback", "ISO-8859-1", #ifdef _WIN32 - "convert_backslash", "TRUE", + "convert_backslash", "TRUE", #else - "convert_backslash", "FALSE", + "convert_backslash", "FALSE", #endif - "export_relative_paths", "TRUE", - "folders_in_playlist", "FALSE", - "generic_title_format", "${?artist:${artist} - }${?album:${album} - }${title}", - "leading_zero", "FALSE", - "show_hours", "TRUE", - "metadata_fallbacks", "TRUE", - "metadata_on_play", "FALSE", - "show_numbers_in_pl", "FALSE", - "slow_probe", "FALSE", - - nullptr}; - -enum OpType { + "export_relative_paths", "TRUE", + "folders_in_playlist", "FALSE", + "generic_title_format", "${?artist:${artist} - }${?album:${album} - }${title}", + "leading_zero", "FALSE", + "show_hours", "TRUE", + "metadata_fallbacks", "TRUE", + "metadata_on_play", "FALSE", + "show_numbers_in_pl", "FALSE", + "slow_probe", "FALSE", + /* clang-format on */ + nullptr}; + +enum OpType +{ OP_IS_DEFAULT, OP_GET, OP_SET, @@ -116,7 +121,8 @@ enum OpType { OP_CLEAR_NO_FLAG }; -struct ConfigItem { +struct ConfigItem +{ String section; String key; String value; @@ -134,14 +140,16 @@ struct ConfigOp unsigned hash; bool result; - ConfigNode * add (const ConfigOp *); - bool found (ConfigNode * node); + ConfigNode * add(const ConfigOp *); + bool found(ConfigNode * node); }; struct ConfigNode : public MultiHash::Node, public ConfigItem { - bool match (const ConfigOp * op) const - { return ! strcmp (section, op->section) && ! strcmp (key, op->key); } + bool match(const ConfigOp * op) const + { + return !strcmp(section, op->section) && !strcmp(key, op->key); + } }; typedef MultiHash_T ConfigTable; @@ -149,12 +157,12 @@ typedef MultiHash_T ConfigTable; static ConfigTable s_defaults, s_config; static volatile bool s_modified; -ConfigNode * ConfigOp::add (const ConfigOp *) +ConfigNode * ConfigOp::add(const ConfigOp *) { switch (type) { case OP_IS_DEFAULT: - result = ! value[0]; /* empty string is default */ + result = !value[0]; /* empty string is default */ return nullptr; case OP_SET: @@ -165,8 +173,8 @@ ConfigNode * ConfigOp::add (const ConfigOp *) case OP_SET_NO_FLAG: { ConfigNode * node = new ConfigNode; - node->section = String (section); - node->key = String (key); + node->section = String(section); + node->key = String(key); node->value = value; return node; } @@ -176,12 +184,12 @@ ConfigNode * ConfigOp::add (const ConfigOp *) } } -bool ConfigOp::found (ConfigNode * node) +bool ConfigOp::found(ConfigNode * node) { switch (type) { case OP_IS_DEFAULT: - result = ! strcmp (node->value, value); + result = !strcmp(node->value, value); return false; case OP_GET: @@ -189,7 +197,7 @@ bool ConfigOp::found (ConfigNode * node) return false; case OP_SET: - result = !! strcmp (node->value, value); + result = !!strcmp(node->value, value); if (result) s_modified = true; // fall-through @@ -212,13 +220,13 @@ bool ConfigOp::found (ConfigNode * node) } } -static bool config_op_run (ConfigOp & op, ConfigTable & table) +static bool config_op_run(ConfigOp & op, ConfigTable & table) { - if (! op.hash) - op.hash = str_calc_hash (op.section) + str_calc_hash (op.key); + if (!op.hash) + op.hash = str_calc_hash(op.section) + str_calc_hash(op.key); op.result = false; - table.lookup (& op, op.hash, op); + table.lookup(&op, op.hash, op); return op.result; } @@ -227,173 +235,191 @@ class ConfigParser : public IniParser private: String section; - void handle_heading (const char * heading) - { section = String (heading); } + void handle_heading(const char * heading) { section = String(heading); } - void handle_entry (const char * key, const char * value) + void handle_entry(const char * key, const char * value) { - if (! section) + if (!section) return; - ConfigOp op = {OP_SET_NO_FLAG, section, key, String (value)}; - config_op_run (op, s_config); + ConfigOp op = {OP_SET_NO_FLAG, section, key, String(value)}; + config_op_run(op, s_config); } }; -void config_load () +void config_load() { - StringBuf path = filename_build ({aud_get_path (AudPath::UserDir), "config"}); - if (VFSFile::test_file (path, VFS_EXISTS)) + StringBuf path = filename_build({aud_get_path(AudPath::UserDir), "config"}); + if (VFSFile::test_file(path, VFS_EXISTS)) { - VFSFile file (path, "r"); + VFSFile file(path, "r"); if (file) - ConfigParser ().parse (file); + ConfigParser().parse(file); } - aud_config_set_defaults (nullptr, core_defaults); + aud_config_set_defaults(nullptr, core_defaults); /* migrate from previous versions */ - if (aud_get_bool (0, "replay_gain_album")) + if (aud_get_bool("replay_gain_album")) + { + aud_set_str("replay_gain_album", ""); + aud_set_int("replay_gain_mode", (int)ReplayGainMode::Album); + } + + double step_size = aud_get_double("gtkui", "step_size"); + if (step_size > 0) + { + aud_set_int("step_size", (int)step_size); + aud_set_str("gtkui", "step_size", ""); + } + + int volume_delta = aud_get_int("statusicon", "volume_delta"); + if (volume_delta > 0) { - aud_set_str (0, "replay_gain_album", ""); - aud_set_int (0, "replay_gain_mode", (int) ReplayGainMode::Album); + aud_set_int("volume_delta", volume_delta); + aud_set_str("statusicon", "volume_delta", ""); } } -void config_save () +void config_save() { - if (! s_modified) + if (!s_modified) return; Index list; - auto add_to_list = [&] (ConfigNode * node) { - list.append (* node); + auto add_to_list = [&](ConfigNode * node) { + list.append(*node); return false; }; - auto finish = [] () { - s_modified = false; // must be inside MultiHash lock + auto finish = []() { + s_modified = false; // must be inside MultiHash lock }; - s_config.iterate (add_to_list, finish); + s_config.iterate(add_to_list, finish); - list.sort ([] (const ConfigItem & a, const ConfigItem & b) { + list.sort([](const ConfigItem & a, const ConfigItem & b) { if (a.section == b.section) - return strcmp (a.key, b.key); + return strcmp(a.key, b.key); else - return strcmp (a.section, b.section); + return strcmp(a.section, b.section); }); String current_heading; - VFSFile file (filename_build ({aud_get_path (AudPath::UserDir), "config"}), "w"); - if (! file) + VFSFile file(filename_build({aud_get_path(AudPath::UserDir), "config"}), + "w"); + if (!file) goto FAILED; for (const ConfigItem & item : list) { if (item.section != current_heading) { - if (! inifile_write_heading (file, item.section)) + if (!inifile_write_heading(file, item.section)) goto FAILED; current_heading = item.section; } - if (! inifile_write_entry (file, item.key, item.value)) + if (!inifile_write_entry(file, item.key, item.value)) goto FAILED; } - if (file.fflush () < 0) + if (file.fflush() < 0) goto FAILED; return; FAILED: - AUDWARN ("Error saving configuration.\n"); + AUDWARN("Error saving configuration.\n"); } -EXPORT void aud_config_set_defaults (const char * section, const char * const * entries) +EXPORT void aud_config_set_defaults(const char * section, + const char * const * entries) { - if (! section) + if (!section) section = DEFAULT_SECTION; while (1) { - const char * name = * entries ++; - const char * value = * entries ++; - if (! name || ! value) + const char * name = *entries++; + const char * value = *entries++; + if (!name || !value) break; - ConfigOp op = {OP_SET_NO_FLAG, section, name, String (value)}; - config_op_run (op, s_defaults); + ConfigOp op = {OP_SET_NO_FLAG, section, name, String(value)}; + config_op_run(op, s_defaults); } } -void config_cleanup () +void config_cleanup() { - s_config.clear (); - s_defaults.clear (); + s_config.clear(); + s_defaults.clear(); } -EXPORT void aud_set_str (const char * section, const char * name, const char * value) +EXPORT void aud_set_str(const char * section, const char * name, + const char * value) { - assert (name && value); + assert(name && value); - ConfigOp op = {OP_IS_DEFAULT, section ? section : DEFAULT_SECTION, name, String (value)}; - bool is_default = config_op_run (op, s_defaults); + ConfigOp op = {OP_IS_DEFAULT, section ? section : DEFAULT_SECTION, name, + String(value)}; + bool is_default = config_op_run(op, s_defaults); op.type = is_default ? OP_CLEAR : OP_SET; - bool changed = config_op_run (op, s_config); + bool changed = config_op_run(op, s_config); - if (changed && ! section) - event_queue (str_concat ({"set ", name}), nullptr); + if (changed && !section) + event_queue(str_concat({"set ", name}), nullptr); } -EXPORT String aud_get_str (const char * section, const char * name) +EXPORT String aud_get_str(const char * section, const char * name) { - assert (name); + assert(name); ConfigOp op = {OP_GET, section ? section : DEFAULT_SECTION, name}; - config_op_run (op, s_config); + config_op_run(op, s_config); - if (! op.value) - config_op_run (op, s_defaults); + if (!op.value) + config_op_run(op, s_defaults); - return op.value ? op.value : String (""); + return op.value ? op.value : String(""); } -EXPORT void aud_set_bool (const char * section, const char * name, bool value) +EXPORT void aud_set_bool(const char * section, const char * name, bool value) { - aud_set_str (section, name, value ? "TRUE" : "FALSE"); + aud_set_str(section, name, value ? "TRUE" : "FALSE"); } -EXPORT bool aud_get_bool (const char * section, const char * name) +EXPORT bool aud_get_bool(const char * section, const char * name) { - return ! strcmp (aud_get_str (section, name), "TRUE"); + return !strcmp(aud_get_str(section, name), "TRUE"); } -EXPORT void aud_toggle_bool (const char * section, const char * name) +EXPORT void aud_toggle_bool(const char * section, const char * name) { - aud_set_bool (section, name, ! aud_get_bool (section, name)); + aud_set_bool(section, name, !aud_get_bool(section, name)); } -EXPORT void aud_set_int (const char * section, const char * name, int value) +EXPORT void aud_set_int(const char * section, const char * name, int value) { - aud_set_str (section, name, int_to_str (value)); + aud_set_str(section, name, int_to_str(value)); } -EXPORT int aud_get_int (const char * section, const char * name) +EXPORT int aud_get_int(const char * section, const char * name) { - return str_to_int (aud_get_str (section, name)); + return str_to_int(aud_get_str(section, name)); } -EXPORT void aud_set_double (const char * section, const char * name, double value) +EXPORT void aud_set_double(const char * section, const char * name, + double value) { - aud_set_str (section, name, double_to_str (value)); + aud_set_str(section, name, double_to_str(value)); } -EXPORT double aud_get_double (const char * section, const char * name) +EXPORT double aud_get_double(const char * section, const char * name) { - return str_to_double (aud_get_str (section, name)); + return str_to_double(aud_get_str(section, name)); } diff --git a/src/libaudcore/cue-cache.cc b/src/libaudcore/cue-cache.cc index b821173..f568f7c 100644 --- a/src/libaudcore/cue-cache.cc +++ b/src/libaudcore/cue-cache.cc @@ -20,68 +20,68 @@ #include "cue-cache.h" #include "multihash.h" #include "playlist-internal.h" +#include "threads.h" -#include - -enum NodeState {NotLoaded, Loading, Loaded}; +enum NodeState +{ + NotLoaded, + Loading, + Loaded +}; -struct CueCacheNode { +struct CueCacheNode +{ Index items; NodeState state = NotLoaded; int refcount = 0; }; static SimpleHash cache; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static aud::mutex mutex; +static aud::condvar cond; -CueCacheRef::CueCacheRef (const char * filename) : - m_filename (filename) +CueCacheRef::CueCacheRef(const char * filename) : m_filename(filename) { - pthread_mutex_lock (& mutex); - - m_node = cache.lookup (m_filename); - if (! m_node) - m_node = cache.add (m_filename, CueCacheNode ()); + auto mh = mutex.take(); - m_node->refcount ++; + m_node = cache.lookup(m_filename); + if (!m_node) + m_node = cache.add(m_filename, CueCacheNode()); - pthread_mutex_unlock (& mutex); + m_node->refcount++; } -CueCacheRef::~CueCacheRef () +CueCacheRef::~CueCacheRef() { - pthread_mutex_lock (& mutex); - - m_node->refcount --; - if (! m_node->refcount) - cache.remove (m_filename); + auto mh = mutex.take(); - pthread_mutex_unlock (& mutex); + m_node->refcount--; + if (!m_node->refcount) + cache.remove(m_filename); } -const Index & CueCacheRef::load () +const Index & CueCacheRef::load() { + auto mh = mutex.take(); String title; // not used - pthread_mutex_lock (& mutex); switch (m_node->state) { case NotLoaded: // load the cuesheet in this thread m_node->state = Loading; - pthread_mutex_unlock (& mutex); - playlist_load (m_filename, title, m_node->items); - pthread_mutex_lock (& mutex); + mh.unlock(); + playlist_load(m_filename, title, m_node->items); + mh.lock(); m_node->state = Loaded; - pthread_cond_broadcast (& cond); + cond.notify_all(); break; case Loading: // wait for cuesheet to load in another thread while (m_node->state != Loaded) - pthread_cond_wait (& cond, & mutex); + cond.wait(mh); break; @@ -90,6 +90,5 @@ const Index & CueCacheRef::load () break; } - pthread_mutex_unlock (& mutex); return m_node->items; } diff --git a/src/libaudcore/cue-cache.h b/src/libaudcore/cue-cache.h index 84ab516..c5af486 100644 --- a/src/libaudcore/cue-cache.h +++ b/src/libaudcore/cue-cache.h @@ -28,10 +28,10 @@ struct CueCacheNode; class CueCacheRef { public: - CueCacheRef (const char * filename); - ~CueCacheRef (); + CueCacheRef(const char * filename); + ~CueCacheRef(); - const Index & load (); + const Index & load(); private: String m_filename; diff --git a/src/libaudcore/drct.cc b/src/libaudcore/drct.cc index 2ad76eb..592f8e8 100644 --- a/src/libaudcore/drct.cc +++ b/src/libaudcore/drct.cc @@ -30,44 +30,44 @@ /* --- PLAYBACK CONTROL --- */ -EXPORT void aud_drct_play () +EXPORT void aud_drct_play() { - if (aud_drct_get_playing ()) + if (aud_drct_get_playing()) { - if (aud_drct_get_paused ()) - aud_drct_pause (); + if (aud_drct_get_paused()) + aud_drct_pause(); else { int a, b; - aud_drct_get_ab_repeat (a, b); - aud_drct_seek (aud::max (a, 0)); + aud_drct_get_ab_repeat(a, b); + aud_drct_seek(aud::max(a, 0)); } } else { - auto playlist = Playlist::active_playlist (); - playlist.set_position (playlist.get_position ()); - playlist.start_playback (); + auto playlist = Playlist::active_playlist(); + playlist.set_position(playlist.get_position()); + playlist.start_playback(); } } -EXPORT void aud_drct_play_pause () +EXPORT void aud_drct_play_pause() { - if (aud_drct_get_playing ()) - aud_drct_pause (); + if (aud_drct_get_playing()) + aud_drct_pause(); else - aud_drct_play (); + aud_drct_play(); } -EXPORT int aud_drct_get_position () +EXPORT int aud_drct_get_position() { - return Playlist::playing_playlist ().get_position (); + return Playlist::playing_playlist().get_position(); } -EXPORT String aud_drct_get_filename () +EXPORT String aud_drct_get_filename() { - auto playlist = Playlist::playing_playlist (); - return playlist.entry_filename (playlist.get_position ()); + auto playlist = Playlist::playing_playlist(); + return playlist.entry_filename(playlist.get_position()); } /* --- RECORDING CONTROL --- */ @@ -77,179 +77,203 @@ EXPORT String aud_drct_get_filename () static PluginHandle * record_plugin; -static bool record_plugin_watcher (PluginHandle *, void *) +static bool record_plugin_watcher(PluginHandle *, void *) { - if (! aud_drct_get_record_enabled ()) - aud_set_bool (nullptr, "record", false); + if (!aud_drct_get_record_enabled()) + aud_set_bool("record", false); - hook_call ("enable record", nullptr); + hook_call("enable record", nullptr); return true; } -static void validate_record_setting (void *, void *) +static void validate_record_setting(void *, void *) { - if (aud_get_bool (nullptr, "record") && ! aud_drct_get_record_enabled ()) + if (aud_get_bool("record") && !aud_drct_get_record_enabled()) { /* User attempted to start recording without a recording plugin enabled. * This is probably not the best response, but better than nothing. */ - aud_set_bool (nullptr, "record", false); - aud_ui_show_error (_("Stream recording must be configured in Audio " - "Settings before it can be used.")); + aud_set_bool("record", false); + aud_ui_show_error(_("Stream recording must be configured in Audio " + "Settings before it can be used.")); } } -void record_init () +void record_init() { - auto plugin = aud_plugin_lookup_basename ("filewriter"); - if (plugin && aud_plugin_get_type (plugin) == PluginType::Output) + // when building under Meson, the plugin may be libfilewriter.so. + auto plugin = aud_plugin_lookup_basename("filewriter"); + if (!plugin) + plugin = aud_plugin_lookup_basename("libfilewriter"); + + if (plugin && aud_plugin_get_type(plugin) == PluginType::Output) { record_plugin = plugin; - aud_plugin_add_watch (plugin, record_plugin_watcher, nullptr); + aud_plugin_add_watch(plugin, record_plugin_watcher, nullptr); } - if (! aud_drct_get_record_enabled ()) - aud_set_bool (nullptr, "record", false); + if (!aud_drct_get_record_enabled()) + aud_set_bool("record", false); - hook_associate ("set record", validate_record_setting, nullptr); + hook_associate("set record", validate_record_setting, nullptr); } -void record_cleanup () +void record_cleanup() { - hook_dissociate ("set record", validate_record_setting); + hook_dissociate("set record", validate_record_setting); if (record_plugin) { - aud_plugin_remove_watch (record_plugin, record_plugin_watcher, nullptr); + aud_plugin_remove_watch(record_plugin, record_plugin_watcher, nullptr); record_plugin = nullptr; } } -EXPORT PluginHandle * aud_drct_get_record_plugin () +EXPORT PluginHandle * aud_drct_get_record_plugin() { /* recording is disabled when FileWriter is the primary output plugin */ - if (! record_plugin || plugin_get_enabled (record_plugin) == PluginEnabled::Primary) + if (!record_plugin || + plugin_get_enabled(record_plugin) == PluginEnabled::Primary) return nullptr; return record_plugin; } -EXPORT bool aud_drct_get_record_enabled () +EXPORT bool aud_drct_get_record_enabled() { - return (record_plugin && plugin_get_enabled (record_plugin) == PluginEnabled::Secondary); + return (record_plugin && + plugin_get_enabled(record_plugin) == PluginEnabled::Secondary); } -EXPORT bool aud_drct_enable_record (bool enable) +EXPORT bool aud_drct_enable_record(bool enable) { - if (! record_plugin || plugin_get_enabled (record_plugin) == PluginEnabled::Primary) + if (!record_plugin || + plugin_get_enabled(record_plugin) == PluginEnabled::Primary) return false; - return plugin_enable_secondary (record_plugin, enable); + return plugin_enable_secondary(record_plugin, enable); } /* --- VOLUME CONTROL --- */ -EXPORT int aud_drct_get_volume_main () +EXPORT int aud_drct_get_volume_main() { - StereoVolume volume = aud_drct_get_volume (); - return aud::max (volume.left, volume.right); + StereoVolume volume = aud_drct_get_volume(); + return aud::max(volume.left, volume.right); } -EXPORT void aud_drct_set_volume_main (int volume) +EXPORT void aud_drct_set_volume_main(int volume) { - StereoVolume old = aud_drct_get_volume (); - int main = aud::max (old.left, old.right); + StereoVolume old = aud_drct_get_volume(); + int main = aud::max(old.left, old.right); if (main > 0) - aud_drct_set_volume ({ - aud::rescale (old.left, main, volume), - aud::rescale (old.right, main, volume) - }); + aud_drct_set_volume({aud::rescale(old.left, main, volume), + aud::rescale(old.right, main, volume)}); else - aud_drct_set_volume ({volume, volume}); + aud_drct_set_volume({volume, volume}); } -EXPORT int aud_drct_get_volume_balance () +EXPORT int aud_drct_get_volume_balance() { - StereoVolume volume = aud_drct_get_volume (); + StereoVolume volume = aud_drct_get_volume(); if (volume.left == volume.right) return 0; else if (volume.left > volume.right) - return -100 + aud::rescale (volume.right, volume.left, 100); + return -100 + aud::rescale(volume.right, volume.left, 100); else - return 100 - aud::rescale (volume.left, volume.right, 100); + return 100 - aud::rescale(volume.left, volume.right, 100); } -EXPORT void aud_drct_set_volume_balance (int balance) +EXPORT void aud_drct_set_volume_balance(int balance) { - int main = aud_drct_get_volume_main (); + int main = aud_drct_get_volume_main(); if (balance < 0) - aud_drct_set_volume ({main, aud::rescale (main, 100, 100 + balance)}); + aud_drct_set_volume({main, aud::rescale(main, 100, 100 + balance)}); else - aud_drct_set_volume ({aud::rescale (main, 100, 100 - balance), main}); + aud_drct_set_volume({aud::rescale(main, 100, 100 - balance), main}); } /* --- PLAYLIST CONTROL --- */ -EXPORT void aud_drct_pl_next () +EXPORT void aud_drct_pl_next() +{ + PlaylistEx playlist = Playlist::playing_playlist(); + if (playlist == Playlist()) + playlist = Playlist::active_playlist(); + + playlist.next_song(aud_get_bool("repeat")); +} + +EXPORT void aud_drct_pl_next_album() +{ + PlaylistEx playlist = Playlist::playing_playlist(); + if (playlist == Playlist()) + playlist = Playlist::active_playlist(); + + playlist.next_album(aud_get_bool("repeat")); +} + +EXPORT void aud_drct_pl_prev() { - PlaylistEx playlist = Playlist::playing_playlist (); - if (playlist == Playlist ()) - playlist = Playlist::active_playlist (); + PlaylistEx playlist = Playlist::playing_playlist(); + if (playlist == Playlist()) + playlist = Playlist::active_playlist(); - playlist.next_song (aud_get_bool (nullptr, "repeat")); + playlist.prev_song(); } -EXPORT void aud_drct_pl_prev () +EXPORT void aud_drct_pl_prev_album() { - PlaylistEx playlist = Playlist::playing_playlist (); - if (playlist == Playlist ()) - playlist = Playlist::active_playlist (); + PlaylistEx playlist = Playlist::playing_playlist(); + if (playlist == Playlist()) + playlist = Playlist::active_playlist(); - playlist.prev_song (); + playlist.prev_album(); } -static void add_list (Index && items, int at, bool to_temp, bool play) +static void add_list(Index && items, int at, bool to_temp, + bool play) { if (to_temp) - Playlist::temporary_playlist ().activate (); + Playlist::temporary_playlist().activate(); - Playlist::active_playlist ().insert_items (at, std::move (items), play); + Playlist::active_playlist().insert_items(at, std::move(items), play); } -EXPORT void aud_drct_pl_add (const char * filename, int at) +EXPORT void aud_drct_pl_add(const char * filename, int at) { Index items; - items.append (String (filename)); - add_list (std::move (items), at, false, false); + items.append(String(filename)); + add_list(std::move(items), at, false, false); } -EXPORT void aud_drct_pl_add_list (Index && items, int at) +EXPORT void aud_drct_pl_add_list(Index && items, int at) { - add_list (std::move (items), at, false, false); + add_list(std::move(items), at, false, false); } -EXPORT void aud_drct_pl_open (const char * filename) +EXPORT void aud_drct_pl_open(const char * filename) { Index items; - items.append (String (filename)); - add_list (std::move (items), -1, aud_get_bool (nullptr, "open_to_temporary"), true); + items.append(String(filename)); + add_list(std::move(items), -1, aud_get_bool("open_to_temporary"), true); } -EXPORT void aud_drct_pl_open_list (Index && items) +EXPORT void aud_drct_pl_open_list(Index && items) { - add_list (std::move (items), -1, aud_get_bool (nullptr, "open_to_temporary"), true); + add_list(std::move(items), -1, aud_get_bool("open_to_temporary"), true); } -EXPORT void aud_drct_pl_open_temp (const char * filename) +EXPORT void aud_drct_pl_open_temp(const char * filename) { Index items; - items.append (String (filename)); - add_list (std::move (items), -1, true, true); + items.append(String(filename)); + add_list(std::move(items), -1, true, true); } -EXPORT void aud_drct_pl_open_temp_list (Index && items) +EXPORT void aud_drct_pl_open_temp_list(Index && items) { - add_list (std::move (items), -1, true, true); + add_list(std::move(items), -1, true, true); } diff --git a/src/libaudcore/drct.h b/src/libaudcore/drct.h index a486660..086a244 100644 --- a/src/libaudcore/drct.h +++ b/src/libaudcore/drct.h @@ -30,42 +30,42 @@ class PluginHandle; /* --- PLAYBACK CONTROL --- */ -void aud_drct_play (); -void aud_drct_play_pause (); -void aud_drct_pause (); -void aud_drct_stop (); -bool aud_drct_get_playing (); -bool aud_drct_get_ready (); -bool aud_drct_get_paused (); +void aud_drct_play(); +void aud_drct_play_pause(); +void aud_drct_pause(); +void aud_drct_stop(); +bool aud_drct_get_playing(); +bool aud_drct_get_ready(); +bool aud_drct_get_paused(); // returns entry number of playing song (zero-based) -int aud_drct_get_position (); +int aud_drct_get_position(); // returns filename of playing song -String aud_drct_get_filename (); +String aud_drct_get_filename(); // returns formatted title of playing song // connect to the "title change" hook to be notified of changes -String aud_drct_get_title (); +String aud_drct_get_title(); // returns metadata of playing song // connect to the "tuple change" hook to be notified of changes -Tuple aud_drct_get_tuple (); +Tuple aud_drct_get_tuple(); // returns some statistics of playing song // connect to the "info change" hook to be notified of changes -void aud_drct_get_info (int & bitrate, int & samplerate, int & channels); +void aud_drct_get_info(int & bitrate, int & samplerate, int & channels); -int aud_drct_get_time (); -int aud_drct_get_length (); -void aud_drct_seek (int time); +int aud_drct_get_time(); +int aud_drct_get_length(); +void aud_drct_seek(int time); /* "A-B repeat": when playback reaches point B, it returns to point A (where A * and B are in milliseconds). The value -1 is interpreted as the beginning of * the song (for A) or the end of the song (for B). A-B repeat is disabled * entirely by setting both A and B to -1. */ -void aud_drct_set_ab_repeat (int a, int b); -void aud_drct_get_ab_repeat (int & a, int & b); +void aud_drct_set_ab_repeat(int a, int b); +void aud_drct_get_ab_repeat(int & a, int & b); /* --- RECORDING CONTROL --- */ @@ -75,35 +75,37 @@ void aud_drct_get_ab_repeat (int & a, int & b); /* Returns the output plugin that will be used for recording, or null if none is * available. Connect to the "enable record" hook to monitor changes. */ -PluginHandle * aud_drct_get_record_plugin (); +PluginHandle * aud_drct_get_record_plugin(); /* Returns true if output recording is enabled, otherwise false. Connect to the * "enable record" hook to monitor changes. */ -bool aud_drct_get_record_enabled (); +bool aud_drct_get_record_enabled(); /* Enables or disables output recording (but does not actually start recording). * Returns true on success, otherwise false. */ -bool aud_drct_enable_record (bool enable); +bool aud_drct_enable_record(bool enable); /* --- VOLUME CONTROL --- */ -StereoVolume aud_drct_get_volume (); -void aud_drct_set_volume (StereoVolume volume); -int aud_drct_get_volume_main (); -void aud_drct_set_volume_main (int volume); -int aud_drct_get_volume_balance (); -void aud_drct_set_volume_balance (int balance); +StereoVolume aud_drct_get_volume(); +void aud_drct_set_volume(StereoVolume volume); +int aud_drct_get_volume_main(); +void aud_drct_set_volume_main(int volume); +int aud_drct_get_volume_balance(); +void aud_drct_set_volume_balance(int balance); /* --- PLAYLIST CONTROL --- */ -void aud_drct_pl_next (); -void aud_drct_pl_prev (); - -void aud_drct_pl_add (const char * filename, int at); -void aud_drct_pl_add_list (Index && items, int at); -void aud_drct_pl_open (const char * filename); -void aud_drct_pl_open_list (Index && items); -void aud_drct_pl_open_temp (const char * filename); -void aud_drct_pl_open_temp_list (Index && items); +void aud_drct_pl_next(); +void aud_drct_pl_next_album(); +void aud_drct_pl_prev(); +void aud_drct_pl_prev_album(); + +void aud_drct_pl_add(const char * filename, int at); +void aud_drct_pl_add_list(Index && items, int at); +void aud_drct_pl_open(const char * filename); +void aud_drct_pl_open_list(Index && items); +void aud_drct_pl_open_temp(const char * filename); +void aud_drct_pl_open_temp_list(Index && items); #endif diff --git a/src/libaudcore/effect.cc b/src/libaudcore/effect.cc index b0538d0..cd348b6 100644 --- a/src/libaudcore/effect.cc +++ b/src/libaudcore/effect.cc @@ -19,13 +19,12 @@ #include "internal.h" -#include - #include "drct.h" #include "list.h" #include "plugin.h" #include "plugins.h" #include "runtime.h" +#include "threads.h" struct Effect : public ListNode { @@ -36,135 +35,130 @@ struct Effect : public ListNode bool remove_flag; }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static List effects; static int input_channels, input_rate; -void effect_start (int & channels, int & rate) +void effect_start(int & channels, int & rate) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - AUDDBG ("Starting effects.\n"); + AUDDBG("Starting effects.\n"); - effects.clear (); + effects.clear(); input_channels = channels; input_rate = rate; - auto & list = aud_plugin_list (PluginType::Effect); + auto & list = aud_plugin_list(PluginType::Effect); - for (int i = 0; i < list.len (); i ++) + for (int i = 0; i < list.len(); i++) { PluginHandle * plugin = list[i]; - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - AUDINFO ("Starting %s at %d channels, %d Hz.\n", - aud_plugin_get_name (plugin), channels, rate); + AUDINFO("Starting %s at %d channels, %d Hz.\n", + aud_plugin_get_name(plugin), channels, rate); - EffectPlugin * header = (EffectPlugin *) aud_plugin_get_header (plugin); - if (! header) + EffectPlugin * header = (EffectPlugin *)aud_plugin_get_header(plugin); + if (!header) continue; - header->start (channels, rate); + header->start(channels, rate); - Effect * effect = new Effect (); + Effect * effect = new Effect(); effect->plugin = plugin; effect->position = i; effect->header = header; effect->channels_returned = channels; effect->rate_returned = rate; - effects.append (effect); + effects.append(effect); } - - pthread_mutex_unlock (& mutex); } -Index & effect_process (Index & data) +Index & effect_process(Index & data) { - Index * cur = & data; - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); + Index * cur = &data; - Effect * e = effects.head (); + Effect * e = effects.head(); while (e) { - Effect * next = effects.next (e); + Effect * next = effects.next(e); if (e->remove_flag) { - cur = & e->header->finish (* cur, false); + cur = &e->header->finish(*cur, false); // simulate end-of-playlist call // first save the current data - Index save = std::move (* cur); - cur = & e->header->finish (* cur, true); + Index save = std::move(*cur); + cur = &e->header->finish(*cur, true); // combine the saved and new data - save.move_from (* cur, 0, -1, -1, true, true); - * cur = std::move (save); + save.move_from(*cur, 0, -1, -1, true, true); + *cur = std::move(save); - effects.remove (e); + effects.remove(e); delete e; } else - cur = & e->header->process (* cur); + cur = &e->header->process(*cur); e = next; } - pthread_mutex_unlock (& mutex); - return * cur; + return *cur; } -bool effect_flush (bool force) +bool effect_flush(bool force) { + auto mh = mutex.take(); bool flushed = true; - pthread_mutex_lock (& mutex); - for (Effect * e = effects.head (); e; e = effects.next (e)) + for (Effect * e = effects.head(); e; e = effects.next(e)) { - if (! e->header->flush (force) && ! force) + if (!e->header->flush(force) && !force) { flushed = false; break; } } - pthread_mutex_unlock (& mutex); return flushed; } -Index & effect_finish (Index & data, bool end_of_playlist) +Index & effect_finish(Index & data, bool end_of_playlist) { - Index * cur = & data; - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); + Index * cur = &data; - for (Effect * e = effects.head (); e; e = effects.next (e)) - cur = & e->header->finish (* cur, end_of_playlist); + for (Effect * e = effects.head(); e; e = effects.next(e)) + cur = &e->header->finish(*cur, end_of_playlist); - pthread_mutex_unlock (& mutex); - return * cur; + return *cur; } -int effect_adjust_delay (int delay) +int effect_adjust_delay(int delay) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - for (Effect * e = effects.tail (); e; e = effects.prev (e)) - delay = e->header->adjust_delay (delay); + for (Effect * e = effects.tail(); e; e = effects.prev(e)) + delay = e->header->adjust_delay(delay); - pthread_mutex_unlock (& mutex); return delay; } -static void effect_insert (PluginHandle * plugin, EffectPlugin * header) +static void effect_insert(aud::mutex::holder &, PluginHandle * plugin, + EffectPlugin * header) { - int position = aud_plugin_list (PluginType::Effect).find (plugin); + int position = aud_plugin_list(PluginType::Effect).find(plugin); Effect * prev = nullptr; - for (Effect * e = effects.head (); e; e = effects.next (e)) + for (Effect * e = effects.head(); e; e = effects.next(e)) { if (e->plugin == plugin) { @@ -178,91 +172,90 @@ static void effect_insert (PluginHandle * plugin, EffectPlugin * header) prev = e; } - AUDDBG ("Adding %s without reset.\n", aud_plugin_get_name (plugin)); + AUDDBG("Adding %s without reset.\n", aud_plugin_get_name(plugin)); int channels, rate; if (prev) { - AUDDBG ("Adding %s after %s.\n", aud_plugin_get_name (plugin), - aud_plugin_get_name (prev->plugin)); + AUDDBG("Adding %s after %s.\n", aud_plugin_get_name(plugin), + aud_plugin_get_name(prev->plugin)); channels = prev->channels_returned; rate = prev->rate_returned; } else { - AUDDBG ("Adding %s as first effect.\n", aud_plugin_get_name (plugin)); + AUDDBG("Adding %s as first effect.\n", aud_plugin_get_name(plugin)); channels = input_channels; rate = input_rate; } - AUDINFO ("Starting %s at %d channels, %d Hz.\n", aud_plugin_get_name (plugin), channels, rate); - header->start (channels, rate); + AUDINFO("Starting %s at %d channels, %d Hz.\n", aud_plugin_get_name(plugin), + channels, rate); + header->start(channels, rate); - Effect * effect = new Effect (); + Effect * effect = new Effect(); effect->plugin = plugin; effect->position = position; effect->header = header; effect->channels_returned = channels; effect->rate_returned = rate; - effects.insert_after (prev, effect); + effects.insert_after(prev, effect); } -static void effect_remove (PluginHandle * plugin) +static void effect_remove(aud::mutex::holder &, PluginHandle * plugin) { - for (Effect * e = effects.head (); e; e = effects.next (e)) + for (Effect * e = effects.head(); e; e = effects.next(e)) { if (e->plugin == plugin) { - AUDDBG ("Removing %s without reset.\n", aud_plugin_get_name (plugin)); + AUDDBG("Removing %s without reset.\n", aud_plugin_get_name(plugin)); e->remove_flag = true; return; } } } -static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, bool enable) +static void effect_enable(PluginHandle * plugin, EffectPlugin * ep, bool enable) { if (ep->preserves_format) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); if (enable) - effect_insert (plugin, ep); + effect_insert(mh, plugin, ep); else - effect_remove (plugin); - - pthread_mutex_unlock (& mutex); + effect_remove(mh, plugin); } else { - AUDDBG ("Reset to add/remove %s.\n", aud_plugin_get_name (plugin)); - aud_output_reset (OutputReset::EffectsOnly); + AUDDBG("Reset to add/remove %s.\n", aud_plugin_get_name(plugin)); + aud_output_reset(OutputReset::EffectsOnly); } } -bool effect_plugin_start (PluginHandle * plugin) +bool effect_plugin_start(PluginHandle * plugin) { - if (aud_drct_get_playing ()) + if (aud_drct_get_playing()) { - EffectPlugin * ep = (EffectPlugin *) aud_plugin_get_header (plugin); - if (! ep) + EffectPlugin * ep = (EffectPlugin *)aud_plugin_get_header(plugin); + if (!ep) return false; - effect_enable (plugin, ep, true); + effect_enable(plugin, ep, true); } return true; } -void effect_plugin_stop (PluginHandle * plugin) +void effect_plugin_stop(PluginHandle * plugin) { - if (aud_drct_get_playing ()) + if (aud_drct_get_playing()) { - EffectPlugin * ep = (EffectPlugin *) aud_plugin_get_header (plugin); - if (! ep) + EffectPlugin * ep = (EffectPlugin *)aud_plugin_get_header(plugin); + if (!ep) return; - effect_enable (plugin, ep, false); + effect_enable(plugin, ep, false); } } diff --git a/src/libaudcore/equalizer-preset.cc b/src/libaudcore/equalizer-preset.cc index 933148f..53e20e2 100644 --- a/src/libaudcore/equalizer-preset.cc +++ b/src/libaudcore/equalizer-preset.cc @@ -1,6 +1,6 @@ /* * equalizer_preset.c - * Copyright 2003-2013 Eugene Zagidullin, William Pitcock, John Lindgren, and + * Copyright 2003-2013 Eugene Zagidullin, Ariadne Conill, John Lindgren, and * Thomas Lange * * Redistribution and use in source and binary forms, with or without @@ -28,64 +28,73 @@ #include "runtime.h" #include "vfs.h" -EXPORT Index aud_eq_read_presets (const char * basename) +EXPORT Index aud_eq_read_presets(const char * basename) { Index list; - GKeyFile * rcfile = g_key_file_new (); - StringBuf filename = filename_build ({aud_get_path (AudPath::UserDir), basename}); + GKeyFile * rcfile = g_key_file_new(); + StringBuf filename = + filename_build({aud_get_path(AudPath::UserDir), basename}); - if (! g_key_file_load_from_file (rcfile, filename, G_KEY_FILE_NONE, nullptr)) + if (!g_key_file_load_from_file(rcfile, filename, G_KEY_FILE_NONE, nullptr)) { - StringBuf filename2 = filename_build ({aud_get_path (AudPath::DataDir), basename}); + StringBuf filename2 = + filename_build({aud_get_path(AudPath::DataDir), basename}); - if (! g_key_file_load_from_file (rcfile, filename2, G_KEY_FILE_NONE, nullptr)) + if (!g_key_file_load_from_file(rcfile, filename2, G_KEY_FILE_NONE, + nullptr)) { - g_key_file_free (rcfile); + g_key_file_free(rcfile); return list; } } - for (int p = 0;; p ++) + for (int p = 0;; p++) { - CharPtr name (g_key_file_get_string (rcfile, "Presets", str_printf ("Preset%d", p), nullptr)); - if (! name) + CharPtr name(g_key_file_get_string(rcfile, "Presets", + str_printf("Preset%d", p), nullptr)); + if (!name || !name[0]) break; - EqualizerPreset & preset = list.append (String (name)); - preset.preamp = g_key_file_get_double (rcfile, name, "Preamp", nullptr); + EqualizerPreset & preset = list.append(String(name)); + preset.preamp = g_key_file_get_double(rcfile, name, "Preamp", nullptr); for (int i = 0; i < AUD_EQ_NBANDS; i++) - preset.bands[i] = g_key_file_get_double (rcfile, name, str_printf ("Band%d", i), nullptr); + preset.bands[i] = g_key_file_get_double( + rcfile, name, str_printf("Band%d", i), nullptr); } - g_key_file_free (rcfile); + g_key_file_free(rcfile); return list; } -EXPORT bool aud_eq_write_presets (const Index & list, const char * basename) +EXPORT bool aud_eq_write_presets(const Index & list, + const char * basename) { - GKeyFile * rcfile = g_key_file_new (); + GKeyFile * rcfile = g_key_file_new(); - for (int p = 0; p < list.len (); p ++) + for (int p = 0; p < list.len(); p++) { const EqualizerPreset & preset = list[p]; - g_key_file_set_string (rcfile, "Presets", str_printf ("Preset%d", p), preset.name); - g_key_file_set_double (rcfile, preset.name, "Preamp", preset.preamp); + g_key_file_set_string(rcfile, "Presets", str_printf("Preset%d", p), + preset.name); + g_key_file_set_double(rcfile, preset.name, "Preamp", preset.preamp); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - g_key_file_set_double (rcfile, preset.name, str_printf ("Band%d", i), preset.bands[i]); + for (int i = 0; i < AUD_EQ_NBANDS; i++) + g_key_file_set_double(rcfile, preset.name, str_printf("Band%d", i), + preset.bands[i]); } size_t len; - CharPtr data (g_key_file_to_data (rcfile, & len, nullptr)); + CharPtr data(g_key_file_to_data(rcfile, &len, nullptr)); - StringBuf filename = filename_build ({aud_get_path (AudPath::UserDir), basename}); - bool success = g_file_set_contents (filename, data, len, nullptr); + StringBuf filename = + filename_build({aud_get_path(AudPath::UserDir), basename}); + bool success = g_file_set_contents(filename, data, len, nullptr); - g_key_file_free (rcfile); + g_key_file_free(rcfile); return success; } @@ -98,7 +107,7 @@ EXPORT bool aud_eq_write_presets (const Index & list, const cha * to represent 0 dB exactly (31 is +0.19 dB, 32 is -0.19 dB) but we * mimic WinAmp in letting 31 mean 0 dB as a special case. */ -static float decode_winamp_val (int val) +static float decode_winamp_val(int val) { if (val == 31) return 0.0f; @@ -106,15 +115,15 @@ static float decode_winamp_val (int val) return (31.5f - val) * (12.0f / 31.5f); } -static int encode_winamp_val (float val) +static int encode_winamp_val(float val) { if (val == 0.0f) return 31; - return lroundf (31.5f - val * (31.5f / 12.0f)); + return lroundf(31.5f - val * (31.5f / 12.0f)); } -EXPORT Index aud_import_winamp_presets (VFSFile & file) +EXPORT Index aud_import_winamp_presets(VFSFile & file) { char header[31]; char bands[11]; @@ -122,95 +131,103 @@ EXPORT Index aud_import_winamp_presets (VFSFile & file) Index list; - if (file.fread (header, 1, sizeof header) != sizeof header || - strncmp (header, "Winamp EQ library file v1.1", 27)) + if (file.fread(header, 1, sizeof header) != sizeof header || + strncmp(header, "Winamp EQ library file v1.1", 27)) return list; - while (file.fread (preset_name, 1, 180) == 180) + while (file.fread(preset_name, 1, 180) == 180 && preset_name[0]) { preset_name[180] = 0; /* protect against buffer overflow */ - if (file.fseek (77, VFS_SEEK_CUR)) /* unknown crap --asphyx */ + if (file.fseek(77, VFS_SEEK_CUR)) /* unknown crap --asphyx */ break; - if (file.fread (bands, 1, 11) != 11) + if (file.fread(bands, 1, 11) != 11) break; - EqualizerPreset & preset = list.append (String (preset_name)); - preset.preamp = decode_winamp_val (bands[10]); + EqualizerPreset & preset = list.append(String(preset_name)); + preset.preamp = decode_winamp_val(bands[10]); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - preset.bands[i] = decode_winamp_val (bands[i]); + for (int i = 0; i < AUD_EQ_NBANDS; i++) + preset.bands[i] = decode_winamp_val(bands[i]); } return list; } -EXPORT bool aud_export_winamp_preset (const EqualizerPreset & preset, VFSFile & file) +EXPORT bool aud_export_winamp_preset(const EqualizerPreset & preset, + VFSFile & file) { char name[257]; char bands[11]; - if (file.fwrite ("Winamp EQ library file v1.1\x1a!--", 1, 31) != 31) + if (file.fwrite("Winamp EQ library file v1.1\x1a!--", 1, 31) != 31) return false; - strncpy (name, preset.name, 257); + strncpy(name, preset.name, 257); - if (file.fwrite (name, 1, 257) != 257) + if (file.fwrite(name, 1, 257) != 257) return false; - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - bands[i] = encode_winamp_val (preset.bands[i]); + for (int i = 0; i < AUD_EQ_NBANDS; i++) + bands[i] = encode_winamp_val(preset.bands[i]); - bands[10] = encode_winamp_val (preset.preamp); + bands[10] = encode_winamp_val(preset.preamp); - if (file.fwrite (bands, 1, 11) != 11) + if (file.fwrite(bands, 1, 11) != 11) return false; return true; } -EXPORT bool aud_save_preset_file (const EqualizerPreset & preset, VFSFile & file) +EXPORT bool aud_save_preset_file(const EqualizerPreset & preset, VFSFile & file) { - GKeyFile * rcfile = g_key_file_new (); + GKeyFile * rcfile = g_key_file_new(); - g_key_file_set_double (rcfile, "Equalizer preset", "Preamp", preset.preamp); + g_key_file_set_double(rcfile, "Equalizer preset", "Preamp", preset.preamp); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - g_key_file_set_double (rcfile, "Equalizer preset", - str_printf ("Band%d", i), preset.bands[i]); + for (int i = 0; i < AUD_EQ_NBANDS; i++) + g_key_file_set_double(rcfile, "Equalizer preset", + str_printf("Band%d", i), preset.bands[i]); size_t len; - CharPtr data (g_key_file_to_data (rcfile, & len, nullptr)); + CharPtr data(g_key_file_to_data(rcfile, &len, nullptr)); - bool success = (file.fwrite (data, 1, len) == (int64_t) len); + bool success = (file.fwrite(data, 1, len) == (int64_t)len); - g_key_file_free (rcfile); + g_key_file_free(rcfile); return success; } -EXPORT bool aud_load_preset_file (EqualizerPreset & preset, VFSFile & file) +EXPORT bool aud_load_preset_file(EqualizerPreset & preset, VFSFile & file) { - GKeyFile * rcfile = g_key_file_new (); + /* get the preset name from the file name */ + StringBuf name = uri_get_display_base(file.filename()); + if (!name || !name[0]) + return false; + + GKeyFile * rcfile = g_key_file_new(); - Index data = file.read_all (); + Index data = file.read_all(); - if (! data.len () || ! g_key_file_load_from_data (rcfile, data.begin (), - data.len (), G_KEY_FILE_NONE, nullptr)) + if (!data.len() || + !g_key_file_load_from_data(rcfile, data.begin(), data.len(), + G_KEY_FILE_NONE, nullptr)) { - g_key_file_free (rcfile); + g_key_file_free(rcfile); return false; } - preset.name = String (""); - preset.preamp = g_key_file_get_double (rcfile, "Equalizer preset", "Preamp", nullptr); + preset.name = String(name); + preset.preamp = + g_key_file_get_double(rcfile, "Equalizer preset", "Preamp", nullptr); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - preset.bands[i] = g_key_file_get_double (rcfile, "Equalizer preset", - str_printf ("Band%d", i), nullptr); + for (int i = 0; i < AUD_EQ_NBANDS; i++) + preset.bands[i] = g_key_file_get_double( + rcfile, "Equalizer preset", str_printf("Band%d", i), nullptr); - g_key_file_free (rcfile); + g_key_file_free(rcfile); return true; } diff --git a/src/libaudcore/equalizer.cc b/src/libaudcore/equalizer.cc index d19c031..7cc6aa8 100644 --- a/src/libaudcore/equalizer.cc +++ b/src/libaudcore/equalizer.cc @@ -28,13 +28,13 @@ #include #include -#include #include #include "audio.h" #include "audstrings.h" #include "hook.h" #include "runtime.h" +#include "threads.h" /* Q value for band-pass filters 1.2247 = (3/2)^(1/2) * Gives 4 dB suppression at Fc*2 and Fc/2 */ @@ -44,33 +44,35 @@ /* These are not the historical WinAmp frequencies, because the IIR filters used * here are designed for each frequency to be twice the previous. Using WinAmp * frequencies leads to too much gain in some bands and too little in others. */ -static const float CF[AUD_EQ_NBANDS] = {31.25f, 62.5f, 125, 250, 500, 1000, - 2000, 4000, 8000, 16000}; +static const float CF[AUD_EQ_NBANDS] = {31.25f, 62.5f, 125, 250, 500, + 1000, 2000, 4000, 8000, 16000}; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static bool active; static int channels, rate; static float a[AUD_EQ_NBANDS][2]; /* A weights */ static float b[AUD_EQ_NBANDS][2]; /* B weights */ -static float wqv[AUD_MAX_CHANNELS][AUD_EQ_NBANDS][2]; /* Circular buffer for W data */ -static float gv[AUD_MAX_CHANNELS][AUD_EQ_NBANDS]; /* Gain factor for each channel and band */ -static int K; /* Number of used EQ bands */ +static float wqv[AUD_MAX_CHANNELS][AUD_EQ_NBANDS] + [2]; /* Circular buffer for W data */ +static float gv[AUD_MAX_CHANNELS] + [AUD_EQ_NBANDS]; /* Gain factor for each channel and band */ +static int K; /* Number of used EQ bands */ /* 2nd order band-pass filter design */ -static void bp2 (float *a, float *b, float fc) +static void bp2(float * a, float * b, float fc) { float th = 2 * (float)M_PI * fc; - float C = (1 - tanf (th * Q / 2)) / (1 + tanf (th * Q / 2)); + float C = (1 - tanf(th * Q / 2)) / (1 + tanf(th * Q / 2)); - a[0] = (1 + C) * cosf (th); + a[0] = (1 + C) * cosf(th); a[1] = -C; b[0] = (1 - C) / 2; b[1] = -1.005f; } -void eq_set_format (int new_channels, int new_rate) +void eq_set_format(int new_channels, int new_rate) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); channels = new_channels; rate = new_rate; @@ -79,60 +81,52 @@ void eq_set_format (int new_channels, int new_rate) * than rate/2Q to avoid singularities in the tangent used in bp2() */ K = AUD_EQ_NBANDS; - while (K > 0 && CF[K - 1] > (float) rate / (2.005f * Q)) - K --; + while (K > 0 && CF[K - 1] > (float)rate / (2.005f * Q)) + K--; /* Generate filter taps */ - for (int k = 0; k < K; k ++) - bp2 (a[k], b[k], CF[k] / (float) rate); + for (int k = 0; k < K; k++) + bp2(a[k], b[k], CF[k] / (float)rate); /* Reset state */ - memset (wqv[0][0], 0, sizeof wqv); - - pthread_mutex_unlock (& mutex); + memset(wqv[0][0], 0, sizeof wqv); } -static void eq_set_bands_real (double preamp, double *values) +static void eq_set_bands_real(aud::mutex::holder &, double preamp, + double * values) { float adj[AUD_EQ_NBANDS]; - for (int i = 0; i < AUD_EQ_NBANDS; i ++) + for (int i = 0; i < AUD_EQ_NBANDS; i++) adj[i] = preamp + values[i]; - for (int c = 0; c < AUD_MAX_CHANNELS; c ++) + for (int c = 0; c < AUD_MAX_CHANNELS; c++) { - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - gv[c][i] = powf (10, adj[i] / 20) - 1; + for (int i = 0; i < AUD_EQ_NBANDS; i++) + gv[c][i] = powf(10, adj[i] / 20) - 1; } } -void eq_filter (float *data, int samples) +void eq_filter(float * data, int samples) { - int channel; - - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! active) - { - pthread_mutex_unlock (& mutex); + if (!active) return; - } - for (channel = 0; channel < channels; channel ++) + for (int channel = 0; channel < channels; channel++) { - float *g = gv[channel]; /* Gain factor */ - float *end = data + samples; - float *f; + float * g = gv[channel]; /* Gain factor */ + float * end = data + samples; - for (f = data + channel; f < end; f += channels) + for (float * f = data + channel; f < end; f += channels) { - int k; /* Frequency band index */ float yt = *f; /* Current input sample */ - for (k = 0; k < K; k ++) + for (int k = 0; k < K; k++) { /* Pointer to circular buffer wq */ - float *wq = wqv[channel][k]; + float * wq = wqv[channel][k]; /* Calculate output from AR part of current filter */ float w = yt * b[k][0] + wq[0] * a[k][0] + wq[1] * a[k][1]; @@ -148,90 +142,86 @@ void eq_filter (float *data, int samples) *f = yt; } } - - pthread_mutex_unlock (& mutex); } -static void eq_update (void *data, void *user) +static void eq_update(void *, void *) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - active = aud_get_bool (nullptr, "equalizer_active"); + active = aud_get_bool("equalizer_active"); double values[AUD_EQ_NBANDS]; - aud_eq_get_bands (values); - eq_set_bands_real (aud_get_double (nullptr, "equalizer_preamp"), values); - - pthread_mutex_unlock (& mutex); + aud_eq_get_bands(values); + eq_set_bands_real(mh, aud_get_double("equalizer_preamp"), values); } -void eq_init () +void eq_init() { - eq_update (nullptr, nullptr); - hook_associate ("set equalizer_active", eq_update, nullptr); - hook_associate ("set equalizer_preamp", eq_update, nullptr); - hook_associate ("set equalizer_bands", eq_update, nullptr); + eq_update(nullptr, nullptr); + hook_associate("set equalizer_active", eq_update, nullptr); + hook_associate("set equalizer_preamp", eq_update, nullptr); + hook_associate("set equalizer_bands", eq_update, nullptr); } -void eq_cleanup () +void eq_cleanup() { - hook_dissociate ("set equalizer_active", eq_update); - hook_dissociate ("set equalizer_preamp", eq_update); - hook_dissociate ("set equalizer_bands", eq_update); + hook_dissociate("set equalizer_active", eq_update); + hook_dissociate("set equalizer_preamp", eq_update); + hook_dissociate("set equalizer_bands", eq_update); } -EXPORT void aud_eq_set_bands (const double values[AUD_EQ_NBANDS]) +EXPORT void aud_eq_set_bands(const double values[AUD_EQ_NBANDS]) { - StringBuf string = double_array_to_str (values, AUD_EQ_NBANDS); - aud_set_str (nullptr, "equalizer_bands", string); + StringBuf string = double_array_to_str(values, AUD_EQ_NBANDS); + aud_set_str("equalizer_bands", string); } -EXPORT void aud_eq_get_bands (double values[AUD_EQ_NBANDS]) +EXPORT void aud_eq_get_bands(double values[AUD_EQ_NBANDS]) { - memset (values, 0, sizeof (double) * AUD_EQ_NBANDS); - String string = aud_get_str (nullptr, "equalizer_bands"); - str_to_double_array (string, values, AUD_EQ_NBANDS); + memset(values, 0, sizeof(double) * AUD_EQ_NBANDS); + String string = aud_get_str("equalizer_bands"); + str_to_double_array(string, values, AUD_EQ_NBANDS); } -EXPORT void aud_eq_set_band (int band, double value) +EXPORT void aud_eq_set_band(int band, double value) { - assert (band >= 0 && band < AUD_EQ_NBANDS); + assert(band >= 0 && band < AUD_EQ_NBANDS); double values[AUD_EQ_NBANDS]; - aud_eq_get_bands (values); + aud_eq_get_bands(values); values[band] = value; - aud_eq_set_bands (values); + aud_eq_set_bands(values); } -EXPORT double aud_eq_get_band (int band) +EXPORT double aud_eq_get_band(int band) { - assert (band >= 0 && band < AUD_EQ_NBANDS); + assert(band >= 0 && band < AUD_EQ_NBANDS); double values[AUD_EQ_NBANDS]; - aud_eq_get_bands (values); + aud_eq_get_bands(values); return values[band]; } -EXPORT void aud_eq_apply_preset (const EqualizerPreset & preset) +EXPORT void aud_eq_apply_preset(const EqualizerPreset & preset) { double bands[AUD_EQ_NBANDS]; /* convert float to double :( */ - for (int i = 0; i < AUD_EQ_NBANDS; i ++) + for (int i = 0; i < AUD_EQ_NBANDS; i++) bands[i] = preset.bands[i]; - aud_eq_set_bands (bands); - aud_set_double (nullptr, "equalizer_preamp", preset.preamp); + aud_eq_set_bands(bands); + aud_set_double("equalizer_preamp", preset.preamp); } -EXPORT void aud_eq_update_preset (EqualizerPreset & preset) +EXPORT void aud_eq_update_preset(EqualizerPreset & preset) { double bands[AUD_EQ_NBANDS]; - aud_eq_get_bands (bands); + aud_eq_get_bands(bands); /* convert double to float :( */ - for (int i = 0; i < AUD_EQ_NBANDS; i ++) + for (int i = 0; i < AUD_EQ_NBANDS; i++) preset.bands[i] = bands[i]; - preset.preamp = aud_get_double (nullptr, "equalizer_preamp"); + preset.preamp = aud_get_double("equalizer_preamp"); } diff --git a/src/libaudcore/equalizer.h b/src/libaudcore/equalizer.h index bfa8ab1..cf9441c 100644 --- a/src/libaudcore/equalizer.h +++ b/src/libaudcore/equalizer.h @@ -28,27 +28,29 @@ class VFSFile; #define AUD_EQ_NBANDS 10 #define AUD_EQ_MAX_GAIN 12 -struct EqualizerPreset { +struct EqualizerPreset +{ String name; float preamp; float bands[AUD_EQ_NBANDS]; }; -void aud_eq_set_bands (const double values[AUD_EQ_NBANDS]); -void aud_eq_get_bands (double values[AUD_EQ_NBANDS]); -void aud_eq_set_band (int band, double value); -double aud_eq_get_band (int band); +void aud_eq_set_bands(const double values[AUD_EQ_NBANDS]); +void aud_eq_get_bands(double values[AUD_EQ_NBANDS]); +void aud_eq_set_band(int band, double value); +double aud_eq_get_band(int band); -void aud_eq_apply_preset (const EqualizerPreset & preset); -void aud_eq_update_preset (EqualizerPreset & preset); +void aud_eq_apply_preset(const EqualizerPreset & preset); +void aud_eq_update_preset(EqualizerPreset & preset); -Index aud_eq_read_presets (const char * basename); -bool aud_eq_write_presets (const Index & list, const char * basename); +Index aud_eq_read_presets(const char * basename); +bool aud_eq_write_presets(const Index & list, + const char * basename); -bool aud_load_preset_file (EqualizerPreset & preset, VFSFile & file); -bool aud_save_preset_file (const EqualizerPreset & preset, VFSFile & file); +bool aud_load_preset_file(EqualizerPreset & preset, VFSFile & file); +bool aud_save_preset_file(const EqualizerPreset & preset, VFSFile & file); -Index aud_import_winamp_presets (VFSFile & file); -bool aud_export_winamp_preset (const EqualizerPreset & preset, VFSFile & file); +Index aud_import_winamp_presets(VFSFile & file); +bool aud_export_winamp_preset(const EqualizerPreset & preset, VFSFile & file); #endif /* LIBAUDCORE_EQUALIZER_H */ diff --git a/src/libaudcore/eventqueue.cc b/src/libaudcore/eventqueue.cc index c65a439..d084dc1 100644 --- a/src/libaudcore/eventqueue.cc +++ b/src/libaudcore/eventqueue.cc @@ -19,92 +19,86 @@ #include "hook.h" -#include #include #include "internal.h" #include "list.h" #include "mainloop.h" #include "objects.h" +#include "threads.h" struct Event : public ListNode { String name; void * data; - void (* destroy) (void *); + void (*destroy)(void *); - Event (const char * name, void * data, EventDestroyFunc destroy) : - name (name), - data (data), - destroy (destroy) {} + Event(const char * name, void * data, EventDestroyFunc destroy) + : name(name), data(data), destroy(destroy) + { + } - ~Event () + ~Event() { if (destroy) - destroy (data); + destroy(data); } }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static List events; static QueuedFunc queued_events; -static void events_execute (void *) +static void events_execute(void *) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); Event * event; - while ((event = events.head ())) + while ((event = events.head())) { - events.remove (event); + events.remove(event); - pthread_mutex_unlock (& mutex); + mh.unlock(); - hook_call (event->name, event->data); + hook_call(event->name, event->data); delete event; - pthread_mutex_lock (& mutex); + mh.lock(); } - - pthread_mutex_unlock (& mutex); } -EXPORT void event_queue (const char * name, void * data, EventDestroyFunc destroy) +EXPORT void event_queue(const char * name, void * data, + EventDestroyFunc destroy) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! events.head ()) - queued_events.queue (events_execute, nullptr); + if (!events.head()) + queued_events.queue(events_execute, nullptr); - events.append (new Event (name, data, destroy)); - - pthread_mutex_unlock (& mutex); + events.append(new Event(name, data, destroy)); } -EXPORT void event_queue_cancel (const char * name, void * data) +EXPORT void event_queue_cancel(const char * name, void * data) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - Event * event = events.head (); + Event * event = events.head(); while (event) { - Event * next = events.next (event); + Event * next = events.next(event); - if (! strcmp (event->name, name) && (! data || event->data == data)) + if (!strcmp(event->name, name) && (!data || event->data == data)) { - events.remove (event); + events.remove(event); delete event; } event = next; } - - pthread_mutex_unlock (& mutex); } -void event_queue_cancel_all () +void event_queue_cancel_all() { - pthread_mutex_lock (& mutex); - events.clear (); - pthread_mutex_unlock (& mutex); + auto mh = mutex.take(); + events.clear(); } diff --git a/src/libaudcore/export.h b/src/libaudcore/export.h index f91ed7c..f34332b 100644 --- a/src/libaudcore/export.h +++ b/src/libaudcore/export.h @@ -21,13 +21,13 @@ #define LIBAUDCORE_EXPORT_H #ifdef _WIN32 - #ifdef LIBAUDCORE_BUILD - #define LIBAUDCORE_PUBLIC __declspec(dllexport) - #else - #define LIBAUDCORE_PUBLIC __declspec(dllimport) - #endif +#ifdef LIBAUDCORE_BUILD +#define LIBAUDCORE_PUBLIC __declspec(dllexport) #else - #define LIBAUDCORE_PUBLIC __attribute__ ((visibility ("default"))) +#define LIBAUDCORE_PUBLIC __declspec(dllimport) +#endif +#else +#define LIBAUDCORE_PUBLIC __attribute__((visibility("default"))) #endif #endif // LIBAUDCORE_EXPORT_H diff --git a/src/libaudcore/fft.cc b/src/libaudcore/fft.cc index c22d769..0587e7b 100644 --- a/src/libaudcore/fft.cc +++ b/src/libaudcore/fft.cc @@ -24,23 +24,23 @@ #define TWO_PI 6.2831853f -#define N 512 /* size of the DFT */ -#define LOGN 9 /* log N (base 2) */ +#define N 512 /* size of the DFT */ +#define LOGN 9 /* log N (base 2) */ typedef std::complex Complex; -static float hamming[N]; /* hamming window, scaled to sum to 1 */ -static int reversed[N]; /* bit-reversal table */ -static Complex roots[N / 2]; /* N-th roots of unity */ -static char generated = 0; /* set if tables have been generated */ +static float hamming[N]; /* hamming window, scaled to sum to 1 */ +static int reversed[N]; /* bit-reversal table */ +static Complex roots[N / 2]; /* N-th roots of unity */ +static char generated = 0; /* set if tables have been generated */ /* Reverse the order of the lowest LOGN bits in an integer. */ -static int bit_reverse (int x) +static int bit_reverse(int x) { int y = 0; - for (int n = LOGN; n --; ) + for (int n = LOGN; n--;) { y = (y << 1) | (x & 1); x >>= 1; @@ -51,17 +51,17 @@ static int bit_reverse (int x) /* Generate lookup tables. */ -static void generate_tables () +static void generate_tables() { if (generated) return; - for (int n = 0; n < N; n ++) - hamming[n] = 1 - 0.85f * cosf (n * (TWO_PI / N)); - for (int n = 0; n < N; n ++) - reversed[n] = bit_reverse (n); - for (int n = 0; n < N / 2; n ++) - roots[n] = exp (Complex (0, n * (TWO_PI / N))); + for (int n = 0; n < N; n++) + hamming[n] = 1 - 0.85f * cosf(n * (TWO_PI / N)); + for (int n = 0; n < N; n++) + reversed[n] = bit_reverse(n); + for (int n = 0; n < N / 2; n++) + roots[n] = exp(Complex(0, n * (TWO_PI / N))); generated = 1; } @@ -69,12 +69,13 @@ static void generate_tables () /* Perform the DFT using the Cooley-Tukey algorithm. At each step s, where * s=1..log N (base 2), there are N/(2^s) groups of intertwined butterfly * operations. Each group contains (2^s)/2 butterflies, and each butterfly has - * a span of (2^s)/2. The twiddle factors are nth roots of unity where n = 2^s. */ + * a span of (2^s)/2. The twiddle factors are nth roots of unity where n = 2^s. + */ -static void do_fft (Complex a[N]) +static void do_fft(Complex a[N]) { - int half = 1; /* (2^s)/2 */ - int inv = N / 2; /* N/(2^s) */ + int half = 1; /* (2^s)/2 */ + int inv = N / 2; /* N/(2^s) */ /* loop through steps */ while (inv) @@ -83,7 +84,7 @@ static void do_fft (Complex a[N]) for (int g = 0; g < N; g += half << 1) { /* loop through butterflies */ - for (int b = 0, r = 0; b < half; b ++, r += inv) + for (int b = 0, r = 0; b < half; b++, r += inv) { Complex even = a[g + b]; Complex odd = roots[r] * a[g + half + b]; @@ -100,23 +101,23 @@ static void do_fft (Complex a[N]) /* Input is N=512 PCM samples. * Output is intensity of frequencies from 1 to N/2=256. */ -void calc_freq (const float data[N], float freq[N / 2]) +void calc_freq(const float data[N], float freq[N / 2]) { - generate_tables (); + generate_tables(); /* input is filtered by a Hamming window */ /* input values are in bit-reversed order */ Complex a[N]; - for (int n = 0; n < N; n ++) + for (int n = 0; n < N; n++) a[reversed[n]] = data[n] * hamming[n]; - do_fft (a); + do_fft(a); /* output values are divided by N */ /* frequencies from 1 to N/2-1 are doubled */ - for (int n = 0; n < N / 2 - 1; n ++) - freq[n] = 2 * abs (a[1 + n]) / N; + for (int n = 0; n < N / 2 - 1; n++) + freq[n] = 2 * abs(a[1 + n]) / N; /* frequency N/2 is not doubled */ - freq[N / 2 - 1] = abs (a[N / 2]) / N; + freq[N / 2 - 1] = abs(a[N / 2]) / N; } diff --git a/src/libaudcore/history.cc b/src/libaudcore/history.cc index b8cfdbd..0f3c2b4 100644 --- a/src/libaudcore/history.cc +++ b/src/libaudcore/history.cc @@ -24,35 +24,35 @@ #define MAX_ENTRIES 30 -EXPORT String aud_history_get (int entry) +EXPORT String aud_history_get(int entry) { - StringBuf name = str_printf ("entry%d", entry); - String path = aud_get_str ("history", name); - return (path[0] ? path : String ()); + StringBuf name = str_printf("entry%d", entry); + String path = aud_get_str("history", name); + return (path[0] ? path : String()); } -EXPORT void aud_history_add (const char * path) +EXPORT void aud_history_add(const char * path) { - String add = String (path); + String add = String(path); - for (int i = 0; i < MAX_ENTRIES; i ++) + for (int i = 0; i < MAX_ENTRIES; i++) { - StringBuf name = str_printf ("entry%d", i); - String old = aud_get_str ("history", name); - aud_set_str ("history", name, add); + StringBuf name = str_printf("entry%d", i); + String old = aud_get_str("history", name); + aud_set_str("history", name, add); - if (! strcmp (old, path)) + if (!strcmp(old, path)) break; add = old; } } -EXPORT void aud_history_clear () +EXPORT void aud_history_clear() { - for (int i = 0; i < MAX_ENTRIES; i ++) + for (int i = 0; i < MAX_ENTRIES; i++) { - StringBuf name = str_printf ("entry%d", i); - aud_set_str ("history", name, ""); + StringBuf name = str_printf("entry%d", i); + aud_set_str("history", name, ""); } } diff --git a/src/libaudcore/hook.cc b/src/libaudcore/hook.cc index e9dd695..0364ced 100644 --- a/src/libaudcore/hook.cc +++ b/src/libaudcore/hook.cc @@ -19,15 +19,15 @@ #include "hook.h" -#include - #include "index.h" #include "internal.h" #include "multihash.h" #include "objects.h" #include "runtime.h" +#include "threads.h" -struct HookItem { +struct HookItem +{ HookFunction func; void * user; }; @@ -37,105 +37,95 @@ struct HookList Index items; int use_count; - void compact () + void compact() { - auto is_empty = [] (const HookItem & item) - { return ! item.func; }; + auto is_empty = [](const HookItem & item) { return !item.func; }; - items.remove_if (is_empty); + items.remove_if(is_empty); } }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static SimpleHash hooks; -EXPORT void hook_associate (const char * name, HookFunction func, void * user) +EXPORT void hook_associate(const char * name, HookFunction func, void * user) { - pthread_mutex_lock (& mutex); - - String key (name); - HookList * list = hooks.lookup (key); - if (! list) - list = hooks.add (key, HookList ()); + auto mh = mutex.take(); - list->items.append (func, user); + String key(name); + HookList * list = hooks.lookup(key); + if (!list) + list = hooks.add(key, HookList()); - pthread_mutex_unlock (& mutex); + list->items.append(func, user); } -EXPORT void hook_dissociate (const char * name, HookFunction func, void * user) +EXPORT void hook_dissociate(const char * name, HookFunction func, void * user) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - String key (name); - HookList * list = hooks.lookup (key); - if (! list) - goto DONE; + String key(name); + HookList * list = hooks.lookup(key); + if (!list) + return; for (HookItem & item : list->items) { - if (item.func == func && (! user || item.user == user)) + if (item.func == func && (!user || item.user == user)) item.func = nullptr; } - if (! list->use_count) + if (!list->use_count) { - list->compact (); - if (! list->items.len ()) - hooks.remove (key); + list->compact(); + if (!list->items.len()) + hooks.remove(key); } - -DONE: - pthread_mutex_unlock (& mutex); } -EXPORT void hook_call (const char * name, void * data) +EXPORT void hook_call(const char * name, void * data) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - String key (name); - HookList * list = hooks.lookup (key); - if (! list) - goto DONE; + String key(name); + HookList * list = hooks.lookup(key); + if (!list) + return; - list->use_count ++; + list->use_count++; /* note: the list may grow (but not shrink) during the hook call */ - for (int i = 0; i < list->items.len (); i ++) + for (int i = 0; i < list->items.len(); i++) { /* copy locally to prevent race condition */ HookItem item = list->items[i]; if (item.func) { - pthread_mutex_unlock (& mutex); - item.func (data, item.user); - pthread_mutex_lock (& mutex); + mh.unlock(); + item.func(data, item.user); + mh.lock(); } } - list->use_count --; + list->use_count--; - if (! list->use_count) + if (!list->use_count) { - list->compact (); - if (! list->items.len ()) - hooks.remove (key); + list->compact(); + if (!list->items.len()) + hooks.remove(key); } - -DONE: - pthread_mutex_unlock (& mutex); } -void hook_cleanup () +void hook_cleanup() { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - hooks.iterate ([] (const String & name, HookList & list) { - AUDWARN ("Hook not disconnected: %s (%d)\n", (const char *) name, list.items.len ()); + hooks.iterate([](const String & name, HookList & list) { + AUDWARN("Hook not disconnected: %s (%d)\n", (const char *)name, + list.items.len()); }); - hooks.clear (); - - pthread_mutex_unlock (& mutex); + hooks.clear(); } diff --git a/src/libaudcore/hook.h b/src/libaudcore/hook.h index 5772844..176076d 100644 --- a/src/libaudcore/hook.h +++ b/src/libaudcore/hook.h @@ -28,20 +28,25 @@ // reducing CPU wakeups. // ======================================================================== -enum class TimerRate { - Hz1, Hz4, Hz10, Hz30, count +enum class TimerRate +{ + Hz1, + Hz4, + Hz10, + Hz30, + count }; -typedef void (* TimerFunc) (void * data); +typedef void (*TimerFunc)(void * data); /* Adds to the list of functions to be called at the given , * unless it has already been added with the same . */ -void timer_add (TimerRate rate, TimerFunc func, void * data = nullptr); +void timer_add(TimerRate rate, TimerFunc func, void * data = nullptr); /* Removes all instances matching and from the list of functions * to be called at the given . If is nullptr, all instances * matching are removed. */ -void timer_remove (TimerRate rate, TimerFunc func, void * data = nullptr); +void timer_remove(TimerRate rate, TimerFunc func, void * data = nullptr); /* Convenience wrapper for C++ classes. Allows non-static member functions to * be used as timer callbacks. The Timer should be made a member of the class @@ -51,31 +56,28 @@ template class Timer { public: - Timer (TimerRate rate, T * target, void (T::* func) ()) : - rate (rate), - target (target), - func (func) {} + Timer(TimerRate rate, T * target, void (T::*func)()) + : rate(rate), target(target), func(func) + { + } - void start () const - { timer_add (rate, run, (void *) this); } - void stop () const - { timer_remove (rate, run, (void *) this); } + void start() const { timer_add(rate, run, (void *)this); } + void stop() const { timer_remove(rate, run, (void *)this); } - ~Timer () - { stop (); } + ~Timer() { stop(); } - Timer (const Timer &) = delete; - void operator= (const Timer &) = delete; + Timer(const Timer &) = delete; + void operator=(const Timer &) = delete; private: const TimerRate rate; T * const target; - void (T::* const func) (); + void (T::*const func)(); - static void run (void * timer_) + static void run(void * timer_) { - auto timer = (const Timer *) timer_; - (timer->target->* timer->func) (); + auto timer = (const Timer *)timer_; + (timer->target->*timer->func)(); } }; @@ -83,30 +85,32 @@ private: // named event, or "hook", is called. // ========================================================================= -typedef void (* HookFunction) (void * data, void * user); +typedef void (*HookFunction)(void * data, void * user); /* Adds to the list of functions to be called when the hook is * triggered. */ -void hook_associate (const char * name, HookFunction func, void * user); +void hook_associate(const char * name, HookFunction func, void * user); /* Removes all instances matching and from the list of functions * to be called when the hook is triggered. If is nullptr, all * instances matching are removed. */ -void hook_dissociate (const char * name, HookFunction func, void * user = nullptr); +void hook_dissociate(const char * name, HookFunction func, + void * user = nullptr); /* Triggers the hook . */ -void hook_call (const char * name, void * data); +void hook_call(const char * name, void * data); -typedef void (* EventDestroyFunc) (void * data); +typedef void (*EventDestroyFunc)(void * data); /* Schedules a call of the hook from the program's main loop. * If is not nullptr, it will be called on after the * hook is called. */ -void event_queue (const char * name, void * data, EventDestroyFunc destroy = nullptr); +void event_queue(const char * name, void * data, + EventDestroyFunc destroy = nullptr); /* Cancels pending hook calls matching and . If is nullptr, * all hook calls matching are canceled. */ -void event_queue_cancel (const char * name, void * data = nullptr); +void event_queue_cancel(const char * name, void * data = nullptr); /* Convenience wrapper for C++ classes. Allows non-static member functions to * be used as hook callbacks. The HookReceiver should be made a member of the @@ -116,29 +120,26 @@ template class HookReceiver { public: - HookReceiver (const char * hook, T * target, void (T::* func) (D)) : - hook (hook), - target (target), - func (func) + HookReceiver(const char * hook, T * target, void (T::*func)(D)) + : hook(hook), target(target), func(func) { - hook_associate (hook, run, this); + hook_associate(hook, run, this); } - ~HookReceiver () - { hook_dissociate (hook, run, this); } + ~HookReceiver() { hook_dissociate(hook, run, this); } - HookReceiver (const HookReceiver &) = delete; - void operator= (const HookReceiver &) = delete; + HookReceiver(const HookReceiver &) = delete; + void operator=(const HookReceiver &) = delete; private: const char * const hook; T * const target; - void (T::* const func) (D); + void (T::*const func)(D); - static void run (void * d, void * recv_) + static void run(void * d, void * recv_) { - auto recv = (const HookReceiver *) recv_; - (recv->target->* recv->func) (aud::from_ptr (d)); + auto recv = (const HookReceiver *)recv_; + (recv->target->*recv->func)(aud::from_ptr(d)); } }; @@ -147,29 +148,26 @@ template class HookReceiver { public: - HookReceiver (const char * hook, T * target, void (T::* func) ()) : - hook (hook), - target (target), - func (func) + HookReceiver(const char * hook, T * target, void (T::*func)()) + : hook(hook), target(target), func(func) { - hook_associate (hook, run, this); + hook_associate(hook, run, this); } - ~HookReceiver () - { hook_dissociate (hook, run, this); } + ~HookReceiver() { hook_dissociate(hook, run, this); } - HookReceiver (const HookReceiver &) = delete; - void operator= (const HookReceiver &) = delete; + HookReceiver(const HookReceiver &) = delete; + void operator=(const HookReceiver &) = delete; private: const char * const hook; T * const target; - void (T::* const func) (); + void (T::*const func)(); - static void run (void *, void * recv_) + static void run(void *, void * recv_) { - auto recv = (const HookReceiver *) recv_; - (recv->target->* recv->func) (); + auto recv = (const HookReceiver *)recv_; + (recv->target->*recv->func)(); } }; diff --git a/src/libaudcore/i18n.h b/src/libaudcore/i18n.h index 5b5205c..bbb48d7 100644 --- a/src/libaudcore/i18n.h +++ b/src/libaudcore/i18n.h @@ -1,6 +1,6 @@ /* * i18n.h - * Copyright 2007 William Pitcock + * Copyright 2007 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,13 +20,26 @@ #ifndef AUDACIOUS_I18N_H #define AUDACIOUS_I18N_H +#ifdef HAVE_GETTEXT + #include -#define _(String) dgettext (PACKAGE, String) +#define _(String) dgettext(PACKAGE, String) + #ifdef gettext_noop -#define N_(String) gettext_noop (String) +#define N_(String) gettext_noop(String) +#else +#define N_(String) (String) +#endif + #else + +#define _(String) (String) #define N_(String) (String) +#define dgettext(package, str) (str) +#define dngettext(package, str1, str2, count) (count > 1 ? str2 : str1) +#define ngettext(str1, str2, count) (count > 1 ? str2 : str1) + #endif #endif /* AUDACIOUS_I18N_H */ diff --git a/src/libaudcore/index.cc b/src/libaudcore/index.cc index 84ca64d..d33a0e0 100644 --- a/src/libaudcore/index.cc +++ b/src/libaudcore/index.cc @@ -24,52 +24,52 @@ #include #include -#include /* for g_qsort_with_data */ +#include /* for g_qsort_with_data */ -static void do_fill (void * data, int len, aud::FillFunc fill_func) +static void do_fill(void * data, int len, aud::FillFunc fill_func) { if (fill_func) - fill_func (data, len); + fill_func(data, len); else - memset (data, 0, len); + memset(data, 0, len); } -static void do_erase (void * data, int len, aud::EraseFunc erase_func) +static void do_erase(void * data, int len, aud::EraseFunc erase_func) { if (erase_func) - erase_func (data, len); + erase_func(data, len); } -EXPORT void IndexBase::clear (aud::EraseFunc erase_func) +EXPORT void IndexBase::clear(aud::EraseFunc erase_func) { - if (! m_data) + if (!m_data) return; - __sync_sub_and_fetch (& misc_bytes_allocated, m_size); + __sync_sub_and_fetch(&misc_bytes_allocated, m_size); - do_erase (m_data, m_len, erase_func); - free (m_data); + do_erase(m_data, m_len, erase_func); + free(m_data); m_data = nullptr; m_len = 0; m_size = 0; } -EXPORT void * IndexBase::insert (int pos, int len) +EXPORT void * IndexBase::insert(int pos, int len) { - assert (pos <= m_len); - assert (len >= 0); + assert(pos <= m_len); + assert(len >= 0); - if (! len) + if (!len) goto out; if (pos < 0) - pos = m_len; /* insert at end */ + pos = m_len; /* insert at end */ if (m_size < m_len + len) { /* never allocate less than 16 bytes */ - int new_size = aud::max (m_size, 16); + int new_size = aud::max(m_size, 16); /* next try 4/3 current size, biased toward multiples of 4 */ if (new_size < m_len + len) @@ -79,153 +79,160 @@ EXPORT void * IndexBase::insert (int pos, int len) if (new_size < m_len + len) new_size = m_len + len; - void * new_data = realloc (m_data, new_size); - if (! new_data) - throw std::bad_alloc (); /* nothing changed yet */ + void * new_data = realloc(m_data, new_size); + if (!new_data) + throw std::bad_alloc(); /* nothing changed yet */ - __sync_add_and_fetch (& misc_bytes_allocated, new_size - m_size); + __sync_add_and_fetch(&misc_bytes_allocated, new_size - m_size); m_data = new_data; m_size = new_size; } - memmove ((char *) m_data + pos + len, (char *) m_data + pos, m_len - pos); + memmove((char *)m_data + pos + len, (char *)m_data + pos, m_len - pos); m_len += len; out: - return (char *) m_data + pos; + return (char *)m_data + pos; } -EXPORT void IndexBase::insert (int pos, int len, aud::FillFunc fill_func) +EXPORT void IndexBase::insert(int pos, int len, aud::FillFunc fill_func) { - void * to = insert (pos, len); + void * to = insert(pos, len); - if (! len) + if (!len) return; if (fill_func) - fill_func (to, len); + fill_func(to, len); else - memset (to, 0, len); + memset(to, 0, len); } -EXPORT void IndexBase::insert (const void * from, int pos, int len, aud::CopyFunc copy_func) +EXPORT void IndexBase::insert(const void * from, int pos, int len, + aud::CopyFunc copy_func) { - void * to = insert (pos, len); + void * to = insert(pos, len); - if (! len) + if (!len) return; if (copy_func) - copy_func (from, to, len); + copy_func(from, to, len); else - memcpy (to, from, len); + memcpy(to, from, len); } -EXPORT void IndexBase::remove (int pos, int len, aud::EraseFunc erase_func) +EXPORT void IndexBase::remove(int pos, int len, aud::EraseFunc erase_func) { - assert (pos >= 0 && pos <= m_len); - assert (len <= m_len - pos); + assert(pos >= 0 && pos <= m_len); + assert(len <= m_len - pos); if (len < 0) - len = m_len - pos; /* remove all following */ + len = m_len - pos; /* remove all following */ - if (! len) + if (!len) return; - do_erase ((char *) m_data + pos, len, erase_func); - memmove ((char *) m_data + pos, (char *) m_data + pos + len, m_len - pos - len); + do_erase((char *)m_data + pos, len, erase_func); + memmove((char *)m_data + pos, (char *)m_data + pos + len, + m_len - pos - len); m_len -= len; } -EXPORT void IndexBase::erase (int pos, int len, aud::FillFunc fill_func, aud::EraseFunc erase_func) +EXPORT void IndexBase::erase(int pos, int len, aud::FillFunc fill_func, + aud::EraseFunc erase_func) { - assert (pos >= 0 && pos <= m_len); - assert (len <= m_len - pos); + assert(pos >= 0 && pos <= m_len); + assert(len <= m_len - pos); if (len < 0) - len = m_len - pos; /* erase all following */ + len = m_len - pos; /* erase all following */ - if (! len) + if (!len) return; - do_erase ((char *) m_data + pos, len, erase_func); - do_fill ((char *) m_data + pos, len, fill_func); + do_erase((char *)m_data + pos, len, erase_func); + do_fill((char *)m_data + pos, len, fill_func); } -EXPORT void IndexBase::shift (int from, int to, int len, aud::FillFunc fill_func, aud::EraseFunc erase_func) +EXPORT void IndexBase::shift(int from, int to, int len, aud::FillFunc fill_func, + aud::EraseFunc erase_func) { - assert (len >= 0 && len <= m_len); - assert (from >= 0 && from + len <= m_len); - assert (to >= 0 && to + len <= m_len); + assert(len >= 0 && len <= m_len); + assert(from >= 0 && from + len <= m_len); + assert(to >= 0 && to + len <= m_len); - if (! len) + if (!len) return; - int erase_len = aud::min (len, abs (to - from)); + int erase_len = aud::min(len, abs(to - from)); if (to < from) - do_erase ((char *) m_data + to, erase_len, erase_func); + do_erase((char *)m_data + to, erase_len, erase_func); else - do_erase ((char *) m_data + to + len - erase_len, erase_len, erase_func); + do_erase((char *)m_data + to + len - erase_len, erase_len, erase_func); - memmove ((char *) m_data + to, (char *) m_data + from, len); + memmove((char *)m_data + to, (char *)m_data + from, len); if (to < from) - do_fill ((char *) m_data + from + len - erase_len, erase_len, fill_func); + do_fill((char *)m_data + from + len - erase_len, erase_len, fill_func); else - do_fill ((char *) m_data + from, erase_len, fill_func); + do_fill((char *)m_data + from, erase_len, fill_func); } -EXPORT void IndexBase::move_from (IndexBase & b, int from, int to, int len, - bool expand, bool collapse, aud::FillFunc fill_func, aud::EraseFunc erase_func) +EXPORT void IndexBase::move_from(IndexBase & b, int from, int to, int len, + bool expand, bool collapse, + aud::FillFunc fill_func, + aud::EraseFunc erase_func) { - assert (this != & b); - assert (from >= 0 && from <= b.m_len); - assert (len <= b.m_len - from); + assert(this != &b); + assert(from >= 0 && from <= b.m_len); + assert(len <= b.m_len - from); if (len < 0) - len = b.m_len - from; /* copy all following */ + len = b.m_len - from; /* copy all following */ - if (! len) + if (!len) return; if (expand) { - assert (to <= m_len); + assert(to <= m_len); if (to < 0) - to = m_len; /* insert at end */ + to = m_len; /* insert at end */ - insert (to, len); + insert(to, len); } else { - assert (to >= 0 && to <= m_len - len); - do_erase ((char *) m_data + to, len, erase_func); + assert(to >= 0 && to <= m_len - len); + do_erase((char *)m_data + to, len, erase_func); } - memcpy ((char *) m_data + to, (char *) b.m_data + from, len); + memcpy((char *)m_data + to, (char *)b.m_data + from, len); if (collapse) { - memmove ((char *) b.m_data + from, (char *) b.m_data + from + len, b.m_len - from - len); + memmove((char *)b.m_data + from, (char *)b.m_data + from + len, + b.m_len - from - len); b.m_len -= len; } else - do_fill ((char *) b.m_data + from, len, fill_func); + do_fill((char *)b.m_data + from, len, fill_func); } -EXPORT void IndexBase::sort (CompareFunc compare, int elemsize, void * userdata) +EXPORT void IndexBase::sort(CompareFunc compare, int elemsize, void * userdata) { - if (! m_len) + if (!m_len) return; // since we require GLib >= 2.32, g_qsort_with_data performs a stable sort - g_qsort_with_data (m_data, m_len / elemsize, elemsize, compare, userdata); + g_qsort_with_data(m_data, m_len / elemsize, elemsize, compare, userdata); } -EXPORT int IndexBase::bsearch (const void * key, CompareFunc compare, - int elemsize, void * userdata) const +EXPORT int IndexBase::bsearch(const void * key, CompareFunc compare, + int elemsize, void * userdata) const { int top = 0; int bottom = m_len / elemsize; @@ -233,7 +240,7 @@ EXPORT int IndexBase::bsearch (const void * key, CompareFunc compare, while (top < bottom) { int middle = top + (bottom - top) / 2; - int match = compare (key, (char *) m_data + middle * elemsize, userdata); + int match = compare(key, (char *)m_data + middle * elemsize, userdata); if (match < 0) bottom = middle; diff --git a/src/libaudcore/index.h b/src/libaudcore/index.h index a97a4b1..efc4ea7 100644 --- a/src/libaudcore/index.h +++ b/src/libaudcore/index.h @@ -34,49 +34,43 @@ class IndexBase { public: - typedef int (* CompareFunc) (const void * a, const void * b, void * userdata); + typedef int (*CompareFunc)(const void * a, const void * b, void * userdata); - constexpr IndexBase () : - m_data (nullptr), - m_len (0), - m_size (0) {} + constexpr IndexBase() : m_data(nullptr), m_len(0), m_size(0) {} - void clear (aud::EraseFunc erase_func); // use as destructor + void clear(aud::EraseFunc erase_func); // use as destructor - IndexBase (IndexBase && b) : - m_data (b.m_data), - m_len (b.m_len), - m_size (b.m_size) + IndexBase(IndexBase && b) + : m_data(b.m_data), m_len(b.m_len), m_size(b.m_size) { b.m_data = nullptr; b.m_len = 0; b.m_size = 0; } - void * begin () - { return m_data; } - const void * begin () const - { return m_data; } - void * end () - { return (char *) m_data + m_len; } - const void * end () const - { return (char *) m_data + m_len; } + void * begin() { return m_data; } + const void * begin() const { return m_data; } + void * end() { return (char *)m_data + m_len; } + const void * end() const { return (char *)m_data + m_len; } - int len () const - { return m_len; } + int len() const { return m_len; } - void * insert (int pos, int len); // no fill - void insert (int pos, int len, aud::FillFunc fill_func); - void insert (const void * from, int pos, int len, aud::CopyFunc copy_func); - void remove (int pos, int len, aud::EraseFunc erase_func); - void erase (int pos, int len, aud::FillFunc fill_func, aud::EraseFunc erase_func); - void shift (int from, int to, int len, aud::FillFunc fill_func, aud::EraseFunc erase_func); + void * insert(int pos, int len); // no fill + void insert(int pos, int len, aud::FillFunc fill_func); + void insert(const void * from, int pos, int len, aud::CopyFunc copy_func); + void remove(int pos, int len, aud::EraseFunc erase_func); + void erase(int pos, int len, aud::FillFunc fill_func, + aud::EraseFunc erase_func); + void shift(int from, int to, int len, aud::FillFunc fill_func, + aud::EraseFunc erase_func); - void move_from (IndexBase & b, int from, int to, int len, bool expand, - bool collapse, aud::FillFunc fill_func, aud::EraseFunc erase_func); + void move_from(IndexBase & b, int from, int to, int len, bool expand, + bool collapse, aud::FillFunc fill_func, + aud::EraseFunc erase_func); - void sort (CompareFunc compare, int elemsize, void * userdata); - int bsearch (const void * key, CompareFunc search, int elemsize, void * userdata) const; + void sort(CompareFunc compare, int elemsize, void * userdata); + int bsearch(const void * key, CompareFunc search, int elemsize, + void * userdata) const; private: void * m_data; @@ -89,74 +83,82 @@ class Index : private IndexBase private: // provides C-style callback to generic comparison functor template - struct WrapCompare { - static int run (const void * key, const void * val, void * func) - { return (* (F *) func) (* (const Key *) key, * (const T *) val); } + struct WrapCompare + { + static int run(const void * key, const void * val, void * func) + { + return (*(F *)func)(*(const Key *)key, *(const T *)val); + } }; public: - constexpr Index () : - IndexBase () {} + constexpr Index() : IndexBase() {} // use with care! - IndexBase & base () - { return * this; } - - void clear () - { IndexBase::clear (aud::erase_func ()); } - ~Index () - { clear (); } - - Index (Index && b) : - IndexBase (std::move (b)) {} - Index & operator= (Index && b) - { return aud::move_assign (* this, std::move (b)); } - - T * begin () - { return (T *) IndexBase::begin (); } - const T * begin () const - { return (const T *) IndexBase::begin (); } - T * end () - { return (T *) IndexBase::end (); } - const T * end () const - { return (const T *) IndexBase::end (); } - - int len () const - { return cooked (IndexBase::len ()); } - - T & operator[] (int i) - { return begin ()[i]; } - const T & operator[] (int i) const - { return begin ()[i]; } - - void insert (int pos, int len) - { IndexBase::insert (raw (pos), raw (len), aud::fill_func ()); } - void insert (const T * from, int pos, int len) - { IndexBase::insert (from, raw (pos), raw (len), aud::copy_func ()); } - void remove (int pos, int len) - { IndexBase::remove (raw (pos), raw (len), aud::erase_func ()); } - void erase (int pos, int len) - { IndexBase::erase (raw (pos), raw (len), aud::fill_func (), aud::erase_func ()); } - void shift (int from, int to, int len) - { IndexBase::shift (raw (from), raw (to), raw (len), aud::fill_func (), aud::erase_func ()); } - - void move_from (Index & b, int from, int to, int len, bool expand, bool collapse) - { IndexBase::move_from (b, raw (from), raw (to), raw (len), expand, - collapse, aud::fill_func (), aud::erase_func ()); } - - template - T & append (Args && ... args) + IndexBase & base() { return *this; } + + void clear() { IndexBase::clear(aud::erase_func()); } + ~Index() { clear(); } + + Index(Index && b) : IndexBase(std::move(b)) {} + Index & operator=(Index && b) { - return * aud::construct::make (IndexBase::insert (-1, sizeof (T)), - std::forward (args) ...); + return aud::move_assign(*this, std::move(b)); } - int find (const T & val) const + T * begin() { return (T *)IndexBase::begin(); } + const T * begin() const { return (const T *)IndexBase::begin(); } + T * end() { return (T *)IndexBase::end(); } + const T * end() const { return (const T *)IndexBase::end(); } + + int len() const { return cooked(IndexBase::len()); } + + T & operator[](int i) { return begin()[i]; } + const T & operator[](int i) const { return begin()[i]; } + + void insert(int pos, int len) { - for (const T * iter = begin (); iter != end (); iter ++) + IndexBase::insert(raw(pos), raw(len), aud::fill_func()); + } + void insert(const T * from, int pos, int len) + { + IndexBase::insert(from, raw(pos), raw(len), aud::copy_func()); + } + void remove(int pos, int len) + { + IndexBase::remove(raw(pos), raw(len), aud::erase_func()); + } + void erase(int pos, int len) + { + IndexBase::erase(raw(pos), raw(len), aud::fill_func(), + aud::erase_func()); + } + void shift(int from, int to, int len) + { + IndexBase::shift(raw(from), raw(to), raw(len), aud::fill_func(), + aud::erase_func()); + } + + void move_from(Index & b, int from, int to, int len, bool expand, + bool collapse) + { + IndexBase::move_from(b, raw(from), raw(to), raw(len), expand, collapse, + aud::fill_func(), aud::erase_func()); + } + + template + T & append(Args &&... args) + { + return *aud::construct::make(IndexBase::insert(-1, sizeof(T)), + std::forward(args)...); + } + + int find(const T & val) const + { + for (const T * iter = begin(); iter != end(); iter++) { - if (* iter == val) - return iter - begin (); + if (*iter == val) + return iter - begin(); } return -1; @@ -164,54 +166,57 @@ public: // func(val) returns true to remove val, false to keep it template - bool remove_if (F func, bool clear_if_empty = false) + bool remove_if(F func, bool clear_if_empty = false) { - T * iter = begin (); + T * iter = begin(); bool changed = false; - while (iter != end ()) + while (iter != end()) { - if (func (* iter)) + if (func(*iter)) { - remove (iter - begin (), 1); + remove(iter - begin(), 1); changed = true; } else - iter ++; + iter++; } - if (clear_if_empty && ! len ()) - clear (); + if (clear_if_empty && !len()) + clear(); return changed; } // compare(a, b) returns <0 if a0 if a>b template - void sort (F compare) - { IndexBase::sort (WrapCompare::run, sizeof (T), & compare); } + void sort(F compare) + { + IndexBase::sort(WrapCompare::run, sizeof(T), &compare); + } // compare(key, val) returns <0 if key0 if key>val template - int bsearch (const Key & key, F compare) - { return IndexBase::bsearch (& key, WrapCompare::run, sizeof (T), & compare); } + int bsearch(const Key & key, F compare) + { + return IndexBase::bsearch(&key, WrapCompare::run, sizeof(T), + &compare); + } // for use of Index as a raw data buffer // unlike insert(), does not zero-fill any added space - void resize (int size) + void resize(int size) { - static_assert (std::is_trivial::value, "for basic types only"); - int diff = size - len (); + static_assert(std::is_trivial::value, "for basic types only"); + int diff = size - len(); if (diff > 0) - IndexBase::insert (-1, raw (diff)); + IndexBase::insert(-1, raw(diff)); else if (diff < 0) - IndexBase::remove (raw (size), -1, nullptr); + IndexBase::remove(raw(size), -1, nullptr); } private: - static constexpr int raw (int len) - { return len * sizeof (T); } - static constexpr int cooked (int len) - { return len / sizeof (T); } + static constexpr int raw(int len) { return len * sizeof(T); } + static constexpr int cooked(int len) { return len / sizeof(T); } }; #endif // LIBAUDCORE_INDEX_H diff --git a/src/libaudcore/inifile.cc b/src/libaudcore/inifile.cc index 046c14a..c7f5da8 100644 --- a/src/libaudcore/inifile.cc +++ b/src/libaudcore/inifile.cc @@ -21,32 +21,32 @@ #include -#include /* for g_ascii_isspace */ +#include /* for g_ascii_isspace */ #include "audstrings.h" #include "vfs.h" -static char * strskip (char * str, char * end) +static char * strskip(char * str, char * end) { - while (str < end && g_ascii_isspace (* str)) - str ++; + while (str < end && g_ascii_isspace(*str)) + str++; return str; } -static char * strtrim (char * str, char * end) +static char * strtrim(char * str, char * end) { - while (end > str && g_ascii_isspace (end[-1])) - end --; + while (end > str && g_ascii_isspace(end[-1])) + end--; - * end = 0; + *end = 0; return str; } -EXPORT void IniParser::parse (VFSFile & file) +EXPORT void IniParser::parse(VFSFile & file) { int size = 512; - StringBuf buf (size); + StringBuf buf(size); char * pos = buf; int len = 0; @@ -54,55 +54,56 @@ EXPORT void IniParser::parse (VFSFile & file) while (1) { - char * newline = (char *) memchr (pos, '\n', len); + char * newline = (char *)memchr(pos, '\n', len); - while (! newline && ! eof) + while (!newline && !eof) { - memmove (buf, pos, len); + memmove(buf, pos, len); pos = buf; if (len >= size - 1) { size <<= 1; - buf.resize (size); + buf.resize(size); pos = buf; } - len += file.fread (buf + len, 1, size - 1 - len); + len += file.fread(buf + len, 1, size - 1 - len); if (len < size - 1) eof = true; - newline = (char *) memchr (pos, '\n', len); + newline = (char *)memchr(pos, '\n', len); } char * end = newline ? newline : pos + len; - char * start = strskip (pos, end); + char * start = strskip(pos, end); char * sep; if (start < end) { - switch (* start) + switch (*start) { case '#': case ';': break; case '[': - if ((end = (char *) memchr (start, ']', end - start))) - handle_heading (strtrim (strskip (start + 1, end), end)); + if ((end = (char *)memchr(start, ']', end - start))) + handle_heading(strtrim(strskip(start + 1, end), end)); break; default: - if ((sep = (char *) memchr (start, '=', end - start))) - handle_entry (strtrim (start, sep), strtrim (strskip (sep + 1, end), end)); + if ((sep = (char *)memchr(start, '=', end - start))) + handle_entry(strtrim(start, sep), + strtrim(strskip(sep + 1, end), end)); break; } } - if (! newline) + if (!newline) break; len -= newline + 1 - pos; @@ -110,14 +111,15 @@ EXPORT void IniParser::parse (VFSFile & file) } } -EXPORT bool inifile_write_heading (VFSFile & file, const char * heading) +EXPORT bool inifile_write_heading(VFSFile & file, const char * heading) { - StringBuf line = str_concat ({"\n[", heading, "]\n"}); - return (file.fwrite (line, 1, line.len ()) == line.len ()); + StringBuf line = str_concat({"\n[", heading, "]\n"}); + return (file.fwrite(line, 1, line.len()) == line.len()); } -EXPORT bool inifile_write_entry (VFSFile & file, const char * key, const char * value) +EXPORT bool inifile_write_entry(VFSFile & file, const char * key, + const char * value) { - StringBuf line = str_concat ({key, "=", value, "\n"}); - return (file.fwrite (line, 1, line.len ()) == line.len ()); + StringBuf line = str_concat({key, "=", value, "\n"}); + return (file.fwrite(line, 1, line.len()) == line.len()); } diff --git a/src/libaudcore/inifile.h b/src/libaudcore/inifile.h index 273d2c6..aa28794 100644 --- a/src/libaudcore/inifile.h +++ b/src/libaudcore/inifile.h @@ -27,18 +27,18 @@ class VFSFile; class LIBAUDCORE_PUBLIC IniParser { public: - virtual ~IniParser () {} + virtual ~IniParser() {} - void parse (VFSFile & file); + void parse(VFSFile & file); protected: - virtual void handle_heading (const char * heading) = 0; - virtual void handle_entry (const char * key, const char * value) = 0; + virtual void handle_heading(const char * heading) = 0; + virtual void handle_entry(const char * key, const char * value) = 0; }; -bool inifile_write_heading (VFSFile & file, const char * heading) - __attribute__ ((warn_unused_result)); -bool inifile_write_entry (VFSFile & file, const char * key, const char * value) - __attribute__ ((warn_unused_result)); +bool inifile_write_heading(VFSFile & file, const char * heading) + __attribute__((warn_unused_result)); +bool inifile_write_entry(VFSFile & file, const char * key, const char * value) + __attribute__((warn_unused_result)); #endif /* LIBAUDCORE_INIFILE_H */ diff --git a/src/libaudcore/interface.cc b/src/libaudcore/interface.cc index ae44093..ce4e5b2 100644 --- a/src/libaudcore/interface.cc +++ b/src/libaudcore/interface.cc @@ -30,10 +30,11 @@ #include "plugins.h" #include "runtime.h" -struct MenuItem { +struct MenuItem +{ const char * name; const char * icon; - void (* func) (); + void (*func)(); }; static PluginHandle * current_plugin; @@ -41,205 +42,203 @@ static IfacePlugin * current_interface; static aud::array> menu_items; -static void add_menu_items () +static void add_menu_items() { - for (AudMenuID id : aud::range ()) + for (AudMenuID id : aud::range()) { for (MenuItem & item : menu_items[id]) - current_interface->plugin_menu_add (id, item.func, item.name, item.icon); + current_interface->plugin_menu_add(id, item.func, item.name, + item.icon); } } -static void remove_menu_items () +static void remove_menu_items() { - for (AudMenuID id : aud::range ()) + for (AudMenuID id : aud::range()) { for (MenuItem & item : menu_items[id]) - current_interface->plugin_menu_remove (id, item.func); + current_interface->plugin_menu_remove(id, item.func); } } -static bool interface_load (PluginHandle * plugin) +static bool interface_load(PluginHandle * plugin) { - auto i = (IfacePlugin *) aud_plugin_get_header (plugin); - if (! i) + auto i = (IfacePlugin *)aud_plugin_get_header(plugin); + if (!i) return false; - AUDINFO ("Loading %s.\n", aud_plugin_get_name (plugin)); + AUDINFO("Loading %s.\n", aud_plugin_get_name(plugin)); - if (! i->init ()) + if (!i->init()) return false; current_interface = i; - add_menu_items (); + add_menu_items(); - if (aud_get_bool (0, "show_interface")) - current_interface->show (true); + if (aud_get_bool("show_interface")) + current_interface->show(true); return true; } -static void interface_unload () +static void interface_unload() { - AUDINFO ("Unloading %s.\n", aud_plugin_get_name (current_plugin)); + AUDINFO("Unloading %s.\n", aud_plugin_get_name(current_plugin)); // call before unloading interface - hook_call ("config save", nullptr); + hook_call("config save", nullptr); - if (aud_get_bool (0, "show_interface")) - current_interface->show (false); + if (aud_get_bool("show_interface")) + current_interface->show(false); - remove_menu_items (); + remove_menu_items(); - current_interface->cleanup (); + current_interface->cleanup(); current_interface = nullptr; } -EXPORT void aud_ui_show (bool show) +EXPORT void aud_ui_show(bool show) { - if (! current_interface) + if (!current_interface) return; - aud_set_bool (0, "show_interface", show); + aud_set_bool("show_interface", show); - current_interface->show (show); + current_interface->show(show); - vis_activate (show); + vis_activate(show); } -EXPORT bool aud_ui_is_shown () +EXPORT bool aud_ui_is_shown() { - if (! current_interface) + if (!current_interface) return false; - return aud_get_bool (0, "show_interface"); + return aud_get_bool("show_interface"); } -EXPORT void aud_ui_startup_notify (const char * id) +EXPORT void aud_ui_startup_notify(const char * id) { if (current_interface) - current_interface->startup_notify (id); + current_interface->startup_notify(id); } -EXPORT void aud_ui_show_error (const char * message) +EXPORT void aud_ui_show_error(const char * message) { - if (aud_get_headless_mode ()) - AUDERR ("%s\n", message); + if (aud_get_headless_mode()) + AUDERR("%s\n", message); else - event_queue ("ui show error", g_strdup (message), g_free); + event_queue("ui show error", g_strdup(message), g_free); } -PluginHandle * iface_plugin_get_current () -{ - return current_plugin; -} +PluginHandle * iface_plugin_get_current() { return current_plugin; } -bool iface_plugin_set_current (PluginHandle * plugin) +bool iface_plugin_set_current(PluginHandle * plugin) { if (current_interface) - interface_unload (); + interface_unload(); - if (! interface_load (plugin)) + if (!interface_load(plugin)) return false; current_plugin = plugin; return true; } -void interface_run () +void interface_run() { - if (aud_get_headless_mode ()) + if (aud_get_headless_mode()) { - mainloop_run (); + mainloop_run(); // call before shutting down - hook_call ("config save", nullptr); + hook_call("config save", nullptr); } else if (current_interface) { - vis_activate (aud_get_bool (0, "show_interface")); + vis_activate(aud_get_bool("show_interface")); - current_interface->run (); - interface_unload (); + current_interface->run(); + interface_unload(); } } -EXPORT void aud_quit () +EXPORT void aud_quit() { // Qt is very sensitive to things being deleted in the correct order // to avoid upsetting it, we'll stop all queued callbacks right now - QueuedFunc::inhibit_all (); + QueuedFunc::inhibit_all(); if (current_interface) - current_interface->quit (); + current_interface->quit(); else - mainloop_quit (); + mainloop_quit(); } -EXPORT void aud_plugin_menu_add (AudMenuID id, void (* func) (), const char * name, const char * icon) +EXPORT void aud_plugin_menu_add(AudMenuID id, void (*func)(), const char * name, + const char * icon) { - menu_items[id].append (name, icon, func); + menu_items[id].append(name, icon, func); if (current_interface) - current_interface->plugin_menu_add (id, func, name, icon); + current_interface->plugin_menu_add(id, func, name, icon); } -EXPORT void aud_plugin_menu_remove (AudMenuID id, void (* func) ()) +EXPORT void aud_plugin_menu_remove(AudMenuID id, void (*func)()) { if (current_interface) - current_interface->plugin_menu_remove (id, func); + current_interface->plugin_menu_remove(id, func); - auto is_match = [=] (const MenuItem & item) - { return item.func == func; }; + auto is_match = [=](const MenuItem & item) { return item.func == func; }; - menu_items[id].remove_if (is_match, true); + menu_items[id].remove_if(is_match, true); } -EXPORT void aud_ui_show_about_window () +EXPORT void aud_ui_show_about_window() { if (current_interface) - current_interface->show_about_window (); + current_interface->show_about_window(); } -EXPORT void aud_ui_hide_about_window () +EXPORT void aud_ui_hide_about_window() { if (current_interface) - current_interface->hide_about_window (); + current_interface->hide_about_window(); } -EXPORT void aud_ui_show_filebrowser (bool open) +EXPORT void aud_ui_show_filebrowser(bool open) { if (current_interface) - current_interface->show_filebrowser (open); + current_interface->show_filebrowser(open); } -EXPORT void aud_ui_hide_filebrowser () +EXPORT void aud_ui_hide_filebrowser() { if (current_interface) - current_interface->hide_filebrowser (); + current_interface->hide_filebrowser(); } -EXPORT void aud_ui_show_jump_to_song () +EXPORT void aud_ui_show_jump_to_song() { if (current_interface) - current_interface->show_jump_to_song (); + current_interface->show_jump_to_song(); } -EXPORT void aud_ui_hide_jump_to_song () +EXPORT void aud_ui_hide_jump_to_song() { if (current_interface) - current_interface->hide_jump_to_song (); + current_interface->hide_jump_to_song(); } -EXPORT void aud_ui_show_prefs_window () +EXPORT void aud_ui_show_prefs_window() { if (current_interface) - current_interface->show_prefs_window (); + current_interface->show_prefs_window(); } -EXPORT void aud_ui_hide_prefs_window () +EXPORT void aud_ui_hide_prefs_window() { if (current_interface) - current_interface->hide_prefs_window (); + current_interface->hide_prefs_window(); } diff --git a/src/libaudcore/interface.h b/src/libaudcore/interface.h index b918a38..0a8821d 100644 --- a/src/libaudcore/interface.h +++ b/src/libaudcore/interface.h @@ -22,7 +22,8 @@ #include -enum class AudMenuID { +enum class AudMenuID +{ Main, Playlist, PlaylistAdd, @@ -30,25 +31,26 @@ enum class AudMenuID { count }; -void aud_ui_show (bool show); -bool aud_ui_is_shown (); +void aud_ui_show(bool show); +bool aud_ui_is_shown(); -void aud_ui_startup_notify (const char * id); -void aud_ui_show_error (const char * message); /* thread-safe */ +void aud_ui_startup_notify(const char * id); +void aud_ui_show_error(const char * message); /* thread-safe */ -void aud_ui_show_about_window (); -void aud_ui_hide_about_window (); -void aud_ui_show_filebrowser (bool open); -void aud_ui_hide_filebrowser (); -void aud_ui_show_jump_to_song (); -void aud_ui_hide_jump_to_song (); -void aud_ui_show_prefs_window (); -void aud_ui_hide_prefs_window (); +void aud_ui_show_about_window(); +void aud_ui_hide_about_window(); +void aud_ui_show_filebrowser(bool open); +void aud_ui_hide_filebrowser(); +void aud_ui_show_jump_to_song(); +void aud_ui_hide_jump_to_song(); +void aud_ui_show_prefs_window(); +void aud_ui_hide_prefs_window(); -void aud_plugin_menu_add (AudMenuID id, void (* func) (), const char * name, const char * icon); -void aud_plugin_menu_remove (AudMenuID id, void (* func) ()); +void aud_plugin_menu_add(AudMenuID id, void (*func)(), const char * name, + const char * icon); +void aud_plugin_menu_remove(AudMenuID id, void (*func)()); -void aud_visualizer_add (Visualizer * vis); -void aud_visualizer_remove (Visualizer * vis); +void aud_visualizer_add(Visualizer * vis); +void aud_visualizer_remove(Visualizer * vis); #endif diff --git a/src/libaudcore/internal.h b/src/libaudcore/internal.h index 7035a20..2a79bef 100644 --- a/src/libaudcore/internal.h +++ b/src/libaudcore/internal.h @@ -32,130 +32,131 @@ class PluginHandle; class VFSFile; class Tuple; -typedef bool (* DirForeachFunc) (const char * path, const char * basename, void * user); +typedef bool (*DirForeachFunc)(const char * path, const char * basename, + void * user); /* adder.cc */ -void adder_cleanup (); +void adder_cleanup(); /* art.cc */ -void art_cache_current (const String & filename, Index && data, String && art_file); -void art_clear_current (); -void art_cleanup (); +void art_cache_current(const String & filename, Index && data, + String && art_file); +void art_clear_current(); +void art_cleanup(); /* art-search.cc */ -String art_search (const char * filename); +String art_search(const char * filename); /* charset.cc */ -void chardet_init (); -void chardet_cleanup (); +void chardet_init(); +void chardet_cleanup(); /* config.cc */ -void config_load (); -void config_save (); -void config_cleanup (); +void config_load(); +void config_save(); +void config_cleanup(); /* drct.cc */ -void record_init (); -void record_cleanup (); +void record_init(); +void record_cleanup(); /* effect.cc */ -void effect_start (int & channels, int & rate); -Index & effect_process (Index & data); -bool effect_flush (bool force); -Index & effect_finish (Index & data, bool end_of_playlist); -int effect_adjust_delay (int delay); +void effect_start(int & channels, int & rate); +Index & effect_process(Index & data); +bool effect_flush(bool force); +Index & effect_finish(Index & data, bool end_of_playlist); +int effect_adjust_delay(int delay); -bool effect_plugin_start (PluginHandle * plugin); -void effect_plugin_stop (PluginHandle * plugin); +bool effect_plugin_start(PluginHandle * plugin); +void effect_plugin_stop(PluginHandle * plugin); /* equalizer.cc */ -void eq_init (); -void eq_cleanup (); -void eq_set_format (int new_channels, int new_rate); -void eq_filter (float * data, int samples); +void eq_init(); +void eq_cleanup(); +void eq_set_format(int new_channels, int new_rate); +void eq_filter(float * data, int samples); /* eventqueue.cc */ -void event_queue_cancel_all (); +void event_queue_cancel_all(); /* fft.cc */ -void calc_freq (const float data[512], float freq[256]); +void calc_freq(const float data[512], float freq[256]); /* hook.cc */ -void hook_cleanup (); +void hook_cleanup(); /* interface.cc */ -PluginHandle * iface_plugin_probe (); -PluginHandle * iface_plugin_get_current (); -bool iface_plugin_set_current (PluginHandle * plugin); +PluginHandle * iface_plugin_probe(); +PluginHandle * iface_plugin_get_current(); +bool iface_plugin_set_current(PluginHandle * plugin); -void interface_run (); +void interface_run(); /* playback.cc */ /* do not call these; use aud_drct_play/stop() instead */ -void playback_play (int seek_time, bool pause); -void playback_stop (bool exiting = false); +void playback_play(int seek_time, bool pause); +void playback_stop(bool exiting = false); -bool playback_check_serial (int serial); -void playback_set_info (int entry, Tuple && tuple); +bool playback_check_serial(int serial); +void playback_set_info(int entry, Tuple && tuple); /* probe.cc */ -bool open_input_file (const char * filename, const char * mode, - InputPlugin * ip, VFSFile & file, String * error = nullptr); -InputPlugin * load_input_plugin (PluginHandle * decoder, String * error = nullptr); +bool open_input_file(const char * filename, const char * mode, InputPlugin * ip, + VFSFile & file, String * error = nullptr); +InputPlugin * load_input_plugin(PluginHandle * decoder, + String * error = nullptr); -#define PROBE_FLAG_HAS_DECODER (1 << 0) +#define PROBE_FLAG_HAS_DECODER (1 << 0) #define PROBE_FLAG_MIGHT_HAVE_SUBTUNES (1 << 1) -int probe_by_filename (const char * filename); +int probe_by_filename(const char * filename); /* runtime.cc */ extern size_t misc_bytes_allocated; /* strpool.cc */ -void string_leak_check (); +void string_leak_check(); /* timer.cc */ -void timer_cleanup (); +void timer_cleanup(); /* util.cc */ -const char * get_home_utf8 (); -bool dir_foreach (const char * path, DirForeachFunc func, void * user_data); -String write_temp_file (const void * data, int64_t len); +const char * get_home_utf8(); +bool dir_foreach(const char * path, DirForeachFunc func, void * user_data); +String write_temp_file(const void * data, int64_t len); -bool same_basename (const char * a, const char * b); -const char * last_path_element (const char * path); -void cut_path_element (char * path, int pos); +bool same_basename(const char * a, const char * b); +const char * last_path_element(const char * path); +void cut_path_element(char * path, int pos); -bool is_cuesheet_entry (const char * filename); -bool is_subtune (const char * filename); -StringBuf strip_subtune (const char * filename); +bool is_cuesheet_entry(const char * filename); +bool is_subtune(const char * filename); +StringBuf strip_subtune(const char * filename); -unsigned int32_hash (unsigned val); -unsigned ptr_hash (const void * ptr); +unsigned int32_hash(unsigned val); +unsigned ptr_hash(const void * ptr); struct IntHashKey { int val; - constexpr IntHashKey (int val) : - val (val) {} - operator int () const - { return val; } - unsigned hash () const - { return int32_hash (val); } + constexpr IntHashKey(int val) : val(val) {} + operator int() const { return val; } + unsigned hash() const { return int32_hash(val); } }; /* vis-runner.cc */ -void vis_runner_start_stop (bool playing, bool paused); -void vis_runner_pass_audio (int time, const Index & data, int channels, int rate); -void vis_runner_flush (); -void vis_runner_enable (bool enable); +void vis_runner_start_stop(bool playing, bool paused); +void vis_runner_pass_audio(int time, const Index & data, int channels, + int rate); +void vis_runner_flush(); +void vis_runner_enable(bool enable); /* visualization.cc */ -void vis_activate (bool activate); -void vis_send_clear (); -void vis_send_audio (const float * data, int channels); +void vis_activate(bool activate); +void vis_send_clear(); +void vis_send_audio(const float * data, int channels); -bool vis_plugin_start (PluginHandle * plugin); -void vis_plugin_stop (PluginHandle * plugin); +bool vis_plugin_start(PluginHandle * plugin); +void vis_plugin_stop(PluginHandle * plugin); #endif diff --git a/src/libaudcore/list.cc b/src/libaudcore/list.cc index f2b7a5e..f5a64e2 100644 --- a/src/libaudcore/list.cc +++ b/src/libaudcore/list.cc @@ -19,7 +19,7 @@ #include "list.h" -EXPORT void ListBase::insert_after (ListNode * prev, ListNode * node) +EXPORT void ListBase::insert_after(ListNode * prev, ListNode * node) { ListNode * next; @@ -43,7 +43,7 @@ EXPORT void ListBase::insert_after (ListNode * prev, ListNode * node) tail = node; } -EXPORT void ListBase::remove (ListNode * node) +EXPORT void ListBase::remove(ListNode * node) { ListNode * prev = node->prev; ListNode * next = node->next; @@ -62,13 +62,13 @@ EXPORT void ListBase::remove (ListNode * node) tail = prev; } -EXPORT void ListBase::clear (DestroyFunc destroy) +EXPORT void ListBase::clear(DestroyFunc destroy) { ListNode * node = head; while (node) { ListNode * next = node->next; - destroy (node); + destroy(node); node = next; } diff --git a/src/libaudcore/list.h b/src/libaudcore/list.h index a3551f1..90ef9af 100644 --- a/src/libaudcore/list.h +++ b/src/libaudcore/list.h @@ -32,54 +32,54 @@ private: class ListBase { protected: - typedef void (* DestroyFunc) (ListNode *); + typedef void (*DestroyFunc)(ListNode *); ListNode * head = nullptr; ListNode * tail = nullptr; - void insert_after (ListNode * prev, ListNode * node); - void remove (ListNode * node); - void clear (DestroyFunc destroy); + void insert_after(ListNode * prev, ListNode * node); + void remove(ListNode * node); + void clear(DestroyFunc destroy); - static ListNode * prev (ListNode * node) - { return node->prev; } - static ListNode * next (ListNode * node) - { return node->next; } + static ListNode * prev(ListNode * node) { return node->prev; } + static ListNode * next(ListNode * node) { return node->next; } }; template class List : private ListBase { public: - C * head () const - { return (C *) ListBase::head; } - C * tail () const - { return (C *) ListBase::tail; } + C * head() const { return (C *)ListBase::head; } + C * tail() const { return (C *)ListBase::tail; } - static C * prev (C * node) - { return (C *) ListBase::prev (node); } - static C * next (C * node) - { return (C *) ListBase::next (node); } + static C * prev(C * node) { return (C *)ListBase::prev(node); } + static C * next(C * node) { return (C *)ListBase::next(node); } - void insert_after (C * prev, C * node) - { ListBase::insert_after (prev, node); } - void remove (C * node) - { ListBase::remove (node); } + void insert_after(C * prev, C * node) + { + ListBase::insert_after(prev, node); + } + void remove(C * node) { ListBase::remove(node); } + + void prepend(C * node) { insert_after(nullptr, node); } + void append(C * node) { insert_after(tail(), node); } - void prepend (C * node) - { insert_after (nullptr, node); } - void append (C * node) - { insert_after (tail (), node); } + void clear() { ListBase::clear(destroy); } - void clear () - { ListBase::clear (destroy); } + C * pop_head() + { + C * node = head(); + if (node) + remove(node); + return node; + } template - C * find (MatchFunc match) + C * find(MatchFunc match) { - for (C * node = head (); node; node = next (node)) + for (C * node = head(); node; node = next(node)) { - if (match (* node)) + if (match(*node)) return node; } @@ -87,8 +87,7 @@ public: } private: - static void destroy (ListNode * node) - { delete (C *) node; } + static void destroy(ListNode * node) { delete (C *)node; } }; #endif // LIBAUDCORE_LIST_H diff --git a/src/libaudcore/logger.cc b/src/libaudcore/logger.cc index 5fa300b..d00a5af 100644 --- a/src/libaudcore/logger.cc +++ b/src/libaudcore/logger.cc @@ -1,6 +1,6 @@ /* * logger.cc - * Copyright 2014 John Lindgren and William Pitcock + * Copyright 2014 John Lindgren and Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,26 +20,27 @@ #include "audstrings.h" #include "index.h" #include "runtime.h" -#include "tinylock.h" +#include "threads.h" #include -namespace audlog { +namespace audlog +{ -struct HandlerData { +struct HandlerData +{ Handler handler; Level level; }; -static TinyRWLock lock; +static aud::spinlock_rw lock; static Index handlers; static Level stderr_level = Warning; static Level min_level = Warning; -EXPORT void set_stderr_level (Level level) +EXPORT void set_stderr_level(Level level) { - tiny_lock_write (& lock); - + auto wr = lock.write(); min_level = stderr_level = level; for (const HandlerData & h : handlers) @@ -47,31 +48,25 @@ EXPORT void set_stderr_level (Level level) if (h.level < min_level) min_level = h.level; } - - tiny_unlock_write (& lock); } -EXPORT void subscribe (Handler handler, Level level) +EXPORT void subscribe(Handler handler, Level level) { - tiny_lock_write (& lock); - - handlers.append (handler, level); + auto wr = lock.write(); + handlers.append(handler, level); if (level < min_level) min_level = level; - - tiny_unlock_write (& lock); } -EXPORT void unsubscribe (Handler handler) +EXPORT void unsubscribe(Handler handler) { - tiny_lock_write (& lock); - - auto is_match = [=] (const HandlerData & data) - { return data.handler == handler; }; - - handlers.remove_if (is_match, true); + auto is_match = [handler](const HandlerData & data) { + return data.handler == handler; + }; + auto wr = lock.write(); + handlers.remove_if(is_match, true); min_level = stderr_level; for (const HandlerData & h : handlers) @@ -79,47 +74,47 @@ EXPORT void unsubscribe (Handler handler) if (h.level < min_level) min_level = h.level; } - - tiny_unlock_write (& lock); } -EXPORT const char * get_level_name (Level level) +EXPORT const char * get_level_name(Level level) { switch (level) { - case Debug: return "DEBUG"; - case Info: return "INFO"; - case Warning: return "WARNING"; - case Error: return "ERROR"; + case Debug: + return "DEBUG"; + case Info: + return "INFO"; + case Warning: + return "WARNING"; + case Error: + return "ERROR"; }; return nullptr; } -EXPORT void log (Level level, const char * file, int line, const char * func, - const char * format, ...) +EXPORT void log(Level level, const char * file, int line, const char * func, + const char * format, ...) { - tiny_lock_read (& lock); + auto rd = lock.read(); if (level >= min_level) { va_list args; - va_start (args, format); - StringBuf message = str_vprintf (format, args); - va_end (args); + va_start(args, format); + StringBuf message = str_vprintf(format, args); + va_end(args); if (level >= stderr_level) - fprintf (stderr, "%s %s:%d [%s]: %s", get_level_name (level), file, - line, func, (const char *) message); + fprintf(stderr, "%s %s:%d [%s]: %s", get_level_name(level), file, + line, func, (const char *)message); for (const HandlerData & h : handlers) { if (level >= h.level) - h.handler (level, file, line, func, message); + h.handler(level, file, line, func, message); } } - - tiny_unlock_read (& lock); } } // namespace audlog diff --git a/src/libaudcore/mainloop.cc b/src/libaudcore/mainloop.cc index 090aeca..359e561 100644 --- a/src/libaudcore/mainloop.cc +++ b/src/libaudcore/mainloop.cc @@ -29,7 +29,8 @@ #include "multihash.h" #include "runtime.h" -struct QueuedFuncParams { +struct QueuedFuncParams +{ QueuedFunc::Func func; void * data; int interval_ms; @@ -47,22 +48,24 @@ struct QueuedFuncHelper // Creates an appropriate helper subclass for the given parameters and // schedules it to run the QueuedFunc - static QueuedFuncHelper * create (QueuedFunc * queued, const QueuedFuncParams & params); + static QueuedFuncHelper * create(QueuedFunc * queued, + const QueuedFuncParams & params); // Callback which runs the QueuedFunc, if still active - void run (); + void run(); // Cancels any scheduled run of the QueuedFunc and marks the helper for // deletion (it may not deleted immediately, but should not be accessed // again after calling this function) - virtual void cancel () = 0; + virtual void cancel() = 0; - virtual ~QueuedFuncHelper () {} + virtual ~QueuedFuncHelper() {} protected: - QueuedFuncHelper (QueuedFunc * queued, const QueuedFuncParams & params) : - queued (queued), params (params) {} - + QueuedFuncHelper(QueuedFunc * queued, const QueuedFuncParams & params) + : queued(queued), params(params) + { + } }; // The following hash table implements a thread-safe "registry" of active @@ -73,27 +76,32 @@ protected: struct QueuedFuncNode : public MultiHash::Node { // Creates a helper to be registered in the hash - QueuedFuncNode (QueuedFunc * queued, const QueuedFuncParams & params) : - helper (QueuedFuncHelper::create (queued, params)) {} + QueuedFuncNode(QueuedFunc * queued, const QueuedFuncParams & params) + : helper(QueuedFuncHelper::create(queued, params)) + { + } // Cancels a helper when it is unregistered from the hash - ~QueuedFuncNode () - { helper->cancel (); } + ~QueuedFuncNode() { helper->cancel(); } // Replaces the registration of one helper with another - void reset (QueuedFunc * queued, const QueuedFuncParams & params) + void reset(QueuedFunc * queued, const QueuedFuncParams & params) { - helper->cancel (); - helper = QueuedFuncHelper::create (queued, params); + helper->cancel(); + helper = QueuedFuncHelper::create(queued, params); } // Checks whether a helper is still registered - bool is_current (QueuedFuncHelper * test_helper) const - { return test_helper == helper; } + bool is_current(QueuedFuncHelper * test_helper) const + { + return test_helper == helper; + } // Hash comparison function - bool match (const QueuedFunc * queued) const - { return queued == helper->queued; } + bool match(const QueuedFunc * queued) const + { + return queued == helper->queued; + } private: QueuedFuncHelper * helper; @@ -112,14 +120,13 @@ struct RunCheck // Called if the QueuedFunc is not registered in the hash // This indicates a "stale" event that should not be processed - QueuedFuncNode * add (const QueuedFunc *) - { return nullptr; } + QueuedFuncNode * add(const QueuedFunc *) { return nullptr; } - bool found (const QueuedFuncNode * node) + bool found(const QueuedFuncNode * node) { // Check whether a different helper has been registered // This also indicates a "stale" event that should not be processed - if (! node->is_current (helper)) + if (!node->is_current(helper)) return false; // We are still registered and good to go @@ -135,15 +142,15 @@ struct RunCheck } }; -void QueuedFuncHelper::run () +void QueuedFuncHelper::run() { // Check whether it's okay to run. The actual check is performed within // the MultiHash lock to eliminate race conditions. RunCheck r = {this, false}; - func_table.lookup (queued, ptr_hash (queued), r); + func_table.lookup(queued, ptr_hash(queued), r); if (r.okay_to_run) - params.func (params.data); + params.func(params.data); } // GLib implementation -- simple wrapper around g_timeout_add_full() @@ -151,30 +158,30 @@ void QueuedFuncHelper::run () class HelperGLib : public QueuedFuncHelper { public: - HelperGLib (QueuedFunc * queued, const QueuedFuncParams & params) : - QueuedFuncHelper (queued, params) + HelperGLib(QueuedFunc * queued, const QueuedFuncParams & params) + : QueuedFuncHelper(queued, params) { - glib_source = g_timeout_add_full (G_PRIORITY_HIGH, params.interval_ms, - run_cb, this, aud::delete_obj); + glib_source = + g_timeout_add_full(G_PRIORITY_HIGH, params.interval_ms, run_cb, + this, aud::delete_obj); } - void cancel () + void cancel() { // GLib will delete the helper after we return to the main loop - g_source_remove (glib_source); + g_source_remove(glib_source); } private: - static gboolean run_cb (void * me) + static gboolean run_cb(void * me) { - (static_cast (me))->run (); + (static_cast(me))->run(); return G_SOURCE_CONTINUE; } int glib_source = 0; }; - #ifdef USE_QT // Qt implementation -- rather more complicated @@ -190,7 +197,7 @@ private: class EventRouter : public QObject { protected: - void customEvent (QEvent * event); + void customEvent(QEvent * event); }; static EventRouter router; @@ -198,18 +205,19 @@ static EventRouter router; class HelperQEvent : public QueuedFuncHelper, public QEvent { public: - HelperQEvent (QueuedFunc * queued, const QueuedFuncParams & params) : - QueuedFuncHelper (queued, params), - QEvent (User) + HelperQEvent(QueuedFunc * queued, const QueuedFuncParams & params) + : QueuedFuncHelper(queued, params), QEvent(User) { - QCoreApplication::postEvent (& router, this, Qt::HighEventPriority); + QCoreApplication::postEvent(&router, this, Qt::HighEventPriority); } - void cancel () {} // Qt will delete the event after it fires + void cancel() {} // Qt will delete the event after it fires }; -void EventRouter::customEvent (QEvent * event) - { dynamic_cast (event)->run (); } +void EventRouter::customEvent(QEvent * event) +{ + dynamic_cast(event)->run(); +} // Periodic callbacks are implemented through QObject's timer capability. In // this case, the QueuedFuncHelper is a QObject that is re-associated with the @@ -223,39 +231,38 @@ void EventRouter::customEvent (QEvent * event) class HelperQTimer : public QueuedFuncHelper, public QObject { public: - HelperQTimer (QueuedFunc * queued, const QueuedFuncParams & params) : - QueuedFuncHelper (queued, params) + HelperQTimer(QueuedFunc * queued, const QueuedFuncParams & params) + : QueuedFuncHelper(queued, params) { - moveToThread (router.thread ()); // main thread - QCoreApplication::postEvent (this, new QEvent (QEvent::User), Qt::HighEventPriority); + moveToThread(router.thread()); // main thread + QCoreApplication::postEvent(this, new QEvent(QEvent::User), + Qt::HighEventPriority); } - void cancel () - { deleteLater (); } + void cancel() { deleteLater(); } protected: - void customEvent (QEvent *) - { startTimer (params.interval_ms); } - void timerEvent (QTimerEvent *) - { run (); } + void customEvent(QEvent *) { startTimer(params.interval_ms); } + void timerEvent(QTimerEvent *) { run(); } }; #endif // USE_QT // creates the appropriate helper subclass -QueuedFuncHelper * QueuedFuncHelper::create (QueuedFunc * queued, const QueuedFuncParams & params) +QueuedFuncHelper * QueuedFuncHelper::create(QueuedFunc * queued, + const QueuedFuncParams & params) { #ifdef USE_QT - if (aud_get_mainloop_type () == MainloopType::Qt) + if (aud_get_mainloop_type() == MainloopType::Qt) { if (params.interval_ms > 0) - return new HelperQTimer (queued, params); + return new HelperQTimer(queued, params); else - return new HelperQEvent (queued, params); + return new HelperQEvent(queued, params); } #endif - return new HelperGLib (queued, params); + return new HelperGLib(queued, params); } // "start" logic executed within the hash table lock @@ -265,38 +272,43 @@ struct Starter const QueuedFuncParams & params; // register a new helper for this QueuedFunc - QueuedFuncNode * add (const QueuedFunc *) - { return in_lockdown ? nullptr : new QueuedFuncNode (queued, params); } + QueuedFuncNode * add(const QueuedFunc *) + { + return in_lockdown ? nullptr : new QueuedFuncNode(queued, params); + } // cancel the old helper and register a replacement - bool found (QueuedFuncNode * node) - { node->reset (queued, params); return false; } + bool found(QueuedFuncNode * node) + { + node->reset(queued, params); + return false; + } }; // common entry point used by all queue() and start() variants -static void start_func (QueuedFunc * queued, const QueuedFuncParams & params) +static void start_func(QueuedFunc * queued, const QueuedFuncParams & params) { Starter s = {queued, params}; - func_table.lookup (queued, ptr_hash (queued), s); + func_table.lookup(queued, ptr_hash(queued), s); } -EXPORT void QueuedFunc::queue (Func func, void * data) +EXPORT void QueuedFunc::queue(Func func, void * data) { - start_func (this, {func, data, 0, false}); + start_func(this, {func, data, 0, false}); _running = false; } -EXPORT void QueuedFunc::queue (int delay_ms, Func func, void * data) +EXPORT void QueuedFunc::queue(int delay_ms, Func func, void * data) { - g_return_if_fail (delay_ms >= 0); - start_func (this, {func, data, delay_ms, false}); + g_return_if_fail(delay_ms >= 0); + start_func(this, {func, data, delay_ms, false}); _running = false; } -EXPORT void QueuedFunc::start (int interval_ms, Func func, void * data) +EXPORT void QueuedFunc::start(int interval_ms, Func func, void * data) { - g_return_if_fail (interval_ms > 0); - start_func (this, {func, data, interval_ms, true}); + g_return_if_fail(interval_ms > 0); + start_func(this, {func, data, interval_ms, true}); _running = true; } @@ -304,68 +316,72 @@ EXPORT void QueuedFunc::start (int interval_ms, Func func, void * data) struct Stopper { // not registered, do nothing - QueuedFuncNode * add (const QueuedFunc *) - { return nullptr; } + QueuedFuncNode * add(const QueuedFunc *) { return nullptr; } // unregister and cancel helper - bool found (QueuedFuncNode * node) - { delete node; return true; } + bool found(QueuedFuncNode * node) + { + delete node; + return true; + } }; -EXPORT void QueuedFunc::stop () +EXPORT void QueuedFunc::stop() { Stopper s; - func_table.lookup (this, ptr_hash (this), s); + func_table.lookup(this, ptr_hash(this), s); _running = false; } // unregister a pending callback at shutdown -static bool cleanup_node (QueuedFuncNode * node) - { delete node; return true; } +static bool cleanup_node(QueuedFuncNode * node) +{ + delete node; + return true; +} // inhibit all future callbacks at shutdown -static void enter_lockdown () - { in_lockdown = true; } +static void enter_lockdown() { in_lockdown = true; } -EXPORT void QueuedFunc::inhibit_all () +EXPORT void QueuedFunc::inhibit_all() { - func_table.iterate (cleanup_node, enter_lockdown); + func_table.iterate(cleanup_node, enter_lockdown); } // main loop implementation follows static GMainLoop * glib_mainloop; -EXPORT void mainloop_run () +EXPORT void mainloop_run() { #ifdef USE_QT - if (aud_get_mainloop_type () == MainloopType::Qt) + if (aud_get_mainloop_type() == MainloopType::Qt) { static char app_name[] = "audacious"; static int dummy_argc = 1; static char * dummy_argv[] = {app_name, nullptr}; - QCoreApplication (dummy_argc, dummy_argv).exec (); + QCoreApplication(dummy_argc, dummy_argv).exec(); } else #endif { - glib_mainloop = g_main_loop_new (nullptr, true); - g_main_loop_run (glib_mainloop); - g_main_loop_unref (glib_mainloop); + glib_mainloop = g_main_loop_new(nullptr, true); + g_main_loop_run(glib_mainloop); + g_main_loop_unref(glib_mainloop); glib_mainloop = nullptr; } } -EXPORT void mainloop_quit () +EXPORT void mainloop_quit() { #ifdef USE_QT - if (aud_get_mainloop_type () == MainloopType::Qt) + if (aud_get_mainloop_type() == MainloopType::Qt) { - qApp->quit (); + qApp->quit(); } else #endif { - g_main_loop_quit (glib_mainloop); + g_main_loop_quit(glib_mainloop); } } diff --git a/src/libaudcore/mainloop.h b/src/libaudcore/mainloop.h index 4c38eba..2d74e28 100644 --- a/src/libaudcore/mainloop.h +++ b/src/libaudcore/mainloop.h @@ -27,43 +27,41 @@ class QueuedFunc { public: - typedef void (* Func) (void * data); + typedef void (*Func)(void * data); // one-time idle callback - void queue (Func func, void * data); + void queue(Func func, void * data); // one-time delayed callback - void queue (int delay_ms, Func func, void * data); + void queue(int delay_ms, Func func, void * data); // periodic timer callback - void start (int interval_ms, Func func, void * data); + void start(int interval_ms, Func func, void * data); // stops any type of callback // note that queue() and start() also stop any previous callback - void stop (); + void stop(); // true if a periodic timer is running // does not apply to one-time callbacks - bool running () const - { return _running; } + bool running() const { return _running; } - constexpr QueuedFunc () = default; - QueuedFunc (const QueuedFunc &) = delete; - void operator= (const QueuedFunc &) = delete; + constexpr QueuedFunc() = default; + QueuedFunc(const QueuedFunc &) = delete; + void operator=(const QueuedFunc &) = delete; - ~QueuedFunc () - { stop (); } + ~QueuedFunc() { stop(); } // cancels any pending callbacks // inhibits all future callbacks // needed to allow safe shutdown of some (Qt!) main loops - static void inhibit_all (); + static void inhibit_all(); private: bool _running = false; }; -void mainloop_run (); -void mainloop_quit (); +void mainloop_run(); +void mainloop_quit(); #endif // LIBAUDCORE_MAINLOOP_H diff --git a/src/libaudcore/meson.build b/src/libaudcore/meson.build new file mode 100644 index 0000000..9c04bb3 --- /dev/null +++ b/src/libaudcore/meson.build @@ -0,0 +1,126 @@ +libaudcore_inc = include_directories('.') + + +libaudcore_sources = [ + 'adder.cc', + 'art.cc', + 'art-search.cc', + 'audio.cc', + 'audstrings.cc', + 'charset.cc', + 'config.cc', + 'cue-cache.cc', + 'drct.cc', + 'effect.cc', + 'equalizer.cc', + 'equalizer-preset.cc', + 'eventqueue.cc', + 'fft.cc', + 'history.cc', + 'hook.cc', + 'index.cc', + 'inifile.cc', + 'interface.cc', + 'list.cc', + 'logger.cc', + 'mainloop.cc', + 'multihash.cc', + 'output.cc', + 'parse.cc', + 'playback.cc', + 'playlist.cc', + 'playlist-cache.cc', + 'playlist-data.cc', + 'playlist-files.cc', + 'playlist-utils.cc', + 'plugin-init.cc', + 'plugin-load.cc', + 'plugin-registry.cc', + 'preferences.cc', + 'probe.cc', + 'probe-buffer.cc', + 'ringbuf.cc', + 'runtime.cc', + 'scanner.cc', + 'stringbuf.cc', + 'strpool.cc', + 'tinylock.cc', + 'timer.cc', + 'tuple.cc', + 'tuple-compiler.cc', + 'util.cc', + 'vfs.cc', + 'vfs_async.cc', + 'vfs_local.cc', + 'vis-runner.cc', + 'visualization.cc' +] + + +libaudcore_headers = [ + 'audstrings.h', + 'drct.h', + 'equalizer.h', + 'export.h', + 'hook.h', + 'i18n.h', + 'index.h', + 'inifile.h', + 'interface.h', + 'list.h', + 'mainloop.h', + 'multihash.h', + 'objects.h', + 'playlist.h', + 'plugin.h', + 'plugins.h', + 'preferences.h', + 'probe.h', + 'ringbuf.h', + 'runtime.h', + 'templates.h', + 'tinylock.h', + 'threads.h', + 'tuple.h', + 'visualizer.h', + 'vfs.h', + 'vfs_async.h' +] + + +audio_h = configure_file(input: 'audio.h.in', + output: 'audio.h', + configuration: conf, + install: true, + install_dir: join_paths(get_option('includedir'), 'libaudcore')) + + +libaudcore_deps = [glib_dep, gmodule_dep] + +if get_option('qt') + libaudcore_deps += [qt_dep] +endif + + +if cc.has_function('iconv') + iconv_dep = [] +else + iconv_dep = cc.find_library('iconv', required: true) +endif + +libaudcore_deps += [iconv_dep] + + +libaudcore_lib = library('audcore', + libaudcore_sources, + cpp_args: ['-DLIBAUDCORE_BUILD'], + include_directories: src_inc, + dependencies: libaudcore_deps, + link_with: libguess_lib, + version: '5.1.0', + soversion: '5', + install: true +) + + +install_headers(libaudcore_headers, subdir: 'libaudcore') diff --git a/src/libaudcore/multihash.cc b/src/libaudcore/multihash.cc index 81f9c83..2068a6c 100644 --- a/src/libaudcore/multihash.cc +++ b/src/libaudcore/multihash.cc @@ -19,9 +19,9 @@ #include "multihash.h" -EXPORT void HashBase::add (Node * node, unsigned hash) +EXPORT void HashBase::add(Node * node, unsigned hash) { - if (! buckets) + if (!buckets) { buckets = new Node *[InitialSize](); size = InitialSize; @@ -32,31 +32,31 @@ EXPORT void HashBase::add (Node * node, unsigned hash) node->hash = hash; buckets[b] = node; - used ++; + used++; if (used > size) - resize (size << 1); + resize(size << 1); } -EXPORT HashBase::Node * HashBase::lookup (MatchFunc match, const void * data, - unsigned hash, NodeLoc * loc) const +EXPORT HashBase::Node * HashBase::lookup(MatchFunc match, const void * data, + unsigned hash, NodeLoc * loc) const { - if (! buckets) + if (!buckets) return nullptr; unsigned b = hash & (size - 1); - Node * * node_ptr = & buckets[b]; - Node * node = * node_ptr; + Node ** node_ptr = &buckets[b]; + Node * node = *node_ptr; while (1) { - if (! node) + if (!node) return nullptr; - if (node->hash == hash && match (node, data)) + if (node->hash == hash && match(node, data)) break; - node_ptr = & node->next; - node = * node_ptr; + node_ptr = &node->next; + node = *node_ptr; } if (loc) @@ -68,47 +68,47 @@ EXPORT HashBase::Node * HashBase::lookup (MatchFunc match, const void * data, return node; } -EXPORT void HashBase::remove (const NodeLoc & loc) +EXPORT void HashBase::remove(const NodeLoc & loc) { - * loc.ptr = loc.next; + *loc.ptr = loc.next; - used --; - if (used < size >> 2 && size > InitialSize) - resize (size >> 1); + used--; + if (used> 2 && size > InitialSize) + resize(size >> 1); } -EXPORT void HashBase::iterate (FoundFunc func, void * state) +EXPORT void HashBase::iterate(FoundFunc func, void * state) { - for (unsigned b = 0; b < size; b ++) + for (unsigned b = 0; b < size; b++) { - Node * * ptr = & buckets[b]; - Node * node = * ptr; + Node ** ptr = &buckets[b]; + Node * node = *ptr; while (node) { Node * next = node->next; - if (func (node, state)) + if (func(node, state)) { - * ptr = next; - used --; + *ptr = next; + used--; } else - ptr = & node->next; + ptr = &node->next; node = next; } } - if (used < size >> 2 && size > InitialSize) - resize (size >> 1); + if (used> 2 && size > InitialSize) + resize(size >> 1); } -void HashBase::resize (unsigned new_size) +void HashBase::resize(unsigned new_size) { - Node * * new_buckets = new Node *[new_size](); + Node ** new_buckets = new Node *[new_size](); - for (unsigned b1 = 0; b1 < size; b1 ++) + for (unsigned b1 = 0; b1 < size; b1++) { Node * node = buckets[b1]; @@ -129,53 +129,51 @@ void HashBase::resize (unsigned new_size) size = new_size; } -EXPORT int MultiHash::lookup (const void * data, unsigned hash, AddFunc add, - FoundFunc found, void * state) +EXPORT int MultiHash::lookup(const void * data, unsigned hash, AddFunc add, + FoundFunc found, void * state) { const unsigned c = (hash >> Shift) & (Channels - 1); HashBase & channel = channels[c]; int status = 0; - tiny_lock (& locks[c]); + auto lh = locks[c].take(); HashBase::NodeLoc loc; - Node * node = channel.lookup (match, data, hash, & loc); + Node * node = channel.lookup(match, data, hash, &loc); if (node) { status |= Found; - if (found && found (node, state)) + if (found && found(node, state)) { status |= Removed; - channel.remove (loc); + channel.remove(loc); } } - else if (add && (node = add (data, state))) + else if (add && (node = add(data, state))) { status |= Added; - channel.add (node, hash); + channel.add(node, hash); } - tiny_unlock (& locks[c]); return status; } -EXPORT void MultiHash::iterate (FoundFunc func, void * state) +EXPORT void MultiHash::iterate(FoundFunc func, void * state) { - iterate (func, state, nullptr, nullptr); + iterate(func, state, nullptr, nullptr); } -EXPORT void MultiHash::iterate (FoundFunc func, void * state, FinalFunc final, void * fstate) +EXPORT void MultiHash::iterate(FoundFunc func, void * state, FinalFunc final, + void * fstate) { - for (TinyLock & lock : locks) - tiny_lock (& lock); + aud::spinlock::holder lh[Channels]; + for (int i = 0; i < Channels; i++) + lh[i] = locks[i].take(); for (HashBase & channel : channels) - channel.iterate (func, state); + channel.iterate(func, state); if (final) - final (fstate); - - for (TinyLock & lock : locks) - tiny_unlock (& lock); + final(fstate); } diff --git a/src/libaudcore/multihash.h b/src/libaudcore/multihash.h index e5bf35b..d370a27 100644 --- a/src/libaudcore/multihash.h +++ b/src/libaudcore/multihash.h @@ -20,8 +20,8 @@ #ifndef LIBAUDCORE_MULTIHASH_H #define LIBAUDCORE_MULTIHASH_H +#include #include -#include /* HashBase is a low-level hash table implementation. It is used as a backend * for SimpleHash as well as for a single channel of MultiHash. */ @@ -32,60 +32,58 @@ public: /* Skeleton structure containing internal members of a hash node (except for * "refs", which is not used internally and included here only to fill an * alignment gap). Actual node structures should subclass Node. */ - struct Node { + struct Node + { Node * next; unsigned hash; unsigned refs; }; /* Represents the location of a node within the table. */ - struct NodeLoc { - Node * * ptr; + struct NodeLoc + { + Node ** ptr; Node * next; }; /* Callback. Returns true if matches , otherwise false. */ - typedef bool (* MatchFunc) (const Node * node, const void * data); + typedef bool (*MatchFunc)(const Node * node, const void * data); /* Callback. Called when a node is found. Returns true if is to be * removed, otherwise false. */ - typedef bool (* FoundFunc) (Node * node, void * state); + typedef bool (*FoundFunc)(Node * node, void * state); - constexpr HashBase () : - buckets (nullptr), - size (0), - used (0) {} + constexpr HashBase() : buckets(nullptr), size(0), used(0) {} - void clear () // use as destructor + void clear() // use as destructor { delete[] buckets; - * this = HashBase (); + *this = HashBase(); } - int n_items () const - { return used; } + int n_items() const { return used; } /* Adds a node. Does not check for duplicates. */ - void add (Node * node, unsigned hash); + void add(Node * node, unsigned hash); /* Locates the node matching . Returns null if no node is found. If * is not null, also returns the location of the node, which can be * used to remove it from the table. */ - Node * lookup (MatchFunc match, const void * data, unsigned hash, - NodeLoc * loc = nullptr) const; + Node * lookup(MatchFunc match, const void * data, unsigned hash, + NodeLoc * loc = nullptr) const; /* Removes a node, given a location returned by lookup_full(). */ - void remove (const NodeLoc & loc); + void remove(const NodeLoc & loc); /* Iterates over all nodes in the table, removing them as desired. */ - void iterate (FoundFunc func, void * state); + void iterate(FoundFunc func, void * state); private: static constexpr unsigned InitialSize = 16; - void resize (unsigned new_size); + void resize(unsigned new_size); - Node * * buckets; + Node ** buckets; unsigned size, used; }; @@ -107,16 +105,13 @@ public: typedef HashBase::Node Node; typedef HashBase::MatchFunc MatchFunc; typedef HashBase::FoundFunc FoundFunc; - typedef void (* FinalFunc) (void * state); + typedef void (*FinalFunc)(void * state); /* Callback. May create a new node representing to be added to the * table. Returns the new node or null. */ - typedef Node * (* AddFunc) (const void * data, void * state); + typedef Node * (*AddFunc)(const void * data, void * state); - MultiHash (MatchFunc match) : - match (match), - locks (), - channels () {} + MultiHash(MatchFunc match) : match(match), locks(), channels() {} /* There is no destructor. In some instances, such as the string pool, it * is never safe to destroy the hash table, since it can be referenced from @@ -129,25 +124,26 @@ public: * the table. is called if a matching node is found, and may return * true to remove the node from the table. Returns the status of the lookup * as a bitmask of Found, Added, and Removed. */ - int lookup (const void * data, unsigned hash, AddFunc add, FoundFunc found, void * state); + int lookup(const void * data, unsigned hash, AddFunc add, FoundFunc found, + void * state); /* All-purpose iteration function. All channels of the table are locked * simultaneously during the iteration to freeze the table in a consistent * state. is called on each node in order, and may return true to * remove the node from the table. */ - void iterate (FoundFunc func, void * state); + void iterate(FoundFunc func, void * state); /* Variant of iterate() which runs a second callback after the iteration * is complete, while the table is still locked. This is useful when some * operation needs to be performed with the table in a known state. */ - void iterate (FoundFunc func, void * state, FinalFunc final, void * fstate); + void iterate(FoundFunc func, void * state, FinalFunc final, void * fstate); private: - static constexpr int Channels = 16; /* must be a power of two */ - static constexpr int Shift = 24; /* bit shift for channel selection */ + static constexpr int Channels = 16; /* must be a power of two */ + static constexpr int Shift = 24; /* bit shift for channel selection */ const MatchFunc match; - TinyLock locks[Channels]; + aud::spinlock locks[Channels]; HashBase channels[Channels]; }; @@ -170,55 +166,70 @@ public: // bool found (Node_T * node); // }; - MultiHash_T () : MultiHash (match_cb) {} + MultiHash_T() : MultiHash(match_cb) {} - void clear () - { MultiHash::iterate (remove_cb, nullptr); } + void clear() { MultiHash::iterate(remove_cb, nullptr); } template - int lookup (const Data_T * data, unsigned hash, Op & op) - { return MultiHash::lookup (data, hash, WrapOp::add, WrapOp::found, & op); } + int lookup(const Data_T * data, unsigned hash, Op & op) + { + return MultiHash::lookup(data, hash, WrapOp::add, WrapOp::found, + &op); + } template - void iterate (F func) - { MultiHash::iterate (WrapIterate::run, & func); } + void iterate(F func) + { + MultiHash::iterate(WrapIterate::run, &func); + } template - void iterate (F func, Final final) - { MultiHash::iterate (WrapIterate::run, & func, WrapFinal::run, & final); } + void iterate(F func, Final final) + { + MultiHash::iterate(WrapIterate::run, &func, WrapFinal::run, + &final); + } private: - static bool match_cb (const Node * node, const void * data) - { return (static_cast (node))->match - (static_cast (data)); } + static bool match_cb(const Node * node, const void * data) + { + return (static_cast(node)) + ->match(static_cast(data)); + } - static bool remove_cb (Node * node, void *) + static bool remove_cb(Node * node, void *) { - delete static_cast (node); + delete static_cast(node); return true; } template - struct WrapOp { - static Node * add (const void * data, void * op) - { return (static_cast (op))->add - (static_cast (data)); } - static bool found (Node * node, void * op) - { return (static_cast (op))->found - (static_cast (node)); } + struct WrapOp + { + static Node * add(const void * data, void * op) + { + return (static_cast(op)) + ->add(static_cast(data)); + } + static bool found(Node * node, void * op) + { + return (static_cast(op))->found(static_cast(node)); + } }; template - struct WrapIterate { - static bool run (Node * node, void * func) - { return (* static_cast (func)) - (static_cast (node)); } + struct WrapIterate + { + static bool run(Node * node, void * func) + { + return (*static_cast(func))(static_cast(node)); + } }; template - struct WrapFinal { - static void run (void * func) - { (* static_cast (func)) (); } + struct WrapFinal + { + static void run(void * func) { (*static_cast(func))(); } }; }; @@ -228,80 +239,87 @@ template class SimpleHash : private HashBase { public: - typedef void (* IterFunc) (const Key & key, Value & value, void * state); + typedef void (*IterFunc)(const Key & key, Value & value, void * state); - ~SimpleHash () - { clear (); } + ~SimpleHash() { clear(); } using HashBase::n_items; - Value * lookup (const Key & key) + Value * lookup(const Key & key) { - auto node = static_cast (HashBase::lookup (match_cb, & key, key.hash ())); - return node ? & node->value : nullptr; + auto node = + static_cast(HashBase::lookup(match_cb, &key, key.hash())); + return node ? &node->value : nullptr; } - Value * add (const Key & key, Value && value) + Value * add(const Key & key, Value && value) { - unsigned hash = key.hash (); - auto node = static_cast (HashBase::lookup (match_cb, & key, hash)); + unsigned hash = key.hash(); + auto node = static_cast(HashBase::lookup(match_cb, &key, hash)); if (node) - node->value = std::move (value); + node->value = std::move(value); else { - node = new Node (key, std::move (value)); - HashBase::add (node, hash); + node = new Node(key, std::move(value)); + HashBase::add(node, hash); } - return & node->value; + return &node->value; } - void remove (const Key & key) + void remove(const Key & key) { NodeLoc loc; - auto node = static_cast (HashBase::lookup (match_cb, & key, key.hash (), & loc)); + auto node = static_cast( + HashBase::lookup(match_cb, &key, key.hash(), &loc)); if (node) { delete node; - HashBase::remove (loc); + HashBase::remove(loc); } } - void clear () + void clear() { - HashBase::iterate (remove_cb, nullptr); - HashBase::clear (); + HashBase::iterate(remove_cb, nullptr); + HashBase::clear(); } template - void iterate (F func) - { HashBase::iterate (WrapIterate::run, & func); } + void iterate(F func) + { + HashBase::iterate(WrapIterate::run, &func); + } private: struct Node : public HashBase::Node { - Node (const Key & key, Value && value) : - key (key), - value (std::move (value)) {} + Node(const Key & key, Value && value) + : key(key), value(std::move(value)) + { + } Key key; Value value; }; - struct IterData { + struct IterData + { IterFunc func; void * state; }; - static bool match_cb (const HashBase::Node * node, const void * data) - { return (static_cast (node))->key == - * static_cast (data); } + static bool match_cb(const HashBase::Node * node, const void * data) + { + return (static_cast(node))->key == + *static_cast(data); + } - static bool remove_cb (HashBase::Node * node, void *) + static bool remove_cb(HashBase::Node * node, void *) { - delete static_cast (node); + delete static_cast(node); return true; } @@ -309,10 +327,10 @@ private: template struct WrapIterate { - static bool run (HashBase::Node * node_, void * func) + static bool run(HashBase::Node * node_, void * func) { - auto node = static_cast (node_); - (* static_cast (func)) (node->key, node->value); + auto node = static_cast(node_); + (*static_cast(func))(node->key, node->value); return false; } }; diff --git a/src/libaudcore/objects.h b/src/libaudcore/objects.h index 214254a..7b79ac6 100644 --- a/src/libaudcore/objects.h +++ b/src/libaudcore/objects.h @@ -34,89 +34,76 @@ struct ArrayRef const T * data; int len; - constexpr ArrayRef (decltype (nullptr) = nullptr) : - data (nullptr), - len (0) {} + constexpr ArrayRef(decltype(nullptr) = nullptr) : data(nullptr), len(0) {} template - constexpr ArrayRef (const T (& array) [N]) : - data (array), - len (N) {} - - constexpr ArrayRef (const T * data, int len) : - data (data), - len (len) {} - - const T * begin () const - { return data; } - const T * end () const - { return data + len; } + constexpr ArrayRef(const T (&array)[N]) : data(array), len(N) + { + } + + constexpr ArrayRef(const T * data, int len) : data(data), len(len) {} + + const T * begin() const { return data; } + const T * end() const { return data + len; } }; // Smart pointer. Deletes object pointed to when the pointer goes out of scope. -template +template class SmartPtr { public: - constexpr SmartPtr () : - ptr (nullptr) {} - explicit constexpr SmartPtr (T * ptr) : - ptr (ptr) {} + constexpr SmartPtr() : ptr(nullptr) {} + explicit constexpr SmartPtr(T * ptr) : ptr(ptr) {} - ~SmartPtr () - { if (ptr) deleter (ptr); } + ~SmartPtr() + { + if (ptr) + deleter(ptr); + } - void capture (T * ptr2) + bool capture(T * ptr2) { - if (ptr) deleter (ptr); + if (ptr) + deleter(ptr); ptr = ptr2; + return (bool)ptr; } - T * release () + T * release() { T * ptr2 = ptr; ptr = nullptr; return ptr2; } - void clear () - { capture (nullptr); } + void clear() { capture(nullptr); } - SmartPtr (SmartPtr && b) : - ptr (b.ptr) + SmartPtr(SmartPtr && b) : ptr(b.ptr) { b.ptr = nullptr; } + + SmartPtr & operator=(SmartPtr && b) { - b.ptr = nullptr; + return aud::move_assign(*this, std::move(b)); } - SmartPtr & operator= (SmartPtr && b) - { return aud::move_assign (* this, std::move (b)); } - - explicit operator bool () const - { return (bool) ptr; } - - T * get () - { return ptr; } - const T * get () const - { return ptr; } - T & operator* () - { return (* ptr); } - const T & operator* () const - { return (* ptr); } - T * operator-> () - { return ptr; } - const T * operator-> () const - { return ptr; } + explicit operator bool() const { return (bool)ptr; } + + T * get() { return ptr; } + const T * get() const { return ptr; } + T & operator*() { return (*ptr); } + const T & operator*() const { return (*ptr); } + T * operator->() { return ptr; } + const T * operator->() const { return ptr; } private: T * ptr; }; -template -SmartPtr SmartNew (Args && ... args) +template +SmartPtr SmartNew(Args &&... args) { - return SmartPtr (aud::construct::make (operator new (sizeof (T)), - std::forward (args) ...)); + return SmartPtr(aud::construct::make(operator new(sizeof(T)), + std::forward(args)...)); } // Convenience wrapper for a GLib-style string (char *). @@ -125,12 +112,11 @@ SmartPtr SmartNew (Args && ... args) class CharPtr : public SmartPtr> { public: - CharPtr () : SmartPtr () {} - explicit CharPtr (char * ptr) : SmartPtr (ptr) {} + CharPtr() : SmartPtr() {} + explicit CharPtr(char * ptr) : SmartPtr(ptr) {} // non-const operator omitted to prevent "CharPtr s; g_free(s);" - operator const char * () const - { return get (); } + operator const char *() const { return get(); } }; #endif @@ -139,54 +125,49 @@ public: class String { public: - constexpr String () : - raw (nullptr) {} + constexpr String() : raw(nullptr) {} - ~String () - { raw_unref (raw); } + ~String() + { + if (raw) + raw_unref(raw); + } - String (const String & b) : - raw (raw_ref (b.raw)) {} + String(const String & b) : raw(raw_ref(b.raw)) {} - String & operator= (const String & b) + String & operator=(const String & b) { - if (this != & b) + if (this != &b) { - raw_unref (raw); - raw = raw_ref (b.raw); + raw_unref(raw); + raw = raw_ref(b.raw); } - return * this; + return *this; } - String (String && b) : - raw (b.raw) + String(String && b) : raw(b.raw) { b.raw = nullptr; } + + String & operator=(String && b) { - b.raw = nullptr; + return aud::move_assign(*this, std::move(b)); } - String & operator= (String && b) - { return aud::move_assign (* this, std::move (b)); } - - bool operator== (const String & b) const - { return raw_equal (raw, b.raw); } + bool operator==(const String & b) const { return raw_equal(raw, b.raw); } - explicit String (const char * str) : - raw (raw_get (str)) {} + explicit String(const char * str) : raw(raw_get(str)) {} - String (decltype (nullptr)) = delete; + String(decltype(nullptr)) = delete; - operator const char * () const - { return raw; } + operator const char *() const { return raw; } - unsigned hash () const - { return raw_hash (raw); } + unsigned hash() const { return raw_hash(raw); } private: - static char * raw_get (const char * str); - static char * raw_ref (const char * str); - static void raw_unref (char * str); - static unsigned raw_hash (const char * str); - static bool raw_equal (const char * str1, const char * str2); + static char * raw_get(const char * str); + static char * raw_ref(const char * str); + static void raw_unref(char * str); + static unsigned raw_hash(const char * str); + static bool raw_equal(const char * str1, const char * str2); char * raw; }; @@ -212,33 +193,27 @@ struct StringStack; class StringBuf { public: - constexpr StringBuf () : - stack (nullptr), - m_data (nullptr), - m_len (0) {} - - explicit StringBuf (int len) : - stack (nullptr), - m_data (nullptr), - m_len (0) + constexpr StringBuf() : stack(nullptr), m_data(nullptr), m_len(0) {} + + explicit StringBuf(int len) : stack(nullptr), m_data(nullptr), m_len(0) { - resize (len); + resize(len); } - StringBuf (StringBuf && other) : - stack (other.stack), - m_data (other.m_data), - m_len (other.m_len) + StringBuf(StringBuf && other) + : stack(other.stack), m_data(other.m_data), m_len(other.m_len) { other.stack = nullptr; other.m_data = nullptr; other.m_len = 0; } - StringBuf & operator= (StringBuf && other) - { return aud::move_assign (* this, std::move (other)); } + StringBuf & operator=(StringBuf && other) + { + return aud::move_assign(*this, std::move(other)); + } - ~StringBuf (); + ~StringBuf(); // Resizes to bytes (not counting the terminating null byte) by // appended uninitialized bytes or truncating. The resized string will be @@ -246,33 +221,31 @@ public: // string as large as possible. This can be useful when the required length // is not known in advance. However, it will be impossible to create any // further StringBufs until resize() is called again. - void resize (int len); + void resize(int len); // Inserts the substring at the given position, or appends it if // is -1. If is -1, is assumed to be null-terminated; otherwise, // indicates the number of bytes to insert. If is a null pointer, // uninitialized bytes are inserted and must not be -1. A pointer to // the inserted substring is returned for convenience. - char * insert (int pos, const char * s, int len = -1); + char * insert(int pos, const char * s, int len = -1); // Removes bytes at the given position. - void remove (int pos, int len); + void remove(int pos, int len); // Collapses any unused space preceding this string. // Judicious use can combat memory fragmentation. // Returns a move reference to allow e.g. "return str.settle();" - StringBuf && settle (); + StringBuf && settle(); - int len () const - { return m_len; } + int len() const { return m_len; } - operator char * () - { return m_data; } + operator char *() { return m_data; } // deprecated, use assignment - void steal (StringBuf && other) __attribute__((deprecated)); + void steal(StringBuf && other) __attribute__((deprecated)); // deprecated, use insert() - void combine (StringBuf && other) __attribute__((deprecated)); + void combine(StringBuf && other) __attribute__((deprecated)); private: StringStack * stack; diff --git a/src/libaudcore/output.cc b/src/libaudcore/output.cc index bb861e5..53931de 100644 --- a/src/libaudcore/output.cc +++ b/src/libaudcore/output.cc @@ -19,8 +19,8 @@ #include "output.h" +#include #include -#include #include #include @@ -32,6 +32,7 @@ #include "plugin.h" #include "plugins.h" #include "runtime.h" +#include "threads.h" /* With Audacious 3.7, there is some support for secondary output plugins. * Notes and limitations: @@ -45,39 +46,101 @@ * - The secondary's write_audio() is called in a tight loop until it has * caught up to the primary, and should never return a zero byte count. */ -static pthread_mutex_t mutex_major = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t mutex_minor = PTHREAD_MUTEX_INITIALIZER; +/* Locking in this module is complicated by the fact that some of the + * output plugin functions (specifically period_wait() and drain()) are + * blocking calls. Various other functions are designed to be called + * in parallel with period_wait() and drain(). + * + * A two-mutex scheme is used to ensure that safe operations are allowed + * while a blocking call is in progress, and unsafe operations are + * prevented. The "major" mutex is locked before an unsafe operations; + * only the "minor" mutex is locked before a safe one. The "minor" mutex + * protects all changes to state data. + * + * The thread performing a blocking call (i.e. the input thread) must + * perform the following sequence: + * + * 1. Lock the major mutex + * 2. Lock the minor mutex + * 3. Check whether state data is correct for the call + * 4. Unlock the minor mutex + * 5. Call the blocking function + * 6. Unlock the major mutex + * + * The following classes attempt to enforce some of the rules regarding + * locking and state data. */ + +/* locks held for a "safe" operation */ +struct SafeLock +{ + aud::mutex::holder minor; +}; + +/* locks held for an "unsafe" operation */ +struct UnsafeLock : SafeLock +{ + aud::mutex::holder major; +}; + +class OutputState +{ +public: + bool input() const { return (m_flags & INPUT); } + bool output() const { return (m_flags & OUTPUT); } + bool secondary() const { return (m_flags & SECONDARY); } + bool paused() const { return (m_flags & PAUSED); } + bool flushed() const { return (m_flags & FLUSHED); } + bool resetting() const { return (m_flags & RESETTING); } + + SafeLock lock_safe() { return {mutex_minor.take()}; } + + UnsafeLock lock_unsafe() + { + UnsafeLock lock; + lock.major = mutex_major.take(); + lock.minor = mutex_minor.take(); + return lock; + } -#define LOCK_MAJOR pthread_mutex_lock (& mutex_major) -#define UNLOCK_MAJOR pthread_mutex_unlock (& mutex_major) -#define LOCK_MINOR pthread_mutex_lock (& mutex_minor) -#define UNLOCK_MINOR pthread_mutex_unlock (& mutex_minor) -#define LOCK_ALL do { LOCK_MAJOR; LOCK_MINOR; } while (0) -#define UNLOCK_ALL do { UNLOCK_MINOR; UNLOCK_MAJOR; } while (0) + /* safe state changes */ + void set_secondary(SafeLock &, bool on) { set_flag(SECONDARY, on); } + void set_paused(SafeLock &, bool on) { set_flag(PAUSED, on); } + void set_flushed(SafeLock &, bool on) { set_flag(FLUSHED, on); } + void set_resetting(SafeLock &, bool on) { set_flag(RESETTING, on); } -/* State variables. State changes that are allowed between LOCK_MINOR and - * UNLOCK_MINOR (all others must take place between LOCK_ALL and UNLOCK_ALL): - * s_paused -> true or false, s_flushed -> true, s_resetting -> true, - * s_secondary -> true or false */ + /* unsafe state changes */ + void set_input(UnsafeLock &, bool on) { set_flag(INPUT, on); } + void set_output(UnsafeLock &, bool on) { set_flag(OUTPUT, on); } -static bool s_input; /* input plugin connected */ -static bool s_output; /* primary output plugin connected */ -static bool s_secondary; /* secondary output plugin connected */ -static bool s_gain; /* replay gain info set */ -static bool s_paused; /* paused */ -static bool s_flushed; /* flushed, writes ignored until resume */ -static bool s_resetting; /* resetting output system */ + void await_change(SafeLock & lock) { cond.wait(lock.minor); } -/* Condition variable linked to LOCK_MINOR. - * The input thread will wait if the following is true: - * ((! s_output || s_paused || s_resetting) && ! s_flushed) - * Hence you must signal if you cause the inverse to be true: - * ((s_output && ! s_paused && ! s_resetting) || s_flushed) */ +private: + static constexpr int INPUT = (1 << 0); /* input plugin connected */ + static constexpr int OUTPUT = + (1 << 1); /* primary output plugin connected */ + static constexpr int SECONDARY = + (1 << 2); /* secondary output plugin connected */ + static constexpr int PAUSED = (1 << 3); /* paused */ + static constexpr int FLUSHED = + (1 << 4); /* flushed, writes ignored until resume */ + static constexpr int RESETTING = (1 << 5); /* resetting output system */ -static pthread_cond_t cond_minor = PTHREAD_COND_INITIALIZER; + int m_flags = 0; + + aud::mutex mutex_major; + aud::mutex mutex_minor; + + aud::condvar cond; + + void set_flag(int flag, bool on) + { + m_flags = on ? (m_flags | flag) : (m_flags & ~flag); + /* wake any thread waiting for a state change */ + cond.notify_all(); + } +}; -#define SIGNAL_MINOR pthread_cond_broadcast (& cond_minor) -#define WAIT_MINOR pthread_cond_wait (& cond_minor, & mutex_minor) +static OutputState state; static OutputPlugin * cop; /* current (primary) output plugin */ static OutputPlugin * sop; /* secondary output plugin */ @@ -94,138 +157,164 @@ static int out_format, out_channels, out_rate; static int out_bytes_per_sec, out_bytes_held; static int64_t in_frames, out_bytes_written; static ReplayGainInfo gain_info; +static bool gain_info_valid; static Index buffer1; static Index buffer2; -static inline int get_format (bool & automatic) +static inline int get_format(bool & automatic) { automatic = false; - switch (aud_get_int (0, "output_bit_depth")) + switch (aud_get_int("output_bit_depth")) { - case 16: return FMT_S16_NE; - case 24: return FMT_S24_3NE; - case 32: return FMT_S32_NE; - - // return FMT_FLOAT for "auto" as well - case -1: automatic = true; - default: return FMT_FLOAT; + case 16: + return FMT_S16_NE; + case 24: + return FMT_S24_3NE; + case 32: + return FMT_S32_NE; + + // return FMT_FLOAT for "auto" as well + case -1: + automatic = true; + default: + return FMT_FLOAT; } } -/* assumes LOCK_ALL, s_input */ -static void setup_effects () +static void setup_effects(SafeLock &) { + assert(state.input()); + effect_channels = in_channels; effect_rate = in_rate; - effect_start (effect_channels, effect_rate); - eq_set_format (effect_channels, effect_rate); + effect_start(effect_channels, effect_rate); + eq_set_format(effect_channels, effect_rate); } -/* assumes LOCK_ALL */ -static void cleanup_output () +static void cleanup_output(UnsafeLock & lock) { - if (! s_output) + if (!state.output()) return; - if (! s_paused && ! s_flushed && ! s_resetting) + // avoid locking up if the input thread reaches close_audio() while + // paused (unlikely but possible with perfect timing) + if (out_bytes_written && !state.paused()) { - UNLOCK_MINOR; - cop->drain (); - LOCK_MINOR; + lock.minor.unlock(); + cop->drain(); + lock.minor.lock(); } - s_output = false; + state.set_output(lock, false); - buffer1.clear (); - buffer2.clear (); + buffer1.clear(); + buffer2.clear(); - cop->close_audio (); - vis_runner_start_stop (false, false); + cop->close_audio(); + vis_runner_start_stop(false, false); } -/* assumes LOCK_MINOR */ -static void cleanup_secondary () +static void cleanup_secondary(SafeLock & lock) { - if (! s_secondary) + if (!state.secondary()) return; - s_secondary = false; - sop->close_audio (); + state.set_secondary(lock, false); + sop->close_audio(); +} + +static void apply_pause(SafeLock & lock, bool pause, bool new_output = false) +{ + if (state.output()) + { + // assume output plugin is unpaused after open_audio() + if (pause != (new_output ? false : state.paused())) + cop->pause(pause); + + vis_runner_start_stop(true, pause); + } + + state.set_paused(lock, pause); } -/* assumes LOCK_MINOR, s_output */ -static void apply_pause () +static bool open_audio_with_info(OutputPlugin * op, const char * filename, + const Tuple & tuple, int format, int rate, + int chans, String & error) { - cop->pause (s_paused); - vis_runner_start_stop (true, s_paused); + op->set_info(filename, tuple); + return op->open_audio(format, rate, chans, error); } -/* assumes LOCK_ALL, s_input */ -static void setup_output (bool new_input) +static void setup_output(UnsafeLock & lock, bool new_input, bool pause) { - if (! cop) + assert(state.input()); + + if (!cop) return; bool automatic; - int format = get_format (automatic); + int format = get_format(automatic); - if (s_output && effect_channels == out_channels && - effect_rate == out_rate && ! (new_input && cop->force_reopen)) + if (state.output() && effect_channels == out_channels && + effect_rate == out_rate && !(new_input && cop->force_reopen)) { - AUDINFO ("Reuse output, %d channels, %d Hz.\n", effect_channels, effect_rate); + AUDINFO("Reuse output, %d channels, %d Hz.\n", effect_channels, + effect_rate); + apply_pause(lock, pause); return; } - AUDINFO ("Setup output, format %d, %d channels, %d Hz.\n", format, effect_channels, effect_rate); + AUDINFO("Setup output, format %d, %d channels, %d Hz.\n", format, + effect_channels, effect_rate); - cleanup_output (); - cop->set_info (in_filename, in_tuple); + cleanup_output(lock); String error; - while (! cop->open_audio (format, effect_rate, effect_channels, error)) + while (!open_audio_with_info(cop, in_filename, in_tuple, format, + effect_rate, effect_channels, error)) { if (automatic && format == FMT_FLOAT) format = FMT_S32_NE; else if (automatic && format == FMT_S32_NE) format = FMT_S16_NE; else if (format == FMT_S24_3NE) - format = FMT_S24_NE; /* some output plugins support only padded 24-bit */ + format = + FMT_S24_NE; /* some output plugins support only padded 24-bit */ else { - aud_ui_show_error (error ? (const char *) error : _("Error opening output stream")); + aud_ui_show_error(error ? (const char *)error + : _("Error opening output stream")); return; } - AUDINFO ("Falling back to format %d.\n", format); + AUDINFO("Falling back to format %d.\n", format); } - s_output = true; + state.set_output(lock, true); out_format = format; out_channels = effect_channels; out_rate = effect_rate; - out_bytes_per_sec = FMT_SIZEOF (format) * out_channels * out_rate; + out_bytes_per_sec = FMT_SIZEOF(format) * out_channels * out_rate; out_bytes_held = 0; out_bytes_written = 0; - apply_pause (); - - if (! s_paused && ! s_flushed && ! s_resetting) - SIGNAL_MINOR; + apply_pause(lock, pause, true); } -/* assumes LOCK_MINOR, s_input */ -static void setup_secondary (bool new_input) +static void setup_secondary(SafeLock & lock, bool new_input) { - if (! sop) + assert(state.input()); + + if (!sop) return; int rate, channels; - record_stream = (OutputStream) aud_get_int (0, "record_stream"); + record_stream = (OutputStream)aud_get_int("record_stream"); if (record_stream < OutputStream::AfterEffects) { @@ -238,145 +327,166 @@ static void setup_secondary (bool new_input) channels = effect_channels; } - if (s_secondary && channels == sec_channels && rate == sec_rate && - ! (new_input && sop->force_reopen)) + if (state.secondary() && channels == sec_channels && rate == sec_rate && + !(new_input && sop->force_reopen)) return; - cleanup_secondary (); - sop->set_info (in_filename, in_tuple); + cleanup_secondary(lock); String error; - if (! sop->open_audio (FMT_FLOAT, rate, channels, error)) + if (!open_audio_with_info(sop, in_filename, in_tuple, FMT_FLOAT, rate, + channels, error)) { - aud_ui_show_error (error ? (const char *) error : _("Error recording output stream")); + aud_ui_show_error(error ? (const char *)error + : _("Error recording output stream")); return; } - s_secondary = true; + state.set_secondary(lock, true); sec_channels = channels; sec_rate = rate; } -/* assumes LOCK_MINOR, s_output */ -static void flush_output () +static void flush_output(SafeLock &) { + assert(state.output()); + out_bytes_held = 0; out_bytes_written = 0; - cop->flush (); - vis_runner_flush (); + cop->flush(); + vis_runner_flush(); } -static void apply_replay_gain (Index & data) +static void apply_replay_gain(SafeLock &, Index & data) { - if (! aud_get_bool (0, "enable_replay_gain")) + if (!aud_get_bool("enable_replay_gain")) return; - float factor = powf (10, aud_get_double (0, "replay_gain_preamp") / 20); + float factor = powf(10, aud_get_double("replay_gain_preamp") / 20); - if (s_gain) + if (gain_info_valid) { float peak; - auto mode = (ReplayGainMode) aud_get_int (0, "replay_gain_mode"); + auto mode = (ReplayGainMode)aud_get_int("replay_gain_mode"); if ((mode == ReplayGainMode::Album) || (mode == ReplayGainMode::Automatic && - (! aud_get_bool (0, "shuffle") || aud_get_bool (0, "album_shuffle")))) + (!aud_get_bool("shuffle") || aud_get_bool("album_shuffle")))) { - factor *= powf (10, gain_info.album_gain / 20); + factor *= powf(10, gain_info.album_gain / 20); peak = gain_info.album_peak; } else { - factor *= powf (10, gain_info.track_gain / 20); + factor *= powf(10, gain_info.track_gain / 20); peak = gain_info.track_peak; } - if (aud_get_bool (0, "enable_clipping_prevention") && peak * factor > 1) + if (aud_get_bool("enable_clipping_prevention") && peak * factor > 1) factor = 1 / peak; } else - factor *= powf (10, aud_get_double (0, "default_gain") / 20); + factor *= powf(10, aud_get_double("default_gain") / 20); if (factor < 0.99 || factor > 1.01) - audio_amplify (data.begin (), 1, data.len (), & factor); + audio_amplify(data.begin(), 1, data.len(), &factor); } -/* assumes LOCK_MINOR, s_secondary */ -static void write_secondary (const Index & data) +static void write_secondary(SafeLock &, const Index & data) { - auto begin = (const char *) data.begin (); - auto end = (const char *) data.end (); + assert(state.secondary()); + + auto begin = (const char *)data.begin(); + auto end = (const char *)data.end(); while (begin < end) - begin += sop->write_audio (begin, end - begin); + begin += sop->write_audio(begin, end - begin); } -/* assumes LOCK_ALL, s_output */ -static void write_output (Index & data) +static void write_output(UnsafeLock & lock, Index & data) { - if (! data.len ()) + assert(state.output()); + + if (!data.len()) return; - if (s_secondary && record_stream == OutputStream::AfterEffects) - write_secondary (data); + if (state.secondary() && record_stream == OutputStream::AfterEffects) + write_secondary(lock, data); - int out_time = aud::rescale (out_bytes_written, out_bytes_per_sec, 1000); - vis_runner_pass_audio (out_time, data, out_channels, out_rate); + int out_time = + aud::rescale(out_bytes_written, out_bytes_per_sec, 1000); + vis_runner_pass_audio(out_time, data, out_channels, out_rate); - eq_filter (data.begin (), data.len ()); + eq_filter(data.begin(), data.len()); - if (s_secondary && record_stream == OutputStream::AfterEqualizer) - write_secondary (data); + if (state.secondary() && record_stream == OutputStream::AfterEqualizer) + write_secondary(lock, data); - if (aud_get_bool (0, "software_volume_control")) + if (aud_get_bool("software_volume_control")) { - StereoVolume v = {aud_get_int (0, "sw_volume_left"), aud_get_int (0, "sw_volume_right")}; - audio_amplify (data.begin (), out_channels, data.len () / out_channels, v); + StereoVolume v = {aud_get_int("sw_volume_left"), + aud_get_int("sw_volume_right")}; + audio_amplify(data.begin(), out_channels, data.len() / out_channels, v); } - if (aud_get_bool (0, "soft_clipping")) - audio_soft_clip (data.begin (), data.len ()); + if (aud_get_bool("soft_clipping")) + audio_soft_clip(data.begin(), data.len()); - const void * out_data = data.begin (); + const void * out_data = data.begin(); if (out_format != FMT_FLOAT) { - buffer2.resize (FMT_SIZEOF (out_format) * data.len ()); - audio_to_int (data.begin (), buffer2.begin (), out_format, data.len ()); - out_data = buffer2.begin (); + buffer2.resize(FMT_SIZEOF(out_format) * data.len()); + audio_to_int(data.begin(), buffer2.begin(), out_format, data.len()); + out_data = buffer2.begin(); } - out_bytes_held = FMT_SIZEOF (out_format) * data.len (); + out_bytes_held = FMT_SIZEOF(out_format) * data.len(); - while (! s_paused && ! s_flushed && ! s_resetting) + while (out_bytes_held && !state.resetting()) { - int written = cop->write_audio (out_data, out_bytes_held); + if (state.paused()) + { + // avoid locking up if the input thread reaches close_audio() while + // paused (unlikely but possible with perfect timing) + if (!state.input()) + break; + + state.await_change(lock); + continue; + } + + int written = cop->write_audio(out_data, out_bytes_held); - out_data = (const char *) out_data + written; + out_data = (const char *)out_data + written; out_bytes_held -= written; out_bytes_written += written; - if (! out_bytes_held) + if (!out_bytes_held) break; - UNLOCK_MINOR; - cop->period_wait (); - LOCK_MINOR; + lock.minor.unlock(); + cop->period_wait(); + lock.minor.lock(); } } -/* assumes LOCK_ALL, s_input, s_output */ -static bool process_audio (const void * data, int size, int stop_time) +static bool process_audio(UnsafeLock & lock, const void * data, int size, + int stop_time) { - int samples = size / FMT_SIZEOF (in_format); + assert(state.input() && state.output()); + + int samples = size / FMT_SIZEOF(in_format); bool stopped = false; if (stop_time != -1) { - int64_t frames_left = aud::rescale (stop_time - seek_time, 1000, in_rate) - in_frames; - int64_t samples_left = in_channels * aud::max ((int64_t) 0, frames_left); + int64_t frames_left = + aud::rescale(stop_time - seek_time, 1000, in_rate) - + in_frames; + int64_t samples_left = in_channels * aud::max((int64_t)0, frames_left); if (samples >= samples_left) { @@ -387,403 +497,346 @@ static bool process_audio (const void * data, int size, int stop_time) in_frames += samples / in_channels; - buffer1.resize (samples); + buffer1.resize(samples); if (in_format == FMT_FLOAT) - memcpy (buffer1.begin (), data, sizeof (float) * samples); + memcpy(buffer1.begin(), data, sizeof(float) * samples); else - audio_from_int (data, in_format, buffer1.begin (), samples); + audio_from_int(data, in_format, buffer1.begin(), samples); - if (s_secondary && record_stream == OutputStream::AsDecoded) - write_secondary (buffer1); + if (state.secondary() && record_stream == OutputStream::AsDecoded) + write_secondary(lock, buffer1); - apply_replay_gain (buffer1); + apply_replay_gain(lock, buffer1); - if (s_secondary && record_stream == OutputStream::AfterReplayGain) - write_secondary (buffer1); + if (state.secondary() && record_stream == OutputStream::AfterReplayGain) + write_secondary(lock, buffer1); - write_output (effect_process (buffer1)); + write_output(lock, effect_process(buffer1)); - return ! stopped; + return !stopped; } -/* assumes LOCK_ALL, s_output */ -static void finish_effects (bool end_of_playlist) +static void finish_effects(UnsafeLock & lock, bool end_of_playlist) { - buffer1.resize (0); - write_output (effect_finish (buffer1, end_of_playlist)); + assert(state.output()); + + buffer1.resize(0); + write_output(lock, effect_finish(buffer1, end_of_playlist)); } -bool output_open_audio (const String & filename, const Tuple & tuple, - int format, int rate, int channels, int start_time) +bool output_open_audio(const String & filename, const Tuple & tuple, int format, + int rate, int channels, int start_time, bool pause) { /* prevent division by zero */ if (rate < 1 || channels < 1 || channels > AUD_MAX_CHANNELS) return false; - LOCK_ALL; + auto lock = state.lock_unsafe(); - if (s_output && s_paused) - { - effect_flush (true); - cleanup_output (); - } + state.set_input(lock, true); + state.set_flushed(lock, false); - s_input = true; - s_gain = s_paused = s_flushed = false; seek_time = start_time; + gain_info_valid = false; in_filename = filename; - in_tuple = tuple.ref (); + in_tuple = tuple.ref(); in_format = format; in_channels = channels; in_rate = rate; in_frames = 0; - setup_effects (); - setup_output (true); + setup_effects(lock); + setup_output(lock, true, pause); - if (aud_get_bool (0, "record")) - setup_secondary (true); + if (aud_get_bool("record")) + setup_secondary(lock, true); - UNLOCK_ALL; return true; } -void output_set_tuple (const Tuple & tuple) +void output_set_tuple(const Tuple & tuple) { - LOCK_MINOR; - - if (s_input) - in_tuple = tuple.ref (); + auto lock = state.lock_safe(); - UNLOCK_MINOR; + if (state.input()) + in_tuple = tuple.ref(); } -void output_set_replay_gain (const ReplayGainInfo & info) +void output_set_replay_gain(const ReplayGainInfo & info) { - LOCK_ALL; + auto lock = state.lock_safe(); - if (s_input) + if (state.input()) { gain_info = info; - s_gain = true; + gain_info_valid = true; - AUDINFO ("Replay Gain info:\n"); - AUDINFO (" album gain: %f dB\n", info.album_gain); - AUDINFO (" album peak: %f\n", info.album_peak); - AUDINFO (" track gain: %f dB\n", info.track_gain); - AUDINFO (" track peak: %f\n", info.track_peak); + AUDINFO("Replay Gain info:\n"); + AUDINFO(" album gain: %f dB\n", info.album_gain); + AUDINFO(" album peak: %f\n", info.album_peak); + AUDINFO(" track gain: %f dB\n", info.track_gain); + AUDINFO(" track peak: %f\n", info.track_peak); } - - UNLOCK_ALL; } /* returns false if stop_time is reached */ -bool output_write_audio (const void * data, int size, int stop_time) +bool output_write_audio(const void * data, int size, int stop_time) { -RETRY: - LOCK_ALL; - bool good = false; - - if (s_input && ! s_flushed) + while (1) { - if (! s_output || s_paused || s_resetting) - { - UNLOCK_MAJOR; - WAIT_MINOR; - UNLOCK_MINOR; - goto RETRY; - } + auto lock = state.lock_unsafe(); + if (!state.input() || state.flushed()) + return false; - good = process_audio (data, size, stop_time); - } + if (state.output() && !state.resetting()) + return process_audio(lock, data, size, stop_time); - UNLOCK_ALL; - return good; + lock.major.unlock(); + state.await_change(lock); + } } -void output_flush (int time, bool force) +void output_flush(int time, bool force) { - LOCK_MINOR; + auto lock = state.lock_safe(); - if (s_input && ! s_flushed) + if (state.input() || state.output()) { - if (s_output && ! s_resetting) - { - // allow effect plugins to prevent the flush, but - // always flush if paused to prevent locking up - if (effect_flush (s_paused || force)) - { - flush_output (); - s_flushed = true; - if (s_paused) - SIGNAL_MINOR; - } - } - else - { - s_flushed = true; - SIGNAL_MINOR; - } + // allow effect plugins to prevent the flush, but + // always flush if paused to prevent locking up + bool flush = effect_flush(state.paused() || force); + if (flush && state.output()) + flush_output(lock); } - if (s_input) + if (state.input()) { + state.set_flushed(lock, true); seek_time = time; in_frames = 0; } - - UNLOCK_MINOR; } -void output_resume () +void output_resume() { - LOCK_ALL; + auto lock = state.lock_safe(); - if (s_input) - s_flushed = false; - - UNLOCK_ALL; + if (state.input()) + state.set_flushed(lock, false); } -void output_pause (bool pause) +void output_pause(bool pause) { - LOCK_MINOR; - - if (s_input && s_paused != pause) - { - s_paused = pause; - - if (s_output) - { - apply_pause (); - if (! s_paused && ! s_flushed && ! s_resetting) - SIGNAL_MINOR; - } - } + auto lock = state.lock_safe(); - UNLOCK_MINOR; + if (state.input()) + apply_pause(lock, pause); } -int output_get_time () +int output_get_time() { - LOCK_MINOR; + auto lock = state.lock_safe(); int time = 0, delay = 0; - if (s_input) + if (state.input()) { - if (s_output) + if (state.output()) { - delay = cop->get_delay (); - delay += aud::rescale (out_bytes_held, out_bytes_per_sec, 1000); + delay = cop->get_delay(); + delay += + aud::rescale(out_bytes_held, out_bytes_per_sec, 1000); } - delay = effect_adjust_delay (delay); - time = aud::rescale (in_frames, in_rate, 1000); - time = seek_time + aud::max (time - delay, 0); + delay = effect_adjust_delay(delay); + time = aud::rescale(in_frames, in_rate, 1000); + time = seek_time + aud::max(time - delay, 0); } - UNLOCK_MINOR; return time; } -int output_get_raw_time () +int output_get_raw_time() { - LOCK_MINOR; + auto lock = state.lock_safe(); int time = 0; - if (s_output) + if (state.output()) { - time = aud::rescale (out_bytes_written, out_bytes_per_sec, 1000); - time = aud::max (time - cop->get_delay (), 0); + time = + aud::rescale(out_bytes_written, out_bytes_per_sec, 1000); + time = aud::max(time - cop->get_delay(), 0); } - UNLOCK_MINOR; return time; } -void output_close_audio () +void output_close_audio() { - LOCK_ALL; + auto lock = state.lock_unsafe(); - if (s_input) + if (state.input()) { - s_input = false; - in_filename = String (); - in_tuple = Tuple (); + state.set_input(lock, false); + in_filename = String(); + in_tuple = Tuple(); - if (s_output && ! (s_paused || s_flushed || s_resetting)) - finish_effects (false); /* first time for end of song */ + if (state.output()) + finish_effects(lock, false); /* first time for end of song */ } - - UNLOCK_ALL; } -void output_drain () +void output_drain() { - LOCK_ALL; + auto lock = state.lock_unsafe(); - if (! s_input) + if (!state.input()) { - if (s_output) - finish_effects (true); /* second time for end of playlist */ + if (state.output()) + finish_effects(lock, true); /* second time for end of playlist */ - cleanup_output (); - cleanup_secondary (); + cleanup_output(lock); + cleanup_secondary(lock); } - - UNLOCK_ALL; } -static void output_reset (OutputReset type, OutputPlugin * op) +static void output_reset(OutputReset type, OutputPlugin * op) { - LOCK_MINOR; + auto lock1 = state.lock_safe(); - s_resetting = true; + state.set_resetting(lock1, true); - if (s_output && ! s_flushed) - flush_output (); + if (state.output()) + flush_output(lock1); - UNLOCK_MINOR; - LOCK_ALL; + lock1.minor.unlock(); + auto lock2 = state.lock_unsafe(); if (type != OutputReset::EffectsOnly) - cleanup_output (); + cleanup_output(lock2); /* this does not reset the secondary plugin */ if (type == OutputReset::ResetPlugin) { if (cop) - cop->cleanup (); + cop->cleanup(); if (op) { /* secondary plugin may become primary */ if (op == sop) { - cleanup_secondary (); + cleanup_secondary(lock2); sop = nullptr; } - else if (! op->init ()) + else if (!op->init()) op = nullptr; } cop = op; } - if (s_input) + if (state.input()) { if (type == OutputReset::EffectsOnly) - setup_effects (); + setup_effects(lock2); - setup_output (false); + setup_output(lock2, false, state.paused()); - if (aud_get_bool (0, "record")) - setup_secondary (false); + if (aud_get_bool("record")) + setup_secondary(lock2, false); } - s_resetting = false; - - if (s_output && ! s_paused && ! s_flushed) - SIGNAL_MINOR; - - UNLOCK_ALL; + state.set_resetting(lock2, false); } -EXPORT void aud_output_reset (OutputReset type) -{ - output_reset (type, cop); -} +EXPORT void aud_output_reset(OutputReset type) { output_reset(type, cop); } -EXPORT StereoVolume aud_drct_get_volume () +EXPORT StereoVolume aud_drct_get_volume() { + auto lock = state.lock_safe(); StereoVolume volume = {0, 0}; - LOCK_MINOR; - if (aud_get_bool (0, "software_volume_control")) - volume = {aud_get_int (0, "sw_volume_left"), aud_get_int (0, "sw_volume_right")}; + if (aud_get_bool("software_volume_control")) + volume = {aud_get_int("sw_volume_left"), + aud_get_int("sw_volume_right")}; else if (cop) - volume = cop->get_volume (); + volume = cop->get_volume(); - UNLOCK_MINOR; return volume; } -EXPORT void aud_drct_set_volume (StereoVolume volume) +EXPORT void aud_drct_set_volume(StereoVolume volume) { - LOCK_MINOR; + auto lock = state.lock_safe(); - volume.left = aud::clamp (volume.left, 0, 100); - volume.right = aud::clamp (volume.right, 0, 100); + volume.left = aud::clamp(volume.left, 0, 100); + volume.right = aud::clamp(volume.right, 0, 100); - if (aud_get_bool (0, "software_volume_control")) + if (aud_get_bool("software_volume_control")) { - aud_set_int (0, "sw_volume_left", volume.left); - aud_set_int (0, "sw_volume_right", volume.right); + aud_set_int("sw_volume_left", volume.left); + aud_set_int("sw_volume_right", volume.right); } else if (cop) - cop->set_volume (volume); - - UNLOCK_MINOR; + cop->set_volume(volume); } -PluginHandle * output_plugin_get_current () +PluginHandle * output_plugin_get_current() { - return cop ? aud_plugin_by_header (cop) : nullptr; + return cop ? aud_plugin_by_header(cop) : nullptr; } -PluginHandle * output_plugin_get_secondary () +PluginHandle * output_plugin_get_secondary() { - return sop ? aud_plugin_by_header (sop) : nullptr; + return sop ? aud_plugin_by_header(sop) : nullptr; } -bool output_plugin_set_current (PluginHandle * plugin) +bool output_plugin_set_current(PluginHandle * plugin) { - output_reset (OutputReset::ResetPlugin, plugin ? - (OutputPlugin *) aud_plugin_get_header (plugin) : nullptr); - return (! plugin || cop); + output_reset(OutputReset::ResetPlugin, + plugin ? (OutputPlugin *)aud_plugin_get_header(plugin) + : nullptr); + return (!plugin || cop); } -bool output_plugin_set_secondary (PluginHandle * plugin) +bool output_plugin_set_secondary(PluginHandle * plugin) { - LOCK_MINOR; + auto lock = state.lock_safe(); - cleanup_secondary (); + cleanup_secondary(lock); if (sop) - sop->cleanup (); + sop->cleanup(); - sop = plugin ? (OutputPlugin *) aud_plugin_get_header (plugin) : nullptr; - if (sop && ! sop->init ()) + sop = plugin ? (OutputPlugin *)aud_plugin_get_header(plugin) : nullptr; + if (sop && !sop->init()) sop = nullptr; - if (s_input && aud_get_bool (0, "record")) - setup_secondary (false); + if (state.input() && aud_get_bool("record")) + setup_secondary(lock, false); - UNLOCK_MINOR; - return (! plugin || sop); + return (!plugin || sop); } -static void record_settings_changed (void *, void *) +static void record_settings_changed(void *, void *) { - LOCK_MINOR; + auto lock = state.lock_safe(); - if (s_input && aud_get_bool (0, "record")) - setup_secondary (false); + if (state.input() && aud_get_bool("record")) + setup_secondary(lock, false); else - cleanup_secondary (); - - UNLOCK_MINOR; + cleanup_secondary(lock); } -void output_init () +void output_init() { - hook_associate ("set record", record_settings_changed, nullptr); - hook_associate ("set record_stream", record_settings_changed, nullptr); + hook_associate("set record", record_settings_changed, nullptr); + hook_associate("set record_stream", record_settings_changed, nullptr); } -void output_cleanup () +void output_cleanup() { - hook_dissociate ("set record", record_settings_changed); - hook_dissociate ("set record_stream", record_settings_changed); + hook_dissociate("set record", record_settings_changed); + hook_dissociate("set record_stream", record_settings_changed); } diff --git a/src/libaudcore/output.h b/src/libaudcore/output.h index a9fafee..7f6e06f 100644 --- a/src/libaudcore/output.h +++ b/src/libaudcore/output.h @@ -26,26 +26,26 @@ class PluginHandle; class Tuple; -void output_init (); -void output_cleanup (); - -bool output_open_audio (const String & filename, const Tuple & tuple, - int format, int rate, int channels, int start_time); -void output_set_tuple (const Tuple & tuple); -void output_set_replay_gain (const ReplayGainInfo & info); -bool output_write_audio (const void * data, int size, int stop_time); -void output_flush (int time, bool force = false); -void output_resume (); -void output_pause (bool pause); - -int output_get_time (); -int output_get_raw_time (); -void output_close_audio (); -void output_drain (); - -PluginHandle * output_plugin_get_current (); -PluginHandle * output_plugin_get_secondary (); -bool output_plugin_set_current (PluginHandle * plugin); -bool output_plugin_set_secondary (PluginHandle * plugin); +void output_init(); +void output_cleanup(); + +bool output_open_audio(const String & filename, const Tuple & tuple, int format, + int rate, int channels, int start_time, bool pause); +void output_set_tuple(const Tuple & tuple); +void output_set_replay_gain(const ReplayGainInfo & info); +bool output_write_audio(const void * data, int size, int stop_time); +void output_flush(int time, bool force = false); +void output_resume(); +void output_pause(bool pause); + +int output_get_time(); +int output_get_raw_time(); +void output_close_audio(); +void output_drain(); + +PluginHandle * output_plugin_get_current(); +PluginHandle * output_plugin_get_secondary(); +bool output_plugin_set_current(PluginHandle * plugin); +bool output_plugin_set_secondary(PluginHandle * plugin); #endif diff --git a/src/libaudcore/parse.cc b/src/libaudcore/parse.cc index 9450e72..ab6c5f3 100644 --- a/src/libaudcore/parse.cc +++ b/src/libaudcore/parse.cc @@ -20,32 +20,31 @@ #include "parse.h" #include -void TextParser::next () +void TextParser::next() { m_val = nullptr; - if (! fgets (m_key, sizeof m_key, m_file)) + if (!fgets(m_key, sizeof m_key, m_file)) return; - char * space = strchr (m_key, ' '); - if (! space) + char * space = strchr(m_key, ' '); + if (!space) return; - * space = 0; + *space = 0; m_val = space + 1; - char * newline = strchr (m_val, '\n'); + char * newline = strchr(m_val, '\n'); if (newline) - * newline = 0; + *newline = 0; } -bool TextParser::get_int (const char * key, int & val) const +bool TextParser::get_int(const char * key, int & val) const { - return (m_val && ! strcmp (m_key, key) && sscanf (m_val, "%d", & val) == 1); + return (m_val && !strcmp(m_key, key) && sscanf(m_val, "%d", &val) == 1); } -String TextParser::get_str (const char * key) const +String TextParser::get_str(const char * key) const { - return (m_val && ! strcmp (m_key, key)) ? String (m_val) : String (); + return (m_val && !strcmp(m_key, key)) ? String(m_val) : String(); } - diff --git a/src/libaudcore/parse.h b/src/libaudcore/parse.h index 0dc63e4..c1f96b3 100644 --- a/src/libaudcore/parse.h +++ b/src/libaudcore/parse.h @@ -20,24 +20,21 @@ #ifndef LIBAUDCORE_PARSE_H #define LIBAUDCORE_PARSE_H -#include #include "objects.h" +#include // simplistic key-value file parser // used for playlist-state and plugin-registry files class TextParser { public: - TextParser (FILE * file) : - m_file (file) - { next (); } + TextParser(FILE * file) : m_file(file) { next(); } - void next (); - bool eof () const - { return ! m_val; } + void next(); + bool eof() const { return !m_val; } - bool get_int (const char * key, int & val) const; - String get_str (const char * key) const; + bool get_int(const char * key, int & val) const; + String get_str(const char * key) const; private: FILE * m_file; diff --git a/src/libaudcore/playback.cc b/src/libaudcore/playback.cc index ce8be6c..321db52 100644 --- a/src/libaudcore/playback.cc +++ b/src/libaudcore/playback.cc @@ -38,7 +38,6 @@ #include "internal.h" #include -#include #include "audstrings.h" #include "hook.h" @@ -48,25 +47,29 @@ #include "output.h" #include "playlist-internal.h" #include "plugin.h" -#include "plugins.h" #include "plugins-internal.h" +#include "plugins.h" #include "runtime.h" +#include "threads.h" -struct PlaybackState { +struct PlaybackState +{ bool playing = false; bool thread_running = false; int control_serial = 0; int playback_serial = 0; }; -struct PlaybackControl { +struct PlaybackControl +{ bool paused = false; int seek = -1; int repeat_a = -1; int repeat_b = -1; }; -struct PlaybackInfo { +struct PlaybackInfo +{ // set by playback_set_info int entry = -1; Tuple tuple; @@ -78,7 +81,7 @@ struct PlaybackInfo { int time_offset = 0; int stop_time = -1; - ReplayGainInfo gain {}; + ReplayGainInfo gain{}; bool gain_valid = false; int bitrate = 0; @@ -91,8 +94,8 @@ struct PlaybackInfo { String error_s; }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static aud::mutex mutex; +static aud::condvar cond; static PlaybackState pb_state; static PlaybackControl pb_control; @@ -102,258 +105,261 @@ static QueuedFunc end_queue; static bool song_finished = false; static int failed_entries = 0; -static void lock () - { pthread_mutex_lock (& mutex); } -static void unlock () - { pthread_mutex_unlock (& mutex); } - -static bool lock_if (bool (* test) ()) +// check that the playback thread is not lagging +static bool in_sync(aud::mutex::holder &) { - lock (); - if (test ()) - return true; - - unlock (); - return false; + return pb_state.playing && + pb_state.control_serial == pb_state.playback_serial; } -// check that the playback thread is not lagging -static bool in_sync () - { return pb_state.playing && pb_state.control_serial == pb_state.playback_serial; } - // check that the playback thread is not lagging and playback is "ready" -static bool is_ready () - { return in_sync () && pb_info.ready; } +static bool is_ready(aud::mutex::holder & mh) +{ + return in_sync(mh) && pb_info.ready; +} // called by playback_entry_set_tuple() to ensure that the tuple still applies // to the current song from the perspective of the main/playlist thread; the // check is necessary because playback_entry_set_tuple() is itself called from // the playback thread -bool playback_check_serial (int serial) +bool playback_check_serial(int serial) { - lock (); - bool okay = (pb_state.playing && pb_state.control_serial == serial); - unlock (); - return okay; + auto mh = mutex.take(); + return pb_state.playing && pb_state.control_serial == serial; } // called from the playlist to update the tuple for the current song -void playback_set_info (int entry, Tuple && tuple) +void playback_set_info(int entry, Tuple && tuple) { // do nothing if the playback thread is lagging behind; // in that case, playback_set_info() will get called again anyway - if (! lock_if (in_sync)) + auto mh = mutex.take(); + if (!in_sync(mh)) return; - if (tuple.valid () && tuple != pb_info.tuple) + if (tuple.valid() && tuple != pb_info.tuple) { - pb_info.tuple = std::move (tuple); + pb_info.tuple = std::move(tuple); // don't call "tuple change" before "playback ready" - if (is_ready ()) + if (is_ready(mh)) { - event_queue ("tuple change", nullptr); - output_set_tuple (pb_info.tuple); + event_queue("tuple change", nullptr); + output_set_tuple(pb_info.tuple); } } - String title = pb_info.tuple.get_str (Tuple::FormattedTitle); + String title = pb_info.tuple.get_str(Tuple::FormattedTitle); if (entry != pb_info.entry || title != pb_info.title) { pb_info.entry = entry; pb_info.title = title; // don't call "title change" before "playback ready" - if (is_ready ()) - event_queue ("title change", nullptr); + if (is_ready(mh)) + event_queue("title change", nullptr); } - - unlock (); } // cleanup common to both playback_play() and playback_stop() -static void playback_cleanup_locked () +static void playback_cleanup(aud::mutex::holder &) { pb_state.playing = false; - pb_control = PlaybackControl (); - - // discard audio buffer if the song did not end on its own - if (! song_finished) - output_flush (0); + pb_control = PlaybackControl(); // miscellaneous cleanup - end_queue.stop (); + end_queue.stop(); song_finished = false; - event_queue_cancel ("playback ready"); - event_queue_cancel ("playback pause"); - event_queue_cancel ("playback unpause"); - event_queue_cancel ("playback seek"); - event_queue_cancel ("info change"); - event_queue_cancel ("title change"); - event_queue_cancel ("tuple change"); + event_queue_cancel("playback ready"); + event_queue_cancel("playback pause"); + event_queue_cancel("playback unpause"); + event_queue_cancel("playback seek"); + event_queue_cancel("info change"); + event_queue_cancel("title change"); + event_queue_cancel("tuple change"); - aud_set_bool (nullptr, "stop_after_current_song", false); + aud_set_bool("stop_after_current_song", false); } // main thread: stops playback when no more songs are to be played -void playback_stop (bool exiting) +void playback_stop(bool exiting) { - if (! pb_state.playing && ! exiting) + if (!pb_state.playing && !exiting) return; - lock (); + auto mh = mutex.take(); + + // discard audio buffer on a user-initiated stop + if (!song_finished || exiting) + output_flush(0, exiting); if (pb_state.playing) - playback_cleanup_locked (); + playback_cleanup(mh); if (pb_state.thread_running) { - // discard audio buffer if exiting - if (exiting) - output_flush (0, true); - // signal playback thread to drain audio buffer - pb_state.control_serial ++; - pthread_cond_broadcast (& cond); + pb_state.control_serial++; + cond.notify_all(); // wait for playback thread to finish if exiting while (exiting && pb_state.thread_running) - pthread_cond_wait (& cond, & mutex); + cond.wait(mh); } - unlock (); - // miscellaneous cleanup failed_entries = 0; } // called from top-level event loop after playback finishes -static void end_cb (void *) +static void end_cb(void *) { song_finished = true; - hook_call ("playback end", nullptr); + hook_call("playback end", nullptr); - PlaylistEx playlist = Playlist::playing_playlist (); + PlaylistEx playlist = Playlist::playing_playlist(); - auto do_stop = [playlist] () - { - aud_drct_stop (); - playlist.set_position (playlist.get_position ()); + auto do_stop = [playlist]() { + aud_drct_stop(); + playlist.set_position(playlist.get_position()); }; - auto do_next = [playlist] () - { - if (! playlist.next_song (aud_get_bool (nullptr, "repeat"))) + auto do_next = [playlist]() { + if (!playlist.next_song(aud_get_bool("repeat"))) { - playlist.set_position (-1); - hook_call ("playlist end reached", nullptr); + playlist.set_position(-1); + hook_call("playlist end reached", nullptr); } }; - if (aud_get_bool (nullptr, "no_playlist_advance")) + if (aud_get_bool("no_playlist_advance")) { // we assume here that repeat is not enabled; // single-song repeats are handled in run_playback() - do_stop (); + do_stop(); } - else if (aud_get_bool (nullptr, "stop_after_current_song")) + else if (aud_get_bool("stop_after_current_song")) { - do_stop (); - do_next (); + do_stop(); + do_next(); } else { // if 10 songs in a row have failed, or if the entire playlist // (for playlists less than 10 songs) has failed, stop trying - if (failed_entries < aud::min (playlist.n_entries (), 10)) - do_next (); + if (failed_entries < aud::min(playlist.n_entries(), 10)) + do_next(); else - do_stop (); + do_stop(); } } // helper, can be called from either main or playback thread -static void request_seek_locked (int time) +static void request_seek(aud::mutex::holder & mh, int time) { // set up "seek" command whether ready or not; // if not ready, it will take effect upon open_audio() - pb_control.seek = aud::max (0, time); + pb_control.seek = aud::max(0, time); // trigger seek immediately if ready - if (is_ready () && pb_info.length > 0) + if (is_ready(mh) && pb_info.length > 0) { - output_flush (aud::clamp (time, 0, pb_info.length)); - event_queue ("playback seek", nullptr); + output_flush(aud::clamp(time, 0, pb_info.length)); + event_queue("playback seek", nullptr); } } // playback thread helper -static void run_playback () +static bool setup_playback(const DecodeInfo & dec) { - // due to mutex ordering, we cannot call into the playlist while locked - DecodeInfo dec = playback_entry_read (pb_state.playback_serial); - - if (! lock_if (in_sync)) - return; + auto mh = mutex.take(); + if (!in_sync(mh)) + return false; // for a cuesheet entry, determine the source filename - pb_info.filename = pb_info.tuple.get_str (Tuple::AudioFile); - if (! pb_info.filename) - pb_info.filename = std::move (dec.filename); + pb_info.filename = pb_info.tuple.get_str(Tuple::AudioFile); + if (!pb_info.filename) + pb_info.filename = std::move(dec.filename); // check that we have all the necessary data - if (! pb_info.filename || ! pb_info.tuple.valid () || ! dec.ip || - (! dec.ip->input_info.keys[InputKey::Scheme] && ! dec.file)) + if (!pb_info.filename || !pb_info.tuple.valid() || !dec.ip || + (!dec.ip->input_info.keys[InputKey::Scheme] && !dec.file)) { pb_info.error = true; - pb_info.error_s = std::move (dec.error); - unlock (); - return; + pb_info.error_s = std::move(dec.error); + return false; } // get various other bits of info from the tuple - pb_info.length = pb_info.tuple.get_int (Tuple::Length); - pb_info.time_offset = aud::max (0, pb_info.tuple.get_int (Tuple::StartTime)); - pb_info.stop_time = aud::max (-1, pb_info.tuple.get_int (Tuple::EndTime) - pb_info.time_offset); - pb_info.gain = pb_info.tuple.get_replay_gain (); - pb_info.gain_valid = pb_info.tuple.has_replay_gain (); + pb_info.length = pb_info.tuple.get_int(Tuple::Length); + pb_info.time_offset = aud::max(0, pb_info.tuple.get_int(Tuple::StartTime)); + pb_info.stop_time = aud::max(-1, pb_info.tuple.get_int(Tuple::EndTime) - + pb_info.time_offset); + pb_info.gain = pb_info.tuple.get_replay_gain(); + pb_info.gain_valid = pb_info.tuple.has_replay_gain(); // force initial seek if we are playing a segmented track if (pb_info.time_offset > 0 && pb_control.seek < 0) pb_control.seek = 0; - unlock (); + return true; +} + +// playback thread helper +static bool check_playback_repeat() +{ + auto mh = mutex.take(); + if (!is_ready(mh)) + return false; + + // check whether we need to repeat + if (pb_control.repeat_a >= 0 || + (aud_get_bool("repeat") && aud_get_bool("no_playlist_advance"))) + { + // treat the repeat as a seek (takes effect at open_audio()) + pb_control.seek = pb_control.repeat_a; + + // force initial seek if we are playing a segmented track + if (pb_info.time_offset > 0 && pb_control.seek < 0) + pb_control.seek = 0; + + event_queue("playback seek", nullptr); + pb_info.ended = false; + return true; + } + + pb_info.ended = true; + return false; +} + +// playback thread helper +static void run_playback() +{ + // due to mutex ordering, we cannot call into the playlist while locked + DecodeInfo dec = playback_entry_read(pb_state.playback_serial); + + if (!setup_playback(dec)) + return; while (1) { // hand off control to input plugin - if (! dec.ip->play (pb_info.filename, dec.file)) + if (!dec.ip->play(pb_info.filename, dec.file)) pb_info.error = true; // close audio (no-op if it wasn't opened) - output_close_audio (); + output_close_audio(); if (pb_info.error || pb_info.length <= 0) break; - if (! lock_if (in_sync)) - break; - - // check whether we need to repeat - pb_info.ended = (pb_control.repeat_a < 0 && ! (aud_get_bool (nullptr, - "repeat") && aud_get_bool (nullptr, "no_playlist_advance"))); - - if (! pb_info.ended) - request_seek_locked (pb_control.repeat_a); - - unlock (); - - if (pb_info.ended) + if (!check_playback_repeat()) break; // rewind file pointer before repeating - if (! open_input_file (pb_info.filename, "r", dec.ip, dec.file, & pb_info.error_s)) + if (!open_input_file(pb_info.filename, "r", dec.ip, dec.file, + &pb_info.error_s)) { pb_info.error = true; break; @@ -362,36 +368,37 @@ static void run_playback () } // playback thread helper -static void finish_playback_locked () +static void finish_playback(aud::mutex::holder &) { // record any playback error that occurred if (pb_info.error) { - failed_entries ++; + failed_entries++; if (pb_info.error_s) - aud_ui_show_error (str_printf (_("Error playing %s:\n%s"), - (const char *) pb_info.filename, (const char *) pb_info.error_s)); + aud_ui_show_error(str_printf(_("Error playing %s:\n%s"), + (const char *)pb_info.filename, + (const char *)pb_info.error_s)); else - AUDERR ("Playback finished with error.\n"); + AUDERR("Playback finished with error.\n"); } else failed_entries = 0; // queue up function to start next song (or perform cleanup) - end_queue.queue (end_cb, nullptr); + end_queue.queue(end_cb, nullptr); } // playback thread -static void * playback_thread (void *) +static void playback_thread() { - lock (); + auto mh = mutex.take(); while (1) { // wait for a command while (pb_state.control_serial == pb_state.playback_serial) - pthread_cond_wait (& cond, & mutex); + cond.wait(mh); // fetch the command (either "play" or "drain") bool play = pb_state.playing; @@ -399,22 +406,23 @@ static void * playback_thread (void *) // update playback thread serial number pb_state.playback_serial = pb_state.control_serial; - unlock (); + mh.unlock(); if (play) - run_playback (); + run_playback(); else - output_drain (); + output_drain(); - lock (); + mh.lock(); if (play) { - // don't report errors or queue next song if another command is pending - if (in_sync ()) - finish_playback_locked (); + // don't report errors or queue next song if another command is + // pending + if (in_sync(mh)) + finish_playback(mh); - pb_info = PlaybackInfo (); + pb_info = PlaybackInfo(); } else { @@ -426,135 +434,129 @@ static void * playback_thread (void *) // signal the main thread that we are quitting pb_state.thread_running = false; - pthread_cond_broadcast (& cond); - unlock (); - return nullptr; + cond.notify_all(); } // main thread: starts playback of a new song -void playback_play (int seek_time, bool pause) +void playback_play(int seek_time, bool pause) { - lock (); + auto mh = mutex.take(); + + // discard audio buffer unless progressing to the next song + if (!song_finished) + output_flush(0); if (pb_state.playing) - playback_cleanup_locked (); + playback_cleanup(mh); // set up "play" command pb_state.playing = true; - pb_state.control_serial ++; + pb_state.control_serial++; pb_control.paused = pause; pb_control.seek = (seek_time > 0) ? seek_time : -1; // start playback thread (or signal it if it's already running) if (pb_state.thread_running) - pthread_cond_broadcast (& cond); + cond.notify_all(); else { - pthread_t thread; - pthread_create (& thread, nullptr, playback_thread, nullptr); - pthread_detach (thread); + std::thread(playback_thread).detach(); pb_state.thread_running = true; } - - unlock (); } // main thread -EXPORT void aud_drct_pause () +EXPORT void aud_drct_pause() { - if (! pb_state.playing) + if (!pb_state.playing) return; - lock (); + auto mh = mutex.take(); // set up "pause" command whether ready or not; // if not ready, it will take effect upon open_audio() - bool pause = ! pb_control.paused; + bool pause = !pb_control.paused; pb_control.paused = pause; // apply pause immediately if ready - if (is_ready ()) - output_pause (pause); - - event_queue (pause ? "playback pause" : "playback unpause", nullptr); + if (is_ready(mh)) + output_pause(pause); - unlock (); + event_queue(pause ? "playback pause" : "playback unpause", nullptr); } // main thread -EXPORT void aud_drct_seek (int time) +EXPORT void aud_drct_seek(int time) { - if (! pb_state.playing) + if (!pb_state.playing) return; - lock (); - request_seek_locked (time); - unlock (); + auto mh = mutex.take(); + request_seek(mh, time); } -EXPORT void InputPlugin::open_audio (int format, int rate, int channels) +EXPORT void InputPlugin::open_audio(int format, int rate, int channels) { // don't open audio if playback thread is lagging - if (! lock_if (in_sync)) + auto mh = mutex.take(); + if (!in_sync(mh)) return; - if (! output_open_audio (pb_info.filename, pb_info.tuple, format, rate, - channels, aud::max (0, pb_control.seek))) + if (!output_open_audio(pb_info.filename, pb_info.tuple, format, rate, + channels, aud::max(0, pb_control.seek), + pb_control.paused)) { pb_info.error = true; - pb_info.error_s = String (_("Invalid audio format")); - unlock (); + pb_info.error_s = String(_("Invalid audio format")); return; } if (pb_info.gain_valid) - output_set_replay_gain (pb_info.gain); - if (pb_control.paused) - output_pause (true); + output_set_replay_gain(pb_info.gain); pb_info.samplerate = rate; pb_info.channels = channels; if (pb_info.ready) - event_queue ("info change", nullptr); + event_queue("info change", nullptr); else - event_queue ("playback ready", nullptr); + event_queue("playback ready", nullptr); pb_info.ready = true; - - unlock (); } -EXPORT void InputPlugin::set_replay_gain (const ReplayGainInfo & gain) +EXPORT void InputPlugin::set_replay_gain(const ReplayGainInfo & gain) { - lock (); + auto mh = mutex.take(); + pb_info.gain = gain; pb_info.gain_valid = true; - if (is_ready ()) - output_set_replay_gain (gain); - - unlock (); + if (is_ready(mh)) + output_set_replay_gain(gain); } -EXPORT void InputPlugin::write_audio (const void * data, int length) +EXPORT void InputPlugin::write_audio(const void * data, int length) { - if (! lock_if (in_sync)) + auto mh = mutex.take(); + if (!in_sync(mh)) return; // fetch A-B repeat settings int a = pb_control.repeat_a; int b = pb_control.repeat_b; - unlock (); + mh.unlock(); // it's okay to call output_write_audio() even if we are no longer in sync, // since it will return immediately if output_flush() has been called int stop_time = (b >= 0) ? b : pb_info.stop_time; - if (output_write_audio (data, length, stop_time)) + if (output_write_audio(data, length, stop_time)) return; - if (! lock_if (in_sync)) + mh.lock(); + + if (!in_sync(mh)) return; // if we are still in sync, then one of the following happened: @@ -564,179 +566,152 @@ EXPORT void InputPlugin::write_audio (const void * data, int length) if (pb_control.seek < 0) { if (b >= 0) - request_seek_locked (a); + request_seek(mh, a); else pb_info.ended = true; } - - unlock (); } -EXPORT Tuple InputPlugin::get_playback_tuple () +EXPORT Tuple InputPlugin::get_playback_tuple() { - lock (); - Tuple tuple = pb_info.tuple.ref (); - unlock (); + auto mh = mutex.take(); + Tuple tuple = pb_info.tuple.ref(); // tuples passed to us from input plugins do not have fallback fields // generated; for consistency, tuples passed back should not either - tuple.delete_fallbacks (); + tuple.delete_fallbacks(); return tuple; } -EXPORT void InputPlugin::set_playback_tuple (Tuple && tuple) +EXPORT void InputPlugin::set_playback_tuple(Tuple && tuple) { // due to mutex ordering, we cannot call into the playlist while locked; // instead, playback_entry_set_tuple() calls back into first // playback_check_serial() and then eventually playback_set_info() - playback_entry_set_tuple (pb_state.playback_serial, std::move (tuple)); + playback_entry_set_tuple(pb_state.playback_serial, std::move(tuple)); } -EXPORT void InputPlugin::set_stream_bitrate (int bitrate) +EXPORT void InputPlugin::set_stream_bitrate(int bitrate) { - lock (); + auto mh = mutex.take(); pb_info.bitrate = bitrate; - if (is_ready ()) - event_queue ("info change", nullptr); - - unlock (); + if (is_ready(mh)) + event_queue("info change", nullptr); } -EXPORT bool InputPlugin::check_stop () +EXPORT bool InputPlugin::check_stop() { - lock (); - bool stop = ! is_ready () || pb_info.ended || pb_info.error; - unlock (); - return stop; + auto mh = mutex.take(); + return !is_ready(mh) || pb_info.ended || pb_info.error; } -EXPORT int InputPlugin::check_seek () +EXPORT int InputPlugin::check_seek() { - lock (); + auto mh = mutex.take(); int seek = -1; - if (is_ready () && pb_control.seek >= 0 && pb_info.length > 0) + if (is_ready(mh) && pb_control.seek >= 0 && pb_info.length > 0) { - seek = pb_info.time_offset + aud::min (pb_control.seek, pb_info.length); + seek = pb_info.time_offset + aud::min(pb_control.seek, pb_info.length); pb_control.seek = -1; - output_resume (); + output_resume(); } - unlock (); return seek; } // thread-safe -EXPORT bool aud_drct_get_playing () +EXPORT bool aud_drct_get_playing() { - lock (); - bool playing = pb_state.playing; - unlock (); - return playing; + auto mh = mutex.take(); + return pb_state.playing; } // thread-safe -EXPORT bool aud_drct_get_ready () +EXPORT bool aud_drct_get_ready() { - lock (); - bool ready = is_ready (); - unlock (); - return ready; + auto mh = mutex.take(); + return is_ready(mh); } // thread-safe -EXPORT bool aud_drct_get_paused () +EXPORT bool aud_drct_get_paused() { - lock (); - bool paused = pb_control.paused; - unlock (); - return paused; + auto mh = mutex.take(); + return pb_control.paused; } // thread-safe -EXPORT String aud_drct_get_title () +EXPORT String aud_drct_get_title() { - if (! lock_if (is_ready)) - return String (); - - String title = pb_info.title; - int entry = pb_info.entry; - int length = pb_info.length; - - unlock (); + auto mh = mutex.take(); + if (!is_ready(mh)) + return String(); - StringBuf prefix = aud_get_bool (nullptr, "show_numbers_in_pl") ? - str_printf ("%d. ", 1 + entry) : StringBuf (0); + StringBuf prefix = aud_get_bool("show_numbers_in_pl") + ? str_printf("%d. ", 1 + pb_info.entry) + : StringBuf(0); - StringBuf time = (length > 0) ? str_format_time (length) : StringBuf (); - StringBuf suffix = time ? str_concat ({" (", time, ")"}) : StringBuf (0); + StringBuf time = + (pb_info.length > 0) ? str_format_time(pb_info.length) : StringBuf(); + StringBuf suffix = time ? str_concat({" (", time, ")"}) : StringBuf(0); - return String (str_concat ({prefix, title, suffix})); + return String(str_concat({prefix, pb_info.title, suffix})); } // thread-safe -EXPORT Tuple aud_drct_get_tuple () +EXPORT Tuple aud_drct_get_tuple() { - lock (); - Tuple tuple = is_ready () ? pb_info.tuple.ref () : Tuple (); - unlock (); - return tuple; + auto mh = mutex.take(); + return is_ready(mh) ? pb_info.tuple.ref() : Tuple(); } // thread-safe -EXPORT void aud_drct_get_info (int & bitrate, int & samplerate, int & channels) +EXPORT void aud_drct_get_info(int & bitrate, int & samplerate, int & channels) { - lock (); + auto mh = mutex.take(); + bool ready = is_ready(mh); - bool ready = is_ready (); bitrate = ready ? pb_info.bitrate : 0; samplerate = ready ? pb_info.samplerate : 0; channels = ready ? pb_info.channels : 0; - - unlock (); } // thread-safe -EXPORT int aud_drct_get_time () +EXPORT int aud_drct_get_time() { - lock (); - int time = is_ready () ? output_get_time () : 0; - unlock (); - return time; + auto mh = mutex.take(); + return is_ready(mh) ? output_get_time() : 0; } // thread-safe -EXPORT int aud_drct_get_length () +EXPORT int aud_drct_get_length() { - lock (); - int length = is_ready () ? pb_info.length : -1; - unlock (); - return length; + auto mh = mutex.take(); + return is_ready(mh) ? pb_info.length : -1; } // main thread -EXPORT void aud_drct_set_ab_repeat (int a, int b) +EXPORT void aud_drct_set_ab_repeat(int a, int b) { - if (! pb_state.playing) + if (!pb_state.playing) return; - lock (); + auto mh = mutex.take(); pb_control.repeat_a = a; pb_control.repeat_b = b; - if (b >= 0 && is_ready () && output_get_time () >= b) - request_seek_locked (a); - - unlock (); + if (b >= 0 && is_ready(mh) && output_get_time() >= b) + request_seek(mh, a); } // thread-safe -EXPORT void aud_drct_get_ab_repeat (int & a, int & b) +EXPORT void aud_drct_get_ab_repeat(int & a, int & b) { - lock (); + auto mh = mutex.take(); + a = pb_control.repeat_a; b = pb_control.repeat_b; - unlock (); } diff --git a/src/libaudcore/playlist-cache.cc b/src/libaudcore/playlist-cache.cc index fe371ac..1cf8035 100644 --- a/src/libaudcore/playlist-cache.cc +++ b/src/libaudcore/playlist-cache.cc @@ -17,72 +17,63 @@ * the use of this software. */ -#include "playlist-internal.h" #include "mainloop.h" #include "multihash.h" - -#include +#include "playlist-internal.h" +#include "threads.h" static SimpleHash cache; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static QueuedFunc clear_timer; -EXPORT void Playlist::cache_selected () const +EXPORT void Playlist::cache_selected() const { - pthread_mutex_lock (& mutex); - - int entries = n_entries (); + auto mh = mutex.take(); + int entries = n_entries(); - for (int i = 0; i < entries; i ++) + for (int i = 0; i < entries; i++) { - if (! entry_selected (i)) + if (!entry_selected(i)) continue; - String filename = entry_filename (i); - Tuple tuple = entry_tuple (i, NoWait); - PluginHandle * decoder = entry_decoder (i, NoWait); + String filename = entry_filename(i); + Tuple tuple = entry_tuple(i, NoWait); + PluginHandle * decoder = entry_decoder(i, NoWait); - if (tuple.valid () || decoder) - cache.add (filename, {filename, std::move (tuple), decoder}); + if (tuple.valid() || decoder) + cache.add(filename, {filename, std::move(tuple), decoder}); } - clear_timer.queue (30000, playlist_cache_clear, nullptr); - - pthread_mutex_unlock (& mutex); + clear_timer.queue(30000, playlist_cache_clear, nullptr); } -void playlist_cache_load (Index & items) +void playlist_cache_load(Index & items) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! cache.n_items ()) - goto out; + if (!cache.n_items()) + return; for (auto & item : items) { - if (item.tuple.valid () && item.decoder) + if (item.tuple.valid() && item.decoder) continue; - auto node = cache.lookup (item.filename); - if (! node) + auto node = cache.lookup(item.filename); + if (!node) continue; - if (! item.tuple.valid () && node->tuple.valid ()) - item.tuple = node->tuple.ref (); - if (! item.decoder && node->decoder) + if (!item.tuple.valid() && node->tuple.valid()) + item.tuple = node->tuple.ref(); + if (!item.decoder && node->decoder) item.decoder = node->decoder; } - -out: - pthread_mutex_unlock (& mutex); } -void playlist_cache_clear (void *) +void playlist_cache_clear(void *) { - pthread_mutex_lock (& mutex); - - cache.clear (); - clear_timer.stop (); + auto mh = mutex.take(); - pthread_mutex_unlock (& mutex); + cache.clear(); + clear_timer.stop(); } diff --git a/src/libaudcore/playlist-data.cc b/src/libaudcore/playlist-data.cc index dd3a3d5..923e6f1 100644 --- a/src/libaudcore/playlist-data.cc +++ b/src/libaudcore/playlist-data.cc @@ -26,16 +26,21 @@ #include "scanner.h" #include "tuple-compiler.h" +#define NO_POS \ + { \ + -1, false \ + } + static TupleCompiler s_tuple_formatter; static bool s_use_tuple_fallbacks = false; struct PlaylistEntry { - PlaylistEntry (PlaylistAddItem && item); - ~PlaylistEntry (); + PlaylistEntry(PlaylistAddItem && item); + ~PlaylistEntry(); - void format (); - void set_tuple (Tuple && new_tuple); + void format(); + void set_tuple(Tuple && new_tuple); String filename; PluginHandle * decoder; @@ -47,207 +52,202 @@ struct PlaylistEntry bool selected, queued; }; -void PlaylistEntry::format () +void PlaylistEntry::format() { - tuple.delete_fallbacks (); + tuple.delete_fallbacks(); if (s_use_tuple_fallbacks) - tuple.generate_fallbacks (); + tuple.generate_fallbacks(); else - tuple.generate_title (); + tuple.generate_title(); - s_tuple_formatter.format (tuple); + s_tuple_formatter.format(tuple); } -void PlaylistEntry::set_tuple (Tuple && new_tuple) +void PlaylistEntry::set_tuple(Tuple && new_tuple) { /* Since 3.8, cuesheet entries are handled differently. The entry filename * points to the .cue file, and the path to the actual audio file is stored * in the Tuple::AudioFile. If Tuple::AudioFile is not set, then assume * that the playlist was created by an older version of Audacious, and * revert to the former behavior (don't refresh this entry). */ - if (tuple.is_set (Tuple::StartTime) && ! tuple.is_set (Tuple::AudioFile)) + if (tuple.is_set(Tuple::StartTime) && !tuple.is_set(Tuple::AudioFile)) return; - error = String (); + error = String(); - if (! new_tuple.valid ()) - new_tuple.set_filename (filename); + if (!new_tuple.valid()) + new_tuple.set_filename(filename); - length = aud::max (0, new_tuple.get_int (Tuple::Length)); - tuple = std::move (new_tuple); + length = aud::max(0, new_tuple.get_int(Tuple::Length)); + tuple = std::move(new_tuple); - format (); + format(); } -PlaylistEntry::PlaylistEntry (PlaylistAddItem && item) : - filename (item.filename), - decoder (item.decoder), - number (-1), - length (0), - shuffle_num (0), - selected (false), - queued (false) +PlaylistEntry::PlaylistEntry(PlaylistAddItem && item) + : filename(item.filename), decoder(item.decoder), number(-1), length(0), + shuffle_num(0), selected(false), queued(false) { - set_tuple (std::move (item.tuple)); + set_tuple(std::move(item.tuple)); } -PlaylistEntry::~PlaylistEntry () +PlaylistEntry::~PlaylistEntry() { pl_signal_entry_deleted(this); } + +void PlaylistData::update_formatter() // static { - pl_signal_entry_deleted (this); + s_tuple_formatter.compile(aud_get_str("generic_title_format")); + s_use_tuple_fallbacks = aud_get_bool("metadata_fallbacks"); } -void PlaylistData::update_formatter () // static +void PlaylistData::cleanup_formatter() // static { - s_tuple_formatter.compile (aud_get_str (nullptr, "generic_title_format")); - s_use_tuple_fallbacks = aud_get_bool (nullptr, "metadata_fallbacks"); + s_tuple_formatter.reset(); } -void PlaylistData::cleanup_formatter () // static - { s_tuple_formatter.reset (); } - -void PlaylistData::delete_entry (PlaylistEntry * entry) // static - { delete entry; } - -PlaylistData::PlaylistData (Playlist::ID * id, const char * title) : - modified (true), - scan_status (NotScanning), - title (title), - resume_time (0), - m_id (id), - m_position (nullptr), - m_focus (nullptr), - m_selected_count (0), - m_last_shuffle_num (0), - m_total_length (0), - m_selected_length (0), - m_last_update (), - m_next_update (), - m_position_changed (false) {} +void PlaylistData::delete_entry(PlaylistEntry * entry) // static +{ + delete entry; +} -PlaylistData::~PlaylistData () +PlaylistData::PlaylistData(Playlist::ID * id, const char * title) + : modified(true), scan_status(NotScanning), title(title), resume_time(0), + m_id(id), m_position(nullptr), m_focus(nullptr), m_selected_count(0), + m_last_shuffle_num(0), m_total_length(0), m_selected_length(0), + m_last_update(), m_next_update(), m_position_changed(false) { - pl_signal_playlist_deleted (m_id); } -void PlaylistData::number_entries (int at, int length) +PlaylistData::~PlaylistData() { pl_signal_playlist_deleted(m_id); } + +void PlaylistData::number_entries(int at, int length) { - for (int i = at; i < at + length; i ++) + for (int i = at; i < at + length; i++) m_entries[i]->number = i; } -PlaylistEntry * PlaylistData::entry_at (int i) +PlaylistEntry * PlaylistData::entry_at(int i) { - return (i >= 0 && i < m_entries.len ()) ? m_entries[i].get () : nullptr; + return (i >= 0 && i < m_entries.len()) ? m_entries[i].get() : nullptr; } -const PlaylistEntry * PlaylistData::entry_at (int i) const +const PlaylistEntry * PlaylistData::entry_at(int i) const { - return (i >= 0 && i < m_entries.len ()) ? m_entries[i].get () : nullptr; + return (i >= 0 && i < m_entries.len()) ? m_entries[i].get() : nullptr; } -String PlaylistData::entry_filename (int i) const +String PlaylistData::entry_filename(int i) const { - auto entry = entry_at (i); - return entry ? entry->filename : String (); + auto entry = entry_at(i); + return entry ? entry->filename : String(); } -PluginHandle * PlaylistData::entry_decoder (int i, String * error) const +PluginHandle * PlaylistData::entry_decoder(int i, String * error) const { - auto entry = entry_at (i); - if (error) * error = entry ? entry->error : String (); + auto entry = entry_at(i); + if (error) + *error = entry ? entry->error : String(); return entry ? entry->decoder : nullptr; } -Tuple PlaylistData::entry_tuple (int i, String * error) const +Tuple PlaylistData::entry_tuple(int i, String * error) const { - auto entry = entry_at (i); - if (error) * error = entry ? entry->error : String (); - return entry ? entry->tuple.ref () : Tuple (); + auto entry = entry_at(i); + if (error) + *error = entry ? entry->error : String(); + return entry ? entry->tuple.ref() : Tuple(); } -void PlaylistData::set_entry_tuple (PlaylistEntry * entry, Tuple && tuple) +static bool same_album(const Tuple & a, const Tuple & b) +{ + String album = a.get_str(Tuple::Album); + return (album && album == b.get_str(Tuple::Album)); +} + +void PlaylistData::set_entry_tuple(PlaylistEntry * entry, Tuple && tuple) { m_total_length -= entry->length; if (entry->selected) m_selected_length -= entry->length; - entry->set_tuple (std::move (tuple)); + entry->set_tuple(std::move(tuple)); m_total_length += entry->length; if (entry->selected) m_selected_length += entry->length; } -void PlaylistData::queue_update (Playlist::UpdateLevel level, int at, int count, int flags) +void PlaylistData::queue_update(Playlist::UpdateLevel level, int at, int count, + int flags) { if (m_next_update.level) { - m_next_update.level = aud::max (m_next_update.level, level); - m_next_update.before = aud::min (m_next_update.before, at); - m_next_update.after = aud::min (m_next_update.after, m_entries.len () - at - count); + m_next_update.level = aud::max(m_next_update.level, level); + m_next_update.before = aud::min(m_next_update.before, at); + m_next_update.after = + aud::min(m_next_update.after, m_entries.len() - at - count); } else { m_next_update.level = level; m_next_update.before = at; - m_next_update.after = m_entries.len () - at - count; + m_next_update.after = m_entries.len() - at - count; } if ((flags & QueueChanged)) m_next_update.queue_changed = true; - pl_signal_update_queued (m_id, level, flags); + pl_signal_update_queued(m_id, level, flags); } -void PlaylistData::queue_position_change () +void PlaylistData::queue_position_change() { m_position_changed = true; - pl_signal_position_changed (m_id); + pl_signal_position_changed(m_id); } -void PlaylistData::cancel_updates () +void PlaylistData::cancel_updates() { - m_last_update = Playlist::Update (); - m_next_update = Playlist::Update (); + m_last_update = Playlist::Update(); + m_next_update = Playlist::Update(); m_position_changed = false; } -void PlaylistData::swap_updates (bool & position_changed) +void PlaylistData::swap_updates(bool & position_changed) { m_last_update = m_next_update; - m_next_update = Playlist::Update (); + m_next_update = Playlist::Update(); position_changed = m_position_changed; m_position_changed = false; } -void PlaylistData::insert_items (int at, Index && items) +void PlaylistData::insert_items(int at, Index && items) { - int n_entries = m_entries.len (); - int n_items = items.len (); + int n_entries = m_entries.len(); + int n_items = items.len(); if (at < 0 || at > n_entries) at = n_entries; - m_entries.insert (at, n_items); + m_entries.insert(at, n_items); int i = at; for (auto & item : items) { - auto entry = new PlaylistEntry (std::move (item)); - m_entries[i ++].capture (entry); + auto entry = new PlaylistEntry(std::move(item)); + m_entries[i++].capture(entry); m_total_length += entry->length; } - items.clear (); + items.clear(); - number_entries (at, n_entries + n_items - at); - queue_update (Playlist::Structure, at, n_items); + number_entries(at, n_entries + n_items - at); + queue_update(Playlist::Structure, at, n_items); } -void PlaylistData::remove_entries (int at, int number) +void PlaylistData::remove_entries(int at, int number) { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); bool position_changed = false; int update_flags = 0; @@ -256,74 +256,72 @@ void PlaylistData::remove_entries (int at, int number) if (number < 0 || number > n_entries - at) number = n_entries - at; - if (m_position && m_position->number >= at && m_position->number < at + number) + if (m_position && m_position->number >= at && + m_position->number < at + number) { - set_position (nullptr, false); + change_position(NO_POS); position_changed = true; } if (m_focus && m_focus->number >= at && m_focus->number < at + number) { if (at + number < n_entries) - m_focus = m_entries[at + number].get (); + m_focus = m_entries[at + number].get(); else if (at > 0) - m_focus = m_entries[at - 1].get (); + m_focus = m_entries[at - 1].get(); else m_focus = nullptr; } - for (int i = 0; i < number; i ++) + for (int i = 0; i < number; i++) { - PlaylistEntry * entry = m_entries [at + i].get (); + PlaylistEntry * entry = m_entries[at + i].get(); if (entry->queued) { - m_queued.remove (m_queued.find (entry), 1); + m_queued.remove(m_queued.find(entry), 1); update_flags |= QueueChanged; } if (entry->selected) { - m_selected_count --; + m_selected_count--; m_selected_length -= entry->length; } m_total_length -= entry->length; } - m_entries.remove (at, number); + m_entries.remove(at, number); - number_entries (at, n_entries - at - number); - queue_update (Playlist::Structure, at, 0, update_flags); + number_entries(at, n_entries - at - number); + queue_update(Playlist::Structure, at, 0, update_flags); if (position_changed) { - if (aud_get_bool (nullptr, "advance_on_delete")) - next_song_with_hint (aud_get_bool (nullptr, "repeat"), at); + if (aud_get_bool("advance_on_delete")) + change_position_to_next(aud_get_bool("repeat"), at); - queue_position_change (); + queue_position_change(); } } -int PlaylistData::position () const +int PlaylistData::position() const { return m_position ? m_position->number : -1; } -int PlaylistData::focus () const -{ - return m_focus ? m_focus->number : -1; -} +int PlaylistData::focus() const { return m_focus ? m_focus->number : -1; } -bool PlaylistData::entry_selected (int entry_num) const +bool PlaylistData::entry_selected(int entry_num) const { - auto entry = entry_at (entry_num); + auto entry = entry_at(entry_num); return entry ? entry->selected : false; } -int PlaylistData::n_selected (int at, int number) const +int PlaylistData::n_selected(int at, int number) const { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); if (at < 0 || at > n_entries) at = n_entries; @@ -336,68 +334,68 @@ int PlaylistData::n_selected (int at, int number) const n_selected = m_selected_count; else { - for (int i = 0; i < number; i ++) + for (int i = 0; i < number; i++) { if (m_entries[at + i]->selected) - n_selected ++; + n_selected++; } } return n_selected; } -void PlaylistData::set_focus (int entry_num) +void PlaylistData::set_focus(int entry_num) { - auto new_focus = entry_at (entry_num); + auto new_focus = entry_at(entry_num); if (new_focus == m_focus) return; - int first = m_entries.len (); + int first = m_entries.len(); int last = -1; if (m_focus) { - first = aud::min (first, m_focus->number); - last = aud::max (last, m_focus->number); + first = aud::min(first, m_focus->number); + last = aud::max(last, m_focus->number); } m_focus = new_focus; if (m_focus) { - first = aud::min (first, m_focus->number); - last = aud::max (last, m_focus->number); + first = aud::min(first, m_focus->number); + last = aud::max(last, m_focus->number); } if (first <= last) - queue_update (Playlist::Selection, first, last + 1 - first); + queue_update(Playlist::Selection, first, last + 1 - first); } -void PlaylistData::select_entry (int entry_num, bool selected) +void PlaylistData::select_entry(int entry_num, bool selected) { - auto entry = entry_at (entry_num); - if (! entry || entry->selected == selected) + auto entry = entry_at(entry_num); + if (!entry || entry->selected == selected) return; entry->selected = selected; if (selected) { - m_selected_count ++; + m_selected_count++; m_selected_length += entry->length; } else { - m_selected_count --; + m_selected_count--; m_selected_length -= entry->length; } - queue_update (Playlist::Selection, entry_num, 1); + queue_update(Playlist::Selection, entry_num, 1); } -void PlaylistData::select_all (bool selected) +void PlaylistData::select_all(bool selected) { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); int first = n_entries, last = 0; for (auto & entry : m_entries) @@ -405,7 +403,7 @@ void PlaylistData::select_all (bool selected) if (entry->selected != selected) { entry->selected = selected; - first = aud::min (first, entry->number); + first = aud::min(first, entry->number); last = entry->number; } } @@ -422,44 +420,44 @@ void PlaylistData::select_all (bool selected) } if (first < n_entries) - queue_update (Playlist::Selection, first, last + 1 - first); + queue_update(Playlist::Selection, first, last + 1 - first); } -int PlaylistData::shift_entries (int entry_num, int distance) +int PlaylistData::shift_entries(int entry_num, int distance) { - PlaylistEntry * entry = entry_at (entry_num); - if (! entry || ! entry->selected || ! distance) + PlaylistEntry * entry = entry_at(entry_num); + if (!entry || !entry->selected || !distance) return 0; - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); int shift = 0, center, top, bottom; if (distance < 0) { - for (center = entry_num; center > 0 && shift > distance; ) + for (center = entry_num; center > 0 && shift > distance;) { - if (! m_entries[-- center]->selected) - shift --; + if (!m_entries[--center]->selected) + shift--; } } else { - for (center = entry_num + 1; center < n_entries && shift < distance; ) + for (center = entry_num + 1; center < n_entries && shift < distance;) { - if (! m_entries[center ++]->selected) - shift ++; + if (!m_entries[center++]->selected) + shift++; } } top = bottom = center; - for (int i = 0; i < top; i ++) + for (int i = 0; i < top; i++) { if (m_entries[i]->selected) top = i; } - for (int i = n_entries; i > bottom; i --) + for (int i = n_entries; i > bottom; i--) { if (m_entries[i - 1]->selected) bottom = i; @@ -467,66 +465,66 @@ int PlaylistData::shift_entries (int entry_num, int distance) Index temp; - for (int i = top; i < center; i ++) + for (int i = top; i < center; i++) { - if (! m_entries[i]->selected) - temp.append (std::move (m_entries[i])); + if (!m_entries[i]->selected) + temp.append(std::move(m_entries[i])); } - for (int i = top; i < bottom; i ++) + for (int i = top; i < bottom; i++) { if (m_entries[i] && m_entries[i]->selected) - temp.append (std::move (m_entries[i])); + temp.append(std::move(m_entries[i])); } - for (int i = center; i < bottom; i ++) + for (int i = center; i < bottom; i++) { - if (m_entries[i] && ! m_entries[i]->selected) - temp.append (std::move (m_entries[i])); + if (m_entries[i] && !m_entries[i]->selected) + temp.append(std::move(m_entries[i])); } - m_entries.move_from (temp, 0, top, bottom - top, false, true); + m_entries.move_from(temp, 0, top, bottom - top, false, true); - number_entries (top, bottom - top); - queue_update (Playlist::Structure, top, bottom - top); + number_entries(top, bottom - top); + queue_update(Playlist::Structure, top, bottom - top); return shift; } -void PlaylistData::remove_selected () +void PlaylistData::remove_selected() { - if (! m_selected_count) + if (!m_selected_count) return; - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); bool position_changed = false; int update_flags = 0; if (m_position && m_position->selected) { - set_position (nullptr, false); + change_position(NO_POS); position_changed = true; } - m_focus = find_unselected_focus (); + m_focus = find_unselected_focus(); - int before = 0; // number of entries before first selected - int after = 0; // number of entries after last selected + int before = 0; // number of entries before first selected + int after = 0; // number of entries after last selected - while (before < n_entries && ! m_entries[before]->selected) - before ++; + while (before < n_entries && !m_entries[before]->selected) + before++; int to = before; - for (int from = before; from < n_entries; from ++) + for (int from = before; from < n_entries; from++) { - PlaylistEntry * entry = m_entries[from].get (); + PlaylistEntry * entry = m_entries[from].get(); if (entry->selected) { if (entry->queued) { - m_queued.remove (m_queued.find (entry), 1); + m_queued.remove(m_queued.find(entry), 1); update_flags |= QueueChanged; } @@ -535,374 +533,431 @@ void PlaylistData::remove_selected () } else { - m_entries[to ++] = std::move (m_entries[from]); - after ++; + m_entries[to++] = std::move(m_entries[from]); + after++; } } n_entries = to; - m_entries.remove (n_entries, -1); + m_entries.remove(n_entries, -1); m_selected_count = 0; m_selected_length = 0; - number_entries (before, n_entries - before); - queue_update (Playlist::Structure, before, n_entries - after - before, update_flags); + number_entries(before, n_entries - before); + queue_update(Playlist::Structure, before, n_entries - after - before, + update_flags); if (position_changed) { - if (aud_get_bool (nullptr, "advance_on_delete")) - next_song_with_hint (aud_get_bool (nullptr, "repeat"), n_entries - after); + if (aud_get_bool("advance_on_delete")) + change_position_to_next(aud_get_bool("repeat"), n_entries - after); - queue_position_change (); + queue_position_change(); } } -void PlaylistData::sort_entries (Index & entries, const CompareData & data) // static +void PlaylistData::sort_entries(Index & entries, + const CompareData & data) // static { - entries.sort ([data] (const EntryPtr & a, const EntryPtr & b) { + entries.sort([data](const EntryPtr & a, const EntryPtr & b) { if (data.filename_compare) - return data.filename_compare (a->filename, b->filename); + return data.filename_compare(a->filename, b->filename); else - return data.tuple_compare (a->tuple, b->tuple); + return data.tuple_compare(a->tuple, b->tuple); }); } -void PlaylistData::sort (const CompareData & data) +void PlaylistData::sort(const CompareData & data) { - sort_entries (m_entries, data); + sort_entries(m_entries, data); - number_entries (0, m_entries.len ()); - queue_update (Playlist::Structure, 0, m_entries.len ()); + number_entries(0, m_entries.len()); + queue_update(Playlist::Structure, 0, m_entries.len()); } -void PlaylistData::sort_selected (const CompareData & data) +void PlaylistData::sort_selected(const CompareData & data) { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); Index selected; for (auto & entry : m_entries) { if (entry->selected) - selected.append (std::move (entry)); + selected.append(std::move(entry)); } - sort_entries (selected, data); + sort_entries(selected, data); int i = 0; for (auto & entry : m_entries) { - if (! entry) - entry = std::move (selected[i ++]); + if (!entry) + entry = std::move(selected[i++]); } - number_entries (0, n_entries); - queue_update (Playlist::Structure, 0, n_entries); + number_entries(0, n_entries); + queue_update(Playlist::Structure, 0, n_entries); } -void PlaylistData::reverse_order () +void PlaylistData::reverse_order() { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); - for (int i = 0; i < n_entries / 2; i ++) - std::swap (m_entries[i], m_entries[n_entries - 1 - i]); + for (int i = 0; i < n_entries / 2; i++) + std::swap(m_entries[i], m_entries[n_entries - 1 - i]); - number_entries (0, n_entries); - queue_update (Playlist::Structure, 0, n_entries); + number_entries(0, n_entries); + queue_update(Playlist::Structure, 0, n_entries); } -void PlaylistData::reverse_selected () +void PlaylistData::reverse_selected() { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); int top = 0; int bottom = n_entries - 1; while (1) { - while (top < bottom && ! m_entries[top]->selected) - top ++; - while (top < bottom && ! m_entries[bottom]->selected) - bottom --; + while (top < bottom && !m_entries[top]->selected) + top++; + while (top < bottom && !m_entries[bottom]->selected) + bottom--; if (top >= bottom) break; - std::swap (m_entries[top ++], m_entries[bottom --]); + std::swap(m_entries[top++], m_entries[bottom--]); } - number_entries (0, n_entries); - queue_update (Playlist::Structure, 0, n_entries); + number_entries(0, n_entries); + queue_update(Playlist::Structure, 0, n_entries); } -void PlaylistData::randomize_order () +void PlaylistData::randomize_order() { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); - for (int i = 0; i < n_entries; i ++) - std::swap (m_entries[i], m_entries[rand () % n_entries]); + for (int i = 0; i < n_entries; i++) + std::swap(m_entries[i], m_entries[rand() % n_entries]); - number_entries (0, n_entries); - queue_update (Playlist::Structure, 0, n_entries); + number_entries(0, n_entries); + queue_update(Playlist::Structure, 0, n_entries); } -void PlaylistData::randomize_selected () +void PlaylistData::randomize_selected() { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); Index selected; for (auto & entry : m_entries) { if (entry->selected) - selected.append (entry.get ()); + selected.append(entry.get()); } - int n_selected = selected.len (); + int n_selected = selected.len(); - for (int i = 0; i < n_selected; i ++) + for (int i = 0; i < n_selected; i++) { int a = selected[i]->number; - int b = selected[rand () % n_selected]->number; - std::swap (m_entries[a], m_entries[b]); + int b = selected[rand() % n_selected]->number; + std::swap(m_entries[a], m_entries[b]); } - number_entries (0, n_entries); - queue_update (Playlist::Structure, 0, n_entries); + number_entries(0, n_entries); + queue_update(Playlist::Structure, 0, n_entries); } -int PlaylistData::queue_get_entry (int at) const +int PlaylistData::queue_get_entry(int at) const { - return (at >= 0 && at < m_queued.len ()) ? m_queued[at]->number : -1; + return (at >= 0 && at < m_queued.len()) ? m_queued[at]->number : -1; } -int PlaylistData::queue_find_entry (int entry_num) const +int PlaylistData::queue_find_entry(int entry_num) const { - auto entry = entry_at (entry_num); - return (entry && entry->queued) ? m_queued.find ((PlaylistEntry *) entry) : -1; + auto entry = entry_at(entry_num); + return (entry && entry->queued) ? m_queued.find((PlaylistEntry *)entry) + : -1; } -void PlaylistData::queue_insert (int at, int entry_num) +void PlaylistData::queue_insert(int at, int entry_num) { - auto entry = entry_at (entry_num); - if (! entry || entry->queued) + auto entry = entry_at(entry_num); + if (!entry || entry->queued) return; - if (at < 0 || at > m_queued.len ()) - m_queued.append (entry); + if (at < 0 || at > m_queued.len()) + m_queued.append(entry); else { - m_queued.insert (at, 1); + m_queued.insert(at, 1); m_queued[at] = entry; } entry->queued = true; - queue_update (Playlist::Selection, entry_num, 1, QueueChanged); + queue_update(Playlist::Selection, entry_num, 1, QueueChanged); } -void PlaylistData::queue_insert_selected (int at) +void PlaylistData::queue_insert_selected(int at) { - if (at < 0 || at > m_queued.len ()) - at = m_queued.len (); + if (at < 0 || at > m_queued.len()) + at = m_queued.len(); Index add; - int first = m_entries.len (); + int first = m_entries.len(); int last = 0; for (auto & entry : m_entries) { - if (! entry->selected || entry->queued) + if (!entry->selected || entry->queued) continue; - add.append (entry.get ()); + add.append(entry.get()); entry->queued = true; - first = aud::min (first, entry->number); + first = aud::min(first, entry->number); last = entry->number; } - m_queued.move_from (add, 0, at, -1, true, true); + m_queued.move_from(add, 0, at, -1, true, true); - if (first < m_entries.len ()) - queue_update (Playlist::Selection, first, last + 1 - first, QueueChanged); + if (first < m_entries.len()) + queue_update(Playlist::Selection, first, last + 1 - first, + QueueChanged); } -void PlaylistData::queue_remove (int at, int number) +void PlaylistData::queue_remove(int at, int number) { - int queue_len = m_queued.len (); + int queue_len = m_queued.len(); if (at < 0 || at > queue_len) at = queue_len; if (number < 0 || number > queue_len - at) number = queue_len - at; - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); int first = n_entries, last = 0; - for (int i = at; i < at + number; i ++) + for (int i = at; i < at + number; i++) { PlaylistEntry * entry = m_queued[i]; entry->queued = false; - first = aud::min (first, entry->number); + first = aud::min(first, entry->number); last = entry->number; } - m_queued.remove (at, number); + m_queued.remove(at, number); if (first < n_entries) - queue_update (Playlist::Selection, first, last + 1 - first, QueueChanged); + queue_update(Playlist::Selection, first, last + 1 - first, + QueueChanged); } -void PlaylistData::queue_remove_selected () +void PlaylistData::queue_remove_selected() { - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); int first = n_entries, last = 0; - for (int i = 0; i < m_queued.len ();) + for (int i = 0; i < m_queued.len();) { PlaylistEntry * entry = m_queued[i]; if (entry->selected) { - m_queued.remove (i, 1); + m_queued.remove(i, 1); entry->queued = false; - first = aud::min (first, entry->number); + first = aud::min(first, entry->number); last = entry->number; } else - i ++; + i++; } if (first < n_entries) - queue_update (Playlist::Selection, first, last + 1 - first, QueueChanged); + queue_update(Playlist::Selection, first, last + 1 - first, + QueueChanged); } -void PlaylistData::set_position (PlaylistEntry * entry, bool update_shuffle) +int PlaylistData::shuffle_pos_before(int ref_pos) const { - m_position = entry; - resume_time = 0; + auto ref_entry = entry_at(ref_pos); + if (!ref_entry) + return -1; - /* move entry to top of shuffle list */ - if (entry && update_shuffle) - entry->shuffle_num = ++ m_last_shuffle_num; + const PlaylistEntry * found = nullptr; + for (auto & entry : m_entries) + { + if (entry->shuffle_num > 0 && + entry->shuffle_num < ref_entry->shuffle_num && + (!found || entry->shuffle_num > found->shuffle_num)) + { + found = entry.get(); + } + } + + return found ? found->number : -1; } -void PlaylistData::set_position (int entry_num) +PlaylistData::PosChange PlaylistData::shuffle_pos_after(int ref_pos, + bool by_album) const { - set_position (entry_at (entry_num), true); - queue_position_change (); + auto ref_entry = entry_at(ref_pos); + if (!ref_entry) + return NO_POS; + + // the reference entry can be beyond the end of the shuffle list + // if we are looking ahead multiple entries, as in next_album() + if (ref_entry->shuffle_num > 0) + { + // look for the next entry in the existing shuffle order + const PlaylistEntry * next = nullptr; + for (auto & entry : m_entries) + { + if (entry->shuffle_num > ref_entry->shuffle_num && + (!next || entry->shuffle_num < next->shuffle_num)) + { + next = entry.get(); + } + } + + if (next) + return {next->number, false}; + } + + if (by_album) + { + // look for the next entry in the album + auto next = entry_at(ref_pos + 1); + if (next && same_album(next->tuple, ref_entry->tuple)) + return {ref_pos + 1, true}; + } + + return NO_POS; } -bool PlaylistData::shuffle_prev () +PlaylistData::PosChange PlaylistData::shuffle_pos_random(bool repeat, + bool by_album) const { - PlaylistEntry * found = nullptr; + Index choices; + const PlaylistEntry * prev_entry = nullptr; for (auto & entry : m_entries) { - if (entry->shuffle_num && - (! m_position || entry->shuffle_num < m_position->shuffle_num) && - (! found || entry->shuffle_num > found->shuffle_num)) + // skip already played entries (unless repeating) + // optionally skip all but first entry in album + if ((entry->shuffle_num == 0 || repeat) && + !(by_album && prev_entry && + same_album(entry->tuple, prev_entry->tuple))) { - found = entry.get (); + choices.append(entry.get()); } + + prev_entry = entry.get(); } - if (! found) - return false; + if (choices.len()) + return {choices[rand() % choices.len()]->number, true}; - set_position (found, false); - return true; + return NO_POS; } -bool PlaylistData::shuffle_next () +int PlaylistData::pos_before(int ref_pos, bool shuffle) const { - bool by_album = aud_get_bool (nullptr, "album_shuffle"); + if (shuffle) + return shuffle_pos_before(ref_pos); - // helper #1: determine whether two entries are in the same album - auto same_album = [] (const Tuple & a, const Tuple & b) - { - String album = a.get_str (Tuple::Album); - return (album && album == b.get_str (Tuple::Album)); - }; + return (ref_pos > 0) ? ref_pos - 1 : -1; +} - // helper #2: determine whether an entry is among the shuffle choices - auto is_choice = [&] (PlaylistEntry * prev, PlaylistEntry * entry) - { - return (! entry->shuffle_num) && (! by_album || ! prev || - prev->shuffle_num || ! same_album (prev->tuple, entry->tuple)); - }; +PlaylistData::PosChange PlaylistData::pos_after(int ref_pos, bool shuffle, + bool by_album) const +{ + if (m_queued.len()) + return NO_POS; // let pos_new() handle queue entries - if (m_position) - { - // step #1: check to see if the shuffle order is already established - PlaylistEntry * next = nullptr; + if (shuffle) + return shuffle_pos_after(ref_pos, by_album); - for (auto & entry : m_entries) - { - if (entry->shuffle_num > m_position->shuffle_num && - (! next || entry->shuffle_num < next->shuffle_num)) - next = entry.get (); - } + if (ref_pos >= 0 && ref_pos + 1 < m_entries.len()) + return {ref_pos + 1, true}; - if (next) - { - set_position (next, false); - return true; - } + return NO_POS; +} - // step #2: check to see if we should advance to the next entry - if (by_album && m_position->number + 1 < m_entries.len ()) - { - next = m_entries[m_position->number + 1].get (); +PlaylistData::PosChange PlaylistData::pos_new(bool repeat, bool shuffle, + bool by_album, int hint_pos) const +{ + if (m_queued.len()) + return {m_queued[0]->number, true}; - if (! next->shuffle_num && same_album (m_position->tuple, next->tuple)) - { - set_position (next, true); - return true; - } - } - } + if (shuffle) + return shuffle_pos_random(repeat, by_album); - // step #3: count the number of possible shuffle choices - int choices = 0; - PlaylistEntry * prev = nullptr; + if (hint_pos >= 0 && hint_pos < m_entries.len()) + return {hint_pos, true}; - for (auto & entry : m_entries) - { - if (is_choice (prev, entry.get ())) - choices ++; + return NO_POS; +} + +PlaylistData::PosChange PlaylistData::pos_new_full(bool repeat, bool shuffle, + bool by_album, int hint_pos, + bool & repeated) const +{ + // first try to pick a new position *without* repeating + auto change = pos_new(false, shuffle, by_album, hint_pos); + repeated = false; - prev = entry.get (); + if (change.new_pos < 0 && repeat) + { + change = pos_new(true, shuffle, by_album, 0); + repeated = (change.new_pos >= 0); } - if (! choices) - return false; + return change; +} + +void PlaylistData::change_position(PosChange change) +{ + m_position = entry_at(change.new_pos); + resume_time = 0; - // step #4: pick one of those choices by random and find it again - choices = rand () % choices; - prev = nullptr; + /* move entry to top of shuffle list */ + if (m_position && change.update_shuffle) + m_position->shuffle_num = ++m_last_shuffle_num; - for (auto & entry : m_entries) + /* remove from queue if it's the first entry */ + if (m_queued.len() && m_position == m_queued[0]) { - if (is_choice (prev, entry.get ())) - { - if (! choices) - { - set_position (entry.get (), true); - return true; - } + m_queued.remove(0, 1); + m_position->queued = false; + queue_update(Playlist::Selection, m_position->number, 1, QueueChanged); + } +} - choices --; - } +bool PlaylistData::change_position_to_next(bool repeat, int hint_pos) +{ + bool shuffle = aud_get_bool("shuffle"); + bool by_album = aud_get_bool("album_shuffle"); + bool repeated = false; + + auto change = pos_after(position(), shuffle, by_album); + if (change.new_pos < 0) + change = pos_new_full(repeat, shuffle, by_album, hint_pos, repeated); + if (change.new_pos < 0) + return false; - prev = entry.get (); - } + if (repeated) + shuffle_reset(); - return false; // never reached + change_position(change); + return true; } -void PlaylistData::shuffle_reset () +void PlaylistData::shuffle_reset() { m_last_shuffle_num = 0; @@ -910,7 +965,7 @@ void PlaylistData::shuffle_reset () entry->shuffle_num = 0; } -Index PlaylistData::shuffle_history () const +Index PlaylistData::shuffle_history() const { Index history; @@ -918,108 +973,152 @@ Index PlaylistData::shuffle_history () const for (auto & entry : m_entries) { if (entry->shuffle_num) - history.append (entry->number); + history.append(entry->number); } // sort by shuffle order - history.sort ([this] (int entry_a, int entry_b) { - return m_entries[entry_a]->shuffle_num - m_entries[entry_b]->shuffle_num; + history.sort([this](int entry_a, int entry_b) { + return m_entries[entry_a]->shuffle_num - + m_entries[entry_b]->shuffle_num; }); return history; } -void PlaylistData::shuffle_replay (const Index & history) +void PlaylistData::shuffle_replay(const Index & history) { - shuffle_reset (); + shuffle_reset(); // replay the given history, entry by entry for (int entry_num : history) { - auto entry = entry_at (entry_num); + auto entry = entry_at(entry_num); if (entry) - entry->shuffle_num = ++ m_last_shuffle_num; + entry->shuffle_num = ++m_last_shuffle_num; } } -bool PlaylistData::prev_song () +void PlaylistData::set_position(int entry_num) { - if (aud_get_bool (nullptr, "shuffle")) - { - if (! shuffle_prev ()) - return false; - } - else - { - int pos = position (); - if (pos < 1) - return false; + change_position({entry_num, true}); + queue_position_change(); +} - set_position (m_entries[pos - 1].get (), true); - } +bool PlaylistData::prev_song() +{ + bool shuffle = aud_get_bool("shuffle"); + int pos = pos_before(position(), shuffle); + if (pos < 0) + return false; - queue_position_change (); + // update shuffle list if entry didn't come from it + change_position({pos, !shuffle}); + queue_position_change(); return true; } -bool PlaylistData::next_song_with_hint (bool repeat, int hint) +bool PlaylistData::next_song(bool repeat) { - int n_entries = m_entries.len (); - if (! n_entries) + if (!change_position_to_next(repeat, -1)) return false; - PlaylistEntry * entry; - if ((entry = queue_pop ())) - { - set_position (entry, true); - return true; - } + queue_position_change(); + return true; +} - if (aud_get_bool (nullptr, "shuffle")) - { - if (shuffle_next ()) - return true; +bool PlaylistData::prev_album() +{ + bool shuffle = aud_get_bool("shuffle"); + int pos = position(); - if (! repeat) + // find the start of the previous album + for (bool in_prev_album = false;;) + { + auto entry = entry_at(pos); + if (!entry) return false; - shuffle_reset (); + while (1) + { + auto prev_entry = entry_at(pos_before(pos, shuffle)); + if (!prev_entry || !same_album(entry->tuple, prev_entry->tuple)) + break; - return shuffle_next (); - } + pos = prev_entry->number; + } - if (hint < 0 || hint >= n_entries) - { - if (! repeat) - return false; + if (in_prev_album) + break; // we're at the start of the previous album - hint = 0; + // we're at the start of the current album + // one more song back puts us in the previous album + pos = pos_before(pos, shuffle); + in_prev_album = true; } - set_position (m_entries[hint].get (), true); + // update shuffle list if entry didn't come from it + change_position({pos, !shuffle}); + queue_position_change(); return true; } -bool PlaylistData::next_song (bool repeat) +bool PlaylistData::next_album(bool repeat) { - if (! next_song_with_hint (repeat, position () + 1)) // -1 becomes 0 + bool shuffle = aud_get_bool("shuffle"); + PosChange change = {position(), false}; + Index skipped; + bool repeated = false; + + auto entry = entry_at(change.new_pos); + if (!entry) return false; - queue_position_change (); + // find the end of the album + while (1) + { + // album shuffle is always on for this function + change = pos_after(change.new_pos, shuffle, true); + + auto next_entry = entry_at(change.new_pos); + if (!next_entry || !same_album(entry->tuple, next_entry->tuple)) + break; + + skipped.append(change); + } + + // get one new position if there was nothing after the album + if (change.new_pos < 0) + { + change = pos_new_full(repeat, shuffle, true, -1, repeated); + if (change.new_pos < 0) + return false; + } + + if (repeated) + shuffle_reset(); + else + { + // add skipped songs to shuffle list + for (auto & skip : skipped) + change_position(skip); + } + + change_position(change); + queue_position_change(); return true; } -int PlaylistData::next_unscanned_entry (int entry_num) const +int PlaylistData::next_unscanned_entry(int entry_num) const { if (entry_num < 0) return -1; - for (; entry_num < m_entries.len (); entry_num ++) + for (; entry_num < m_entries.len(); entry_num++) { auto & entry = *m_entries[entry_num]; - if (entry.tuple.state () == Tuple::Initial && - strncmp (entry.filename, "stdin://", 8)) // blacklist stdin + if (entry.tuple.state() == Tuple::Initial && + strncmp(entry.filename, "stdin://", 8)) // blacklist stdin { return entry_num; } @@ -1028,128 +1127,119 @@ int PlaylistData::next_unscanned_entry (int entry_num) const return -1; } -ScanRequest * PlaylistData::create_scan_request (PlaylistEntry * entry, - ScanRequest::Callback callback, int extra_flags) +ScanRequest * PlaylistData::create_scan_request(PlaylistEntry * entry, + ScanRequest::Callback callback, + int extra_flags) { int flags = extra_flags; - if (! entry->tuple.valid ()) + if (!entry->tuple.valid()) flags |= SCAN_TUPLE; /* scanner uses Tuple::AudioFile from existing tuple, if valid */ - return new ScanRequest (entry->filename, flags, callback, entry->decoder, - (flags & SCAN_TUPLE) ? Tuple () : entry->tuple.ref ()); + return new ScanRequest(entry->filename, flags, callback, entry->decoder, + (flags & SCAN_TUPLE) ? Tuple() : entry->tuple.ref()); } -void PlaylistData::update_entry_from_scan (PlaylistEntry * entry, ScanRequest * request, int update_flags) +void PlaylistData::update_entry_from_scan(PlaylistEntry * entry, + ScanRequest * request, + int update_flags) { - if (! entry->decoder) + if (!entry->decoder) entry->decoder = request->decoder; - if (! entry->tuple.valid () && request->tuple.valid ()) + if (!entry->tuple.valid() && request->tuple.valid()) { - set_entry_tuple (entry, std::move (request->tuple)); - queue_update (Playlist::Metadata, entry->number, 1, update_flags); + set_entry_tuple(entry, std::move(request->tuple)); + queue_update(Playlist::Metadata, entry->number, 1, update_flags); } - if (! entry->decoder || ! entry->tuple.valid ()) + if (!entry->decoder || !entry->tuple.valid()) entry->error = request->error; - if (entry->tuple.state () == Tuple::Initial) + if (entry->tuple.state() == Tuple::Initial) { - entry->tuple.set_state (Tuple::Failed); - queue_update (Playlist::Metadata, entry->number, 1, update_flags); + entry->tuple.set_state(Tuple::Failed); + queue_update(Playlist::Metadata, entry->number, 1, update_flags); } } -void PlaylistData::update_playback_entry (Tuple && tuple) +void PlaylistData::update_playback_entry(Tuple && tuple) { /* don't update cuesheet entries with stream metadata */ - if (m_position && ! m_position->tuple.is_set (Tuple::StartTime)) + if (m_position && !m_position->tuple.is_set(Tuple::StartTime)) { - set_entry_tuple (m_position, std::move (tuple)); - queue_update (Playlist::Metadata, m_position->number, 1); + set_entry_tuple(m_position, std::move(tuple)); + queue_update(Playlist::Metadata, m_position->number, 1); } } -bool PlaylistData::entry_needs_rescan (PlaylistEntry * entry, bool need_decoder, bool need_tuple) +bool PlaylistData::entry_needs_rescan(PlaylistEntry * entry, bool need_decoder, + bool need_tuple) { - if (! strncmp (entry->filename, "stdin://", 8)) // blacklist stdin + if (!strncmp(entry->filename, "stdin://", 8)) // blacklist stdin return false; // check whether requested data (decoder and/or tuple) has been read - return (need_decoder && ! entry->decoder) || (need_tuple && ! entry->tuple.valid ()); + return (need_decoder && !entry->decoder) || + (need_tuple && !entry->tuple.valid()); } -void PlaylistData::reformat_titles () +void PlaylistData::reformat_titles() { for (auto & entry : m_entries) - entry->format (); + entry->format(); - queue_update (Playlist::Metadata, 0, m_entries.len ()); + queue_update(Playlist::Metadata, 0, m_entries.len()); } -void PlaylistData::reset_tuples (bool selected_only) +void PlaylistData::reset_tuples(bool selected_only) { for (auto & entry : m_entries) { - if (! selected_only || entry->selected) - set_entry_tuple (entry.get (), Tuple ()); + if (!selected_only || entry->selected) + set_entry_tuple(entry.get(), Tuple()); } - queue_update (Playlist::Metadata, 0, m_entries.len ()); - pl_signal_rescan_needed (m_id); + queue_update(Playlist::Metadata, 0, m_entries.len()); + pl_signal_rescan_needed(m_id); } -void PlaylistData::reset_tuple_of_file (const char * filename) +void PlaylistData::reset_tuple_of_file(const char * filename) { bool found = false; for (auto & entry : m_entries) { - if (! strcmp (entry->filename, filename)) + if (!strcmp(entry->filename, filename)) { - set_entry_tuple (entry.get (), Tuple ()); - queue_update (Playlist::Metadata, entry->number, 1); + set_entry_tuple(entry.get(), Tuple()); + queue_update(Playlist::Metadata, entry->number, 1); found = true; } } if (found) - pl_signal_rescan_needed (m_id); + pl_signal_rescan_needed(m_id); } -PlaylistEntry * PlaylistData::find_unselected_focus () +PlaylistEntry * PlaylistData::find_unselected_focus() { - if (! m_focus || ! m_focus->selected) + if (!m_focus || !m_focus->selected) return m_focus; - int n_entries = m_entries.len (); + int n_entries = m_entries.len(); - for (int search = m_focus->number + 1; search < n_entries; search ++) + for (int search = m_focus->number + 1; search < n_entries; search++) { - if (! m_entries[search]->selected) - return m_entries[search].get (); + if (!m_entries[search]->selected) + return m_entries[search].get(); } - for (int search = m_focus->number; search --;) + for (int search = m_focus->number; search--;) { - if (! m_entries[search]->selected) - return m_entries[search].get (); + if (!m_entries[search]->selected) + return m_entries[search].get(); } return nullptr; } - -PlaylistEntry * PlaylistData::queue_pop () -{ - if (! m_queued.len ()) - return nullptr; - - auto entry = m_queued[0]; - m_queued.remove (0, 1); - entry->queued = false; - - queue_update (Playlist::Selection, entry->number, 1, QueueChanged); - - return entry; -} diff --git a/src/libaudcore/playlist-data.h b/src/libaudcore/playlist-data.h index 663c565..662261e 100644 --- a/src/libaudcore/playlist-data.h +++ b/src/libaudcore/playlist-data.h @@ -30,122 +30,147 @@ class PlaylistData { public: /* update flags */ - enum { - QueueChanged = (1 << 0), + enum + { + QueueChanged = (1 << 0), DelayedUpdate = (1 << 1) }; /* scan status */ - enum ScanStatus { + enum ScanStatus + { NotScanning, ScanActive, ScanEnding }; - struct CompareData { + struct CompareData + { Playlist::StringCompareFunc filename_compare; Playlist::TupleCompareFunc tuple_compare; }; - PlaylistData (Playlist::ID * m_id, const char * title); - ~PlaylistData (); + PlaylistData(Playlist::ID * m_id, const char * title); + ~PlaylistData(); - PlaylistEntry * entry_at (int i); - const PlaylistEntry * entry_at (int i) const; + PlaylistEntry * entry_at(int i); + const PlaylistEntry * entry_at(int i) const; - String entry_filename (int i) const; - PluginHandle * entry_decoder (int i, String * error = nullptr) const; - Tuple entry_tuple (int i, String * error = nullptr) const; + String entry_filename(int i) const; + PluginHandle * entry_decoder(int i, String * error = nullptr) const; + Tuple entry_tuple(int i, String * error = nullptr) const; - void cancel_updates (); - void swap_updates (bool & position_changed); + void cancel_updates(); + void swap_updates(bool & position_changed); - void insert_items (int at, Index && items); - void remove_entries (int at, int number); + void insert_items(int at, Index && items); + void remove_entries(int at, int number); - int position () const; - int focus () const; + int position() const; + int focus() const; - bool entry_selected (int entry_num) const; - int n_selected (int at, int number) const; + bool entry_selected(int entry_num) const; + int n_selected(int at, int number) const; - void set_focus (int entry_num); + void set_focus(int entry_num); - void select_entry (int entry_num, bool selected); - void select_all (bool selected); - int shift_entries (int entry_num, int distance); - void remove_selected (); + void select_entry(int entry_num, bool selected); + void select_all(bool selected); + int shift_entries(int entry_num, int distance); + void remove_selected(); - void sort (const CompareData & data); - void sort_selected (const CompareData & data); + void sort(const CompareData & data); + void sort_selected(const CompareData & data); - void reverse_order (); - void randomize_order (); - void reverse_selected (); - void randomize_selected (); + void reverse_order(); + void randomize_order(); + void reverse_selected(); + void randomize_selected(); - int queue_get_entry (int at) const; - int queue_find_entry (int entry_num) const; + int queue_get_entry(int at) const; + int queue_find_entry(int entry_num) const; - void queue_insert (int at, int entry_num); - void queue_insert_selected (int pos); - void queue_remove (int at, int number); - void queue_remove_selected (); + void queue_insert(int at, int entry_num); + void queue_insert_selected(int pos); + void queue_remove(int at, int number); + void queue_remove_selected(); - void set_position (int entry_num); + Index shuffle_history() const; + void shuffle_replay(const Index & history); - Index shuffle_history () const; - void shuffle_replay (const Index & history); + void set_position(int entry_num); - bool prev_song (); - bool next_song (bool repeat); + bool prev_song(); + bool next_song(bool repeat); + bool prev_album(); + bool next_album(bool repeat); - int next_unscanned_entry (int entry_num) const; - bool entry_needs_rescan (PlaylistEntry * entry, bool need_decoder, bool need_tuple); - ScanRequest * create_scan_request (PlaylistEntry * entry, - ScanRequest::Callback callback, int extra_flags); - void update_entry_from_scan (PlaylistEntry * entry, ScanRequest * request, int update_flags); - void update_playback_entry (Tuple && tuple); + int next_unscanned_entry(int entry_num) const; + bool entry_needs_rescan(PlaylistEntry * entry, bool need_decoder, + bool need_tuple); + ScanRequest * create_scan_request(PlaylistEntry * entry, + ScanRequest::Callback callback, + int extra_flags); + void update_entry_from_scan(PlaylistEntry * entry, ScanRequest * request, + int update_flags); + void update_playback_entry(Tuple && tuple); - void reformat_titles (); - void reset_tuples (bool selected_only); - void reset_tuple_of_file (const char * filename); + void reformat_titles(); + void reset_tuples(bool selected_only); + void reset_tuple_of_file(const char * filename); - Playlist::ID * id () const { return m_id; } + Playlist::ID * id() const { return m_id; } - int n_entries () const { return m_entries.len (); } - int n_queued () const { return m_queued.len (); } + int n_entries() const { return m_entries.len(); } + int n_queued() const { return m_queued.len(); } - int64_t total_length () const { return m_total_length; } - int64_t selected_length () const { return m_selected_length; } + int64_t total_length() const { return m_total_length; } + int64_t selected_length() const { return m_selected_length; } - const Playlist::Update & last_update () const { return m_last_update; } - bool update_pending () const { return m_next_update.level != Playlist::NoUpdate; } + const Playlist::Update & last_update() const { return m_last_update; } + bool update_pending() const + { + return m_next_update.level != Playlist::NoUpdate; + } - static void update_formatter (); - static void cleanup_formatter (); + static void update_formatter(); + static void cleanup_formatter(); private: - static void delete_entry (PlaylistEntry * entry); + struct PosChange + { + int new_pos; + bool update_shuffle; + }; + + static void delete_entry(PlaylistEntry * entry); typedef SmartPtr EntryPtr; - void number_entries (int at, int length); - void set_entry_tuple (PlaylistEntry * entry, Tuple && tuple); - void queue_update (Playlist::UpdateLevel level, int at, int count, int flags = 0); - void queue_position_change (); + void number_entries(int at, int length); + void set_entry_tuple(PlaylistEntry * entry, Tuple && tuple); + void queue_update(Playlist::UpdateLevel level, int at, int count, + int flags = 0); + void queue_position_change(); - static void sort_entries (Index & entries, const CompareData & data); + static void sort_entries(Index & entries, + const CompareData & data); - void set_position (PlaylistEntry * entry, bool update_shuffle); + int shuffle_pos_before(int ref_pos) const; + PosChange shuffle_pos_after(int ref_pos, bool by_album) const; + PosChange shuffle_pos_random(bool repeat, bool by_album) const; - bool shuffle_prev (); - bool shuffle_next (); - void shuffle_reset (); + int pos_before(int ref_pos, bool shuffle) const; + PosChange pos_after(int ref_pos, bool shuffle, bool by_album) const; + PosChange pos_new(bool repeat, bool shuffle, bool by_album, + int hint_pos) const; + PosChange pos_new_full(bool repeat, bool shuffle, bool by_album, + int hint_pos, bool & repeated) const; - bool next_song_with_hint (bool repeat, int hint); + void change_position(PosChange change); + bool change_position_to_next(bool repeat, int hint_pos); + void shuffle_reset(); - PlaylistEntry * find_unselected_focus (); - PlaylistEntry * queue_pop (); + PlaylistEntry * find_unselected_focus(); public: bool modified; @@ -156,7 +181,7 @@ public: private: Playlist::ID * m_id; Index m_entries; - PlaylistEntry * m_position, * m_focus; + PlaylistEntry *m_position, *m_focus; int m_selected_count; int m_last_shuffle_num; Index m_queued; @@ -166,10 +191,11 @@ private: }; /* callbacks or "signals" (in the QObject sense) */ -void pl_signal_entry_deleted (PlaylistEntry * entry); -void pl_signal_position_changed (Playlist::ID * id); -void pl_signal_update_queued (Playlist::ID * id, Playlist::UpdateLevel level, int flags); -void pl_signal_rescan_needed (Playlist::ID * id); -void pl_signal_playlist_deleted (Playlist::ID * id); +void pl_signal_entry_deleted(PlaylistEntry * entry); +void pl_signal_position_changed(Playlist::ID * id); +void pl_signal_update_queued(Playlist::ID * id, Playlist::UpdateLevel level, + int flags); +void pl_signal_rescan_needed(Playlist::ID * id); +void pl_signal_playlist_deleted(Playlist::ID * id); #endif // PLAYLIST_DATA_H diff --git a/src/libaudcore/playlist-files.cc b/src/libaudcore/playlist-files.cc index a2914b1..c11c505 100644 --- a/src/libaudcore/playlist-files.cc +++ b/src/libaudcore/playlist-files.cc @@ -26,15 +26,16 @@ #include "plugins-internal.h" #include "runtime.h" -EXPORT bool Playlist::filename_is_playlist (const char * filename) +EXPORT bool Playlist::filename_is_playlist(const char * filename) { - StringBuf ext = uri_get_extension (filename); + StringBuf ext = uri_get_extension(filename); if (ext) { - for (PluginHandle * plugin : aud_plugin_list (PluginType::Playlist)) + for (PluginHandle * plugin : aud_plugin_list(PluginType::Playlist)) { - if (aud_plugin_get_enabled (plugin) && playlist_plugin_has_ext (plugin, ext)) + if (aud_plugin_get_enabled(plugin) && + playlist_plugin_has_ext(plugin, ext)) return true; } } @@ -42,48 +43,52 @@ EXPORT bool Playlist::filename_is_playlist (const char * filename) return false; } -bool playlist_load (const char * filename, String & title, Index & items) +bool playlist_load(const char * filename, String & title, + Index & items) { - AUDINFO ("Loading playlist %s.\n", filename); + AUDINFO("Loading playlist %s.\n", filename); - StringBuf ext = uri_get_extension (filename); + StringBuf ext = uri_get_extension(filename); bool plugin_found = false; if (ext) { - for (PluginHandle * plugin : aud_plugin_list (PluginType::Playlist)) + for (PluginHandle * plugin : aud_plugin_list(PluginType::Playlist)) { - if (! aud_plugin_get_enabled (plugin) || ! playlist_plugin_has_ext (plugin, ext)) + if (!aud_plugin_get_enabled(plugin) || + !playlist_plugin_has_ext(plugin, ext)) continue; - AUDINFO ("Trying playlist plugin %s.\n", aud_plugin_get_name (plugin)); + AUDINFO("Trying playlist plugin %s.\n", + aud_plugin_get_name(plugin)); plugin_found = true; - auto pp = (PlaylistPlugin *) aud_plugin_get_header (plugin); - if (! pp) + auto pp = (PlaylistPlugin *)aud_plugin_get_header(plugin); + if (!pp) continue; - VFSFile file (filename, "r"); - if (! file) + VFSFile file(filename, "r"); + if (!file) { - aud_ui_show_error (str_printf (_("Error opening %s:\n%s"), - filename, file.error ())); + aud_ui_show_error(str_printf(_("Error opening %s:\n%s"), + filename, file.error())); return false; } - if (pp->load (filename, file, title, items)) + if (pp->load(filename, file, title, items)) return true; - title = String (); - items.clear (); + title = String(); + items.clear(); } } if (plugin_found) - aud_ui_show_error (str_printf (_("Error loading %s."), filename)); + aud_ui_show_error(str_printf(_("Error loading %s."), filename)); else - aud_ui_show_error (str_printf (_("Cannot load %s: unsupported file " - "name extension."), filename)); + aud_ui_show_error(str_printf(_("Cannot load %s: unsupported file " + "name extension."), + filename)); return false; } @@ -93,87 +98,91 @@ bool playlist_load (const char * filename, String & title, Index items; - if (! playlist_load (filename, title, items)) + if (!playlist_load(filename, title, items)) return false; if (title) - set_title (title); + set_title(title); - insert_flat_items (0, std::move (items)); + insert_flat_items(0, std::move(items)); return true; } -EXPORT bool Playlist::save_to_file (const char * filename, GetMode mode) const +EXPORT bool Playlist::save_to_file(const char * filename, GetMode mode) const { - String title = get_title (); + String title = get_title(); Index items; - items.insert (0, n_entries ()); + items.insert(0, n_entries()); int i = 0; for (PlaylistAddItem & item : items) { - item.filename = entry_filename (i); - item.tuple = entry_tuple (i, mode); - item.tuple.delete_fallbacks (); - i ++; + item.filename = entry_filename(i); + item.tuple = entry_tuple(i, mode); + item.tuple.delete_fallbacks(); + i++; } - AUDINFO ("Saving playlist %s.\n", filename); + AUDINFO("Saving playlist %s.\n", filename); - StringBuf ext = uri_get_extension (filename); + StringBuf ext = uri_get_extension(filename); if (ext) { - for (PluginHandle * plugin : aud_plugin_list (PluginType::Playlist)) + for (PluginHandle * plugin : aud_plugin_list(PluginType::Playlist)) { - if (! aud_plugin_get_enabled (plugin) || ! playlist_plugin_has_ext (plugin, ext)) + if (!aud_plugin_get_enabled(plugin) || + !playlist_plugin_has_ext(plugin, ext)) continue; - PlaylistPlugin * pp = (PlaylistPlugin *) aud_plugin_get_header (plugin); - if (! pp || ! pp->can_save) + PlaylistPlugin * pp = + (PlaylistPlugin *)aud_plugin_get_header(plugin); + if (!pp || !pp->can_save) continue; - VFSFile file (filename, "w"); - if (! file) + VFSFile file(filename, "w"); + if (!file) { - aud_ui_show_error (str_printf (_("Error opening %s:\n%s"), - filename, file.error ())); + aud_ui_show_error(str_printf(_("Error opening %s:\n%s"), + filename, file.error())); return false; } - if (pp->save (filename, file, title, items) && file.fflush () == 0) + if (pp->save(filename, file, title, items) && file.fflush() == 0) return true; - aud_ui_show_error (str_printf (_("Error saving %s."), filename)); + aud_ui_show_error(str_printf(_("Error saving %s."), filename)); return false; } } - aud_ui_show_error (str_printf (_("Cannot save %s: unsupported file name extension."), filename)); + aud_ui_show_error(str_printf( + _("Cannot save %s: unsupported file name extension."), filename)); return false; } -EXPORT Index Playlist::save_formats () +EXPORT Index Playlist::save_formats() { Index formats; - for (auto plugin : aud_plugin_list (PluginType::Playlist)) + for (auto plugin : aud_plugin_list(PluginType::Playlist)) { - if (! aud_plugin_get_enabled (plugin) || ! playlist_plugin_can_save (plugin)) + if (!aud_plugin_get_enabled(plugin) || + !playlist_plugin_can_save(plugin)) continue; - auto & format = formats.append (); - format.name = String (aud_plugin_get_name (plugin)); + auto & format = formats.append(); + format.name = String(aud_plugin_get_name(plugin)); - for (auto & ext : playlist_plugin_get_exts (plugin)) - format.exts.append (ext); + for (auto & ext : playlist_plugin_get_exts(plugin)) + format.exts.append(ext); } return formats; diff --git a/src/libaudcore/playlist-internal.h b/src/libaudcore/playlist-internal.h index bbccd6b..6333ecb 100644 --- a/src/libaudcore/playlist-internal.h +++ b/src/libaudcore/playlist-internal.h @@ -37,43 +37,42 @@ struct DecodeInfo class PlaylistEx : public Playlist { public: - PlaylistEx (Playlist::ID * id = nullptr) : - Playlist (id) {} - PlaylistEx (Playlist playlist) : - Playlist (playlist) {} + PlaylistEx(Playlist::ID * id = nullptr) : Playlist(id) {} + PlaylistEx(Playlist playlist) : Playlist(playlist) {} - int stamp () const; + int stamp() const; - static Playlist insert_with_stamp (int at, int stamp); + static Playlist insert_with_stamp(int at, int stamp); - bool get_modified () const; - void set_modified (bool modified) const; + bool get_modified() const; + void set_modified(bool modified) const; - bool insert_flat_playlist (const char * filename) const; - void insert_flat_items (int at, Index && items) const; + bool insert_flat_playlist(const char * filename) const; + void insert_flat_items(int at, Index && items) const; }; /* playlist.cc */ -void playlist_init (); -void playlist_enable_scan (bool enable); -void playlist_clear_updates (); -void playlist_end (); +void playlist_init(); +void playlist_enable_scan(bool enable); +void playlist_clear_updates(); +void playlist_end(); -void playlist_load_state (); -void playlist_save_state (); +void playlist_load_state(); +void playlist_save_state(); -DecodeInfo playback_entry_read (int serial); -void playback_entry_set_tuple (int serial, Tuple && tuple); +DecodeInfo playback_entry_read(int serial); +void playback_entry_set_tuple(int serial, Tuple && tuple); /* playlist-cache.cc */ -void playlist_cache_load (Index & items); -void playlist_cache_clear (void * = nullptr); +void playlist_cache_load(Index & items); +void playlist_cache_clear(void * = nullptr); /* playlist-files.cc */ -bool playlist_load (const char * filename, String & title, Index & items); +bool playlist_load(const char * filename, String & title, + Index & items); /* playlist-utils.cc */ -void load_playlists (); -void save_playlists (bool exiting); +void load_playlists(); +void save_playlists(bool exiting); #endif diff --git a/src/libaudcore/playlist-utils.cc b/src/libaudcore/playlist-utils.cc index 9492f29..ff78a2f 100644 --- a/src/libaudcore/playlist-utils.cc +++ b/src/libaudcore/playlist-utils.cc @@ -31,80 +31,115 @@ #include "tuple.h" #include "vfs.h" -static const char * get_basename (const char * filename) +static const char * get_basename(const char * filename) { - const char * slash = strrchr (filename, '/'); + const char * slash = strrchr(filename, '/'); return slash ? slash + 1 : filename; } -static int filename_compare_basename (const char * a, const char * b) +static int filename_compare_path(const char * a, const char * b) { - return str_compare_encoded (get_basename (a), get_basename (b)); + int dirlen_a = get_basename(a) - a; + int dirlen_b = get_basename(b) - b; + + // if one folder is a subfolder of the other, sort it last + if (dirlen_a != dirlen_b && memcmp(a, b, aud::min(dirlen_a, dirlen_b)) == 0) + return dirlen_a - dirlen_b; + + // in all other cases, compare the entire paths + return str_compare_encoded(a, b); } -static int tuple_compare_string (const Tuple & a, const Tuple & b, Tuple::Field field) +static int filename_compare_basename(const char * a, const char * b) { - String string_a = a.get_str (field); - String string_b = b.get_str (field); + return str_compare_encoded(get_basename(a), get_basename(b)); +} - if (! string_a) - return (! string_b) ? 0 : -1; +static int tuple_compare_string(const Tuple & a, const Tuple & b, + Tuple::Field field) +{ + String string_a = a.get_str(field); + String string_b = b.get_str(field); - return (! string_b) ? 1 : str_compare (string_a, string_b); + if (!string_a) + return (!string_b) ? 0 : -1; + + return (!string_b) ? 1 : str_compare(string_a, string_b); } -static int tuple_compare_int (const Tuple & a, const Tuple & b, Tuple::Field field) +static int tuple_compare_int(const Tuple & a, const Tuple & b, + Tuple::Field field) { - if (a.get_value_type (field) != Tuple::Int) - return (b.get_value_type (field) != Tuple::Int) ? 0 : -1; - if (b.get_value_type (field) != Tuple::Int) + if (a.get_value_type(field) != Tuple::Int) + return (b.get_value_type(field) != Tuple::Int) ? 0 : -1; + if (b.get_value_type(field) != Tuple::Int) return 1; - int int_a = a.get_int (field); - int int_b = b.get_int (field); + int int_a = a.get_int(field); + int int_b = b.get_int(field); return (int_a < int_b) ? -1 : (int_a > int_b); } -static int tuple_compare_title (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::Title); } -static int tuple_compare_album (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::Album); } -static int tuple_compare_artist (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::Artist); } -static int tuple_compare_album_artist (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::AlbumArtist); } -static int tuple_compare_date (const Tuple & a, const Tuple & b) - { return tuple_compare_int (a, b, Tuple::Year); } -static int tuple_compare_genre (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::Genre); } -static int tuple_compare_track (const Tuple & a, const Tuple & b) - { return tuple_compare_int (a, b, Tuple::Track); } -static int tuple_compare_formatted_title (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::FormattedTitle); } -static int tuple_compare_length (const Tuple & a, const Tuple & b) - { return tuple_compare_int (a, b, Tuple::Length); } -static int tuple_compare_comment (const Tuple & a, const Tuple & b) - { return tuple_compare_string (a, b, Tuple::Comment); } +static int tuple_compare_title(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::Title); +} +static int tuple_compare_album(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::Album); +} +static int tuple_compare_artist(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::Artist); +} +static int tuple_compare_album_artist(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::AlbumArtist); +} +static int tuple_compare_date(const Tuple & a, const Tuple & b) +{ + return tuple_compare_int(a, b, Tuple::Year); +} +static int tuple_compare_genre(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::Genre); +} +static int tuple_compare_track(const Tuple & a, const Tuple & b) +{ + return tuple_compare_int(a, b, Tuple::Track); +} +static int tuple_compare_formatted_title(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::FormattedTitle); +} +static int tuple_compare_length(const Tuple & a, const Tuple & b) +{ + return tuple_compare_int(a, b, Tuple::Length); +} +static int tuple_compare_comment(const Tuple & a, const Tuple & b) +{ + return tuple_compare_string(a, b, Tuple::Comment); +} static const Playlist::StringCompareFunc filename_comparisons[] = { - str_compare_encoded, // path - filename_compare_basename, // filename - nullptr, // title - nullptr, // album - nullptr, // artist - nullptr, // album artist - nullptr, // date - nullptr, // genre - nullptr, // track - nullptr, // formatted title - nullptr, // length - nullptr // comment + filename_compare_path, // path + filename_compare_basename, // filename + nullptr, // title + nullptr, // album + nullptr, // artist + nullptr, // album artist + nullptr, // date + nullptr, // genre + nullptr, // track + nullptr, // formatted title + nullptr, // length + nullptr // comment }; static const Playlist::TupleCompareFunc tuple_comparisons[] = { - nullptr, // path - nullptr, // filename + nullptr, // path + nullptr, // filename tuple_compare_title, tuple_compare_album, tuple_compare_artist, @@ -114,51 +149,50 @@ static const Playlist::TupleCompareFunc tuple_comparisons[] = { tuple_compare_track, tuple_compare_formatted_title, tuple_compare_length, - tuple_compare_comment -}; + tuple_compare_comment}; -static_assert (aud::n_elems (filename_comparisons) == Playlist::n_sort_types && - aud::n_elems (tuple_comparisons) == Playlist::n_sort_types, - "Update playlist comparison functions"); +static_assert(aud::n_elems(filename_comparisons) == Playlist::n_sort_types && + aud::n_elems(tuple_comparisons) == Playlist::n_sort_types, + "Update playlist comparison functions"); -EXPORT void Playlist::sort_entries (SortType scheme) const +EXPORT void Playlist::sort_entries(SortType scheme) const { if (filename_comparisons[scheme]) - sort_by_filename (filename_comparisons[scheme]); + sort_by_filename(filename_comparisons[scheme]); else if (tuple_comparisons[scheme]) - sort_by_tuple (tuple_comparisons[scheme]); + sort_by_tuple(tuple_comparisons[scheme]); } -EXPORT void Playlist::sort_selected (SortType scheme) const +EXPORT void Playlist::sort_selected(SortType scheme) const { if (filename_comparisons[scheme]) - sort_selected_by_filename (filename_comparisons[scheme]); + sort_selected_by_filename(filename_comparisons[scheme]); else if (tuple_comparisons[scheme]) - sort_selected_by_tuple (tuple_comparisons[scheme]); + sort_selected_by_tuple(tuple_comparisons[scheme]); } /* FIXME: this considers empty fields as duplicates */ -EXPORT void Playlist::remove_duplicates (SortType scheme) const +EXPORT void Playlist::remove_duplicates(SortType scheme) const { - int entries = n_entries (); + int entries = n_entries(); if (entries < 1) return; - select_all (false); + select_all(false); if (filename_comparisons[scheme]) { StringCompareFunc compare = filename_comparisons[scheme]; - sort_by_filename (compare); - String last = entry_filename (0); + sort_by_filename(compare); + String last = entry_filename(0); - for (int i = 1; i < entries; i ++) + for (int i = 1; i < entries; i++) { - String current = entry_filename (i); + String current = entry_filename(i); - if (compare (last, current) == 0) - select_entry (i, true); + if (compare(last, current) == 0) + select_entry(i, true); last = current; } @@ -167,227 +201,232 @@ EXPORT void Playlist::remove_duplicates (SortType scheme) const { TupleCompareFunc compare = tuple_comparisons[scheme]; - sort_by_tuple (compare); - Tuple last = entry_tuple (0); + sort_by_tuple(compare); + Tuple last = entry_tuple(0); - for (int i = 1; i < entries; i ++) + for (int i = 1; i < entries; i++) { - Tuple current = entry_tuple (i); + Tuple current = entry_tuple(i); - if (last.valid () && current.valid () && compare (last, current) == 0) - select_entry (i, true); + if (last.valid() && current.valid() && compare(last, current) == 0) + select_entry(i, true); - last = std::move (current); + last = std::move(current); } } - remove_selected (); + remove_selected(); } -EXPORT void Playlist::remove_unavailable () const +EXPORT void Playlist::remove_unavailable() const { - int entries = n_entries (); + int entries = n_entries(); - select_all (false); + select_all(false); - for (int i = 0; i < entries; i ++) + for (int i = 0; i < entries; i++) { - String filename = entry_filename (i); + String filename = entry_filename(i); /* use VFS_NO_ACCESS since VFS_EXISTS doesn't distinguish between * inaccessible files and URI schemes that don't support file_test() */ - if (VFSFile::test_file (filename, VFS_NO_ACCESS)) - select_entry (i, true); + if (VFSFile::test_file(filename, VFS_NO_ACCESS)) + select_entry(i, true); } - remove_selected (); + remove_selected(); } -EXPORT void Playlist::select_by_patterns (const Tuple & patterns) const +EXPORT void Playlist::select_by_patterns(const Tuple & patterns) const { - int entries = n_entries (); + int entries = n_entries(); - select_all (true); + select_all(true); - for (Tuple::Field field : {Tuple::Title, Tuple::Album, Tuple::Artist, Tuple::Basename}) + for (Tuple::Field field : + {Tuple::Title, Tuple::Album, Tuple::Artist, Tuple::Basename}) { - String pattern = patterns.get_str (field); + String pattern = patterns.get_str(field); GRegex * regex; - if (! pattern || ! pattern[0] || ! (regex = g_regex_new (pattern, - G_REGEX_CASELESS, (GRegexMatchFlags) 0, nullptr))) + if (!pattern || !pattern[0] || + !(regex = g_regex_new(pattern, G_REGEX_CASELESS, + (GRegexMatchFlags)0, nullptr))) continue; - for (int i = 0; i < entries; i ++) + for (int i = 0; i < entries; i++) { - if (! entry_selected (i)) + if (!entry_selected(i)) continue; - Tuple tuple = entry_tuple (i); - String string = tuple.get_str (field); + Tuple tuple = entry_tuple(i); + String string = tuple.get_str(field); - if (! string || ! g_regex_match (regex, string, (GRegexMatchFlags) 0, nullptr)) - select_entry (i, false); + if (!string || + !g_regex_match(regex, string, (GRegexMatchFlags)0, nullptr)) + select_entry(i, false); } - g_regex_unref (regex); + g_regex_unref(regex); } } -static StringBuf make_playlist_path (int playlist) +static StringBuf make_playlist_path(int playlist) { - if (! playlist) - return filename_build ({aud_get_path (AudPath::UserDir), "playlist.xspf"}); + if (!playlist) + return filename_build( + {aud_get_path(AudPath::UserDir), "playlist.xspf"}); - return filename_build ({aud_get_path (AudPath::UserDir), - str_printf ("playlist_%02d.xspf", 1 + playlist)}); + return filename_build({aud_get_path(AudPath::UserDir), + str_printf("playlist_%02d.xspf", 1 + playlist)}); } -static void load_playlists_real () +static void load_playlists_real() { - const char * folder = aud_get_path (AudPath::PlaylistDir); + const char * folder = aud_get_path(AudPath::PlaylistDir); /* old (v3.1 and earlier) naming scheme */ int count; - for (count = 0; ; count ++) + for (count = 0;; count++) { - StringBuf path = make_playlist_path (count); - if (! g_file_test (path, G_FILE_TEST_EXISTS)) + StringBuf path = make_playlist_path(count); + if (!g_file_test(path, G_FILE_TEST_EXISTS)) break; - PlaylistEx playlist = Playlist::insert_playlist (count); - playlist.insert_flat_playlist (filename_to_uri (path)); - playlist.set_modified (true); + PlaylistEx playlist = Playlist::insert_playlist(count); + playlist.insert_flat_playlist(filename_to_uri(path)); + playlist.set_modified(true); } /* unique ID-based naming scheme */ - StringBuf order_path = filename_build ({folder, "order"}); - auto order_string = VFSFile::read_file (order_path, - VFSReadOptions (VFS_APPEND_NULL | VFS_IGNORE_MISSING)); - auto order = str_list_to_index (order_string.begin (), " "); + StringBuf order_path = filename_build({folder, "order"}); + auto order_string = VFSFile::read_file( + order_path, VFSReadOptions(VFS_APPEND_NULL | VFS_IGNORE_MISSING)); + auto order = str_list_to_index(order_string.begin(), " "); - for (int i = 0; i < order.len (); i ++) + for (int i = 0; i < order.len(); i++) { const char * number = order[i]; - StringBuf path = filename_build ({folder, str_concat ({number, ".audpl"})}); - if (! g_file_test (path, G_FILE_TEST_EXISTS)) - path = filename_build ({folder, str_concat ({number, ".xspf"})}); + StringBuf path = + filename_build({folder, str_concat({number, ".audpl"})}); + if (!g_file_test(path, G_FILE_TEST_EXISTS)) + path = filename_build({folder, str_concat({number, ".xspf"})}); - PlaylistEx playlist = PlaylistEx::insert_with_stamp (count + i, atoi (number)); - playlist.insert_flat_playlist (filename_to_uri (path)); - playlist.set_modified (g_str_has_suffix (path, ".xspf")); + PlaylistEx playlist = + PlaylistEx::insert_with_stamp(count + i, atoi(number)); + playlist.insert_flat_playlist(filename_to_uri(path)); + playlist.set_modified(g_str_has_suffix(path, ".xspf")); } - if (! Playlist::n_playlists ()) - Playlist::insert_playlist (0); + if (!Playlist::n_playlists()) + Playlist::insert_playlist(0); } -static void save_playlists_real () +static void save_playlists_real() { - int lists = Playlist::n_playlists (); - const char * folder = aud_get_path (AudPath::PlaylistDir); + int lists = Playlist::n_playlists(); + const char * folder = aud_get_path(AudPath::PlaylistDir); /* save playlists */ Index order; SimpleHash saved; - for (int i = 0; i < lists; i ++) + for (int i = 0; i < lists; i++) { - PlaylistEx playlist = Playlist::by_index (i); - StringBuf number = int_to_str (playlist.stamp ()); - StringBuf name = str_concat ({number, ".audpl"}); + PlaylistEx playlist = Playlist::by_index(i); + StringBuf number = int_to_str(playlist.stamp()); + StringBuf name = str_concat({number, ".audpl"}); - if (playlist.get_modified ()) + if (playlist.get_modified()) { - StringBuf path = filename_build ({folder, name}); - playlist.save_to_file (filename_to_uri (path), Playlist::NoWait); - playlist.set_modified (false); + StringBuf path = filename_build({folder, name}); + playlist.save_to_file(filename_to_uri(path), Playlist::NoWait); + playlist.set_modified(false); } - order.append (String (number)); - saved.add (String (name), true); + order.append(String(number)); + saved.add(String(name), true); } - StringBuf order_string = index_to_str_list (order, " "); - StringBuf order_path = filename_build ({folder, "order"}); - auto old_order_string = VFSFile::read_file (order_path, - VFSReadOptions (VFS_APPEND_NULL | VFS_IGNORE_MISSING)); + StringBuf order_string = index_to_str_list(order, " "); + StringBuf order_path = filename_build({folder, "order"}); + auto old_order_string = VFSFile::read_file( + order_path, VFSReadOptions(VFS_APPEND_NULL | VFS_IGNORE_MISSING)); - if (strcmp (old_order_string.begin (), order_string)) - VFSFile::write_file (order_path, (const char *) order_string, order_string.len ()); + if (strcmp(old_order_string.begin(), order_string)) + VFSFile::write_file(order_path, (const char *)order_string, + order_string.len()); /* clean up deleted playlists and files from old naming scheme */ - g_unlink (make_playlist_path (0)); + g_unlink(make_playlist_path(0)); - GDir * dir = g_dir_open (folder, 0, nullptr); - if (! dir) + GDir * dir = g_dir_open(folder, 0, nullptr); + if (!dir) return; const char * name; - while ((name = g_dir_read_name (dir))) + while ((name = g_dir_read_name(dir))) { - if (! g_str_has_suffix (name, ".audpl") && ! g_str_has_suffix (name, ".xspf")) + if (!g_str_has_suffix(name, ".audpl") && + !g_str_has_suffix(name, ".xspf")) continue; - if (! saved.lookup (String (name))) - g_unlink (filename_build ({folder, name})); + if (!saved.lookup(String(name))) + g_unlink(filename_build({folder, name})); } - g_dir_close (dir); + g_dir_close(dir); } static bool hooks_added, state_changed; -static void update_cb (void * data, void *) +static void update_cb(void * data, void *) { - auto level = aud::from_ptr (data); + auto level = aud::from_ptr(data); if (level >= Playlist::Metadata) state_changed = true; } -static void state_cb (void * data, void * user) -{ - state_changed = true; -} +static void state_cb(void * data, void * user) { state_changed = true; } -void load_playlists () +void load_playlists() { - load_playlists_real (); - playlist_load_state (); + load_playlists_real(); + playlist_load_state(); state_changed = false; - if (! hooks_added) + if (!hooks_added) { - hook_associate ("playlist update", update_cb, nullptr); - hook_associate ("playlist activate", state_cb, nullptr); - hook_associate ("playlist position", state_cb, nullptr); + hook_associate("playlist update", update_cb, nullptr); + hook_associate("playlist activate", state_cb, nullptr); + hook_associate("playlist position", state_cb, nullptr); hooks_added = true; } } -void save_playlists (bool exiting) +void save_playlists(bool exiting) { - save_playlists_real (); + save_playlists_real(); /* on exit, save resume states */ if (state_changed || exiting) { - playlist_save_state (); + playlist_save_state(); state_changed = false; } if (exiting && hooks_added) { - hook_dissociate ("playlist update", update_cb); - hook_dissociate ("playlist activate", state_cb); - hook_dissociate ("playlist position", state_cb); + hook_dissociate("playlist update", update_cb); + hook_dissociate("playlist activate", state_cb); + hook_dissociate("playlist position", state_cb); hooks_added = false; } diff --git a/src/libaudcore/playlist.cc b/src/libaudcore/playlist.cc index 6b64808..d7543c9 100644 --- a/src/libaudcore/playlist.cc +++ b/src/libaudcore/playlist.cc @@ -20,7 +20,6 @@ #include "playlist-internal.h" #include -#include #include #include #include @@ -38,22 +37,26 @@ #include "parse.h" #include "playlist-data.h" #include "runtime.h" +#include "threads.h" -enum { +enum +{ ResumeStop, ResumePlay, ResumePause }; /* update hooks */ -enum { - SetActive = (1 << 0), - SetPlaying = (1 << 1), +enum +{ + SetActive = (1 << 0), + SetPlaying = (1 << 1), PlaybackBegin = (1 << 2), - PlaybackStop = (1 << 3) + PlaybackStop = (1 << 3) }; -enum class UpdateState { +enum class UpdateState +{ None, Delayed, Queued @@ -61,35 +64,25 @@ enum class UpdateState { #define STATE_FILE "playlist-state" -#define ENTER pthread_mutex_lock (& mutex) -#define LEAVE pthread_mutex_unlock (& mutex) - -#define RETURN(...) do { \ - pthread_mutex_unlock (& mutex); \ - return __VA_ARGS__; \ -} while (0) +#define ENTER_GET_PLAYLIST(...) \ + auto mh = mutex.take(); \ + PlaylistData * playlist = m_id ? m_id->data : nullptr; \ + if (!playlist) \ + return __VA_ARGS__ -#define ENTER_GET_PLAYLIST(...) \ - ENTER; \ - PlaylistData * playlist = m_id ? m_id->data : nullptr; \ - if (! playlist) \ - RETURN (__VA_ARGS__) +#define SIMPLE_WRAPPER(type, failcode, func, ...) \ + ENTER_GET_PLAYLIST(failcode); \ + return playlist->func(__VA_ARGS__) -#define SIMPLE_WRAPPER(type, failcode, func, ...) \ - ENTER_GET_PLAYLIST (failcode); \ - type retval = playlist->func (__VA_ARGS__); \ - RETURN (retval) - -#define SIMPLE_VOID_WRAPPER(func, ...) \ - ENTER_GET_PLAYLIST (); \ - playlist->func (__VA_ARGS__); \ - LEAVE +#define SIMPLE_VOID_WRAPPER(func, ...) \ + ENTER_GET_PLAYLIST(); \ + playlist->func(__VA_ARGS__) static const char * const default_title = N_("New Playlist"); static const char * const temp_title = N_("Now Playing"); -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static aud::mutex mutex; +static aud::condvar condvar; /* * Each playlist is associated with its own ID struct, which contains a unique @@ -106,9 +99,9 @@ static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; */ struct Playlist::ID { - int stamp; // integer stamp, determines filename - int index; // display order - PlaylistData * data; // pointer to actual playlist data + int stamp; // integer stamp, determines filename + int index; // display order + PlaylistData * data; // pointer to actual playlist data }; static SimpleHash id_table; @@ -127,13 +120,12 @@ static UpdateState update_state; struct ScanItem : public ListNode { - ScanItem (PlaylistData * playlist, PlaylistEntry * entry, - ScanRequest * request, bool for_playback) : - playlist (playlist), - entry (entry), - request (request), - for_playback (for_playback), - handled_by_playback (false) {} + ScanItem(PlaylistData * playlist, PlaylistEntry * entry, + ScanRequest * request, bool for_playback) + : playlist(playlist), entry(entry), request(request), + for_playback(for_playback), handled_by_playback(false) + { + } PlaylistData * playlist; PlaylistEntry * entry; @@ -146,39 +138,39 @@ static bool scan_enabled_nominal, scan_enabled; static int scan_playlist, scan_row; static List scan_list; -static void scan_finish (ScanRequest * request); -static void scan_cancel (PlaylistEntry * entry); -static void scan_restart (); +static void scan_finish(ScanRequest * request); +static void scan_cancel(PlaylistEntry * entry); +static void scan_restart(); /* creates a new playlist with the requested stamp (if not already in use) */ -static Playlist::ID * create_playlist (int stamp) +static Playlist::ID * create_playlist(int stamp) { Playlist::ID * id; - if (stamp >= 0 && ! id_table.lookup (stamp)) - id = id_table.add (stamp, {stamp, -1, nullptr}); + if (stamp >= 0 && !id_table.lookup(stamp)) + id = id_table.add(stamp, {stamp, -1, nullptr}); else { - while (id_table.lookup (next_stamp)) - next_stamp ++; + while (id_table.lookup(next_stamp)) + next_stamp++; - id = id_table.add (next_stamp, {next_stamp, -1, nullptr}); + id = id_table.add(next_stamp, {next_stamp, -1, nullptr}); } - id->data = new PlaylistData (id, _(default_title)); + id->data = new PlaylistData(id, _(default_title)); return id; } -static void number_playlists (int at, int length) +static void number_playlists(int at, int length) { - for (int i = at; i < at + length; i ++) - playlists[i]->id ()->index = i; + for (int i = at; i < at + length; i++) + playlists[i]->id()->index = i; } -static void update (void *) +static void update(void *) { - ENTER; + auto mh = mutex.take(); int hooks = update_hooks; auto level = update_level; @@ -188,35 +180,35 @@ static void update (void *) for (auto & p : playlists) { bool position_changed = false; - p->swap_updates (position_changed); + p->swap_updates(position_changed); if (position_changed) - position_change_list.append (p->id ()); + position_change_list.append(p->id()); } update_hooks = 0; update_level = Playlist::NoUpdate; update_state = UpdateState::None; - LEAVE; + mh.unlock(); if (level != Playlist::NoUpdate) - hook_call ("playlist update", aud::to_ptr (level)); + hook_call("playlist update", aud::to_ptr(level)); for (PlaylistEx playlist : position_change_list) - hook_call ("playlist position", aud::to_ptr (playlist)); + hook_call("playlist position", aud::to_ptr(playlist)); if ((hooks & SetActive)) - hook_call ("playlist activate", nullptr); + hook_call("playlist activate", nullptr); if ((hooks & SetPlaying)) - hook_call ("playlist set playing", nullptr); + hook_call("playlist set playing", nullptr); if ((hooks & PlaybackBegin)) - hook_call ("playback begin", nullptr); + hook_call("playback begin", nullptr); if ((hooks & PlaybackStop)) - hook_call ("playback stop", nullptr); + hook_call("playback stop", nullptr); } -static void queue_update_hooks (int hooks) +static void queue_update_hooks(int hooks) { if ((hooks & PlaybackBegin)) update_hooks &= ~PlaybackStop; @@ -227,21 +219,21 @@ static void queue_update_hooks (int hooks) if (update_state < UpdateState::Queued) { - queued_update.queue (update, nullptr); + queued_update.queue(update, nullptr); update_state = UpdateState::Queued; } } -static void queue_global_update (Playlist::UpdateLevel level, int flags = 0) +static void queue_global_update(Playlist::UpdateLevel level, int flags = 0) { if (level == Playlist::Structure) - scan_restart (); + scan_restart(); if ((flags & PlaylistData::DelayedUpdate)) { if (update_state < UpdateState::Delayed) { - queued_update.queue (250, update, nullptr); + queued_update.queue(250, update, nullptr); update_state = UpdateState::Delayed; } } @@ -249,291 +241,286 @@ static void queue_global_update (Playlist::UpdateLevel level, int flags = 0) { if (update_state < UpdateState::Queued) { - queued_update.queue (update, nullptr); + queued_update.queue(update, nullptr); update_state = UpdateState::Queued; } } - update_level = aud::max (update_level, level); + update_level = aud::max(update_level, level); } -EXPORT bool Playlist::update_pending_any () +EXPORT bool Playlist::update_pending_any() { - ENTER; - bool pending = (update_level != Playlist::NoUpdate); - RETURN (pending); + auto mh = mutex.take(); + return (update_level != Playlist::NoUpdate); } -EXPORT void Playlist::process_pending_update () -{ - update (nullptr); -} +EXPORT void Playlist::process_pending_update() { update(nullptr); } -EXPORT bool Playlist::scan_in_progress () const +EXPORT bool Playlist::scan_in_progress() const { - ENTER_GET_PLAYLIST (false); - bool scanning = (playlist->scan_status != PlaylistData::NotScanning); - RETURN (scanning); + ENTER_GET_PLAYLIST(false); + return (playlist->scan_status != PlaylistData::NotScanning); } -EXPORT bool Playlist::scan_in_progress_any () +EXPORT bool Playlist::scan_in_progress_any() { - ENTER; + auto mh = mutex.take(); - bool scanning = false; for (auto & p : playlists) { if (p->scan_status != PlaylistData::NotScanning) - scanning = true; + return true; } - RETURN (scanning); + return false; } -static ScanItem * scan_list_find_entry (PlaylistEntry * entry) +static ScanItem * scan_list_find_entry(PlaylistEntry * entry) { - auto match = [entry] (const ScanItem & item) - { return item.entry == entry; }; + auto match = [entry](const ScanItem & item) { return item.entry == entry; }; - return scan_list.find (match); + return scan_list.find(match); } -static void scan_queue_entry (PlaylistData * playlist, PlaylistEntry * entry, bool for_playback = false) +static void scan_queue_entry(PlaylistData * playlist, PlaylistEntry * entry, + bool for_playback = false) { int extra_flags = for_playback ? (SCAN_IMAGE | SCAN_FILE) : 0; - auto request = playlist->create_scan_request (entry, scan_finish, extra_flags); + auto request = + playlist->create_scan_request(entry, scan_finish, extra_flags); - scan_list.append (new ScanItem (playlist, entry, request, for_playback)); + scan_list.append(new ScanItem(playlist, entry, request, for_playback)); /* playback entry will be scanned by the playback thread */ - if (! for_playback) - scanner_request (request); + if (!for_playback) + scanner_request(request); } -static void scan_reset_playback () +static void scan_reset_playback() { - auto match = [] (const ScanItem & item) - { return item.for_playback; }; + auto match = [](const ScanItem & item) { return item.for_playback; }; - ScanItem * item = scan_list.find (match); - if (! item) + ScanItem * item = scan_list.find(match); + if (!item) return; item->for_playback = false; /* if playback was canceled before the entry was scanned, requeue it */ - if (! item->handled_by_playback) - scanner_request (item->request); + if (!item->handled_by_playback) + scanner_request(item->request); } -static void scan_check_complete (PlaylistData * playlist) +static void scan_check_complete(PlaylistData * playlist) { - auto match = [playlist] (const ScanItem & item) - { return item.playlist == playlist; }; + auto match = [playlist](const ScanItem & item) { + return item.playlist == playlist; + }; - if (playlist->scan_status != PlaylistData::ScanEnding || scan_list.find (match)) + if (playlist->scan_status != PlaylistData::ScanEnding || + scan_list.find(match)) return; playlist->scan_status = PlaylistData::NotScanning; if (update_state == UpdateState::Delayed) { - queued_update.queue (update, nullptr); + queued_update.queue(update, nullptr); update_state = UpdateState::Queued; } - event_queue_cancel ("playlist scan complete"); - event_queue ("playlist scan complete", nullptr); + event_queue_cancel("playlist scan complete"); + event_queue("playlist scan complete", nullptr); } -static bool scan_queue_next_entry () +static bool scan_queue_next_entry() { - if (! scan_enabled) + if (!scan_enabled) return false; - while (scan_playlist < playlists.len ()) + while (scan_playlist < playlists.len()) { - PlaylistData * playlist = playlists[scan_playlist].get (); + PlaylistData * playlist = playlists[scan_playlist].get(); if (playlist->scan_status == PlaylistData::ScanActive) { while (1) { - scan_row = playlist->next_unscanned_entry (scan_row); + scan_row = playlist->next_unscanned_entry(scan_row); if (scan_row < 0) break; - auto entry = playlist->entry_at (scan_row); - if (! scan_list_find_entry (entry)) + auto entry = playlist->entry_at(scan_row); + if (!scan_list_find_entry(entry)) { - scan_queue_entry (playlist, entry); + scan_queue_entry(playlist, entry); return true; } - scan_row ++; + scan_row++; } playlist->scan_status = PlaylistData::ScanEnding; - scan_check_complete (playlist); + scan_check_complete(playlist); } - scan_playlist ++; + scan_playlist++; scan_row = 0; } return false; } -static void scan_schedule () +static void scan_schedule() { int scheduled = 0; - for (ScanItem * item = scan_list.head (); item; item = scan_list.next (item)) + for (ScanItem * item = scan_list.head(); item; item = scan_list.next(item)) { - if (++ scheduled >= SCAN_THREADS) + if (++scheduled >= SCAN_THREADS) return; } - while (scan_queue_next_entry ()) + while (scan_queue_next_entry()) { - if (++ scheduled >= SCAN_THREADS) + if (++scheduled >= SCAN_THREADS) return; } } -static void scan_finish (ScanRequest * request) +static void scan_finish(ScanRequest * request) { - ENTER; + auto mh = mutex.take(); - auto match = [request] (const ScanItem & item) - { return item.request == request; }; + auto match = [request](const ScanItem & item) { + return item.request == request; + }; - ScanItem * item = scan_list.find (match); - if (! item) - RETURN (); + ScanItem * item = scan_list.find(match); + if (!item) + return; PlaylistData * playlist = item->playlist; PlaylistEntry * entry = item->entry; - scan_list.remove (item); + scan_list.remove(item); // only use delayed update if a scan is still in progress int update_flags = 0; if (scan_enabled && playlist->scan_status != PlaylistData::NotScanning) update_flags = PlaylistData::DelayedUpdate; - playlist->update_entry_from_scan (entry, request, update_flags); + playlist->update_entry_from_scan(entry, request, update_flags); delete item; - scan_check_complete (playlist); - scan_schedule (); + scan_check_complete(playlist); + scan_schedule(); - pthread_cond_broadcast (& cond); - - LEAVE; + condvar.notify_all(); } -static void scan_cancel (PlaylistEntry * entry) +static void scan_cancel(PlaylistEntry * entry) { - ScanItem * item = scan_list_find_entry (entry); - if (! item) + ScanItem * item = scan_list_find_entry(entry); + if (!item) return; - scan_list.remove (item); + scan_list.remove(item); delete (item); } -static void scan_restart () +static void scan_restart() { scan_playlist = 0; scan_row = 0; - scan_schedule (); + scan_schedule(); } /* mutex may be unlocked during the call */ -static void wait_for_entry (PlaylistData * playlist, int entry_num, bool need_decoder, bool need_tuple) +static void wait_for_entry(aud::mutex::holder & mh, PlaylistData * playlist, + int entry_num, bool need_decoder, bool need_tuple) { bool scan_started = false; while (1) { - PlaylistEntry * entry = playlist->entry_at (entry_num); + PlaylistEntry * entry = playlist->entry_at(entry_num); // check whether entry is deleted or has already been scanned - if (! entry || ! playlist->entry_needs_rescan (entry, need_decoder, need_tuple)) + if (!entry || + !playlist->entry_needs_rescan(entry, need_decoder, need_tuple)) return; // start scan if not already running ... - if (! scan_list_find_entry (entry)) + if (!scan_list_find_entry(entry)) { // ... but only once if (scan_started) return; - scan_queue_entry (playlist, entry); + scan_queue_entry(playlist, entry); } // wait for scan to finish scan_started = true; - pthread_cond_wait (& cond, & mutex); + condvar.wait(mh); } } -static void start_playback_locked (int seek_time, bool pause) +static void start_playback_locked(int seek_time, bool pause) { - art_clear_current (); - scan_reset_playback (); + art_clear_current(); + scan_reset_playback(); - playback_play (seek_time, pause); + playback_play(seek_time, pause); auto playlist = playing_id->data; - auto entry = playlist->entry_at (playlist->position ()); + auto entry = playlist->entry_at(playlist->position()); // playback always begins with a rescan of the current entry in order to // open the file, ensure a valid tuple, and read album art - scan_cancel (entry); - scan_queue_entry (playlist, entry, true); + scan_cancel(entry); + scan_queue_entry(playlist, entry, true); } -static void stop_playback_locked () +static void stop_playback_locked() { - art_clear_current (); - scan_reset_playback (); + art_clear_current(); + scan_reset_playback(); - playback_stop (); + playback_stop(); } -void pl_signal_entry_deleted (PlaylistEntry * entry) -{ - scan_cancel (entry); -} +void pl_signal_entry_deleted(PlaylistEntry * entry) { scan_cancel(entry); } -void pl_signal_position_changed (Playlist::ID * id) +void pl_signal_position_changed(Playlist::ID * id) { if (update_state < UpdateState::Queued) { - queued_update.queue (update, nullptr); + queued_update.queue(update, nullptr); update_state = UpdateState::Queued; } if (id == playing_id) { - if (id->data->position () >= 0) + if (id->data->position() >= 0) { - start_playback_locked (0, aud_drct_get_paused ()); - queue_update_hooks (PlaybackBegin); + start_playback_locked(0, aud_drct_get_paused()); + queue_update_hooks(PlaybackBegin); } else { playing_id = nullptr; - stop_playback_locked (); - queue_update_hooks (SetPlaying | PlaybackStop); + stop_playback_locked(); + queue_update_hooks(SetPlaying | PlaybackStop); } } } -void pl_signal_update_queued (Playlist::ID * id, Playlist::UpdateLevel level, int flags) +void pl_signal_update_queued(Playlist::ID * id, Playlist::UpdateLevel level, + int flags) { auto playlist = id->data; @@ -542,56 +529,53 @@ void pl_signal_update_queued (Playlist::ID * id, Playlist::UpdateLevel level, in if (level >= Playlist::Metadata) { - int pos = playlist->position (); + int pos = playlist->position(); if (id == playing_id && pos >= 0) - playback_set_info (pos, playlist->entry_tuple (pos)); + playback_set_info(pos, playlist->entry_tuple(pos)); playlist->modified = true; } - queue_global_update (level, flags); + queue_global_update(level, flags); } -void pl_signal_rescan_needed (Playlist::ID * id) +void pl_signal_rescan_needed(Playlist::ID * id) { id->data->scan_status = PlaylistData::ScanActive; - scan_restart (); + scan_restart(); } -void pl_signal_playlist_deleted (Playlist::ID * id) +void pl_signal_playlist_deleted(Playlist::ID * id) { /* break weak pointer link */ id->data = nullptr; id->index = -1; } -static void pl_hook_reformat_titles (void *, void *) +static void pl_hook_reformat_titles(void *, void *) { - ENTER; + auto mh = mutex.take(); - PlaylistData::update_formatter (); + PlaylistData::update_formatter(); for (auto & playlist : playlists) - playlist->reformat_titles (); - - LEAVE; + playlist->reformat_titles(); } -static void pl_hook_trigger_scan (void *, void *) +static void pl_hook_trigger_scan(void *, void *) { - ENTER; - scan_enabled = scan_enabled_nominal && ! aud_get_bool (nullptr, "metadata_on_play"); - scan_restart (); - LEAVE; + auto mh = mutex.take(); + scan_enabled = scan_enabled_nominal && !aud_get_bool("metadata_on_play"); + scan_restart(); } -void playlist_init () +void playlist_init() { - srand (time (nullptr)); + srand(time(nullptr)); - ENTER; + auto mh = mutex.take(); - PlaylistData::update_formatter (); + PlaylistData::update_formatter(); update_level = Playlist::NoUpdate; update_hooks = 0; @@ -599,644 +583,693 @@ void playlist_init () scan_enabled = scan_enabled_nominal = false; scan_playlist = scan_row = 0; - LEAVE; + mh.unlock(); - hook_associate ("set generic_title_format", pl_hook_reformat_titles, nullptr); - hook_associate ("set leading_zero", pl_hook_reformat_titles, nullptr); - hook_associate ("set metadata_fallbacks", pl_hook_reformat_titles, nullptr); - hook_associate ("set show_hours", pl_hook_reformat_titles, nullptr); - hook_associate ("set show_numbers_in_pl", pl_hook_reformat_titles, nullptr); - hook_associate ("set metadata_on_play", pl_hook_trigger_scan, nullptr); + hook_associate("set generic_title_format", pl_hook_reformat_titles, + nullptr); + hook_associate("set leading_zero", pl_hook_reformat_titles, nullptr); + hook_associate("set metadata_fallbacks", pl_hook_reformat_titles, nullptr); + hook_associate("set show_hours", pl_hook_reformat_titles, nullptr); + hook_associate("set show_numbers_in_pl", pl_hook_reformat_titles, nullptr); + hook_associate("set metadata_on_play", pl_hook_trigger_scan, nullptr); } -void playlist_enable_scan (bool enable) +void playlist_enable_scan(bool enable) { - ENTER; + auto mh = mutex.take(); scan_enabled_nominal = enable; - scan_enabled = scan_enabled_nominal && ! aud_get_bool (nullptr, "metadata_on_play"); - scan_restart (); - - LEAVE; + scan_enabled = scan_enabled_nominal && !aud_get_bool("metadata_on_play"); + scan_restart(); } -void playlist_clear_updates () +void playlist_clear_updates() { - ENTER; + auto mh = mutex.take(); /* clear updates queued during init sequence */ for (auto & playlist : playlists) - playlist->cancel_updates (); + playlist->cancel_updates(); - queued_update.stop (); + queued_update.stop(); update_level = Playlist::NoUpdate; update_hooks = 0; update_state = UpdateState::None; - - LEAVE; } -void playlist_end () +void playlist_end() { - hook_dissociate ("set generic_title_format", pl_hook_reformat_titles); - hook_dissociate ("set leading_zero", pl_hook_reformat_titles); - hook_dissociate ("set metadata_fallbacks", pl_hook_reformat_titles); - hook_dissociate ("set show_hours", pl_hook_reformat_titles); - hook_dissociate ("set show_numbers_in_pl", pl_hook_reformat_titles); - hook_dissociate ("set metadata_on_play", pl_hook_trigger_scan); + hook_dissociate("set generic_title_format", pl_hook_reformat_titles); + hook_dissociate("set leading_zero", pl_hook_reformat_titles); + hook_dissociate("set metadata_fallbacks", pl_hook_reformat_titles); + hook_dissociate("set show_hours", pl_hook_reformat_titles); + hook_dissociate("set show_numbers_in_pl", pl_hook_reformat_titles); + hook_dissociate("set metadata_on_play", pl_hook_trigger_scan); - playlist_cache_clear (); + playlist_cache_clear(); - ENTER; + auto mh = mutex.take(); /* playback should already be stopped */ - assert (! playing_id); - assert (! scan_list.head ()); + assert(!playing_id); + assert(!scan_list.head()); - queued_update.stop (); + queued_update.stop(); active_id = nullptr; resume_playlist = -1; resume_paused = false; - playlists.clear (); - id_table.clear (); - - PlaylistData::cleanup_formatter (); - - LEAVE; -} - -EXPORT int Playlist::n_entries () const - { SIMPLE_WRAPPER (int, 0, n_entries); } -EXPORT void Playlist::remove_entries (int at, int number) const - { SIMPLE_VOID_WRAPPER (remove_entries, at, number); } -EXPORT String Playlist::entry_filename (int entry_num) const - { SIMPLE_WRAPPER (String, String (), entry_filename, entry_num); } - -EXPORT int Playlist::get_position () const - { SIMPLE_WRAPPER (int, -1, position); } -EXPORT void Playlist::set_position (int entry_num) const - { SIMPLE_VOID_WRAPPER (set_position, entry_num); } -EXPORT bool Playlist::prev_song () const - { SIMPLE_WRAPPER (bool, false, prev_song); } -EXPORT bool Playlist::next_song (bool repeat) const - { SIMPLE_WRAPPER (bool, false, next_song, repeat); } -EXPORT int Playlist::get_focus () const - { SIMPLE_WRAPPER (int, -1, focus); } -EXPORT void Playlist::set_focus (int entry_num) const - { SIMPLE_VOID_WRAPPER (set_focus, entry_num); } -EXPORT bool Playlist::entry_selected (int entry_num) const - { SIMPLE_WRAPPER (bool, false, entry_selected, entry_num); } -EXPORT void Playlist::select_entry (int entry_num, bool selected) const - { SIMPLE_VOID_WRAPPER (select_entry, entry_num, selected); } -EXPORT int Playlist::n_selected (int at, int number) const - { SIMPLE_WRAPPER (int, 0, n_selected, at, number); } -EXPORT void Playlist::select_all (bool selected) const - { SIMPLE_VOID_WRAPPER (select_all, selected); } -EXPORT int Playlist::shift_entries (int entry_num, int distance) const - { SIMPLE_WRAPPER (int, 0, shift_entries, entry_num, distance); } -EXPORT void Playlist::remove_selected () const - { SIMPLE_VOID_WRAPPER (remove_selected); } - -EXPORT void Playlist::sort_by_filename (StringCompareFunc compare) const - { SIMPLE_VOID_WRAPPER (sort, {compare, nullptr}); } -EXPORT void Playlist::sort_by_tuple (TupleCompareFunc compare) const - { SIMPLE_VOID_WRAPPER (sort, {nullptr, compare}); } -EXPORT void Playlist::sort_selected_by_filename (StringCompareFunc compare) const - { SIMPLE_VOID_WRAPPER (sort_selected, {compare, nullptr}); } -EXPORT void Playlist::sort_selected_by_tuple (TupleCompareFunc compare) const - { SIMPLE_VOID_WRAPPER (sort_selected, {nullptr, compare}); } -EXPORT void Playlist::reverse_order () const - { SIMPLE_VOID_WRAPPER (reverse_order); } -EXPORT void Playlist::reverse_selected () const - { SIMPLE_VOID_WRAPPER (reverse_selected); } -EXPORT void Playlist::randomize_order () const - { SIMPLE_VOID_WRAPPER (randomize_order); } -EXPORT void Playlist::randomize_selected () const - { SIMPLE_VOID_WRAPPER (randomize_selected); } - -EXPORT void Playlist::rescan_all () const - { SIMPLE_VOID_WRAPPER (reset_tuples, false); } -EXPORT void Playlist::rescan_selected () const - { SIMPLE_VOID_WRAPPER (reset_tuples, true); } - -EXPORT int64_t Playlist::total_length_ms () const - { SIMPLE_WRAPPER (int64_t, 0, total_length); } -EXPORT int64_t Playlist::selected_length_ms () const - { SIMPLE_WRAPPER (int64_t, 0, selected_length); } - -EXPORT int Playlist::n_queued () const - { SIMPLE_WRAPPER (int, 0, n_queued); } -EXPORT void Playlist::queue_insert (int at, int entry_num) const - { SIMPLE_VOID_WRAPPER (queue_insert, at, entry_num); } -EXPORT void Playlist::queue_insert_selected (int at) const - { SIMPLE_VOID_WRAPPER (queue_insert_selected, at); } -EXPORT int Playlist::queue_get_entry (int at) const - { SIMPLE_WRAPPER (int, -1, queue_get_entry, at); } -EXPORT int Playlist::queue_find_entry (int entry_num) const - { SIMPLE_WRAPPER (int, -1, queue_find_entry, entry_num); } -EXPORT void Playlist::queue_remove (int at, int number) const - { SIMPLE_VOID_WRAPPER (queue_remove, at, number); } -EXPORT void Playlist::queue_remove_selected () const - { SIMPLE_VOID_WRAPPER (queue_remove_selected); } - -EXPORT bool Playlist::update_pending () const - { SIMPLE_WRAPPER (bool, false, update_pending); } -EXPORT Playlist::Update Playlist::update_detail () const - { SIMPLE_WRAPPER (Update, Update (), last_update); } - -void PlaylistEx::insert_flat_items (int at, Index && items) const - { SIMPLE_VOID_WRAPPER (insert_items, at, std::move (items)); } - -EXPORT int Playlist::index () const -{ - ENTER_GET_PLAYLIST (-1); - int at = m_id->index; - RETURN (at); + playlists.clear(); + id_table.clear(); + + PlaylistData::cleanup_formatter(); } -EXPORT int PlaylistEx::stamp () const +EXPORT int Playlist::n_entries() const { SIMPLE_WRAPPER(int, 0, n_entries); } +EXPORT void Playlist::remove_entries(int at, int number) const +{ + SIMPLE_VOID_WRAPPER(remove_entries, at, number); +} +EXPORT String Playlist::entry_filename(int entry_num) const { - ENTER_GET_PLAYLIST (-1); - int stamp = m_id->stamp; - RETURN (stamp); + SIMPLE_WRAPPER(String, String(), entry_filename, entry_num); } -EXPORT int Playlist::n_playlists () +EXPORT int Playlist::get_position() const { SIMPLE_WRAPPER(int, -1, position); } +EXPORT void Playlist::set_position(int entry_num) const +{ + SIMPLE_VOID_WRAPPER(set_position, entry_num); +} +EXPORT bool Playlist::prev_song() const +{ + SIMPLE_WRAPPER(bool, false, prev_song); +} +EXPORT bool Playlist::prev_album() const +{ + SIMPLE_WRAPPER(bool, false, prev_album); +} +EXPORT bool Playlist::next_song(bool repeat) const { - ENTER; - int count = playlists.len (); - RETURN (count); + SIMPLE_WRAPPER(bool, false, next_song, repeat); +} +EXPORT bool Playlist::next_album(bool repeat) const +{ + SIMPLE_WRAPPER(bool, false, next_album, repeat); +} +EXPORT int Playlist::get_focus() const { SIMPLE_WRAPPER(int, -1, focus); } +EXPORT void Playlist::set_focus(int entry_num) const +{ + SIMPLE_VOID_WRAPPER(set_focus, entry_num); +} +EXPORT bool Playlist::entry_selected(int entry_num) const +{ + SIMPLE_WRAPPER(bool, false, entry_selected, entry_num); +} +EXPORT void Playlist::select_entry(int entry_num, bool selected) const +{ + SIMPLE_VOID_WRAPPER(select_entry, entry_num, selected); +} +EXPORT int Playlist::n_selected(int at, int number) const +{ + SIMPLE_WRAPPER(int, 0, n_selected, at, number); +} +EXPORT void Playlist::select_all(bool selected) const +{ + SIMPLE_VOID_WRAPPER(select_all, selected); +} +EXPORT int Playlist::shift_entries(int entry_num, int distance) const +{ + SIMPLE_WRAPPER(int, 0, shift_entries, entry_num, distance); +} +EXPORT void Playlist::remove_selected() const +{ + SIMPLE_VOID_WRAPPER(remove_selected); } -EXPORT Playlist Playlist::by_index (int at) +EXPORT void Playlist::sort_by_filename(StringCompareFunc compare) const +{ + SIMPLE_VOID_WRAPPER(sort, {compare, nullptr}); +} +EXPORT void Playlist::sort_by_tuple(TupleCompareFunc compare) const { - ENTER; - Playlist::ID * id = (at >= 0 && at < playlists.len ()) ? playlists[at]->id () : nullptr; - RETURN (Playlist (id)); + SIMPLE_VOID_WRAPPER(sort, {nullptr, compare}); +} +EXPORT void Playlist::sort_selected_by_filename(StringCompareFunc compare) const +{ + SIMPLE_VOID_WRAPPER(sort_selected, {compare, nullptr}); +} +EXPORT void Playlist::sort_selected_by_tuple(TupleCompareFunc compare) const +{ + SIMPLE_VOID_WRAPPER(sort_selected, {nullptr, compare}); +} +EXPORT void Playlist::reverse_order() const +{ + SIMPLE_VOID_WRAPPER(reverse_order); +} +EXPORT void Playlist::reverse_selected() const +{ + SIMPLE_VOID_WRAPPER(reverse_selected); +} +EXPORT void Playlist::randomize_order() const +{ + SIMPLE_VOID_WRAPPER(randomize_order); +} +EXPORT void Playlist::randomize_selected() const +{ + SIMPLE_VOID_WRAPPER(randomize_selected); } -static Playlist::ID * insert_playlist_locked (int at, int stamp = -1) +EXPORT void Playlist::rescan_all() const { - if (at < 0 || at > playlists.len ()) - at = playlists.len (); + SIMPLE_VOID_WRAPPER(reset_tuples, false); +} +EXPORT void Playlist::rescan_selected() const +{ + SIMPLE_VOID_WRAPPER(reset_tuples, true); +} - auto id = create_playlist (stamp); +EXPORT int64_t Playlist::total_length_ms() const +{ + SIMPLE_WRAPPER(int64_t, 0, total_length); +} +EXPORT int64_t Playlist::selected_length_ms() const +{ + SIMPLE_WRAPPER(int64_t, 0, selected_length); +} - playlists.insert (at, 1); - playlists[at].capture (id->data); +EXPORT int Playlist::n_queued() const { SIMPLE_WRAPPER(int, 0, n_queued); } +EXPORT void Playlist::queue_insert(int at, int entry_num) const +{ + SIMPLE_VOID_WRAPPER(queue_insert, at, entry_num); +} +EXPORT void Playlist::queue_insert_selected(int at) const +{ + SIMPLE_VOID_WRAPPER(queue_insert_selected, at); +} +EXPORT int Playlist::queue_get_entry(int at) const +{ + SIMPLE_WRAPPER(int, -1, queue_get_entry, at); +} +EXPORT int Playlist::queue_find_entry(int entry_num) const +{ + SIMPLE_WRAPPER(int, -1, queue_find_entry, entry_num); +} +EXPORT void Playlist::queue_remove(int at, int number) const +{ + SIMPLE_VOID_WRAPPER(queue_remove, at, number); +} +EXPORT void Playlist::queue_remove_selected() const +{ + SIMPLE_VOID_WRAPPER(queue_remove_selected); +} - number_playlists (at, playlists.len () - at); +EXPORT bool Playlist::update_pending() const +{ + SIMPLE_WRAPPER(bool, false, update_pending); +} +EXPORT Playlist::Update Playlist::update_detail() const +{ + SIMPLE_WRAPPER(Update, Update(), last_update); +} + +void PlaylistEx::insert_flat_items(int at, + Index && items) const +{ + SIMPLE_VOID_WRAPPER(insert_items, at, std::move(items)); +} + +EXPORT int Playlist::index() const +{ + ENTER_GET_PLAYLIST(-1); + return m_id->index; +} + +EXPORT int PlaylistEx::stamp() const +{ + ENTER_GET_PLAYLIST(-1); + return m_id->stamp; +} + +EXPORT int Playlist::n_playlists() +{ + auto mh = mutex.take(); + return playlists.len(); +} + +EXPORT Playlist Playlist::by_index(int at) +{ + auto mh = mutex.take(); + Playlist::ID * id = + (at >= 0 && at < playlists.len()) ? playlists[at]->id() : nullptr; + return Playlist(id); +} + +static Playlist::ID * insert_playlist_locked(int at, int stamp = -1) +{ + if (at < 0 || at > playlists.len()) + at = playlists.len(); + + auto id = create_playlist(stamp); + + playlists.insert(at, 1); + playlists[at].capture(id->data); + + number_playlists(at, playlists.len() - at); /* this will only happen at startup */ - if (! active_id) + if (!active_id) active_id = id; - queue_global_update (Playlist::Structure); + queue_global_update(Playlist::Structure); return id; } -static Playlist::ID * get_blank_locked () +static Playlist::ID * get_blank_locked() { - if (! strcmp (active_id->data->title, _(default_title)) && ! active_id->data->n_entries ()) + if (!strcmp(active_id->data->title, _(default_title)) && + !active_id->data->n_entries()) return active_id; - return insert_playlist_locked (active_id->index + 1); + return insert_playlist_locked(active_id->index + 1); } -Playlist PlaylistEx::insert_with_stamp (int at, int stamp) +Playlist PlaylistEx::insert_with_stamp(int at, int stamp) { - ENTER; - auto id = insert_playlist_locked (at, stamp); - RETURN (Playlist (id)); + auto mh = mutex.take(); + auto id = insert_playlist_locked(at, stamp); + return Playlist(id); } -EXPORT Playlist Playlist::insert_playlist (int at) +EXPORT Playlist Playlist::insert_playlist(int at) { - ENTER; - auto id = insert_playlist_locked (at); - RETURN (Playlist (id)); + auto mh = mutex.take(); + auto id = insert_playlist_locked(at); + return Playlist(id); } -EXPORT void Playlist::reorder_playlists (int from, int to, int count) +EXPORT void Playlist::reorder_playlists(int from, int to, int count) { - ENTER; + auto mh = mutex.take(); - if (from < 0 || from + count > playlists.len () || to < 0 || to + - count > playlists.len () || count < 0) - RETURN (); + if (from < 0 || from + count > playlists.len() || to < 0 || + to + count > playlists.len() || count < 0) + return; Index> displaced; if (to < from) - displaced.move_from (playlists, to, -1, from - to, true, false); + displaced.move_from(playlists, to, -1, from - to, true, false); else - displaced.move_from (playlists, from + count, -1, to - from, true, false); + displaced.move_from(playlists, from + count, -1, to - from, true, + false); - playlists.shift (from, to, count); + playlists.shift(from, to, count); if (to < from) { - playlists.move_from (displaced, 0, to + count, from - to, false, true); - number_playlists (to, from + count - to); + playlists.move_from(displaced, 0, to + count, from - to, false, true); + number_playlists(to, from + count - to); } else { - playlists.move_from (displaced, 0, from, to - from, false, true); - number_playlists (from, to + count - from); + playlists.move_from(displaced, 0, from, to - from, false, true); + number_playlists(from, to + count - from); } - queue_global_update (Structure); - LEAVE; + queue_global_update(Structure); } -EXPORT void Playlist::remove_playlist () const +EXPORT void Playlist::remove_playlist() const { - ENTER_GET_PLAYLIST (); + ENTER_GET_PLAYLIST(); int at = m_id->index; - playlists.remove (at, 1); + playlists.remove(at, 1); - if (! playlists.len ()) - playlists.append (create_playlist (-1)->data); + if (!playlists.len()) + playlists.append(create_playlist(-1)->data); - number_playlists (at, playlists.len () - at); + number_playlists(at, playlists.len() - at); if (m_id == active_id) { - int active_num = aud::min (at, playlists.len () - 1); - active_id = playlists[active_num]->id (); - queue_update_hooks (SetActive); + int active_num = aud::min(at, playlists.len() - 1); + active_id = playlists[active_num]->id(); + queue_update_hooks(SetActive); } if (m_id == playing_id) { playing_id = nullptr; - stop_playback_locked (); - queue_update_hooks (SetPlaying | PlaybackStop); + stop_playback_locked(); + queue_update_hooks(SetPlaying | PlaybackStop); } - queue_global_update (Structure); - LEAVE; + queue_global_update(Structure); } -EXPORT void Playlist::set_filename (const char * filename) const +EXPORT void Playlist::set_filename(const char * filename) const { - ENTER_GET_PLAYLIST (); + ENTER_GET_PLAYLIST(); - playlist->filename = String (filename); + playlist->filename = String(filename); playlist->modified = true; - queue_global_update (Metadata); - LEAVE; + queue_global_update(Metadata); } -EXPORT String Playlist::get_filename () const +EXPORT String Playlist::get_filename() const { - ENTER_GET_PLAYLIST (String ()); - String filename = playlist->filename; - RETURN (filename); + ENTER_GET_PLAYLIST(String()); + return playlist->filename; } -EXPORT void Playlist::set_title (const char * title) const +EXPORT void Playlist::set_title(const char * title) const { - ENTER_GET_PLAYLIST (); + ENTER_GET_PLAYLIST(); - playlist->title = String (title); + playlist->title = String(title); playlist->modified = true; - queue_global_update (Metadata); - LEAVE; + queue_global_update(Metadata); } -EXPORT String Playlist::get_title () const +EXPORT String Playlist::get_title() const { - ENTER_GET_PLAYLIST (String ()); - String title = playlist->title; - RETURN (title); + ENTER_GET_PLAYLIST(String()); + return playlist->title; } -void PlaylistEx::set_modified (bool modified) const +void PlaylistEx::set_modified(bool modified) const { - ENTER_GET_PLAYLIST (); + ENTER_GET_PLAYLIST(); playlist->modified = modified; - LEAVE; } -bool PlaylistEx::get_modified () const +bool PlaylistEx::get_modified() const { - ENTER_GET_PLAYLIST (false); - bool modified = playlist->modified; - RETURN (modified); + ENTER_GET_PLAYLIST(false); + return playlist->modified; } -EXPORT void Playlist::activate () const +EXPORT void Playlist::activate() const { - ENTER_GET_PLAYLIST (); + ENTER_GET_PLAYLIST(); if (m_id != active_id) { active_id = m_id; - queue_update_hooks (SetActive); + queue_update_hooks(SetActive); } - - LEAVE; } -EXPORT Playlist Playlist::active_playlist () +EXPORT Playlist Playlist::active_playlist() { - ENTER; - auto id = active_id; - RETURN (Playlist (id)); + auto mh = mutex.take(); + return Playlist(active_id); } -EXPORT Playlist Playlist::new_playlist () +EXPORT Playlist Playlist::new_playlist() { - ENTER; + auto mh = mutex.take(); int at = active_id->index + 1; - auto id = insert_playlist_locked (at); + auto id = insert_playlist_locked(at); active_id = id; - queue_update_hooks (SetActive); + queue_update_hooks(SetActive); - RETURN (Playlist (id)); + return Playlist(id); } -static void set_playing_locked (Playlist::ID * id, bool paused) +static void set_playing_locked(Playlist::ID * id, bool paused) { if (id == playing_id) { /* already playing, just need to pause/unpause */ - if (aud_drct_get_paused () != paused) - aud_drct_pause (); + if (aud_drct_get_paused() != paused) + aud_drct_pause(); return; } if (playing_id) - playing_id->data->resume_time = aud_drct_get_time (); + playing_id->data->resume_time = aud_drct_get_time(); /* is there anything to play? */ - if (id && id->data->position () < 0 && ! id->data->next_song (true)) + if (id && id->data->position() < 0 && !id->data->next_song(true)) id = nullptr; playing_id = id; if (id) { - start_playback_locked (id->data->resume_time, paused); - queue_update_hooks (SetPlaying | PlaybackBegin); + start_playback_locked(id->data->resume_time, paused); + queue_update_hooks(SetPlaying | PlaybackBegin); } else { - stop_playback_locked (); - queue_update_hooks (SetPlaying | PlaybackStop); + stop_playback_locked(); + queue_update_hooks(SetPlaying | PlaybackStop); } } -EXPORT void Playlist::start_playback (bool paused) const +EXPORT void Playlist::start_playback(bool paused) const { - ENTER_GET_PLAYLIST (); - set_playing_locked (m_id, paused); - LEAVE; + ENTER_GET_PLAYLIST(); + set_playing_locked(m_id, paused); } -EXPORT void aud_drct_stop () +EXPORT void aud_drct_stop() { - ENTER; - set_playing_locked (nullptr, false); - LEAVE; + auto mh = mutex.take(); + set_playing_locked(nullptr, false); } -EXPORT Playlist Playlist::playing_playlist () +EXPORT Playlist Playlist::playing_playlist() { - ENTER; - auto id = playing_id; - RETURN (Playlist (id)); + auto mh = mutex.take(); + return Playlist(playing_id); } -EXPORT Playlist Playlist::blank_playlist () +EXPORT Playlist Playlist::blank_playlist() { - ENTER; - auto id = get_blank_locked (); - RETURN (Playlist (id)); + auto mh = mutex.take(); + auto id = get_blank_locked(); + return Playlist(id); } -EXPORT Playlist Playlist::temporary_playlist () +EXPORT Playlist Playlist::temporary_playlist() { - ENTER; + auto mh = mutex.take(); const char * title = _(temp_title); ID * id = nullptr; for (auto & playlist : playlists) { - if (! strcmp (playlist->title, title)) + if (!strcmp(playlist->title, title)) { - id = playlist->id (); + id = playlist->id(); break; } } - if (! id) + if (!id) { - id = get_blank_locked (); - id->data->title = String (title); + id = get_blank_locked(); + id->data->title = String(title); } - RETURN (Playlist (id)); + return Playlist(id); } -EXPORT PluginHandle * Playlist::entry_decoder (int entry_num, GetMode mode, String * error) const +EXPORT PluginHandle * Playlist::entry_decoder(int entry_num, GetMode mode, + String * error) const { - ENTER_GET_PLAYLIST (nullptr); - wait_for_entry (playlist, entry_num, (mode == Wait), false); - PluginHandle * decoder = playlist->entry_decoder (entry_num, error); - RETURN (decoder); + ENTER_GET_PLAYLIST(nullptr); + wait_for_entry(mh, playlist, entry_num, (mode == Wait), false); + return playlist->entry_decoder(entry_num, error); } -EXPORT Tuple Playlist::entry_tuple (int entry_num, GetMode mode, String * error) const +EXPORT Tuple Playlist::entry_tuple(int entry_num, GetMode mode, + String * error) const { - ENTER_GET_PLAYLIST (Tuple ()); - wait_for_entry (playlist, entry_num, false, (mode == Wait)); - Tuple tuple = playlist->entry_tuple (entry_num, error); - RETURN (tuple); + ENTER_GET_PLAYLIST(Tuple()); + wait_for_entry(mh, playlist, entry_num, false, (mode == Wait)); + return playlist->entry_tuple(entry_num, error); } -EXPORT void Playlist::rescan_file (const char * filename) +EXPORT void Playlist::rescan_file(const char * filename) { - ENTER; + auto mh = mutex.take(); for (auto & playlist : playlists) - playlist->reset_tuple_of_file (filename); - - LEAVE; + playlist->reset_tuple_of_file(filename); } // called from playback thread -DecodeInfo playback_entry_read (int serial) +DecodeInfo playback_entry_read(int serial) { - ENTER; + auto mh = mutex.take(); DecodeInfo dec; - if (playback_check_serial (serial)) + if (playback_check_serial(serial)) { auto playlist = playing_id->data; - auto entry = playlist->entry_at (playlist->position ()); + auto entry = playlist->entry_at(playlist->position()); - ScanItem * item = scan_list_find_entry (entry); - assert (item && item->for_playback); + ScanItem * item = scan_list_find_entry(entry); + assert(item && item->for_playback); ScanRequest * request = item->request; item->handled_by_playback = true; - LEAVE; - request->run (); - ENTER; + mh.unlock(); + request->run(); + mh.lock(); - if (playback_check_serial (serial)) + if (playback_check_serial(serial)) { - assert (playlist == playing_id->data); + assert(playlist == playing_id->data); - int pos = playlist->position (); - playback_set_info (pos, playlist->entry_tuple (pos)); + int pos = playlist->position(); + playback_set_info(pos, playlist->entry_tuple(pos)); - art_cache_current (request->filename, - std::move (request->image_data), std::move (request->image_file)); + art_cache_current(request->filename, std::move(request->image_data), + std::move(request->image_file)); dec.filename = request->filename; dec.ip = request->ip; - dec.file = std::move (request->file); - dec.error = std::move (request->error); + dec.file = std::move(request->file); + dec.error = std::move(request->error); } delete request; } - RETURN (dec); + return dec; } // called from playback thread -void playback_entry_set_tuple (int serial, Tuple && tuple) +void playback_entry_set_tuple(int serial, Tuple && tuple) { - ENTER; - - if (playback_check_serial (serial)) - playing_id->data->update_playback_entry (std::move (tuple)); + auto mh = mutex.take(); - LEAVE; + if (playback_check_serial(serial)) + playing_id->data->update_playback_entry(std::move(tuple)); } -void playlist_save_state () +void playlist_save_state() { /* get playback state before locking playlists */ - bool paused = aud_drct_get_paused (); - int time = aud_drct_get_time (); + bool paused = aud_drct_get_paused(); + int time = aud_drct_get_time(); - ENTER; + auto mh = mutex.take(); - const char * user_dir = aud_get_path (AudPath::UserDir); - StringBuf path = filename_build ({user_dir, STATE_FILE}); + const char * user_dir = aud_get_path(AudPath::UserDir); + StringBuf path = filename_build({user_dir, STATE_FILE}); - FILE * handle = g_fopen (path, "w"); - if (! handle) - RETURN (); + FILE * handle = g_fopen(path, "w"); + if (!handle) + return; - fprintf (handle, "active %d\n", active_id ? active_id->index : -1); - fprintf (handle, "playing %d\n", playing_id ? playing_id->index : -1); + fprintf(handle, "active %d\n", active_id ? active_id->index : -1); + fprintf(handle, "playing %d\n", playing_id ? playing_id->index : -1); for (auto & playlist : playlists) { - fprintf (handle, "playlist %d\n", playlist->id ()->index); + fprintf(handle, "playlist %d\n", playlist->id()->index); if (playlist->filename) - fprintf (handle, "filename %s\n", (const char *) playlist->filename); + fprintf(handle, "filename %s\n", (const char *)playlist->filename); - fprintf (handle, "position %d\n", playlist->position ()); + fprintf(handle, "position %d\n", playlist->position()); /* save shuffle history */ - auto history = playlist->shuffle_history (); + auto history = playlist->shuffle_history(); - for (int i = 0; i < history.len (); i += 16) + for (int i = 0; i < history.len(); i += 16) { - int count = aud::min (16, history.len () - i); - auto list = int_array_to_str (& history[i], count); - fprintf (handle, "shuffle %s\n", (const char *) list); + int count = aud::min(16, history.len() - i); + auto list = int_array_to_str(&history[i], count); + fprintf(handle, "shuffle %s\n", (const char *)list); } /* resume state is stored per-playlist for historical reasons */ - bool is_playing = (playlist->id () == playing_id); - fprintf (handle, "resume-state %d\n", (is_playing && paused) ? ResumePause : ResumePlay); - fprintf (handle, "resume-time %d\n", is_playing ? time : playlist->resume_time); + bool is_playing = (playlist->id() == playing_id); + fprintf(handle, "resume-state %d\n", + (is_playing && paused) ? ResumePause : ResumePlay); + fprintf(handle, "resume-time %d\n", + is_playing ? time : playlist->resume_time); } - fclose (handle); - LEAVE; + fclose(handle); } -void playlist_load_state () +void playlist_load_state() { - ENTER; + auto mh = mutex.take(); int playlist_num; - const char * user_dir = aud_get_path (AudPath::UserDir); - StringBuf path = filename_build ({user_dir, STATE_FILE}); + const char * user_dir = aud_get_path(AudPath::UserDir); + StringBuf path = filename_build({user_dir, STATE_FILE}); - FILE * handle = g_fopen (path, "r"); - if (! handle) - RETURN (); + FILE * handle = g_fopen(path, "r"); + if (!handle) + return; - TextParser parser (handle); + TextParser parser(handle); - if (parser.get_int ("active", playlist_num)) + if (parser.get_int("active", playlist_num)) { - if (playlist_num >= 0 && playlist_num < playlists.len ()) - active_id = playlists[playlist_num]->id (); + if (playlist_num >= 0 && playlist_num < playlists.len()) + active_id = playlists[playlist_num]->id(); - parser.next (); + parser.next(); } - if (parser.get_int ("playing", resume_playlist)) - parser.next (); + if (parser.get_int("playing", resume_playlist)) + parser.next(); - while (parser.get_int ("playlist", playlist_num) && - playlist_num >= 0 && playlist_num < playlists.len ()) + while (parser.get_int("playlist", playlist_num) && playlist_num >= 0 && + playlist_num < playlists.len()) { - PlaylistData * playlist = playlists[playlist_num].get (); + PlaylistData * playlist = playlists[playlist_num].get(); - parser.next (); + parser.next(); - playlist->filename = parser.get_str ("filename"); + playlist->filename = parser.get_str("filename"); if (playlist->filename) - parser.next (); + parser.next(); int position = -1; - if (parser.get_int ("position", position)) + if (parser.get_int("position", position)) { - playlist->set_position (position); - parser.next (); + playlist->set_position(position); + parser.next(); } /* restore shuffle history */ Index history; - for (String list; (list = parser.get_str ("shuffle")); parser.next ()) + for (String list; (list = parser.get_str("shuffle")); parser.next()) { - auto split = str_list_to_index (list, ", "); + auto split = str_list_to_index(list, ", "); for (auto & str : split) - history.append (str_to_int (str)); + history.append(str_to_int(str)); } - if (history.len ()) - playlist->shuffle_replay (history); + if (history.len()) + playlist->shuffle_replay(history); /* resume state is stored per-playlist for historical reasons */ int resume_state = ResumePlay; - if (parser.get_int ("resume-state", resume_state)) - parser.next (); + if (parser.get_int("resume-state", resume_state)) + parser.next(); if (playlist_num == resume_playlist) { @@ -1246,33 +1279,31 @@ void playlist_load_state () resume_paused = true; } - if (parser.get_int ("resume-time", playlist->resume_time)) - parser.next (); + if (parser.get_int("resume-time", playlist->resume_time)) + parser.next(); } - fclose (handle); + fclose(handle); /* set initial focus and selection */ for (auto & playlist : playlists) { - int focus = playlist->position (); - if (focus < 0 && playlist->n_entries ()) + int focus = playlist->position(); + if (focus < 0 && playlist->n_entries()) focus = 0; if (focus >= 0) { - playlist->set_focus (focus); - playlist->select_entry (focus, true); + playlist->set_focus(focus); + playlist->select_entry(focus, true); } } - - LEAVE; } -EXPORT void aud_resume () +EXPORT void aud_resume() { - if (aud_get_bool (nullptr, "always_resume_paused")) + if (aud_get_bool("always_resume_paused")) resume_paused = true; - Playlist::by_index (resume_playlist).start_playback (resume_paused); + Playlist::by_index(resume_playlist).start_playback(resume_paused); } diff --git a/src/libaudcore/playlist.h b/src/libaudcore/playlist.h index e9270c1..e88ec30 100644 --- a/src/libaudcore/playlist.h +++ b/src/libaudcore/playlist.h @@ -40,33 +40,37 @@ public: /* The values which can be passed to the "playlist update" hook. Selection * means that entries have been selected or unselected, or that entries have - * been added to or removed from the queue. Metadata means that new metadata - * has been read for some entries, or that the title or filename of a playlist - * has changed, and implies Selection. Structure covers any other change, and - * implies both Selection and Metadata. */ - enum UpdateLevel { + * been added to or removed from the queue. Metadata means that new + * metadata has been read for some entries, or that the title or filename of + * a playlist has changed, and implies Selection. Structure covers any + * other change, and implies both Selection and Metadata. */ + enum UpdateLevel + { NoUpdate = 0, Selection, Metadata, Structure }; - struct Update { - UpdateLevel level; // type of update - int before; // number of unaffected entries at playlist start - int after; // number of unaffected entries at playlist end - bool queue_changed; // true if entries have been added to/removed from queue + struct Update + { + UpdateLevel level; // type of update + int before; // number of unaffected entries at playlist start + int after; // number of unaffected entries at playlist end + bool queue_changed; // true if entries have been added to/removed from + // queue }; /* Preset sorting "schemes" */ - enum SortType { - Path, // entry's entire URI - Filename, // base name (no folder path) + enum SortType + { + Path, // entry's entire URI + Filename, // base name (no folder path) Title, Album, Artist, AlbumArtist, - Date, // release date (not modification time) + Date, // release date (not modification time) Genre, Track, FormattedTitle, @@ -76,105 +80,108 @@ public: }; /* Possible behaviors for entry_{decoder, tuple}. */ - enum GetMode { - NoWait, // non-blocking call; returned tuple will be in Initial state if not yet scanned - Wait // blocking call; returned tuple will be either Valid or Failed + enum GetMode + { + NoWait, // non-blocking call; returned tuple will be in Initial state if + // not yet scanned + Wait // blocking call; returned tuple will be either Valid or Failed }; /* Format descriptor returned by save_formats() */ - struct SaveFormat { - String name; // human-readable format name - Index exts; // supported filename extensions + struct SaveFormat + { + String name; // human-readable format name + Index exts; // supported filename extensions }; - typedef bool (* FilterFunc) (const char * filename, void * user); - typedef int (* StringCompareFunc) (const char * a, const char * b); - typedef int (* TupleCompareFunc) (const Tuple & a, const Tuple & b); + typedef bool (*FilterFunc)(const char * filename, void * user); + typedef int (*StringCompareFunc)(const char * a, const char * b); + typedef int (*TupleCompareFunc)(const Tuple & a, const Tuple & b); /* --- CONSTRUCTOR ETC. --- */ /* Default constructor; indicates "no playlist" */ - constexpr Playlist () : m_id (nullptr) {} + constexpr Playlist() : m_id(nullptr) {} - bool operator== (const Playlist & b) const { return m_id == b.m_id; } - bool operator!= (const Playlist & b) const { return m_id != b.m_id; } + bool operator==(const Playlist & b) const { return m_id == b.m_id; } + bool operator!=(const Playlist & b) const { return m_id != b.m_id; } /* The number of the playlist in display order, starting from 0. * Returns -1 if the playlist no longer exists. */ - int index () const; + int index() const; /* True if the playlist exists (i.e. has not been deleted). */ - bool exists () const { return index () >= 0; } + bool exists() const { return index() >= 0; } /* --- CORE (STATIC) API --- */ /* Returns the number of playlists currently open (>= 1). */ - static int n_playlists (); + static int n_playlists(); /* Looks up a playlist by display order. */ - static Playlist by_index (int at); + static Playlist by_index(int at); /* Adds a new playlist before the one numbered (-1 = insert at end). */ - static Playlist insert_playlist (int at); + static Playlist insert_playlist(int at); /* Moves a contiguous block of playlists starting with the one * numbered such that that playlist ends up at the position . */ - static void reorder_playlists (int from, int to, int count); + static void reorder_playlists(int from, int to, int count); /* Returns the active (i.e. displayed) playlist. */ - static Playlist active_playlist (); + static Playlist active_playlist(); /* Convenience function which adds a new playlist after the active one and * then sets the new one as active. Returns the new playlist. */ - static Playlist new_playlist (); + static Playlist new_playlist(); /* Returns the currently playing playlist. If no playlist is playing, * returns Playlist(). */ - static Playlist playing_playlist (); + static Playlist playing_playlist(); /* Returns the number of a "blank" playlist. The active playlist is * returned if it has the default title and has no entries; otherwise, a new * playlist is added and returned. */ - static Playlist blank_playlist (); + static Playlist blank_playlist(); /* Returns the number of the "temporary" playlist (which is no different * from any other playlist except in name). If the playlist does not exist, * a "blank" playlist is renamed to become the temporary playlist. */ - static Playlist temporary_playlist (); + static Playlist temporary_playlist(); /* Discards the metadata stored for all the entries that refer to a * particular song file, in whatever playlist they appear, and starts * reading it afresh from that file in the background. */ - static void rescan_file (const char * filename); + static void rescan_file(const char * filename); /* --- CORE (NON-STATIC) API --- */ /* Gets/sets the filename associated with this playlist. * (Audacious currently makes no use of the filename.) */ - String get_filename () const; - void set_filename (const char * filename) const; + String get_filename() const; + void set_filename(const char * filename) const; /* Gets/sets the title of the playlist. */ - String get_title () const; - void set_title (const char * title) const; + String get_title() const; + void set_title(const char * title) const; /* Closes the playlist. * The playlist is not saved, and no confirmation is presented to the user. * When the last playlist is closed, a new one is added in its place. * When the active playlist is closed, another is made active. * When the playing playlist is closed, playback stops. */ - void remove_playlist () const; + void remove_playlist() const; /* Makes this the active (i.e. displayed) playlist. */ - void activate () const; + void activate() const; /* Starts playback of this playlist, unless it is empty. * Resumes from the position last played if possible. * If is true, starts playback in a paused state. */ - void start_playback (bool paused = false) const; + void start_playback(bool paused = false) const; /* Returns the number of entries (numbered from 0). */ - int n_entries () const; + int n_entries() const; /* Adds a single song file, playlist file, or folder before the entry . * If is negative or equal to the number of entries, the item is added @@ -183,210 +190,225 @@ public: * Audacious will begin playback of the items once they have been added. * * This function is asynchronous (the items are added in the background). */ - void insert_entry (int at, const char * filename, Tuple && tuple, bool play) const; + void insert_entry(int at, const char * filename, Tuple && tuple, + bool play) const; /* Adds multiple song files, playlist files, or folders to a playlist. */ - void insert_items (int at, Index && items, bool play) const; + void insert_items(int at, Index && items, bool play) const; /* Similar to insert_items() but allows the caller to prevent some items * from being added by returning false from the callback. Useful * for searching a folder and adding only new files to the playlist. * is an opaque pointer passed to the callback. */ - void insert_filtered (int at, Index && items, - FilterFunc filter, void * user, bool play) const; + void insert_filtered(int at, Index && items, + FilterFunc filter, void * user, bool play) const; /* Removes entries from the playlist. The playback position may be moved, * or playback may be stopped (according to user preference). */ - void remove_entries (int at, int number) const; - void remove_entry (int at) const { remove_entries (at, 1); } - void remove_all_entries () const { remove_entries (0, -1); } + void remove_entries(int at, int number) const; + void remove_entry(int at) const { remove_entries(at, 1); } + void remove_all_entries() const { remove_entries(0, -1); } /* Returns an entry's filename. */ - String entry_filename (int entry) const; + String entry_filename(int entry) const; /* Returns an entry's decoder plugin. On error, or if the entry has not yet * been scanned, returns nullptr according to . An optional error * message may be returned. */ - PluginHandle * entry_decoder (int entry, GetMode mode = Wait, String * error = nullptr) const; + PluginHandle * entry_decoder(int entry, GetMode mode = Wait, + String * error = nullptr) const; /* Returns an entry's metadata. The state of the returned tuple may * indicate that the entry has not yet been scanned, or an error occurred, * according to . An optional error message may be returned. */ - Tuple entry_tuple (int entry, GetMode mode = Wait, String * error = nullptr) const; + Tuple entry_tuple(int entry, GetMode mode = Wait, + String * error = nullptr) const; /* Gets/sets the playing or last-played entry (-1 = no entry). * Affects playback only if this playlist is currently playing. * set_position(get_position()) restarts playback from 0:00. * set_position(-1) stops playback. */ - int get_position () const; - void set_position (int position) const; + int get_position() const; + void set_position(int position) const; /* Advances the playlist position to the next entry in playback order, * taking current shuffle settings into account. At the end of the * playlist, wraps around to the beginning if is true. Returns * true on success, false if playlist position was not changed. */ - bool next_song (bool repeat) const; + bool next_song(bool repeat) const; + + /* Advances the playlist position to the first entry of the next album in + * playback order, taking current shuffle settings into account. At the + * end of the playlist, wraps around to the beginning if is true. + * Returns true on success, false if playlist position was not changed. */ + bool next_album(bool repeat) const; /* Returns the playlist position to the previous entry in playback order. * Does not support wrapping past the beginning of the playlist. Returns * true on success, false if playlist position was not changed. */ - bool prev_song () const; + bool prev_song() const; + + /* Returns the playlist position to the first entry in playback order where + * the album is not the current album. Does not support wrapping past the + * beginning of the playlist. Returns true on success, false if playlist + * position was not changed. */ + bool prev_album() const; /* Gets/sets the entry which has keyboard focus (-1 = no entry). */ - int get_focus () const; - void set_focus (int entry) const; + int get_focus() const; + void set_focus(int entry) const; /* Gets/sets whether an entry is selected. */ - bool entry_selected (int entry) const; - void select_entry (int entry, bool selected) const; + bool entry_selected(int entry) const; + void select_entry(int entry, bool selected) const; /* Returns the number of selected entries. * An optional range of entries to examine may be specified. */ - int n_selected (int at = 0, int number = -1) const; + int n_selected(int at = 0, int number = -1) const; /* Selects all (or none) of the entries in a playlist. */ - void select_all (bool selected) const; + void select_all(bool selected) const; /* Moves a selected entry within a playlist by an offset of * entries. Other selected entries are gathered around it. Returns the * offset by which the entry was actually moved (which may be less than the * requested offset. */ - int shift_entries (int position, int distance) const; + int shift_entries(int position, int distance) const; /* Removes all selected entries. */ - void remove_selected () const; + void remove_selected() const; /* Sorts the entries in a playlist based on filename. The callback function * should return negative if the first filename comes before the second, * positive if it comes after, or zero if the two are indistinguishable. */ - void sort_by_filename (StringCompareFunc compare) const; + void sort_by_filename(StringCompareFunc compare) const; /* Sorts the entries in a playlist based on tuple. May fail if metadata * scanning is still in progress (or has been disabled). */ - void sort_by_tuple (TupleCompareFunc compare) const; + void sort_by_tuple(TupleCompareFunc compare) const; - /* Sorts the entries in a playlist based on formatted title string. May fail if - * metadata scanning is still in progress (or has been disabled). */ - void sort_by_title (StringCompareFunc compare) const; + /* Sorts the entries in a playlist based on formatted title string. May + * fail if metadata scanning is still in progress (or has been disabled). */ + void sort_by_title(StringCompareFunc compare) const; /* Sorts only the selected entries in a playlist based on filename. */ - void sort_selected_by_filename (StringCompareFunc compare) const; + void sort_selected_by_filename(StringCompareFunc compare) const; - /* Sorts only the selected entries in a playlist based on tuple. May fail if - * metadata scanning is still in progress (or has been disabled). */ - void sort_selected_by_tuple (TupleCompareFunc compare) const; + /* Sorts only the selected entries in a playlist based on tuple. May fail + * if metadata scanning is still in progress (or has been disabled). */ + void sort_selected_by_tuple(TupleCompareFunc compare) const; /* Sorts only the selected entries in a playlist based on formatted title * string. May fail if metadata scanning is still in progress (or has been * disabled). */ - void sort_selected_by_title (StringCompareFunc compare) const; + void sort_selected_by_title(StringCompareFunc compare) const; /* Reverses the order of the entries in a playlist. */ - void reverse_order () const; + void reverse_order() const; /* Reorders the entries in a playlist randomly. */ - void randomize_order () const; + void randomize_order() const; /* Reverses the order of the selected entries in a playlist. */ - void reverse_selected () const; + void reverse_selected() const; /* Reorders the selected entries in a playlist randomly. */ - void randomize_selected () const; + void randomize_selected() const; /* Discards the metadata stored for entries in a playlist and starts reading * it fresh from the song files in the background. */ - void rescan_all () const; - void rescan_selected () const; + void rescan_all() const; + void rescan_selected() const; /* Calculates the length in milliseconds of entries in a playlist. Only * takes into account entries for which metadata has already been read. */ - int64_t total_length_ms () const; - int64_t selected_length_ms () const; + int64_t total_length_ms() const; + int64_t selected_length_ms() const; /* Returns the number of entries in a playlist queue. */ - int n_queued () const; + int n_queued() const; /* Adds an entry to the queue at (-1 = at end of queue). * The same entry cannot be added to the queue more than once. */ - void queue_insert (int pos, int entry) const; - void queue_insert_selected (int pos) const; + void queue_insert(int pos, int entry) const; + void queue_insert_selected(int pos) const; /* Returns the entry at the given queue position. */ - int queue_get_entry (int pos) const; + int queue_get_entry(int pos) const; /* Returns the queue position of the given entry (-1 if not queued). */ - int queue_find_entry (int entry) const; + int queue_find_entry(int entry) const; /* Removes entries from the queue. */ - void queue_remove (int pos, int number = 1) const; - void queue_remove_all () const { queue_remove (0, -1); } + void queue_remove(int pos, int number = 1) const; + void queue_remove_all() const { queue_remove(0, -1); } - /* Removes the selected entries in a playlist from the queue, if they are in it. */ - void queue_remove_selected () const; + /* Removes the selected entries in a playlist from the queue, if they are in + * it. */ + void queue_remove_selected() const; /* Returns true if a "playlist update" hook call is pending. * A running hook call is not considered pending. */ - bool update_pending () const; - static bool update_pending_any (); + bool update_pending() const; + static bool update_pending_any(); /* Immediately calls any pending "playlist update" hook. Use cautiously. */ - static void process_pending_update (); + static void process_pending_update(); /* May be called within the "playlist update" hook to determine the update * level and number of entries changed in a playlist. */ - Update update_detail () const; + Update update_detail() const; /* Returns true if entries are being added in the background. */ - bool add_in_progress () const; - static bool add_in_progress_any (); + bool add_in_progress() const; + static bool add_in_progress_any(); /* Returns true if entries are being scanned in the background. */ - bool scan_in_progress () const; - static bool scan_in_progress_any (); + bool scan_in_progress() const; + static bool scan_in_progress_any(); /* --- UTILITY API --- */ /* Sorts entries according to a preset scheme. */ - void sort_entries (SortType scheme) const; - void sort_selected (SortType scheme) const; + void sort_entries(SortType scheme) const; + void sort_selected(SortType scheme) const; /* Removes duplicate entries according to a preset scheme. * The current implementation also sorts the playlist. */ - void remove_duplicates (SortType scheme) const; + void remove_duplicates(SortType scheme) const; /* Removes all entries referring to inaccessible files in a playlist. */ - void remove_unavailable () const; + void remove_unavailable() const; /* Selects entries by matching regular expressions. * Example: To select all titles starting with the letter "A", * create a blank tuple and set its title field to "^A". */ - void select_by_patterns (const Tuple & patterns) const; + void select_by_patterns(const Tuple & patterns) const; /* Saves metadata for the selected entries to an internal cache. * This will speed up adding those entries to another playlist. */ - void cache_selected () const; + void cache_selected() const; /* Saves the entries in a playlist to a playlist file. * The format of the file is determined from the file extension. * specifies whether to wait for metadata scanning to complete. * Returns true on success. */ - bool save_to_file (const char * filename, GetMode mode) const; + bool save_to_file(const char * filename, GetMode mode) const; /* Checks a filename for an extension matching a known playlist format. */ - static bool filename_is_playlist (const char * filename); + static bool filename_is_playlist(const char * filename); /* Generates a list of the currently supported formats for saving playlists. - * The list should not be cached since it may change as plugins are enabled or - * disabled. */ - static Index save_formats (); + * The list should not be cached since it may change as plugins are enabled + * or disabled. */ + static Index save_formats(); /* --- IMPLEMENTATION --- */ private: ID * m_id; - explicit constexpr Playlist (ID * id) : - m_id (id) {} + explicit constexpr Playlist(ID * id) : m_id(id) {} friend class PlaylistEx; }; diff --git a/src/libaudcore/plugin-init.cc b/src/libaudcore/plugin-init.cc index 0674a76..5d2ae39 100644 --- a/src/libaudcore/plugin-init.cc +++ b/src/libaudcore/plugin-init.cc @@ -29,38 +29,37 @@ #include "plugin.h" #include "runtime.h" -static bool general_plugin_start (PluginHandle * plugin) +static bool general_plugin_start(PluginHandle * plugin) { - auto gp = (GeneralPlugin *) aud_plugin_get_header (plugin); - return gp && gp->init (); + auto gp = (GeneralPlugin *)aud_plugin_get_header(plugin); + return gp && gp->init(); } -void general_plugin_stop (PluginHandle * plugin) +void general_plugin_stop(PluginHandle * plugin) { - GeneralPlugin * gp = (GeneralPlugin *) aud_plugin_get_header (plugin); + GeneralPlugin * gp = (GeneralPlugin *)aud_plugin_get_header(plugin); if (gp) - gp->cleanup (); + gp->cleanup(); } struct MultiFuncs { - bool (* start) (PluginHandle * plugin); - void (* stop) (PluginHandle * plugin); + bool (*start)(PluginHandle * plugin); + void (*stop)(PluginHandle * plugin); }; struct SingleFuncs { - PluginHandle * (* get_current) (); - bool (* set_current) (PluginHandle * plugin); + PluginHandle * (*get_current)(); + bool (*set_current)(PluginHandle * plugin); }; -union PluginFuncs -{ +union PluginFuncs { MultiFuncs m; SingleFuncs s; - constexpr PluginFuncs (MultiFuncs multi) : m (multi) {} - constexpr PluginFuncs (SingleFuncs single) : s (single) {} + constexpr PluginFuncs(MultiFuncs multi) : m(multi) {} + constexpr PluginFuncs(SingleFuncs single) : s(single) {} }; struct PluginParams @@ -69,319 +68,334 @@ struct PluginParams bool is_single; PluginFuncs f; - constexpr PluginParams (const char * name, MultiFuncs multi) : - name (name), is_single (false), f (multi) {} - constexpr PluginParams (const char * name, SingleFuncs single) : - name (name), is_single (true), f (single) {} + constexpr PluginParams(const char * name, MultiFuncs multi) + : name(name), is_single(false), f(multi) + { + } + constexpr PluginParams(const char * name, SingleFuncs single) + : name(name), is_single(true), f(single) + { + } }; static constexpr aud::array table = { - PluginParams ("transport", MultiFuncs ({nullptr, nullptr})), - PluginParams ("playlist", MultiFuncs ({nullptr, nullptr})), - PluginParams ("input", MultiFuncs ({nullptr, nullptr})), - PluginParams ("effect", MultiFuncs ({effect_plugin_start, effect_plugin_stop})), - PluginParams ("output", SingleFuncs ({output_plugin_get_current, output_plugin_set_current})), - PluginParams ("visualization", MultiFuncs ({vis_plugin_start, vis_plugin_stop})), - PluginParams ("general", MultiFuncs ({general_plugin_start, general_plugin_stop})), - PluginParams ("interface", SingleFuncs ({iface_plugin_get_current, iface_plugin_set_current})) -}; - -static bool start_plugin (PluginType type, PluginHandle * p, bool secondary = false) + PluginParams("transport", MultiFuncs({nullptr, nullptr})), + PluginParams("playlist", MultiFuncs({nullptr, nullptr})), + PluginParams("input", MultiFuncs({nullptr, nullptr})), + PluginParams("effect", + MultiFuncs({effect_plugin_start, effect_plugin_stop})), + PluginParams("output", SingleFuncs({output_plugin_get_current, + output_plugin_set_current})), + PluginParams("visualization", + MultiFuncs({vis_plugin_start, vis_plugin_stop})), + PluginParams("general", + MultiFuncs({general_plugin_start, general_plugin_stop})), + PluginParams("interface", SingleFuncs({iface_plugin_get_current, + iface_plugin_set_current}))}; + +static bool start_plugin(PluginType type, PluginHandle * p, + bool secondary = false) { bool success; if (secondary) - success = output_plugin_set_secondary (p); + success = output_plugin_set_secondary(p); else if (table[type].is_single) - success = table[type].f.s.set_current (p); + success = table[type].f.s.set_current(p); else - success = table[type].f.m.start (p); + success = table[type].f.m.start(p); - if (! success) + if (!success) { - AUDWARN ("%s failed to start.\n", aud_plugin_get_name (p)); - plugin_set_failed (p); + AUDWARN("%s failed to start.\n", aud_plugin_get_name(p)); + plugin_set_failed(p); } return success; } -static PluginHandle * find_selected (PluginType type, PluginEnabled enabled) +static PluginHandle * find_selected(PluginType type, PluginEnabled enabled) { - for (PluginHandle * p : aud_plugin_list (type)) + for (PluginHandle * p : aud_plugin_list(type)) { - if (plugin_get_enabled (p) == enabled) + if (plugin_get_enabled(p) == enabled) return p; } return nullptr; } -static void start_required (PluginType type) +static void start_required(PluginType type) { PluginHandle * sel; - if ((sel = find_selected (type, PluginEnabled::Primary))) + if ((sel = find_selected(type, PluginEnabled::Primary))) { - AUDINFO ("Starting selected %s plugin %s.\n", table[type].name, - aud_plugin_get_name (sel)); + AUDINFO("Starting selected %s plugin %s.\n", table[type].name, + aud_plugin_get_name(sel)); - if (start_plugin (type, sel)) + if (start_plugin(type, sel)) return; } - AUDINFO ("Probing for %s plugin.\n", table[type].name); + AUDINFO("Probing for %s plugin.\n", table[type].name); - for (PluginHandle * p : aud_plugin_list (type)) + for (PluginHandle * p : aud_plugin_list(type)) { if (p == sel) continue; - AUDINFO ("Trying to start %s.\n", aud_plugin_get_name (p)); - plugin_set_enabled (p, PluginEnabled::Primary); + AUDINFO("Trying to start %s.\n", aud_plugin_get_name(p)); + plugin_set_enabled(p, PluginEnabled::Primary); - if (start_plugin (type, p)) + if (start_plugin(type, p)) return; } - AUDERR ("No %s plugin found.\n" - "(Did you forget to install audacious-plugins?)\n", table[type].name); - abort (); + AUDERR("No %s plugin found.\n" + "(Did you forget to install audacious-plugins?)\n", + table[type].name); + abort(); } -static void start_plugins (PluginType type) +static void start_plugins(PluginType type) { /* no interface plugin in headless mode */ - if (type == PluginType::Iface && aud_get_headless_mode ()) + if (type == PluginType::Iface && aud_get_headless_mode()) return; if (table[type].is_single) { - start_required (type); + start_required(type); if (type == PluginType::Output) { PluginHandle * sel; - if ((sel = find_selected (type, PluginEnabled::Secondary))) + if ((sel = find_selected(type, PluginEnabled::Secondary))) { - AUDINFO ("Starting secondary output plugin %s.\n", aud_plugin_get_name (sel)); - start_plugin (type, sel, true); + AUDINFO("Starting secondary output plugin %s.\n", + aud_plugin_get_name(sel)); + start_plugin(type, sel, true); } } } else if (table[type].f.m.start) { - for (PluginHandle * p : aud_plugin_list (type)) + for (PluginHandle * p : aud_plugin_list(type)) { - if (aud_plugin_get_enabled (p)) + if (aud_plugin_get_enabled(p)) { - AUDINFO ("Starting %s.\n", aud_plugin_get_name (p)); - start_plugin (type, p); + AUDINFO("Starting %s.\n", aud_plugin_get_name(p)); + start_plugin(type, p); } } } } -void start_plugins_one () +void start_plugins_one() { - plugin_system_init (); + plugin_system_init(); - start_plugins (PluginType::Transport); - start_plugins (PluginType::Playlist); - start_plugins (PluginType::Input); - start_plugins (PluginType::Effect); - start_plugins (PluginType::Output); + start_plugins(PluginType::Transport); + start_plugins(PluginType::Playlist); + start_plugins(PluginType::Input); + start_plugins(PluginType::Effect); + start_plugins(PluginType::Output); } -void start_plugins_two () +void start_plugins_two() { - start_plugins (PluginType::Vis); - start_plugins (PluginType::General); - start_plugins (PluginType::Iface); + start_plugins(PluginType::Vis); + start_plugins(PluginType::General); + start_plugins(PluginType::Iface); } -static void stop_plugins (PluginType type) +static void stop_plugins(PluginType type) { if (table[type].is_single) { - PluginHandle * p = table[type].f.s.get_current (); - AUDINFO ("Shutting down %s.\n", aud_plugin_get_name (p)); - table[type].f.s.set_current (nullptr); + PluginHandle * p = table[type].f.s.get_current(); + AUDINFO("Shutting down %s.\n", aud_plugin_get_name(p)); + table[type].f.s.set_current(nullptr); - if (type == PluginType::Output && (p = output_plugin_get_secondary ())) + if (type == PluginType::Output && (p = output_plugin_get_secondary())) { - AUDINFO ("Shutting down %s.\n", aud_plugin_get_name (p)); - output_plugin_set_secondary (nullptr); + AUDINFO("Shutting down %s.\n", aud_plugin_get_name(p)); + output_plugin_set_secondary(nullptr); } } else if (table[type].f.m.stop) { - for (PluginHandle * p : aud_plugin_list (type)) + for (PluginHandle * p : aud_plugin_list(type)) { - if (aud_plugin_get_enabled (p)) + if (aud_plugin_get_enabled(p)) { - AUDINFO ("Shutting down %s.\n", aud_plugin_get_name (p)); - table[type].f.m.stop (p); + AUDINFO("Shutting down %s.\n", aud_plugin_get_name(p)); + table[type].f.m.stop(p); } } } } -void stop_plugins_two () +void stop_plugins_two() { /* interface plugin is already shut down */ - stop_plugins (PluginType::General); - stop_plugins (PluginType::Vis); + stop_plugins(PluginType::General); + stop_plugins(PluginType::Vis); } -void stop_plugins_one () +void stop_plugins_one() { - stop_plugins (PluginType::Output); - stop_plugins (PluginType::Effect); - stop_plugins (PluginType::Input); - stop_plugins (PluginType::Playlist); - stop_plugins (PluginType::Transport); + stop_plugins(PluginType::Output); + stop_plugins(PluginType::Effect); + stop_plugins(PluginType::Input); + stop_plugins(PluginType::Playlist); + stop_plugins(PluginType::Transport); - plugin_system_cleanup (); + plugin_system_cleanup(); } -EXPORT PluginHandle * aud_plugin_get_current (PluginType type) +EXPORT PluginHandle * aud_plugin_get_current(PluginType type) { - assert (table[type].is_single); - return table[type].f.s.get_current (); + assert(table[type].is_single); + return table[type].f.s.get_current(); } -static bool enable_single (PluginType type, PluginHandle * p) +static bool enable_single(PluginType type, PluginHandle * p) { - PluginHandle * old = table[type].f.s.get_current (); + PluginHandle * old = table[type].f.s.get_current(); - AUDINFO ("Switching from %s to %s.\n", aud_plugin_get_name (old), - aud_plugin_get_name (p)); + AUDINFO("Switching from %s to %s.\n", aud_plugin_get_name(old), + aud_plugin_get_name(p)); - plugin_set_enabled (old, PluginEnabled::Disabled); - plugin_set_enabled (p, PluginEnabled::Primary); + plugin_set_enabled(old, PluginEnabled::Disabled); + plugin_set_enabled(p, PluginEnabled::Primary); - if (start_plugin (type, p)) + if (start_plugin(type, p)) return true; - AUDINFO ("Falling back to %s.\n", aud_plugin_get_name (old)); - plugin_set_enabled (old, PluginEnabled::Primary); + AUDINFO("Falling back to %s.\n", aud_plugin_get_name(old)); + plugin_set_enabled(old, PluginEnabled::Primary); - if (start_plugin (type, old)) + if (start_plugin(type, old)) return false; - abort (); + abort(); } -static bool enable_multi (PluginType type, PluginHandle * p, bool enable) +static bool enable_multi(PluginType type, PluginHandle * p, bool enable) { - AUDINFO ("%sabling %s.\n", enable ? "En" : "Dis", aud_plugin_get_name (p)); + AUDINFO("%sabling %s.\n", enable ? "En" : "Dis", aud_plugin_get_name(p)); if (enable) { - plugin_set_enabled (p, PluginEnabled::Primary); + plugin_set_enabled(p, PluginEnabled::Primary); - if (table[type].f.m.start && ! start_plugin (type, p)) + if (table[type].f.m.start && !start_plugin(type, p)) return false; if (type == PluginType::Vis || type == PluginType::General) - hook_call ("dock plugin enabled", p); + hook_call("dock plugin enabled", p); } else { - plugin_set_enabled (p, PluginEnabled::Disabled); + plugin_set_enabled(p, PluginEnabled::Disabled); if (type == PluginType::Vis || type == PluginType::General) - hook_call ("dock plugin disabled", p); + hook_call("dock plugin disabled", p); if (table[type].f.m.stop) - table[type].f.m.stop (p); + table[type].f.m.stop(p); } return true; } -EXPORT bool aud_plugin_enable (PluginHandle * plugin, bool enable) +EXPORT bool aud_plugin_enable(PluginHandle * plugin, bool enable) { - PluginEnabled enabled = plugin_get_enabled (plugin); + PluginEnabled enabled = plugin_get_enabled(plugin); if (enabled == (enable ? PluginEnabled::Primary : PluginEnabled::Disabled)) return true; - PluginType type = aud_plugin_get_type (plugin); + PluginType type = aud_plugin_get_type(plugin); if (table[type].is_single) { - assert (enable); - return enable_single (type, plugin); + assert(enable); + return enable_single(type, plugin); } - return enable_multi (type, plugin, enable); + return enable_multi(type, plugin, enable); } -bool plugin_enable_secondary (PluginHandle * plugin, bool enable) +bool plugin_enable_secondary(PluginHandle * plugin, bool enable) { - assert (aud_plugin_get_type (plugin) == PluginType::Output); + assert(aud_plugin_get_type(plugin) == PluginType::Output); - PluginEnabled enabled = plugin_get_enabled (plugin); - assert (enabled != PluginEnabled::Primary); + PluginEnabled enabled = plugin_get_enabled(plugin); + assert(enabled != PluginEnabled::Primary); - if (enabled == (enable ? PluginEnabled::Secondary : PluginEnabled::Disabled)) + if (enabled == + (enable ? PluginEnabled::Secondary : PluginEnabled::Disabled)) return true; if (enable) { PluginHandle * old; - if ((old = output_plugin_get_secondary ())) - plugin_enable_secondary (old, false); + if ((old = output_plugin_get_secondary())) + plugin_enable_secondary(old, false); - AUDINFO ("Enabling secondary output plugin %s.\n", aud_plugin_get_name (plugin)); - plugin_set_enabled (plugin, PluginEnabled::Secondary); - return start_plugin (PluginType::Output, plugin, true); + AUDINFO("Enabling secondary output plugin %s.\n", + aud_plugin_get_name(plugin)); + plugin_set_enabled(plugin, PluginEnabled::Secondary); + return start_plugin(PluginType::Output, plugin, true); } else { - AUDINFO ("Disabling secondary output plugin %s.\n", aud_plugin_get_name (plugin)); - plugin_set_enabled (plugin, PluginEnabled::Disabled); - output_plugin_set_secondary (nullptr); + AUDINFO("Disabling secondary output plugin %s.\n", + aud_plugin_get_name(plugin)); + plugin_set_enabled(plugin, PluginEnabled::Disabled); + output_plugin_set_secondary(nullptr); return true; } } /* Miscellaneous plugin-related functions ... */ -EXPORT int aud_plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size) +EXPORT int aud_plugin_send_message(PluginHandle * plugin, const char * code, + const void * data, int size) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) return -1; - Plugin * header = (Plugin *) aud_plugin_get_header (plugin); - if (! header) + Plugin * header = (Plugin *)aud_plugin_get_header(plugin); + if (!header) return -1; - return header->take_message (code, data, size); + return header->take_message(code, data, size); } -EXPORT void * aud_plugin_get_gtk_widget (PluginHandle * plugin) +EXPORT void * aud_plugin_get_gtk_widget(PluginHandle * plugin) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) return nullptr; - PluginType type = aud_plugin_get_type (plugin); + PluginType type = aud_plugin_get_type(plugin); if (type != PluginType::General && type != PluginType::Vis) return nullptr; - auto dp = (DockablePlugin *) aud_plugin_get_header (plugin); - return dp ? dp->get_gtk_widget () : nullptr; + auto dp = (DockablePlugin *)aud_plugin_get_header(plugin); + return dp ? dp->get_gtk_widget() : nullptr; } -EXPORT void * aud_plugin_get_qt_widget (PluginHandle * plugin) +EXPORT void * aud_plugin_get_qt_widget(PluginHandle * plugin) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) return nullptr; - PluginType type = aud_plugin_get_type (plugin); + PluginType type = aud_plugin_get_type(plugin); if (type != PluginType::General && type != PluginType::Vis) return nullptr; - auto dp = (DockablePlugin *) aud_plugin_get_header (plugin); - return dp ? dp->get_qt_widget () : nullptr; + auto dp = (DockablePlugin *)aud_plugin_get_header(plugin); + return dp ? dp->get_qt_widget() : nullptr; } diff --git a/src/libaudcore/plugin-load.cc b/src/libaudcore/plugin-load.cc index 5edb062..cf3953e 100644 --- a/src/libaudcore/plugin-load.cc +++ b/src/libaudcore/plugin-load.cc @@ -1,6 +1,6 @@ /* * plugin-load.cc - * Copyright 2007-2013 William Pitcock and John Lindgren + * Copyright 2007-2013 Ariadne Conill and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -33,145 +32,146 @@ #include "plugin.h" #include "runtime.h" -static const char * plugin_dir_list[] = { - "Transport", - "Container", - "Input", - "Output", - "Effect", - "General", - "Visualization" -}; +static const char * plugin_dir_list[] = {"Transport", "Container", "Input", + "Output", "Effect", "General", + "Visualization"}; -struct LoadedModule { +struct LoadedModule +{ Plugin * header; GModule * module; }; static Index loaded_modules; -bool plugin_check_flags (int flags) +bool plugin_check_flags(int flags) { - switch (aud_get_mainloop_type ()) + switch (aud_get_mainloop_type()) { - case MainloopType::GLib: flags &= ~PluginGLibOnly; break; - case MainloopType::Qt: flags &= ~PluginQtOnly; break; + case MainloopType::GLib: + flags &= ~PluginGLibOnly; + break; + case MainloopType::Qt: + flags &= ~PluginQtOnly; + break; } - return ! flags; + return !flags; } -Plugin * plugin_load (const char * filename) +Plugin * plugin_load(const char * filename) { - AUDINFO ("Loading plugin: %s.\n", filename); + AUDINFO("Loading plugin: %s.\n", filename); - GModule * module = g_module_open (filename, G_MODULE_BIND_LOCAL); + GModule * module = g_module_open(filename, G_MODULE_BIND_LOCAL); - if (! module) + if (!module) { - AUDERR ("%s could not be loaded: %s\n", filename, g_module_error ()); + AUDERR("%s could not be loaded: %s\n", filename, g_module_error()); return nullptr; } Plugin * header; - if (! g_module_symbol (module, "aud_plugin_instance", (void * *) & header)) + if (!g_module_symbol(module, "aud_plugin_instance", (void **)&header)) header = nullptr; - if (! header || header->magic != _AUD_PLUGIN_MAGIC) + if (!header || header->magic != _AUD_PLUGIN_MAGIC) { - AUDERR ("%s is not a valid Audacious plugin.\n", filename); - g_module_close (module); + AUDERR("%s is not a valid Audacious plugin.\n", filename); + g_module_close(module); return nullptr; } if (header->version < _AUD_PLUGIN_VERSION_MIN || header->version > _AUD_PLUGIN_VERSION) { - AUDERR ("%s is not compatible with this version of Audacious.\n", filename); - g_module_close (module); + AUDERR("%s is not compatible with this version of Audacious.\n", + filename); + g_module_close(module); return nullptr; } - if (plugin_check_flags (header->info.flags) && + if (plugin_check_flags(header->info.flags) && (header->type == PluginType::Transport || header->type == PluginType::Playlist || header->type == PluginType::Input || header->type == PluginType::Effect)) { - if (! header->init ()) + if (!header->init()) { - AUDERR ("%s failed to initialize.\n", filename); - g_module_close (module); + AUDERR("%s failed to initialize.\n", filename); + g_module_close(module); return nullptr; } } - loaded_modules.append (header, module); + loaded_modules.append(header, module); return header; } -static void plugin_unload (LoadedModule & loaded) +static void plugin_unload(LoadedModule & loaded) { - if (plugin_check_flags (loaded.header->info.flags) && + if (plugin_check_flags(loaded.header->info.flags) && (loaded.header->type == PluginType::Transport || loaded.header->type == PluginType::Playlist || loaded.header->type == PluginType::Input || loaded.header->type == PluginType::Effect)) { - loaded.header->cleanup (); + loaded.header->cleanup(); } #ifndef VALGRIND_FRIENDLY - g_module_close (loaded.module); + g_module_close(loaded.module); #endif } /******************************************************************/ -static bool scan_plugin_func (const char * path, const char * basename, void * data) +static bool scan_plugin_func(const char * path, const char * basename, + void * data) { - if (! str_has_suffix_nocase (basename, PLUGIN_SUFFIX)) + if (!str_has_suffix_nocase(basename, PLUGIN_SUFFIX)) return false; GStatBuf st; - if (g_stat (path, & st) < 0) + if (g_stat(path, &st) < 0) { - AUDERR ("Unable to stat %s: %s\n", path, strerror (errno)); + AUDERR("Unable to stat %s: %s\n", path, strerror(errno)); return false; } - if (S_ISREG (st.st_mode)) - plugin_register (path, st.st_mtime); + if (S_ISREG(st.st_mode)) + plugin_register(path, st.st_mtime); return false; } -static void scan_plugins (const char * path) +static void scan_plugins(const char * path) { - dir_foreach (path, scan_plugin_func, nullptr); + dir_foreach(path, scan_plugin_func, nullptr); } -void plugin_system_init () +void plugin_system_init() { - assert (g_module_supported ()); + assert(g_module_supported()); - plugin_registry_load (); + plugin_registry_load(); - const char * path = aud_get_path (AudPath::PluginDir); + const char * path = aud_get_path(AudPath::PluginDir); for (const char * dir : plugin_dir_list) - scan_plugins (filename_build ({path, dir})); + scan_plugins(filename_build({path, dir})); - plugin_registry_prune (); + plugin_registry_prune(); } -void plugin_system_cleanup () +void plugin_system_cleanup() { - plugin_registry_save (); - plugin_registry_cleanup (); + plugin_registry_save(); + plugin_registry_cleanup(); for (LoadedModule & loaded : loaded_modules) - plugin_unload (loaded); + plugin_unload(loaded); - loaded_modules.clear (); + loaded_modules.clear(); } diff --git a/src/libaudcore/plugin-registry.cc b/src/libaudcore/plugin-registry.cc index 3ca79f3..b5e8167 100644 --- a/src/libaudcore/plugin-registry.cc +++ b/src/libaudcore/plugin-registry.cc @@ -20,7 +20,6 @@ #include "plugins-internal.h" #include -#include #include #include @@ -31,17 +30,20 @@ #include "parse.h" #include "plugin.h" #include "runtime.h" +#include "threads.h" #define FILENAME "plugin-registry" /* Increment this when the format of the plugin-registry file changes. - * Add 10 if the format changes in a way that will break parse_plugins_fallback(). */ + * Add 10 if the format changes in a way that will break + * parse_plugins_fallback(). */ #define FORMAT 11 /* Oldest file format supported by parse_plugins_fallback() */ -#define MIN_FORMAT 2 // "enabled" flag was added in Audacious 2.4 +#define MIN_FORMAT 2 // "enabled" flag was added in Audacious 2.4 -struct PluginWatch { +struct PluginWatch +{ PluginWatchFunc func; void * data; }; @@ -71,347 +73,333 @@ public: aud::array> keys; int has_subtunes, writes_tag; - PluginHandle (const char * basename, const char * path, bool loaded, - int timestamp, int version, int flags, PluginType type, Plugin * header) : - basename (basename), - path (path), - loaded (loaded), - timestamp (timestamp), - version (version), - flags (flags), - type (type), - header (header), - priority (0), - has_about (false), - has_configure (false), - enabled ((type == PluginType::Transport || - type == PluginType::Playlist || type == PluginType::Input) ? - PluginEnabled::Primary : PluginEnabled::Disabled), - can_save (false), - has_subtunes (false), - writes_tag (false) {} - - ~PluginHandle () + PluginHandle(const char * basename, const char * path, bool loaded, + int timestamp, int version, int flags, PluginType type, + Plugin * header) + : basename(basename), path(path), loaded(loaded), timestamp(timestamp), + version(version), flags(flags), type(type), header(header), + priority(0), has_about(false), has_configure(false), + enabled((type == PluginType::Transport || + type == PluginType::Playlist || type == PluginType::Input) + ? PluginEnabled::Primary + : PluginEnabled::Disabled), + can_save(false), has_subtunes(false), writes_tag(false) + { + } + + ~PluginHandle() { - if (watches.len ()) - AUDWARN ("Plugin watch count not zero at exit!\n"); + if (watches.len()) + AUDWARN("Plugin watch count not zero at exit!\n"); } }; static constexpr aud::array plugin_type_names = { - "transport", - "playlist", - "input", - "effect", - "output", - "vis", - "general", - "iface" -}; + "transport", "playlist", "input", "effect", + "output", "vis", "general", "iface"}; static constexpr aud::array input_key_names = { - "scheme", - "ext", - "mime" -}; + "scheme", "ext", "mime"}; static aud::array> plugins; static aud::array> compatible; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static bool modified = false; -static StringBuf get_basename (const char * path) +static StringBuf get_basename(const char * path) { - const char * slash = strrchr (path, G_DIR_SEPARATOR); - const char * dot = slash ? strrchr (slash + 1, '.') : nullptr; + const char * slash = strrchr(path, G_DIR_SEPARATOR); + const char * dot = slash ? strrchr(slash + 1, '.') : nullptr; - return dot ? str_copy (slash + 1, dot - (slash + 1)) : StringBuf (); + return dot ? str_copy(slash + 1, dot - (slash + 1)) : StringBuf(); } -static FILE * open_registry_file (const char * mode) +static FILE * open_registry_file(const char * mode) { - StringBuf path = filename_build ({aud_get_path (AudPath::UserDir), FILENAME}); - FILE * handle = g_fopen (path, mode); + StringBuf path = filename_build({aud_get_path(AudPath::UserDir), FILENAME}); + FILE * handle = g_fopen(path, mode); - if (! handle && errno != ENOENT) - AUDWARN ("%s: %s\n", (const char *) path, strerror (errno)); + if (!handle && errno != ENOENT) + AUDWARN("%s: %s\n", (const char *)path, strerror(errno)); return handle; } -static void transport_plugin_save (PluginHandle * plugin, FILE * handle) +static void transport_plugin_save(PluginHandle * plugin, FILE * handle) { for (const String & scheme : plugin->schemes) - fprintf (handle, "scheme %s\n", (const char *) scheme); + fprintf(handle, "scheme %s\n", (const char *)scheme); } -static void playlist_plugin_save (PluginHandle * plugin, FILE * handle) +static void playlist_plugin_save(PluginHandle * plugin, FILE * handle) { for (const String & ext : plugin->exts) - fprintf (handle, "ext %s\n", (const char *) ext); + fprintf(handle, "ext %s\n", (const char *)ext); - fprintf (handle, "saves %d\n", plugin->can_save); + fprintf(handle, "saves %d\n", plugin->can_save); } -static void input_plugin_save (PluginHandle * plugin, FILE * handle) +static void input_plugin_save(PluginHandle * plugin, FILE * handle) { - for (auto k : aud::range ()) + for (auto k : aud::range()) { for (const String & key : plugin->keys[k]) - fprintf (handle, "%s %s\n", input_key_names[k], (const char *) key); + fprintf(handle, "%s %s\n", input_key_names[k], (const char *)key); } - fprintf (handle, "subtunes %d\n", plugin->has_subtunes); - fprintf (handle, "writes %d\n", plugin->writes_tag); + fprintf(handle, "subtunes %d\n", plugin->has_subtunes); + fprintf(handle, "writes %d\n", plugin->writes_tag); } -static void plugin_save (PluginHandle * plugin, FILE * handle) +static void plugin_save(PluginHandle * plugin, FILE * handle) { - fprintf (handle, "%s %s\n", plugin_type_names[plugin->type], (const char *) plugin->path); - fprintf (handle, "stamp %d\n", plugin->timestamp); - fprintf (handle, "version %d\n", plugin->version); - fprintf (handle, "flags %d\n", plugin->flags); - fprintf (handle, "name %s\n", (const char *) plugin->name); + fprintf(handle, "%s %s\n", plugin_type_names[plugin->type], + (const char *)plugin->path); + fprintf(handle, "stamp %d\n", plugin->timestamp); + fprintf(handle, "version %d\n", plugin->version); + fprintf(handle, "flags %d\n", plugin->flags); + fprintf(handle, "name %s\n", (const char *)plugin->name); if (plugin->domain) - fprintf (handle, "domain %s\n", (const char *) plugin->domain); + fprintf(handle, "domain %s\n", (const char *)plugin->domain); - fprintf (handle, "priority %d\n", plugin->priority); - fprintf (handle, "about %d\n", plugin->has_about); - fprintf (handle, "config %d\n", plugin->has_configure); - fprintf (handle, "enabled %d\n", (int) plugin->enabled); + fprintf(handle, "priority %d\n", plugin->priority); + fprintf(handle, "about %d\n", plugin->has_about); + fprintf(handle, "config %d\n", plugin->has_configure); + fprintf(handle, "enabled %d\n", (int)plugin->enabled); if (plugin->type == PluginType::Transport) - transport_plugin_save (plugin, handle); + transport_plugin_save(plugin, handle); else if (plugin->type == PluginType::Playlist) - playlist_plugin_save (plugin, handle); + playlist_plugin_save(plugin, handle); else if (plugin->type == PluginType::Input) - input_plugin_save (plugin, handle); + input_plugin_save(plugin, handle); } -void plugin_registry_save () +void plugin_registry_save() { - if (! modified) + if (!modified) return; - FILE * handle = open_registry_file ("w"); - if (! handle) + FILE * handle = open_registry_file("w"); + if (!handle) return; - fprintf (handle, "format %d\n", FORMAT); + fprintf(handle, "format %d\n", FORMAT); for (auto & list : plugins) { for (PluginHandle * plugin : list) - plugin_save (plugin, handle); + plugin_save(plugin, handle); } - fclose (handle); + fclose(handle); modified = false; } -void plugin_registry_cleanup () +void plugin_registry_cleanup() { for (auto & list : plugins) { for (PluginHandle * plugin : list) delete plugin; - list.clear (); + list.clear(); } for (auto & list : compatible) - list.clear (); + list.clear(); } -static void transport_plugin_parse (PluginHandle * plugin, TextParser & parser) +static void transport_plugin_parse(PluginHandle * plugin, TextParser & parser) { while (1) { - String value = parser.get_str ("scheme"); - if (! value) + String value = parser.get_str("scheme"); + if (!value) break; - plugin->schemes.append (std::move (value)); - parser.next (); + plugin->schemes.append(std::move(value)); + parser.next(); } } -static void playlist_plugin_parse (PluginHandle * plugin, TextParser & parser) +static void playlist_plugin_parse(PluginHandle * plugin, TextParser & parser) { while (1) { - String value = parser.get_str ("ext"); - if (! value) + String value = parser.get_str("ext"); + if (!value) break; - plugin->exts.append (std::move (value)); - parser.next (); + plugin->exts.append(std::move(value)); + parser.next(); } - if (parser.get_int ("saves", plugin->can_save)) - parser.next (); + if (parser.get_int("saves", plugin->can_save)) + parser.next(); } -static void input_plugin_parse (PluginHandle * plugin, TextParser & parser) +static void input_plugin_parse(PluginHandle * plugin, TextParser & parser) { - for (auto key : aud::range ()) + for (auto key : aud::range()) { while (1) { - String value = parser.get_str (input_key_names[key]); - if (! value) + String value = parser.get_str(input_key_names[key]); + if (!value) break; - plugin->keys[key].append (std::move (value)); - parser.next (); + plugin->keys[key].append(std::move(value)); + parser.next(); } } - if (parser.get_int ("subtunes", plugin->has_subtunes)) - parser.next (); - if (parser.get_int ("writes", plugin->writes_tag)) - parser.next (); + if (parser.get_int("subtunes", plugin->has_subtunes)) + parser.next(); + if (parser.get_int("writes", plugin->writes_tag)) + parser.next(); } -static bool plugin_parse (TextParser & parser) +static bool plugin_parse(TextParser & parser) { PluginType type; String path; - for (auto type2 : aud::range ()) + for (auto type2 : aud::range()) { type = type2; - if ((path = parser.get_str (plugin_type_names[type2]))) + if ((path = parser.get_str(plugin_type_names[type2]))) break; } - if (! path) + if (!path) return false; - StringBuf basename = get_basename (path); - if (! basename) + StringBuf basename = get_basename(path); + if (!basename) return false; - parser.next (); + parser.next(); int timestamp; - if (! parser.get_int ("stamp", timestamp)) + if (!parser.get_int("stamp", timestamp)) return false; - parser.next (); + parser.next(); int version = 0, flags = 0; - if (parser.get_int ("version", version)) - parser.next (); - if (parser.get_int ("flags", flags)) - parser.next (); + if (parser.get_int("version", version)) + parser.next(); + if (parser.get_int("flags", flags)) + parser.next(); - auto plugin = new PluginHandle (basename, String (), false, timestamp, - version, flags, type, nullptr); + auto plugin = new PluginHandle(basename, String(), false, timestamp, + version, flags, type, nullptr); - plugins[type].append (plugin); + plugins[type].append(plugin); - plugin->name = parser.get_str ("name"); + plugin->name = parser.get_str("name"); if (plugin->name) - parser.next (); + parser.next(); - plugin->domain = parser.get_str ("domain"); + plugin->domain = parser.get_str("domain"); if (plugin->domain) - parser.next (); + parser.next(); - if (parser.get_int ("priority", plugin->priority)) - parser.next (); - if (parser.get_int ("about", plugin->has_about)) - parser.next (); - if (parser.get_int ("config", plugin->has_configure)) - parser.next (); + if (parser.get_int("priority", plugin->priority)) + parser.next(); + if (parser.get_int("about", plugin->has_about)) + parser.next(); + if (parser.get_int("config", plugin->has_configure)) + parser.next(); int enabled; - if (parser.get_int ("enabled", enabled)) + if (parser.get_int("enabled", enabled)) { - plugin->enabled = (PluginEnabled) enabled; - parser.next (); + plugin->enabled = (PluginEnabled)enabled; + parser.next(); } if (type == PluginType::Transport) - transport_plugin_parse (plugin, parser); + transport_plugin_parse(plugin, parser); else if (type == PluginType::Playlist) - playlist_plugin_parse (plugin, parser); + playlist_plugin_parse(plugin, parser); else if (type == PluginType::Input) - input_plugin_parse (plugin, parser); + input_plugin_parse(plugin, parser); return true; } /* try to migrate enabled status from another version */ -static void parse_plugins_fallback (TextParser & parser) +static void parse_plugins_fallback(TextParser & parser) { - for (; ! parser.eof (); parser.next ()) + for (; !parser.eof(); parser.next()) { PluginType type; String path; int enabled; - for (auto type2 : aud::range ()) + for (auto type2 : aud::range()) { type = type2; - if ((path = parser.get_str (plugin_type_names[type2]))) + if ((path = parser.get_str(plugin_type_names[type2]))) break; } - if (! path) + if (!path) continue; - StringBuf basename = get_basename (path); - if (! basename) + StringBuf basename = get_basename(path); + if (!basename) continue; - parser.next (); + parser.next(); - for (; ! parser.eof (); parser.next ()) + for (; !parser.eof(); parser.next()) { - if (parser.get_int ("enabled", enabled)) + if (parser.get_int("enabled", enabled)) break; } - if (parser.eof ()) + if (parser.eof()) return; // setting timestamp to zero forces a rescan - auto plugin = new PluginHandle (basename, String (), false, 0, 0, 0, type, nullptr); - plugins[type].append (plugin); - plugin->enabled = (PluginEnabled) enabled; + auto plugin = + new PluginHandle(basename, String(), false, 0, 0, 0, type, nullptr); + plugins[type].append(plugin); + plugin->enabled = (PluginEnabled)enabled; } } -void plugin_registry_load () +void plugin_registry_load() { - FILE * handle = open_registry_file ("r"); - if (! handle) + FILE * handle = open_registry_file("r"); + if (!handle) return; - TextParser parser (handle); + TextParser parser(handle); int format; - if (! parser.get_int ("format", format)) + if (!parser.get_int("format", format)) goto ERR; - parser.next (); + parser.next(); if (format == FORMAT) { - while (plugin_parse (parser)) + while (plugin_parse(parser)) continue; } else if (format >= MIN_FORMAT && format < FORMAT + 10) - parse_plugins_fallback (parser); + parse_plugins_fallback(parser); ERR: - fclose (handle); + fclose(handle); } -static int plugin_compare (PluginHandle * const & a, PluginHandle * const & b) +static int plugin_compare(PluginHandle * const & a, PluginHandle * const & b) { if (a->type < b->type) return -1; @@ -423,51 +411,52 @@ static int plugin_compare (PluginHandle * const & a, PluginHandle * const & b) return 1; int diff; - if ((diff = str_compare (dgettext (a->domain, a->name), dgettext (b->domain, b->name)))) + if ((diff = str_compare(dgettext(a->domain, a->name), + dgettext(b->domain, b->name)))) return diff; - return str_compare (a->path, b->path); + return str_compare(a->path, b->path); } -void plugin_registry_prune () +void plugin_registry_prune() { - auto check_not_found = [] (PluginHandle * plugin) - { + auto check_not_found = [](PluginHandle * plugin) { if (plugin->path) return false; - AUDINFO ("Plugin not found: %s\n", (const char *) plugin->basename); + AUDINFO("Plugin not found: %s\n", (const char *)plugin->basename); delete plugin; return true; }; - auto check_incompatible = [] (PluginHandle * plugin) - { - if (plugin_check_flags (plugin->flags)) + auto check_incompatible = [](PluginHandle * plugin) { + if (plugin_check_flags(plugin->flags)) return false; - AUDINFO ("Incompatible plugin flags: %s\n", (const char *) plugin->basename); + AUDINFO("Incompatible plugin flags: %s\n", + (const char *)plugin->basename); return true; }; - for (auto type : aud::range ()) + for (auto type : aud::range()) { - plugins[type].remove_if (check_not_found); - plugins[type].sort (plugin_compare); - compatible[type].insert (plugins[type].begin (), 0, plugins[type].len ()); - compatible[type].remove_if (check_incompatible); + plugins[type].remove_if(check_not_found); + plugins[type].sort(plugin_compare); + compatible[type].insert(plugins[type].begin(), 0, plugins[type].len()); + compatible[type].remove_if(check_incompatible); } } /* Note: If there are multiple plugins with the same basename, this returns only * one of them. Different plugins should be given different basenames. */ -static PluginHandle * plugin_lookup_basename (const char * basename, bool compat_only) +static PluginHandle * plugin_lookup_basename(const char * basename, + bool compat_only) { for (auto & list : (compat_only ? compatible : plugins)) { for (PluginHandle * plugin : list) { - if (! strcmp (plugin->basename, basename)) + if (!strcmp(plugin->basename, basename)) return plugin; } } @@ -475,145 +464,147 @@ static PluginHandle * plugin_lookup_basename (const char * basename, bool compat return nullptr; } -EXPORT PluginHandle * aud_plugin_lookup_basename (const char * basename) +EXPORT PluginHandle * aud_plugin_lookup_basename(const char * basename) { - return plugin_lookup_basename (basename, true); + return plugin_lookup_basename(basename, true); } -static void plugin_get_info (PluginHandle * plugin, bool is_new) +static void plugin_get_info(PluginHandle * plugin, bool is_new) { Plugin * header = plugin->header; plugin->version = header->version; plugin->flags = header->info.flags; - plugin->name = String (header->info.name); - plugin->domain = String (header->info.domain); - plugin->has_about = (bool) header->info.about; - plugin->has_configure = (bool) header->info.prefs; + plugin->name = String(header->info.name); + plugin->domain = String(header->info.domain); + plugin->has_about = (bool)header->info.about; + plugin->has_configure = (bool)header->info.prefs; if (header->type == PluginType::Transport) { - TransportPlugin * tp = (TransportPlugin *) header; + TransportPlugin * tp = (TransportPlugin *)header; - plugin->schemes.clear (); + plugin->schemes.clear(); for (const char * scheme : tp->schemes) - plugin->schemes.append (String (scheme)); + plugin->schemes.append(String(scheme)); } else if (header->type == PluginType::Playlist) { - PlaylistPlugin * pp = (PlaylistPlugin *) header; + PlaylistPlugin * pp = (PlaylistPlugin *)header; - plugin->exts.clear (); + plugin->exts.clear(); for (const char * ext : pp->extensions) - plugin->exts.append (String (ext)); + plugin->exts.append(String(ext)); plugin->can_save = pp->can_save; } else if (header->type == PluginType::Input) { - InputPlugin * ip = (InputPlugin *) header; + InputPlugin * ip = (InputPlugin *)header; plugin->priority = ip->input_info.priority; - for (auto k : aud::range ()) + for (auto k : aud::range()) { - plugin->keys[k].clear (); - for (auto key = ip->input_info.keys[k]; key && * key; key ++) - plugin->keys[k].append (String (* key)); + plugin->keys[k].clear(); + for (auto key = ip->input_info.keys[k]; key && *key; key++) + plugin->keys[k].append(String(*key)); } - plugin->has_subtunes = (ip->input_info.flags & InputPlugin::FlagSubtunes); - plugin->writes_tag = (ip->input_info.flags & InputPlugin::FlagWritesTag); + plugin->has_subtunes = + (ip->input_info.flags & InputPlugin::FlagSubtunes); + plugin->writes_tag = + (ip->input_info.flags & InputPlugin::FlagWritesTag); } else if (header->type == PluginType::Output) { - OutputPlugin * op = (OutputPlugin *) header; + OutputPlugin * op = (OutputPlugin *)header; plugin->priority = 10 - op->priority; } else if (header->type == PluginType::Effect) { - EffectPlugin * ep = (EffectPlugin *) header; + EffectPlugin * ep = (EffectPlugin *)header; plugin->priority = ep->order; } else if (header->type == PluginType::General) { - GeneralPlugin * gp = (GeneralPlugin *) header; + GeneralPlugin * gp = (GeneralPlugin *)header; if (is_new && gp->enabled_by_default) plugin->enabled = PluginEnabled::Primary; } } -void plugin_register (const char * path, int timestamp) +void plugin_register(const char * path, int timestamp) { - StringBuf basename = get_basename (path); - if (! basename) + StringBuf basename = get_basename(path); + if (!basename) return; - PluginHandle * plugin = plugin_lookup_basename (basename, false); + PluginHandle * plugin = plugin_lookup_basename(basename, false); if (plugin) { - AUDINFO ("Register plugin: %s\n", path); - plugin->path = String (path); + AUDINFO("Register plugin: %s\n", path); + plugin->path = String(path); if (plugin->timestamp != timestamp) { - AUDINFO ("Rescan plugin: %s\n", path); - Plugin * header = plugin_load (path); - if (! header || header->type != plugin->type) + AUDINFO("Rescan plugin: %s\n", path); + Plugin * header = plugin_load(path); + if (!header || header->type != plugin->type) return; plugin->loaded = true; plugin->header = header; plugin->timestamp = timestamp; - plugin_get_info (plugin, false); + plugin_get_info(plugin, false); modified = true; } } else { - AUDINFO ("New plugin: %s\n", path); - Plugin * header = plugin_load (path); - if (! header) + AUDINFO("New plugin: %s\n", path); + Plugin * header = plugin_load(path); + if (!header) return; - plugin = new PluginHandle (basename, path, true, timestamp, - header->version, header->info.flags, header->type, header); - plugins[plugin->type].append (plugin); + plugin = + new PluginHandle(basename, path, true, timestamp, header->version, + header->info.flags, header->type, header); + plugins[plugin->type].append(plugin); - plugin_get_info (plugin, true); + plugin_get_info(plugin, true); modified = true; } } -EXPORT PluginType aud_plugin_get_type (PluginHandle * plugin) +EXPORT PluginType aud_plugin_get_type(PluginHandle * plugin) { return plugin->type; } -EXPORT const char * aud_plugin_get_basename (PluginHandle * plugin) +EXPORT const char * aud_plugin_get_basename(PluginHandle * plugin) { return plugin->basename; } -EXPORT const void * aud_plugin_get_header (PluginHandle * plugin) +EXPORT const void * aud_plugin_get_header(PluginHandle * plugin) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! plugin->loaded) + if (!plugin->loaded) { - Plugin * header = plugin_load (plugin->path); + Plugin * header = plugin_load(plugin->path); if (header && header->type == plugin->type) plugin->header = header; plugin->loaded = true; } - pthread_mutex_unlock (& mutex); return plugin->header; } -EXPORT PluginHandle * aud_plugin_by_header (const void * header) +EXPORT PluginHandle * aud_plugin_by_header(const void * header) { for (auto & list : compatible) { @@ -627,119 +618,159 @@ EXPORT PluginHandle * aud_plugin_by_header (const void * header) return nullptr; } -EXPORT const Index & aud_plugin_list (PluginType type) +EXPORT const Index & aud_plugin_list(PluginType type) { return compatible[type]; } -EXPORT const char * aud_plugin_get_name (PluginHandle * plugin) +EXPORT const char * aud_plugin_get_name(PluginHandle * plugin) { - return dgettext (plugin->domain, plugin->name); + return dgettext(plugin->domain, plugin->name); } -EXPORT bool aud_plugin_has_about (PluginHandle * plugin) +EXPORT bool aud_plugin_has_about(PluginHandle * plugin) { return plugin->has_about; } -EXPORT bool aud_plugin_has_configure (PluginHandle * plugin) +EXPORT bool aud_plugin_has_configure(PluginHandle * plugin) { return plugin->has_configure; } -EXPORT bool aud_plugin_get_enabled (PluginHandle * plugin) +EXPORT bool aud_plugin_get_enabled(PluginHandle * plugin) { return plugin->enabled != PluginEnabled::Disabled; } -static void plugin_call_watches (PluginHandle * plugin) +static void plugin_call_watches(PluginHandle * plugin) { - auto call_and_check_remove = [=] (const PluginWatch & watch) - { return ! watch.func (plugin, watch.data); }; + auto call_and_check_remove = [=](const PluginWatch & watch) { + return !watch.func(plugin, watch.data); + }; - plugin->watches.remove_if (call_and_check_remove); + plugin->watches.remove_if(call_and_check_remove); } -PluginEnabled plugin_get_enabled (PluginHandle * plugin) +PluginEnabled plugin_get_enabled(PluginHandle * plugin) { return plugin->enabled; } -void plugin_set_enabled (PluginHandle * plugin, PluginEnabled enabled) +void plugin_set_enabled(PluginHandle * plugin, PluginEnabled enabled) { plugin->enabled = enabled; - plugin_call_watches (plugin); + plugin_call_watches(plugin); modified = true; } -void plugin_set_failed (PluginHandle * plugin) +void plugin_set_failed(PluginHandle * plugin) { plugin->header = nullptr; - plugin_set_enabled (plugin, PluginEnabled::Disabled); + plugin_set_enabled(plugin, PluginEnabled::Disabled); } -EXPORT void aud_plugin_add_watch (PluginHandle * plugin, PluginWatchFunc func, void * data) +EXPORT void aud_plugin_add_watch(PluginHandle * plugin, PluginWatchFunc func, + void * data) { - plugin->watches.append (func, data); + plugin->watches.append(func, data); } -EXPORT void aud_plugin_remove_watch (PluginHandle * plugin, PluginWatchFunc func, void * data) +EXPORT void aud_plugin_remove_watch(PluginHandle * plugin, PluginWatchFunc func, + void * data) { - auto is_match = [=] (const PluginWatch & watch) - { return watch.func == func && watch.data == data; }; + auto is_match = [=](const PluginWatch & watch) { + return watch.func == func && watch.data == data; + }; - plugin->watches.remove_if (is_match); + plugin->watches.remove_if(is_match); } -bool transport_plugin_has_scheme (PluginHandle * plugin, const char * scheme) +const Index & transport_plugin_get_schemes(PluginHandle * plugin) +{ + return plugin->schemes; +} + +bool transport_plugin_has_scheme(PluginHandle * plugin, const char * scheme) { for (String & s : plugin->schemes) { - if (! strcmp (s, scheme)) + if (!strcmp(s, scheme)) return true; } return false; } -bool playlist_plugin_can_save (PluginHandle * plugin) +bool playlist_plugin_can_save(PluginHandle * plugin) { return plugin->can_save; } -const Index & playlist_plugin_get_exts (PluginHandle * plugin) +const Index & playlist_plugin_get_exts(PluginHandle * plugin) { return plugin->exts; } -bool playlist_plugin_has_ext (PluginHandle * plugin, const char * ext) +bool playlist_plugin_has_ext(PluginHandle * plugin, const char * ext) { for (String & e : plugin->exts) { - if (! strcmp_nocase (e, ext)) + if (!strcmp_nocase(e, ext)) return true; } return false; } -bool input_plugin_has_key (PluginHandle * plugin, InputKey key, const char * value) +bool input_plugin_has_key(PluginHandle * plugin, InputKey key, + const char * value) { for (String & s : plugin->keys[key]) { - if (! strcmp_nocase (s, value)) + if (!strcmp_nocase(s, value)) return true; } return false; } -bool input_plugin_has_subtunes (PluginHandle * plugin) +bool input_plugin_has_subtunes(PluginHandle * plugin) { return plugin->has_subtunes; } -bool input_plugin_can_write_tuple (PluginHandle * plugin) +bool input_plugin_can_write_tuple(PluginHandle * plugin) { return plugin->writes_tag; } + +EXPORT Index aud_plugin_get_supported_mime_types() +{ + Index mimes; + + for (PluginHandle * p : aud_plugin_list(PluginType::Input)) + { + if (!aud_plugin_get_enabled(p)) + continue; + + for (auto k : p->keys[InputKey::MIME]) + mimes.append((const char *)k); + } + + /* sort and remove duplicates */ + /* lambda needed to avoid -Wnoexcept-type with GCC */ + mimes.sort([](const char * a, const char * b) { return strcmp(a, b); }); + + int len = mimes.len(); + for (int i = 0; i + 1 < len; i++) + { + if (!strcmp(mimes[i], mimes[i + 1])) + mimes[i] = nullptr; + } + + mimes.remove_if([](const char * m) { return m == nullptr; }); + mimes.append(nullptr); + + return mimes; +} diff --git a/src/libaudcore/plugin.h b/src/libaudcore/plugin.h index 65d0428..bd45fea 100644 --- a/src/libaudcore/plugin.h +++ b/src/libaudcore/plugin.h @@ -1,6 +1,6 @@ /* * plugin.h - * Copyright 2005-2013 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin, and + * Copyright 2005-2013 Ariadne Conill, Yoshiki Yazawa, Eugene Zagidullin, and * John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -25,14 +25,14 @@ #include #include #include -#include #include +#include enum class AudMenuID; struct PluginPreferences; /* "Magic" bytes identifying an Audacious plugin header. */ -#define _AUD_PLUGIN_MAGIC ((int) 0x8EAC8DE2) +#define _AUD_PLUGIN_MAGIC ((int)0x8EAC8DE2) /* API version. Plugins are marked with this number at compile time. * @@ -48,7 +48,10 @@ struct PluginPreferences; * _AUD_PLUGIN_VERSION_MIN to the same value. */ #define _AUD_PLUGIN_VERSION_MIN 48 /* 3.8-devel */ -#define _AUD_PLUGIN_VERSION 48 /* 3.8-devel */ +#define _AUD_PLUGIN_VERSION 48 /* 3.8-devel */ + +/* Default priority. */ +#define _AUD_PLUGIN_DEFAULT_PRIO 5 /* A NOTE ON THREADS * @@ -80,7 +83,8 @@ struct PluginPreferences; * Since 3.2, Audacious implements a basic messaging system between plugins. * Messages are sent using aud_plugin_send_message() and received through the * take_message() method specified in the header of the receiving plugin. - * Plugins that do not need to receive messages can set take_message() to nullptr. + * Plugins that do not need to receive messages can set take_message() to + * nullptr. * * Each message includes a code indicating the type of message, a pointer to * some data, and a value indicating the size of that data. What the message @@ -97,9 +101,10 @@ struct PluginPreferences; * program's main thread. */ /* plugin flags */ -enum { +enum +{ PluginGLibOnly = 0x1, // plugin requires GLib main loop - PluginQtOnly = 0x2 // plugin requires Qt main loop + PluginQtOnly = 0x2 // plugin requires Qt main loop }; struct PluginInfo @@ -114,9 +119,9 @@ struct PluginInfo class LIBAUDCORE_PUBLIC Plugin { public: - constexpr Plugin (PluginType type, PluginInfo info) : - type (type), - info (info) {} + constexpr Plugin(PluginType type, PluginInfo info) : type(type), info(info) + { + } const int magic = _AUD_PLUGIN_MAGIC; const int version = _AUD_PLUGIN_VERSION; @@ -124,40 +129,52 @@ public: const PluginType type; const PluginInfo info; - virtual bool init () { return true; } - virtual void cleanup () {} + virtual bool init() { return true; } + virtual void cleanup() {} - virtual int take_message (const char * code, const void * data, int size) { return -1; } + virtual int take_message(const char * code, const void * data, int size) + { + return -1; + } }; class LIBAUDCORE_PUBLIC TransportPlugin : public Plugin { public: - constexpr TransportPlugin (const PluginInfo info, - const ArrayRef schemes) : - Plugin (PluginType::Transport, info), - schemes (schemes) {} + constexpr TransportPlugin(const PluginInfo info, + const ArrayRef schemes) + : Plugin(PluginType::Transport, info), schemes(schemes) + { + } /* supported URI schemes (without "://") */ const ArrayRef schemes; - virtual VFSImpl * fopen (const char * filename, const char * mode, String & error) = 0; + virtual VFSImpl * fopen(const char * filename, const char * mode, + String & error) = 0; - virtual VFSFileTest test_file (const char * filename, VFSFileTest test, String & error) - { return VFSFileTest (0); } + virtual VFSFileTest test_file(const char * filename, VFSFileTest test, + String & error) + { + return VFSFileTest(0); + } - virtual Index read_folder (const char * filename, String & error) - { return Index (); } + virtual Index read_folder(const char * filename, String & error) + { + return Index(); + } }; class LIBAUDCORE_PUBLIC PlaylistPlugin : public Plugin { public: - constexpr PlaylistPlugin (const PluginInfo info, - const ArrayRef extensions, bool can_save) : - Plugin (PluginType::Playlist, info), - extensions (extensions), - can_save (can_save) {} + constexpr PlaylistPlugin(const PluginInfo info, + const ArrayRef extensions, + bool can_save) + : Plugin(PluginType::Playlist, info), extensions(extensions), + can_save(can_save) + { + } /* supported file extensions (without periods) */ const ArrayRef extensions; @@ -169,26 +186,32 @@ public: * file: VFS handle of playlist file (in, read-only file, not seekable) * title: title of playlist (out) * items: playlist entries (out) */ - virtual bool load (const char * path, VFSFile & file, String & title, - Index & items) = 0; + virtual bool load(const char * path, VFSFile & file, String & title, + Index & items) = 0; /* path: URI of playlist file (in) * file: VFS handle of playlist file (in, write-only file, not seekable) * title: title of playlist (in) * items: playlist entries (in) */ - virtual bool save (const char * path, VFSFile & file, const char * title, - const Index & items) { return false; } + virtual bool save(const char * path, VFSFile & file, const char * title, + const Index & items) + { + return false; + } }; class LIBAUDCORE_PUBLIC OutputPlugin : public Plugin { public: - constexpr OutputPlugin (const PluginInfo info, int priority, bool force_reopen = false) : - Plugin (PluginType::Output, info), - priority (priority), - force_reopen (force_reopen) {} + constexpr OutputPlugin(const PluginInfo info, int priority, + bool force_reopen = false) + : Plugin(PluginType::Output, info), priority(priority), + force_reopen(force_reopen) + { + } - /* During probing, plugins with higher priority (10 to 0) are tried first. */ + /* During probing, plugins with higher priority (10 to 0) are tried first. + */ const int priority; /* Whether close_audio() and open_audio() must always be called between @@ -197,56 +220,59 @@ public: const bool force_reopen; /* Returns current volume for left and right channels (0 to 100). */ - virtual StereoVolume get_volume () = 0; + virtual StereoVolume get_volume() = 0; /* Changes volume for left and right channels (0 to 100). */ - virtual void set_volume (StereoVolume volume) = 0; + virtual void set_volume(StereoVolume volume) = 0; /* Sets information about the song being played. This function will be * called before open_audio(). */ - virtual void set_info (const char * filename, const Tuple & tuple) {} + virtual void set_info(const char * filename, const Tuple & tuple) {} /* Begins playback of a PCM stream. is one of the FMT_* * enumeration values defined in libaudcore/audio.h. Returns true on * success. */ - virtual bool open_audio (int format, int rate, int chans, String & error) = 0; + virtual bool open_audio(int format, int rate, int chans, + String & error) = 0; /* Ends playback. Any buffered audio data is discarded. */ - virtual void close_audio () = 0; + virtual void close_audio() = 0; /* Waits until write_audio() will return a size greater than zero. * get_delay(), pause(), and flush() may be called meanwhile; if flush() * is called, period_wait() should return immediately. */ - virtual void period_wait () = 0; + virtual void period_wait() = 0; /* Writes up to bytes of data, in the format given to open_audio(). * If there is not enough buffer space for all bytes, writes only as * many bytes as can be written immediately without blocking. Returns the * number of bytes actually written. */ - virtual int write_audio (const void * data, int size) = 0; + virtual int write_audio(const void * data, int size) = 0; /* Waits until all buffered data has been heard by the user. */ - virtual void drain () = 0; + virtual void drain() = 0; /* Returns an estimate of how many milliseconds will pass before all the * data passed to write_audio() has been heard by the user. */ - virtual int get_delay () = 0; + virtual int get_delay() = 0; /* Pauses the stream if

is nonzero; otherwise unpauses it. * write_audio() will not be called while the stream is paused. */ - virtual void pause (bool pause) = 0; + virtual void pause(bool pause) = 0; /* Discards any buffered audio data. */ - virtual void flush () = 0; + virtual void flush() = 0; }; class LIBAUDCORE_PUBLIC EffectPlugin : public Plugin { public: - constexpr EffectPlugin (const PluginInfo info, int order, bool preserves_format) : - Plugin (PluginType::Effect, info), - order (order), - preserves_format (preserves_format) {} + constexpr EffectPlugin(const PluginInfo info, int order, + bool preserves_format) + : Plugin(PluginType::Effect, info), order(order), + preserves_format(preserves_format) + { + } /* Effects with lowest order (0 to 9) are applied first. */ const int order; @@ -258,27 +284,29 @@ public: /* All processing is done in floating point. If the effect plugin wants to * change the channel count or sample rate, it can change the parameters * passed to start(). They cannot be changed in the middle of a song. */ - virtual void start (int & channels, int & rate) = 0; + virtual void start(int & channels, int & rate) = 0; /* Performs effect processing. process() may modify the audio samples in * place and return a reference to the same buffer, or it may return a * reference to an internal working buffer. The number of output samples * need not be the same as the number of input samples. */ - virtual Index & process (Index & data) = 0; + virtual Index & process(Index & data) = 0; /* Optional. A seek is taking place; any buffers should be discarded. * Unless the "force" flag is set, the plugin may choose to override the * normal flush behavior and handle the flush itself (for example, to * perform crossfading). The flush() function should return false in this - * case to prevent flush() from being called in downstream effect plugins. */ - virtual bool flush (bool force) - { return true; } + * case to prevent flush() from being called in downstream effect plugins. + */ + virtual bool flush(bool force) { return true; } /* Exactly like process() except that any buffers should be drained (i.e. * the data processed and returned). finish() will be called a second time * at the end of the last song in the playlist. */ - virtual Index & finish (Index & data, bool end_of_playlist) - { return process (data); } + virtual Index & finish(Index & data, bool end_of_playlist) + { + return process(data); + } /* Required only for plugins that change the time domain (e.g. a time * stretch) or use read-ahead buffering. translate_delay() must do two @@ -286,11 +314,11 @@ public: * output time domain back to the input time domain; second, increase * by the size of the read-ahead buffer. It should return the * adjusted delay. */ - virtual int adjust_delay (int delay) - { return delay; } + virtual int adjust_delay(int delay) { return delay; } }; -enum class InputKey { +enum class InputKey +{ Ext, MIME, Scheme, @@ -300,7 +328,8 @@ enum class InputKey { class LIBAUDCORE_PUBLIC InputPlugin : public Plugin { public: - enum { + enum + { /* Indicates that the plugin can write file tags */ FlagWritesTag = (1 << 0), @@ -330,67 +359,86 @@ public: int flags, priority; aud::array keys; - constexpr InputInfo (int flags = 0) : - flags (flags), priority (0), keys {} {} + constexpr InputInfo(int flags = 0) + : flags(flags), priority(_AUD_PLUGIN_DEFAULT_PRIO), keys{} + { + } /* Associates file extensions with the plugin. */ - constexpr InputInfo with_exts (List exts) const - { return InputInfo (flags, priority, - exts, keys[InputKey::MIME], keys[InputKey::Scheme]); } + constexpr InputInfo with_exts(List exts) const + { + return InputInfo(flags, priority, exts, keys[InputKey::MIME], + keys[InputKey::Scheme]); + } /* Associates MIME types with the plugin. */ - constexpr InputInfo with_mimes (List mimes) const - { return InputInfo (flags, priority, - keys[InputKey::Ext], mimes, keys[InputKey::Scheme]); } + constexpr InputInfo with_mimes(List mimes) const + { + return InputInfo(flags, priority, keys[InputKey::Ext], mimes, + keys[InputKey::Scheme]); + } /* Associates custom URI schemes with the plugin. Plugins using custom * URI schemes are expected to handle their own I/O. Hence, any VFSFile * passed to play(), read_tuple(), etc. will be null. */ - constexpr InputInfo with_schemes (List schemes) const - { return InputInfo (flags, priority, - keys[InputKey::Ext], keys[InputKey::MIME], schemes); } + constexpr InputInfo with_schemes(List schemes) const + { + return InputInfo(flags, priority, keys[InputKey::Ext], + keys[InputKey::MIME], schemes); + } /* Sets how quickly the plugin should be tried in searching for a plugin * to handle a file which could not be identified from its extension. * Plugins with priority 0 are tried first, 10 last. */ - constexpr InputInfo with_priority (int priority) const - { return InputInfo (flags, priority, - keys[InputKey::Ext], keys[InputKey::MIME], keys[InputKey::Scheme]); } + constexpr InputInfo with_priority(int priority) const + { + return InputInfo(flags, priority, keys[InputKey::Ext], + keys[InputKey::MIME], keys[InputKey::Scheme]); + } private: - constexpr InputInfo (int flags, int priority, List exts, List mimes, List schemes) : - flags (flags), priority (priority), keys {exts, mimes, schemes} {} + constexpr InputInfo(int flags, int priority, List exts, List mimes, + List schemes) + : flags(flags), priority(priority), keys{exts, mimes, schemes} + { + } }; - constexpr InputPlugin (PluginInfo info, InputInfo input_info) : - Plugin (PluginType::Input, info), - input_info (input_info) {} + constexpr InputPlugin(PluginInfo info, InputInfo input_info) + : Plugin(PluginType::Input, info), input_info(input_info) + { + } const InputInfo input_info; /* Returns true if the plugin can handle the file. */ - virtual bool is_our_file (const char * filename, VFSFile & file) = 0; + virtual bool is_our_file(const char * filename, VFSFile & file) = 0; /* Reads metadata and album art (if requested and available) from the file. * The filename fields of the tuple are already set before the function is * called. If album art is not needed, will be nullptr. The return * value should be true if was successfully read, regardless of * whether album art was read. */ - virtual bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, - Index * image) = 0; + virtual bool read_tag(const char * filename, VFSFile & file, Tuple & tuple, + Index * image) = 0; /* Plays the file. Returns false on error. Also see input-api.h. */ - virtual bool play (const char * filename, VFSFile & file) = 0; + virtual bool play(const char * filename, VFSFile & file) = 0; /* Optional. Writes metadata to the file, returning false on error. */ - virtual bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple) - { return false; } + virtual bool write_tuple(const char * filename, VFSFile & file, + const Tuple & tuple) + { + return false; + } /* Optional. Displays a window showing info about the file. In general, * this function should be avoided since Audacious already provides a file * info window. */ - virtual bool file_info_box (const char * filename, VFSFile & file) - { return false; } + virtual bool file_info_box(const char * filename, VFSFile & file) + { + return false; + } protected: /* Prepares the output system for playback in the specified format. Also @@ -399,57 +447,62 @@ protected: * calling open_audio. There is no return value. If the requested audio * format is not supported, write_audio() will do nothing and check_stop() * will immediately return true. */ - static void open_audio (int format, int rate, int channels); + static void open_audio(int format, int rate, int channels); /* Informs the output system of replay gain values for the current song so * that volume levels can be adjusted accordingly, if the user so desires. - * This may be called at any time during playback should the values change. */ - static void set_replay_gain (const ReplayGainInfo & gain); + * This may be called at any time during playback should the values change. + */ + static void set_replay_gain(const ReplayGainInfo & gain); /* Passes audio data to the output system for playback. The data must be in * the format passed to open_audio(), and the length (in bytes) must be an * integral number of frames. This function blocks until all the data has * been written (though it may not yet be heard by the user). */ - static void write_audio (const void * data, int length); + static void write_audio(const void * data, int length); /* Returns the current tuple for the stream. */ - static Tuple get_playback_tuple (); + static Tuple get_playback_tuple(); /* Updates the tuple for the stream. */ - static void set_playback_tuple (Tuple && tuple); + static void set_playback_tuple(Tuple && tuple); /* Updates the displayed bitrate, in bits per second. */ - static void set_stream_bitrate (int bitrate); + static void set_stream_bitrate(int bitrate); /* Checks whether playback is to be stopped. The play() function should * poll check_stop() periodically and return as soon as check_stop() returns * true. */ - static bool check_stop (); + static bool check_stop(); /* Checks whether a seek has been requested. If so, returns the position to * seek to, in milliseconds. Otherwise, returns -1. */ - static int check_seek (); + static int check_seek(); }; class LIBAUDCORE_PUBLIC DockablePlugin : public Plugin { public: - constexpr DockablePlugin (PluginType type, PluginInfo info) : - Plugin (type, info) {} + constexpr DockablePlugin(PluginType type, PluginInfo info) + : Plugin(type, info) + { + } /* GtkWidget * get_gtk_widget () */ - virtual void * get_gtk_widget () { return nullptr; } + virtual void * get_gtk_widget() { return nullptr; } /* QWidget * get_qt_widget () */ - virtual void * get_qt_widget () { return nullptr; } + virtual void * get_qt_widget() { return nullptr; } }; class LIBAUDCORE_PUBLIC GeneralPlugin : public DockablePlugin { public: - constexpr GeneralPlugin (PluginInfo info, bool enabled_by_default) : - DockablePlugin (PluginType::General, info), - enabled_by_default (enabled_by_default) {} + constexpr GeneralPlugin(PluginInfo info, bool enabled_by_default) + : DockablePlugin(PluginType::General, info), + enabled_by_default(enabled_by_default) + { + } const bool enabled_by_default; }; @@ -457,33 +510,34 @@ public: class LIBAUDCORE_PUBLIC VisPlugin : public DockablePlugin, public Visualizer { public: - constexpr VisPlugin (PluginInfo info, int type_mask) : - DockablePlugin (PluginType::Vis, info), - Visualizer (type_mask) {} + constexpr VisPlugin(PluginInfo info, int type_mask) + : DockablePlugin(PluginType::Vis, info), Visualizer(type_mask) + { + } }; class LIBAUDCORE_PUBLIC IfacePlugin : public Plugin { public: - constexpr IfacePlugin (PluginInfo info) : - Plugin (PluginType::Iface, info) {} - - virtual void show (bool show) = 0; - virtual void run () = 0; - virtual void quit () = 0; - - virtual void show_about_window () = 0; - virtual void hide_about_window () = 0; - virtual void show_filebrowser (bool open) = 0; - virtual void hide_filebrowser () = 0; - virtual void show_jump_to_song () = 0; - virtual void hide_jump_to_song () = 0; - virtual void show_prefs_window () = 0; - virtual void hide_prefs_window () = 0; - virtual void plugin_menu_add (AudMenuID id, void func (), const char * name, const char * icon) = 0; - virtual void plugin_menu_remove (AudMenuID id, void func ()) = 0; - - virtual void startup_notify (const char * id) {} + constexpr IfacePlugin(PluginInfo info) : Plugin(PluginType::Iface, info) {} + + virtual void show(bool show) = 0; + virtual void run() = 0; + virtual void quit() = 0; + + virtual void show_about_window() = 0; + virtual void hide_about_window() = 0; + virtual void show_filebrowser(bool open) = 0; + virtual void hide_filebrowser() = 0; + virtual void show_jump_to_song() = 0; + virtual void hide_jump_to_song() = 0; + virtual void show_prefs_window() = 0; + virtual void hide_prefs_window() = 0; + virtual void plugin_menu_add(AudMenuID id, void func(), const char * name, + const char * icon) = 0; + virtual void plugin_menu_remove(AudMenuID id, void func()) = 0; + + virtual void startup_notify(const char * id) {} }; #endif diff --git a/src/libaudcore/plugins-internal.h b/src/libaudcore/plugins-internal.h index d521c5c..23ae67b 100644 --- a/src/libaudcore/plugins-internal.h +++ b/src/libaudcore/plugins-internal.h @@ -20,49 +20,52 @@ #ifndef LIBAUDCORE_PLUGINS_INTERNAL_H #define LIBAUDCORE_PLUGINS_INTERNAL_H -#include "plugins.h" #include "objects.h" +#include "plugins.h" enum class InputKey; class Plugin; -enum class PluginEnabled { +enum class PluginEnabled +{ Disabled = 0, Primary = 1, Secondary = 2 }; /* plugin-init.c */ -void start_plugins_one (); -void start_plugins_two (); -void stop_plugins_two (); -void stop_plugins_one (); +void start_plugins_one(); +void start_plugins_two(); +void stop_plugins_two(); +void stop_plugins_one(); -bool plugin_enable_secondary (PluginHandle * plugin, bool enable); +bool plugin_enable_secondary(PluginHandle * plugin, bool enable); /* plugin-load.c */ -void plugin_system_init (); -void plugin_system_cleanup (); -bool plugin_check_flags (int flags); -Plugin * plugin_load (const char * path); +void plugin_system_init(); +void plugin_system_cleanup(); +bool plugin_check_flags(int flags); +Plugin * plugin_load(const char * path); /* plugin-registry.c */ -void plugin_registry_load (); -void plugin_registry_prune (); -void plugin_registry_save (); -void plugin_registry_cleanup (); +void plugin_registry_load(); +void plugin_registry_prune(); +void plugin_registry_save(); +void plugin_registry_cleanup(); -void plugin_register (const char * path, int timestamp); -PluginEnabled plugin_get_enabled (PluginHandle * plugin); -void plugin_set_enabled (PluginHandle * plugin, PluginEnabled enabled); -void plugin_set_failed (PluginHandle * plugin); +void plugin_register(const char * path, int timestamp); +PluginEnabled plugin_get_enabled(PluginHandle * plugin); +void plugin_set_enabled(PluginHandle * plugin, PluginEnabled enabled); +void plugin_set_failed(PluginHandle * plugin); -bool transport_plugin_has_scheme (PluginHandle * plugin, const char * scheme); -bool playlist_plugin_can_save (PluginHandle * plugin); -const Index & playlist_plugin_get_exts (PluginHandle * plugin); -bool playlist_plugin_has_ext (PluginHandle * plugin, const char * ext); -bool input_plugin_has_key (PluginHandle * plugin, InputKey key, const char * value); -bool input_plugin_has_subtunes (PluginHandle * plugin); -bool input_plugin_can_write_tuple (PluginHandle * plugin); +const Index & transport_plugin_get_schemes(PluginHandle * plugin); +bool transport_plugin_has_scheme(PluginHandle * plugin, const char * scheme); +bool playlist_plugin_can_save(PluginHandle * plugin); +const Index & playlist_plugin_get_exts(PluginHandle * plugin); +bool playlist_plugin_has_ext(PluginHandle * plugin, const char * ext); +bool input_plugin_has_key(PluginHandle * plugin, InputKey key, + const char * value); +bool input_plugin_has_subtunes(PluginHandle * plugin); +bool input_plugin_can_write_tuple(PluginHandle * plugin); #endif diff --git a/src/libaudcore/plugins.h b/src/libaudcore/plugins.h index 7223560..bf156f6 100644 --- a/src/libaudcore/plugins.h +++ b/src/libaudcore/plugins.h @@ -22,7 +22,8 @@ #include -enum class PluginType { +enum class PluginType +{ Transport, Playlist, Input, @@ -38,31 +39,37 @@ class PluginHandle; /* CAUTION: These functions are not thread safe. */ -PluginHandle * aud_plugin_get_current (PluginType type); -bool aud_plugin_get_enabled (PluginHandle * plugin); -bool aud_plugin_enable (PluginHandle * plugin, bool enable); +PluginHandle * aud_plugin_get_current(PluginType type); +bool aud_plugin_get_enabled(PluginHandle * plugin); +bool aud_plugin_enable(PluginHandle * plugin, bool enable); -int aud_plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size); -void * aud_plugin_get_gtk_widget (PluginHandle * plugin); // returns (GtkWidget *) -void * aud_plugin_get_qt_widget (PluginHandle * plugin); // return (QWidget *) +int aud_plugin_send_message(PluginHandle * plugin, const char * code, + const void * data, int size); +void * +aud_plugin_get_gtk_widget(PluginHandle * plugin); // returns (GtkWidget *) +void * aud_plugin_get_qt_widget(PluginHandle * plugin); // return (QWidget *) -PluginType aud_plugin_get_type (PluginHandle * plugin); -const char * aud_plugin_get_basename (PluginHandle * plugin); -PluginHandle * aud_plugin_lookup_basename (const char * basename); +PluginType aud_plugin_get_type(PluginHandle * plugin); +const char * aud_plugin_get_basename(PluginHandle * plugin); +PluginHandle * aud_plugin_lookup_basename(const char * basename); -const void * aud_plugin_get_header (PluginHandle * plugin); -PluginHandle * aud_plugin_by_header (const void * header); +const void * aud_plugin_get_header(PluginHandle * plugin); +PluginHandle * aud_plugin_by_header(const void * header); -const Index & aud_plugin_list (PluginType type); +const Index & aud_plugin_list(PluginType type); -const char * aud_plugin_get_name (PluginHandle * plugin); -bool aud_plugin_has_about (PluginHandle * plugin); -bool aud_plugin_has_configure (PluginHandle * plugin); +const char * aud_plugin_get_name(PluginHandle * plugin); +bool aud_plugin_has_about(PluginHandle * plugin); +bool aud_plugin_has_configure(PluginHandle * plugin); /* returns true to continue watching, false to stop */ -typedef bool (* PluginWatchFunc) (PluginHandle * plugin, void * data); +typedef bool (*PluginWatchFunc)(PluginHandle * plugin, void * data); -void aud_plugin_add_watch (PluginHandle * plugin, PluginWatchFunc func, void * data); -void aud_plugin_remove_watch (PluginHandle * plugin, PluginWatchFunc func, void * data); +void aud_plugin_add_watch(PluginHandle * plugin, PluginWatchFunc func, + void * data); +void aud_plugin_remove_watch(PluginHandle * plugin, PluginWatchFunc func, + void * data); + +Index aud_plugin_get_supported_mime_types(); #endif diff --git a/src/libaudcore/preferences.cc b/src/libaudcore/preferences.cc index 4f14e39..3d6d8a2 100644 --- a/src/libaudcore/preferences.cc +++ b/src/libaudcore/preferences.cc @@ -22,102 +22,102 @@ #include -EXPORT bool WidgetConfig::get_bool () const +EXPORT bool WidgetConfig::get_bool() const { - assert (type == Bool); + assert(type == Bool); if (value) - return * (bool *) value; + return *(bool *)value; else if (name) - return aud_get_bool (section, name); + return aud_get_bool(section, name); else return false; } -EXPORT void WidgetConfig::set_bool (bool val) const +EXPORT void WidgetConfig::set_bool(bool val) const { - assert (type == Bool); + assert(type == Bool); if (value) - * (bool *) value = val; + *(bool *)value = val; else if (name) - aud_set_bool (section, name, val); + aud_set_bool(section, name, val); if (callback) - callback (); + callback(); } -EXPORT int WidgetConfig::get_int () const +EXPORT int WidgetConfig::get_int() const { - assert (type == Int); + assert(type == Int); if (value) - return * (int *) value; + return *(int *)value; else if (name) - return aud_get_int (section, name); + return aud_get_int(section, name); else return 0; } -EXPORT void WidgetConfig::set_int (int val) const +EXPORT void WidgetConfig::set_int(int val) const { - assert (type == Int); + assert(type == Int); if (value) - * (int *) value = val; + *(int *)value = val; else if (name) - aud_set_int (section, name, val); + aud_set_int(section, name, val); if (callback) - callback (); + callback(); } -EXPORT double WidgetConfig::get_float () const +EXPORT double WidgetConfig::get_float() const { - assert (type == Float); + assert(type == Float); if (value) - return * (double *) value; + return *(double *)value; else if (name) - return aud_get_double (section, name); + return aud_get_double(section, name); else return 0; } -EXPORT void WidgetConfig::set_float (double val) const +EXPORT void WidgetConfig::set_float(double val) const { - assert (type == Float); + assert(type == Float); if (value) - * (double *) value = val; + *(double *)value = val; else if (name) - aud_set_double (section, name, val); + aud_set_double(section, name, val); if (callback) - callback (); + callback(); } -EXPORT String WidgetConfig::get_string () const +EXPORT String WidgetConfig::get_string() const { - assert (type == String); + assert(type == String); if (value) - return * (::String *) value; + return *(::String *)value; else if (name) - return aud_get_str (section, name); + return aud_get_str(section, name); else - return ::String (); + return ::String(); } -EXPORT void WidgetConfig::set_string (const char * val) const +EXPORT void WidgetConfig::set_string(const char * val) const { - assert (type == String); + assert(type == String); if (value) - * (::String *) value = ::String (val); + *(::String *)value = ::String(val); else if (name) - aud_set_str (section, name, val); + aud_set_str(section, name, val); if (callback) - callback (); + callback(); } diff --git a/src/libaudcore/preferences.h b/src/libaudcore/preferences.h index 8946b01..957c928 100644 --- a/src/libaudcore/preferences.h +++ b/src/libaudcore/preferences.h @@ -1,6 +1,6 @@ /* * preferences.h - * Copyright 2007-2014 Tomasz Moń, William Pitcock, and John Lindgren + * Copyright 2007-2014 Tomasz Moń, Ariadne Conill, and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -24,83 +24,98 @@ struct PreferencesWidget; -enum class FileSelectMode { +enum class FileSelectMode +{ File, Folder }; -struct ComboItem { +struct ComboItem +{ const char * label; const char * str; int num; - constexpr ComboItem (const char * label, const char * str) : - label (label), - str (str), - num (-1) {} + constexpr ComboItem(const char * label, const char * str) + : label(label), str(str), num(-1) + { + } - constexpr ComboItem (const char * label, int num) : - label (label), - str (nullptr), - num (num) {} + constexpr ComboItem(const char * label, int num) + : label(label), str(nullptr), num(num) + { + } }; -struct WidgetVButton { - void (* callback) (); +struct WidgetVButton +{ + void (*callback)(); const char * icon; }; -struct WidgetVRadio { +struct WidgetVRadio +{ int value; }; -struct WidgetVSpin { +struct WidgetVSpin +{ double min, max, step; const char * right_label; /* text right to widget */ }; -struct WidgetVTable { +struct WidgetVTable +{ ArrayRef widgets; }; -struct WidgetVFonts { +struct WidgetVFonts +{ const char * title; }; -struct WidgetVEntry { +struct WidgetVEntry +{ bool password; }; -struct WidgetVFileEntry { +struct WidgetVFileEntry +{ FileSelectMode mode; }; -struct WidgetVCombo { +struct WidgetVCombo +{ /* static init */ ArrayRef elems; /* runtime init */ - ArrayRef (* fill) (); + ArrayRef (*fill)(); }; -struct WidgetVBox { +struct WidgetVBox +{ ArrayRef widgets; - bool horizontal; /* false gives vertical, true gives horizontal alignment of child widgets */ - bool frame; /* whether to draw frame around box */ + bool horizontal; /* false gives vertical, true gives horizontal alignment of + child widgets */ + bool frame; /* whether to draw frame around box */ }; -struct NotebookTab { +struct NotebookTab +{ const char * name; ArrayRef widgets; }; -struct WidgetVNotebook { +struct WidgetVNotebook +{ ArrayRef tabs; }; -struct WidgetVSeparator { - bool horizontal; /* false gives vertical, true gives horizontal separator */ +struct WidgetVSeparator +{ + bool horizontal; /* false gives vertical, true gives horizontal separator */ }; union WidgetVariant { @@ -119,27 +134,33 @@ union WidgetVariant { /* for custom GTK or Qt widgets */ /* GtkWidget * (* populate) (); */ /* QWidget * (* populate) (); */ - void * (* populate) (); - - constexpr WidgetVariant (WidgetVButton button) : button (button) {} - constexpr WidgetVariant (WidgetVRadio radio) : radio_btn (radio) {} - constexpr WidgetVariant (WidgetVSpin spin) : spin_btn (spin) {} - constexpr WidgetVariant (WidgetVTable table) : table (table) {} - constexpr WidgetVariant (WidgetVFonts fonts) : font_btn (fonts) {} - constexpr WidgetVariant (WidgetVEntry entry) : entry (entry) {} - constexpr WidgetVariant (WidgetVFileEntry file_entry) : file_entry (file_entry) {} - constexpr WidgetVariant (WidgetVCombo combo) : combo (combo) {} - constexpr WidgetVariant (WidgetVBox box) : box (box) {} - constexpr WidgetVariant (WidgetVNotebook notebook) : notebook (notebook) {} - constexpr WidgetVariant (WidgetVSeparator separator) : separator (separator) {} + void * (*populate)(); + + constexpr WidgetVariant(WidgetVButton button) : button(button) {} + constexpr WidgetVariant(WidgetVRadio radio) : radio_btn(radio) {} + constexpr WidgetVariant(WidgetVSpin spin) : spin_btn(spin) {} + constexpr WidgetVariant(WidgetVTable table) : table(table) {} + constexpr WidgetVariant(WidgetVFonts fonts) : font_btn(fonts) {} + constexpr WidgetVariant(WidgetVEntry entry) : entry(entry) {} + constexpr WidgetVariant(WidgetVFileEntry file_entry) + : file_entry(file_entry) + { + } + constexpr WidgetVariant(WidgetVCombo combo) : combo(combo) {} + constexpr WidgetVariant(WidgetVBox box) : box(box) {} + constexpr WidgetVariant(WidgetVNotebook notebook) : notebook(notebook) {} + constexpr WidgetVariant(WidgetVSeparator separator) : separator(separator) + { + } /* also serves as default constructor */ - constexpr WidgetVariant (void * (* populate) () = 0) : populate (populate) {} + constexpr WidgetVariant(void * (*populate)() = 0) : populate(populate) {} }; struct WidgetConfig { - enum Type { + enum Type + { None, Bool, Int, @@ -152,68 +173,91 @@ struct WidgetConfig /* pointer to immediate value */ void * value; /* identifier for configuration value */ - const char * section, * name; + const char *section, *name; /* called when value is changed */ - void (* callback) (); + void (*callback)(); /* widget updates when this hook is called */ const char * hook; - constexpr WidgetConfig () : - type (None), - value (nullptr), - section (nullptr), - name (nullptr), - callback (nullptr), - hook (nullptr) {} - - constexpr WidgetConfig (Type type, void * value, const char * section, - const char * name, void (* callback) (), const char * hook) : - type (type), - value (value), - section (section), - name (name), - callback (callback), - hook (hook) {} - - bool get_bool () const; - void set_bool (bool val) const; - int get_int () const; - void set_int (int val) const; - double get_float () const; - void set_float (double val) const; - ::String get_string () const; - void set_string (const char * val) const; + constexpr WidgetConfig() + : type(None), value(nullptr), section(nullptr), name(nullptr), + callback(nullptr), hook(nullptr) + { + } + + constexpr WidgetConfig(Type type, void * value, const char * section, + const char * name, void (*callback)(), + const char * hook) + : type(type), value(value), section(section), name(name), + callback(callback), hook(hook) + { + } + + bool get_bool() const; + void set_bool(bool val) const; + int get_int() const; + void set_int(int val) const; + double get_float() const; + void set_float(double val) const; + ::String get_string() const; + void set_string(const char * val) const; }; -constexpr WidgetConfig WidgetBool (bool & value, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::Bool, (void *) & value, 0, 0, callback, hook); } -constexpr WidgetConfig WidgetInt (int & value, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::Int, (void *) & value, 0, 0, callback, hook); } -constexpr WidgetConfig WidgetFloat (double & value, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::Float, (void *) & value, 0, 0, callback, hook); } -constexpr WidgetConfig WidgetString (String & value, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::String, (void *) & value, 0, 0, callback, hook); } - -constexpr WidgetConfig WidgetBool (const char * section, const char * name, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::Bool, 0, section, name, callback, hook); } -constexpr WidgetConfig WidgetInt (const char * section, const char * name, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::Int, 0, section, name, callback, hook); } -constexpr WidgetConfig WidgetFloat (const char * section, const char * name, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::Float, 0, section, name, callback, hook); } -constexpr WidgetConfig WidgetString (const char * section, const char * name, - void (* callback) () = nullptr, const char * hook = nullptr) - { return WidgetConfig (WidgetConfig::String, 0, section, name, callback, hook); } +constexpr WidgetConfig WidgetBool(bool & value, void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::Bool, (void *)&value, 0, 0, callback, + hook); +} +constexpr WidgetConfig WidgetInt(int & value, void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::Int, (void *)&value, 0, 0, callback, + hook); +} +constexpr WidgetConfig WidgetFloat(double & value, void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::Float, (void *)&value, 0, 0, callback, + hook); +} +constexpr WidgetConfig WidgetString(String & value, + void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::String, (void *)&value, 0, 0, callback, + hook); +} + +constexpr WidgetConfig WidgetBool(const char * section, const char * name, + void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::Bool, 0, section, name, callback, hook); +} +constexpr WidgetConfig WidgetInt(const char * section, const char * name, + void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::Int, 0, section, name, callback, hook); +} +constexpr WidgetConfig WidgetFloat(const char * section, const char * name, + void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::Float, 0, section, name, callback, hook); +} +constexpr WidgetConfig WidgetString(const char * section, const char * name, + void (*callback)() = nullptr, + const char * hook = nullptr) +{ + return WidgetConfig(WidgetConfig::String, 0, section, name, callback, hook); +} struct PreferencesWidget { - enum Type { + enum Type + { Label, Button, CheckButton, @@ -232,90 +276,134 @@ struct PreferencesWidget }; Type type; - const char * label; /* widget title (for SPIN_BTN it's text left to widget) */ + const char * + label; /* widget title (for SPIN_BTN it's text left to widget) */ bool child; WidgetConfig cfg; WidgetVariant data; }; -enum WidgetIsChild { +enum WidgetIsChild +{ WIDGET_NOT_CHILD, WIDGET_CHILD }; -constexpr PreferencesWidget WidgetLabel (const char * label, - WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::Label, label, (child == WIDGET_CHILD)}; } - -constexpr PreferencesWidget WidgetButton (const char * label, - WidgetVButton button, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::Button, label, (child == WIDGET_CHILD), {}, button}; } - -constexpr PreferencesWidget WidgetCheck (const char * label, - WidgetConfig cfg, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::CheckButton, label, - (child == WIDGET_CHILD), cfg}; } - -constexpr PreferencesWidget WidgetRadio (const char * label, - WidgetConfig cfg, WidgetVRadio radio, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::RadioButton, label, - (child == WIDGET_CHILD), cfg, radio}; } - -constexpr PreferencesWidget WidgetSpin (const char * label, - WidgetConfig cfg, WidgetVSpin spin, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::SpinButton, label, - (child == WIDGET_CHILD), cfg, spin}; } - -constexpr PreferencesWidget WidgetEntry (const char * label, - WidgetConfig cfg, WidgetVEntry entry = WidgetVEntry(), - WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::Entry, label, - (child == WIDGET_CHILD), cfg, entry}; } - -constexpr PreferencesWidget WidgetFileEntry (const char * label, - WidgetConfig cfg, WidgetVFileEntry file_entry = WidgetVFileEntry(), - WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::FileEntry, label, - (child == WIDGET_CHILD), cfg, file_entry}; } - -constexpr PreferencesWidget WidgetCombo (const char * label, - WidgetConfig cfg, WidgetVCombo combo, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::ComboBox, label, - (child == WIDGET_CHILD), cfg, combo}; } - -constexpr PreferencesWidget WidgetFonts (const char * label, - WidgetConfig cfg, WidgetVFonts fonts, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::FontButton, label, - (child == WIDGET_CHILD), cfg, fonts}; } - -constexpr PreferencesWidget WidgetBox (WidgetVBox box, WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::Box, 0, (child == WIDGET_CHILD), {}, box}; } - -constexpr PreferencesWidget WidgetTable (WidgetVTable table, - WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::Table, 0, (child == WIDGET_CHILD), {}, table}; } - -constexpr PreferencesWidget WidgetNotebook (WidgetVNotebook notebook) - { return {PreferencesWidget::Notebook, 0, 0, {}, notebook}; } - -constexpr PreferencesWidget WidgetSeparator (WidgetVSeparator separator = WidgetVSeparator ()) - { return {PreferencesWidget::Separator, 0, 0, {}, separator}; } - -constexpr PreferencesWidget WidgetCustomGTK (void * (* populate) (), - WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::CustomGTK, 0, (child == WIDGET_CHILD), {}, populate}; } - -constexpr PreferencesWidget WidgetCustomQt (void * (* populate) (), - WidgetIsChild child = WIDGET_NOT_CHILD) - { return {PreferencesWidget::CustomQt, 0, (child == WIDGET_CHILD), {}, populate}; } - -struct PluginPreferences { +constexpr PreferencesWidget WidgetLabel(const char * label, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::Label, label, (child == WIDGET_CHILD)}; +} + +constexpr PreferencesWidget WidgetButton(const char * label, + WidgetVButton button, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return { + PreferencesWidget::Button, label, (child == WIDGET_CHILD), {}, button}; +} + +constexpr PreferencesWidget WidgetCheck(const char * label, WidgetConfig cfg, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::CheckButton, label, (child == WIDGET_CHILD), + cfg}; +} + +constexpr PreferencesWidget WidgetRadio(const char * label, WidgetConfig cfg, + WidgetVRadio radio, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::RadioButton, label, (child == WIDGET_CHILD), cfg, + radio}; +} + +constexpr PreferencesWidget WidgetSpin(const char * label, WidgetConfig cfg, + WidgetVSpin spin, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::SpinButton, label, (child == WIDGET_CHILD), cfg, + spin}; +} + +constexpr PreferencesWidget WidgetEntry(const char * label, WidgetConfig cfg, + WidgetVEntry entry = WidgetVEntry(), + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::Entry, label, (child == WIDGET_CHILD), cfg, + entry}; +} + +constexpr PreferencesWidget +WidgetFileEntry(const char * label, WidgetConfig cfg, + WidgetVFileEntry file_entry = WidgetVFileEntry(), + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::FileEntry, label, (child == WIDGET_CHILD), cfg, + file_entry}; +} + +constexpr PreferencesWidget WidgetCombo(const char * label, WidgetConfig cfg, + WidgetVCombo combo, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::ComboBox, label, (child == WIDGET_CHILD), cfg, + combo}; +} + +constexpr PreferencesWidget WidgetFonts(const char * label, WidgetConfig cfg, + WidgetVFonts fonts, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::FontButton, label, (child == WIDGET_CHILD), cfg, + fonts}; +} + +constexpr PreferencesWidget WidgetBox(WidgetVBox box, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::Box, 0, (child == WIDGET_CHILD), {}, box}; +} + +constexpr PreferencesWidget WidgetTable(WidgetVTable table, + WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return {PreferencesWidget::Table, 0, (child == WIDGET_CHILD), {}, table}; +} + +constexpr PreferencesWidget WidgetNotebook(WidgetVNotebook notebook) +{ + return {PreferencesWidget::Notebook, 0, 0, {}, notebook}; +} + +constexpr PreferencesWidget +WidgetSeparator(WidgetVSeparator separator = WidgetVSeparator()) +{ + return {PreferencesWidget::Separator, 0, 0, {}, separator}; +} + +constexpr PreferencesWidget +WidgetCustomGTK(void * (*populate)(), WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return { + PreferencesWidget::CustomGTK, 0, (child == WIDGET_CHILD), {}, populate}; +} + +constexpr PreferencesWidget +WidgetCustomQt(void * (*populate)(), WidgetIsChild child = WIDGET_NOT_CHILD) +{ + return { + PreferencesWidget::CustomQt, 0, (child == WIDGET_CHILD), {}, populate}; +} + +struct PluginPreferences +{ ArrayRef widgets; - void (* init) (); - void (* apply) (); - void (* cleanup) (); + void (*init)(); + void (*apply)(); + void (*cleanup)(); }; #endif /* LIBAUDCORE_PREFERENCES_H */ diff --git a/src/libaudcore/probe-buffer.cc b/src/libaudcore/probe-buffer.cc index e23992c..f5ce248 100644 --- a/src/libaudcore/probe-buffer.cc +++ b/src/libaudcore/probe-buffer.cc @@ -24,41 +24,37 @@ static constexpr int MAXBUF = 256 * 1024; -ProbeBuffer::ProbeBuffer (const char * filename, VFSImpl * file) : - m_filename (filename), - m_file (file) +ProbeBuffer::ProbeBuffer(const char * filename, VFSImpl * file) + : m_filename(filename), m_file(file) { - AUDINFO ("<%p> buffering enabled for %s\n", this, (const char *) m_filename); + AUDINFO("<%p> buffering enabled for %s\n", this, (const char *)m_filename); } -ProbeBuffer::~ProbeBuffer () -{ - delete[] m_buffer; -} +ProbeBuffer::~ProbeBuffer() { delete[] m_buffer; } -void ProbeBuffer::increase_buffer (int64_t size) +void ProbeBuffer::increase_buffer(int64_t size) { - size = aud::min ((size + 0xFF) & ~0xFF, (int64_t) MAXBUF); + size = aud::min((size + 0xFF) & ~0xFF, (int64_t)MAXBUF); if (m_filled < size) { - if (! m_buffer) + if (!m_buffer) m_buffer = new char[MAXBUF]; - m_filled += m_file->fread (m_buffer + m_filled, 1, size - m_filled); + m_filled += m_file->fread(m_buffer + m_filled, 1, size - m_filled); } } -void ProbeBuffer::release_buffer () +void ProbeBuffer::release_buffer() { - AUDINFO ("<%p> buffering disabled for %s\n", this, (const char *) m_filename); + AUDINFO("<%p> buffering disabled for %s\n", this, (const char *)m_filename); delete[] m_buffer; m_buffer = nullptr; m_filled = 0; m_at = -1; } -int64_t ProbeBuffer::fread (void * buffer, int64_t size, int64_t count) +int64_t ProbeBuffer::fread(void * buffer, int64_t size, int64_t count) { int64_t total = 0; int64_t remain = size * count; @@ -66,37 +62,37 @@ int64_t ProbeBuffer::fread (void * buffer, int64_t size, int64_t count) /* read from buffer if possible */ if (remain && m_at >= 0 && m_at < MAXBUF) { - increase_buffer (m_at + remain); + increase_buffer(m_at + remain); - int copy = aud::min (remain, (int64_t) (m_filled - m_at)); - memcpy (buffer, m_buffer + m_at, copy); + int copy = aud::min(remain, (int64_t)(m_filled - m_at)); + memcpy(buffer, m_buffer + m_at, copy); m_at += copy; - buffer = (char *) buffer + copy; + buffer = (char *)buffer + copy; total += copy; remain -= copy; } /* then read from real file if allowed */ - if (remain && ! m_limited) + if (remain && !m_limited) { /* release buffer if leaving bufferable area */ if (m_at == MAXBUF) - release_buffer (); + release_buffer(); if (m_at < 0) - total += m_file->fread (buffer, 1, remain); + total += m_file->fread(buffer, 1, remain); } return (size > 0) ? total / size : 0; } -int64_t ProbeBuffer::fwrite (const void * data, int64_t size, int64_t count) +int64_t ProbeBuffer::fwrite(const void * data, int64_t size, int64_t count) { return 0; /* not allowed */ } -int ProbeBuffer::fseek (int64_t offset, VFSSeekType whence) +int ProbeBuffer::fseek(int64_t offset, VFSSeekType whence) { /* seek within the buffer if possible */ if (m_at >= 0 && whence != VFS_SEEK_END) @@ -113,7 +109,7 @@ int ProbeBuffer::fseek (int64_t offset, VFSSeekType whence) if (offset <= MAXBUF) { - increase_buffer (offset); + increase_buffer(offset); if (offset > m_filled) return -1; /* seek past end of file */ @@ -124,56 +120,48 @@ int ProbeBuffer::fseek (int64_t offset, VFSSeekType whence) } /* seek within real file if allowed */ - if (m_limited || m_file->fseek (offset, whence) < 0) + if (m_limited || m_file->fseek(offset, whence) < 0) return -1; /* release buffer only if real seek succeeded * (prevents change of file position if seek failed) */ if (m_at >= 0) - release_buffer (); + release_buffer(); /* activate buffering again when seeking to beginning of file */ if (whence == VFS_SEEK_SET && offset == 0) { - AUDINFO ("<%p> buffering enabled for %s\n", this, (const char *) m_filename); + AUDINFO("<%p> buffering enabled for %s\n", this, + (const char *)m_filename); m_at = 0; } return 0; } -int64_t ProbeBuffer::ftell () +int64_t ProbeBuffer::ftell() { if (m_at >= 0) return m_at; - return m_file->ftell (); + return m_file->ftell(); } -bool ProbeBuffer::feof () +bool ProbeBuffer::feof() { if (m_at >= 0 && m_at < m_filled) return false; - return m_file->feof (); + return m_file->feof(); } -int ProbeBuffer::ftruncate (int64_t size) -{ - return -1; /* not allowed */ -} +int ProbeBuffer::ftruncate(int64_t size) { return -1; /* not allowed */ } -int ProbeBuffer::fflush () -{ - return 0; /* no-op */ -} +int ProbeBuffer::fflush() { return 0; /* no-op */ } -int64_t ProbeBuffer::fsize () -{ - return m_file->fsize (); -} +int64_t ProbeBuffer::fsize() { return m_file->fsize(); } -String ProbeBuffer::get_metadata (const char * field) +String ProbeBuffer::get_metadata(const char * field) { - return m_file->get_metadata (field); + return m_file->get_metadata(field); } diff --git a/src/libaudcore/probe-buffer.h b/src/libaudcore/probe-buffer.h index 5cdfc29..1f85b69 100644 --- a/src/libaudcore/probe-buffer.h +++ b/src/libaudcore/probe-buffer.h @@ -39,28 +39,27 @@ class ProbeBuffer : public VFSImpl { public: - ProbeBuffer (const char * filename, VFSImpl * file); - ~ProbeBuffer (); + ProbeBuffer(const char * filename, VFSImpl * file); + ~ProbeBuffer(); - int64_t fread (void * ptr, int64_t size, int64_t nmemb); - int fseek (int64_t offset, VFSSeekType whence); + int64_t fread(void * ptr, int64_t size, int64_t nmemb); + int fseek(int64_t offset, VFSSeekType whence); - int64_t ftell (); - int64_t fsize (); - bool feof (); + int64_t ftell(); + int64_t fsize(); + bool feof(); - int64_t fwrite (const void * ptr, int64_t size, int64_t nmemb); - int ftruncate (int64_t length); - int fflush (); + int64_t fwrite(const void * ptr, int64_t size, int64_t nmemb); + int ftruncate(int64_t length); + int fflush(); - String get_metadata (const char * field); + String get_metadata(const char * field); - void set_limit_to_buffer (bool limit) - { m_limited = limit; } + void set_limit_to_buffer(bool limit) { m_limited = limit; } private: - void increase_buffer (int64_t size); - void release_buffer (); + void increase_buffer(int64_t size); + void release_buffer(); String m_filename; SmartPtr m_file; diff --git a/src/libaudcore/probe.cc b/src/libaudcore/probe.cc index 38cf73d..5868167 100644 --- a/src/libaudcore/probe.cc +++ b/src/libaudcore/probe.cc @@ -17,8 +17,8 @@ * the use of this software. */ -#include "internal.h" #include "probe.h" +#include "internal.h" #include @@ -29,52 +29,53 @@ #include "plugins-internal.h" #include "runtime.h" -bool open_input_file (const char * filename, const char * mode, - InputPlugin * ip, VFSFile & file, String * error) +bool open_input_file(const char * filename, const char * mode, InputPlugin * ip, + VFSFile & file, String * error) { /* no need to open a handle for custom URI schemes */ if (ip && ip->input_info.keys[InputKey::Scheme]) return true; /* already open? */ - if (file && file.fseek (0, VFS_SEEK_SET) == 0) + if (file && file.fseek(0, VFS_SEEK_SET) == 0) return true; - file = VFSFile (filename, mode); - if (! file && error) - * error = String (file.error ()); + file = VFSFile(filename, mode); + if (!file && error) + *error = String(file.error()); - return (bool) file; + return (bool)file; } -InputPlugin * load_input_plugin (PluginHandle * decoder, String * error) +InputPlugin * load_input_plugin(PluginHandle * decoder, String * error) { - auto ip = (InputPlugin *) aud_plugin_get_header (decoder); - if (! ip && error) - * error = String (_("Error loading plugin")); + auto ip = (InputPlugin *)aud_plugin_get_header(decoder); + if (!ip && error) + *error = String(_("Error loading plugin")); return ip; } /* figure out some basic info without opening the file */ -int probe_by_filename (const char * filename) +int probe_by_filename(const char * filename) { int flags = 0; - auto & list = aud_plugin_list (PluginType::Input); + auto & list = aud_plugin_list(PluginType::Input); - StringBuf scheme = uri_get_scheme (filename); - StringBuf ext = uri_get_extension (filename); + StringBuf scheme = uri_get_scheme(filename); + StringBuf ext = uri_get_extension(filename); for (PluginHandle * plugin : list) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - if ((scheme && input_plugin_has_key (plugin, InputKey::Scheme, scheme)) || - (ext && input_plugin_has_key (plugin, InputKey::Ext, ext))) + if ((scheme && + input_plugin_has_key(plugin, InputKey::Scheme, scheme)) || + (ext && input_plugin_has_key(plugin, InputKey::Ext, ext))) { flags |= PROBE_FLAG_HAS_DECODER; - if (input_plugin_has_subtunes (plugin)) + if (input_plugin_has_subtunes(plugin)) flags |= PROBE_FLAG_MIGHT_HAVE_SUBTUNES; } } @@ -82,164 +83,167 @@ int probe_by_filename (const char * filename) return flags; } -EXPORT PluginHandle * aud_file_find_decoder (const char * filename, bool fast, - VFSFile & file, String * error) +EXPORT PluginHandle * aud_file_find_decoder(const char * filename, bool fast, + VFSFile & file, String * error) { - AUDINFO ("%s %s.\n", fast ? "Fast-probing" : "Probing", filename); + AUDINFO("%s %s.\n", fast ? "Fast-probing" : "Probing", filename); - auto & list = aud_plugin_list (PluginType::Input); + auto & list = aud_plugin_list(PluginType::Input); - StringBuf scheme = uri_get_scheme (filename); - StringBuf ext = uri_get_extension (filename); + StringBuf scheme = uri_get_scheme(filename); + StringBuf ext = uri_get_extension(filename); Index ext_matches; for (PluginHandle * plugin : list) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - if (scheme && input_plugin_has_key (plugin, InputKey::Scheme, scheme)) + if (scheme && input_plugin_has_key(plugin, InputKey::Scheme, scheme)) { - AUDINFO ("Matched %s by URI scheme.\n", aud_plugin_get_name (plugin)); + AUDINFO("Matched %s by URI scheme.\n", aud_plugin_get_name(plugin)); return plugin; } - if (ext && input_plugin_has_key (plugin, InputKey::Ext, ext)) - ext_matches.append (plugin); + if (ext && input_plugin_has_key(plugin, InputKey::Ext, ext)) + ext_matches.append(plugin); } - if (ext_matches.len () == 1) + if (ext_matches.len() == 1) { - AUDINFO ("Matched %s by extension.\n", aud_plugin_get_name (ext_matches[0])); + AUDINFO("Matched %s by extension.\n", + aud_plugin_get_name(ext_matches[0])); return ext_matches[0]; } - AUDDBG ("Matched %d plugins by extension.\n", ext_matches.len ()); + AUDDBG("Matched %d plugins by extension.\n", ext_matches.len()); - if (fast && ! ext_matches.len ()) + if (fast && !ext_matches.len()) return nullptr; - AUDDBG ("Opening %s.\n", filename); + AUDDBG("Opening %s.\n", filename); - if (! open_input_file (filename, "r", nullptr, file, error)) + if (!open_input_file(filename, "r", nullptr, file, error)) { - AUDINFO ("Open failed.\n"); + AUDINFO("Open failed.\n"); return nullptr; } - String mime = file.get_metadata ("content-type"); + String mime = file.get_metadata("content-type"); if (mime) { - for (PluginHandle * plugin : (ext_matches.len () ? ext_matches : list)) + for (PluginHandle * plugin : (ext_matches.len() ? ext_matches : list)) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - if (input_plugin_has_key (plugin, InputKey::MIME, mime)) + if (input_plugin_has_key(plugin, InputKey::MIME, mime)) { - AUDINFO ("Matched %s by MIME type %s.\n", - aud_plugin_get_name (plugin), (const char *) mime); + AUDINFO("Matched %s by MIME type %s.\n", + aud_plugin_get_name(plugin), (const char *)mime); return plugin; } } } - file.set_limit_to_buffer (true); + file.set_limit_to_buffer(true); - for (PluginHandle * plugin : (ext_matches.len () ? ext_matches : list)) + for (PluginHandle * plugin : (ext_matches.len() ? ext_matches : list)) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - AUDINFO ("Trying %s.\n", aud_plugin_get_name (plugin)); + AUDINFO("Trying %s.\n", aud_plugin_get_name(plugin)); - auto ip = (InputPlugin *) aud_plugin_get_header (plugin); - if (! ip) + auto ip = (InputPlugin *)aud_plugin_get_header(plugin); + if (!ip) continue; - if (ip->is_our_file (filename, file)) + if (ip->is_our_file(filename, file)) { - AUDINFO ("Matched %s by content.\n", aud_plugin_get_name (plugin)); - file.set_limit_to_buffer (false); + AUDINFO("Matched %s by content.\n", aud_plugin_get_name(plugin)); + file.set_limit_to_buffer(false); return plugin; } - if (file.fseek (0, VFS_SEEK_SET) != 0) + if (file.fseek(0, VFS_SEEK_SET) != 0) { if (error) - * error = String (_("Seek error")); + *error = String(_("Seek error")); - AUDINFO ("Seek failed.\n"); + AUDINFO("Seek failed.\n"); return nullptr; } } if (error) - * error = String (_("File format not recognized")); + *error = String(_("File format not recognized")); - AUDINFO ("No plugins matched.\n"); + AUDINFO("No plugins matched.\n"); return nullptr; } -EXPORT bool aud_file_read_tag (const char * filename, PluginHandle * decoder, - VFSFile & file, Tuple & tuple, Index * image, String * error) +EXPORT bool aud_file_read_tag(const char * filename, PluginHandle * decoder, + VFSFile & file, Tuple & tuple, + Index * image, String * error) { - auto ip = load_input_plugin (decoder, error); - if (! ip) + auto ip = load_input_plugin(decoder, error); + if (!ip) return false; - if (! open_input_file (filename, "r", ip, file, error)) + if (!open_input_file(filename, "r", ip, file, error)) return false; Tuple new_tuple; - new_tuple.set_filename (filename); + new_tuple.set_filename(filename); - if (ip->read_tag (filename, file, new_tuple, image)) + if (ip->read_tag(filename, file, new_tuple, image)) { // cleanly replace existing tuple - new_tuple.set_state (Tuple::Valid); - tuple = std::move (new_tuple); + new_tuple.set_state(Tuple::Valid); + tuple = std::move(new_tuple); return true; } if (error) - * error = String (_("Error reading metadata")); + *error = String(_("Error reading metadata")); return false; } -EXPORT bool aud_file_can_write_tuple (const char * filename, PluginHandle * decoder) +EXPORT bool aud_file_can_write_tuple(const char * filename, + PluginHandle * decoder) { - return input_plugin_can_write_tuple (decoder); + return input_plugin_can_write_tuple(decoder); } -EXPORT bool aud_file_write_tuple (const char * filename, - PluginHandle * decoder, const Tuple & tuple) +EXPORT bool aud_file_write_tuple(const char * filename, PluginHandle * decoder, + const Tuple & tuple) { - auto ip = (InputPlugin *) aud_plugin_get_header (decoder); - if (! ip) + auto ip = (InputPlugin *)aud_plugin_get_header(decoder); + if (!ip) return false; VFSFile file; - if (! open_input_file (filename, "r+", ip, file)) + if (!open_input_file(filename, "r+", ip, file)) return false; - bool success = ip->write_tuple (filename, file, tuple); + bool success = ip->write_tuple(filename, file, tuple); - if (success && file && file.fflush () != 0) + if (success && file && file.fflush() != 0) success = false; if (success) - Playlist::rescan_file (filename); + Playlist::rescan_file(filename); return success; } -EXPORT bool aud_custom_infowin (const char * filename, PluginHandle * decoder) +EXPORT bool aud_custom_infowin(const char * filename, PluginHandle * decoder) { // blacklist stdin - if (! strncmp (filename, "stdin://", 8)) + if (!strncmp(filename, "stdin://", 8)) return false; // In hindsight, a flag should have been added indicating whether a @@ -247,17 +251,17 @@ EXPORT bool aud_custom_infowin (const char * filename, PluginHandle * decoder) // plugins do so. Since custom info windows are deprecated anyway, // check for those two plugins explicitly and in all other cases, // don't open the input file to prevent freezing the UI. - const char * base = aud_plugin_get_basename (decoder); - if (strcmp (base, "amidi-plug") && strcmp (base, "vtx")) + const char * base = aud_plugin_get_basename(decoder); + if (strcmp(base, "amidi-plug") && strcmp(base, "vtx")) return false; - auto ip = (InputPlugin *) aud_plugin_get_header (decoder); - if (! ip) + auto ip = (InputPlugin *)aud_plugin_get_header(decoder); + if (!ip) return false; VFSFile file; - if (! open_input_file (filename, "r", ip, file)) + if (!open_input_file(filename, "r", ip, file)) return false; - return ip->file_info_box (filename, file); + return ip->file_info_box(filename, file); } diff --git a/src/libaudcore/probe.h b/src/libaudcore/probe.h index c206f6c..c2be567 100644 --- a/src/libaudcore/probe.h +++ b/src/libaudcore/probe.h @@ -30,30 +30,32 @@ class VFSFile; /* ====== ALBUM ART API ====== */ /* request format */ -enum { - AUD_ART_DATA = (1 << 0), /* image data in memory */ - AUD_ART_FILE = (1 << 1) /* filename of image data on disk */ +enum +{ + AUD_ART_DATA = (1 << 0), /* image data in memory */ + AUD_ART_FILE = (1 << 1) /* filename of image data on disk */ }; /* opaque type storing art data */ struct AudArtItem; /* don't use these directly, use AudArtPtr */ -const Index * aud_art_data (const AudArtItem * item); -const char * aud_art_file (const AudArtItem * item); -void aud_art_unref (AudArtItem * item); +const Index * aud_art_data(const AudArtItem * item); +const char * aud_art_file(const AudArtItem * item); +void aud_art_unref(AudArtItem * item); /* handle for accessing/tracking album art data */ class AudArtPtr : public SmartPtr { public: - AudArtPtr () : SmartPtr () {} - explicit AudArtPtr (AudArtItem * ptr) : SmartPtr (ptr) {} + AudArtPtr() : SmartPtr() {} + explicit AudArtPtr(AudArtItem * ptr) : SmartPtr(ptr) {} - const Index * data () const - { return get () ? aud_art_data (get ()) : nullptr; } - const char * file () const - { return get () ? aud_art_file (get ()) : nullptr; } + const Index * data() const + { + return get() ? aud_art_data(get()) : nullptr; + } + const char * file() const { return get() ? aud_art_file(get()) : nullptr; } }; /* @@ -71,22 +73,25 @@ public: * * On error, a null pointer is returned and *queued is set to false. */ -AudArtPtr aud_art_request (const char * file, int format, bool * queued = nullptr); +AudArtPtr aud_art_request(const char * file, int format, + bool * queued = nullptr); /* ====== GENERAL PROBING API ====== */ /* The following two functions take an additional VFSFile parameter to allow * opening a file, probing for a decoder, and then reading the song metadata * without opening the file a second time. If you don't already have a file - * handle open, then just pass in a null VFSFile and it will be opened for you. */ -PluginHandle * aud_file_find_decoder (const char * filename, bool fast, - VFSFile & file, String * error = nullptr); -bool aud_file_read_tag (const char * filename, PluginHandle * decoder, - VFSFile & file, Tuple & tuple, Index * image = nullptr, - String * error = nullptr); + * handle open, then just pass in a null VFSFile and it will be opened for you. + */ +PluginHandle * aud_file_find_decoder(const char * filename, bool fast, + VFSFile & file, String * error = nullptr); +bool aud_file_read_tag(const char * filename, PluginHandle * decoder, + VFSFile & file, Tuple & tuple, + Index * image = nullptr, String * error = nullptr); -bool aud_file_can_write_tuple (const char * filename, PluginHandle * decoder); -bool aud_file_write_tuple (const char * filename, PluginHandle * decoder, const Tuple & tuple); -bool aud_custom_infowin (const char * filename, PluginHandle * decoder); +bool aud_file_can_write_tuple(const char * filename, PluginHandle * decoder); +bool aud_file_write_tuple(const char * filename, PluginHandle * decoder, + const Tuple & tuple); +bool aud_custom_infowin(const char * filename, PluginHandle * decoder); #endif diff --git a/src/libaudcore/ringbuf.cc b/src/libaudcore/ringbuf.cc index 07fbc59..0c5fef1 100644 --- a/src/libaudcore/ringbuf.cc +++ b/src/libaudcore/ringbuf.cc @@ -24,40 +24,40 @@ #include #include -void RingBufBase::get_areas (int pos, int len, Areas & areas) +void RingBufBase::get_areas(int pos, int len, Areas & areas) { - assert (pos >= 0 && len >= 0 && pos + len <= m_len); + assert(pos >= 0 && len >= 0 && pos + len <= m_len); int start = (m_offset + pos) % m_size; - int part = aud::min (len, m_size - start); + int part = aud::min(len, m_size - start); - areas.area1 = (char *) m_data + start; + areas.area1 = (char *)m_data + start; areas.area2 = m_data; areas.len1 = part; areas.len2 = len - part; } -void RingBufBase::do_realloc (int size) +void RingBufBase::do_realloc(int size) { - void * mem = realloc (m_data, size); - if (size && ! mem) - throw std::bad_alloc (); /* nothing changed yet */ + void * mem = realloc(m_data, size); + if (size && !mem) + throw std::bad_alloc(); /* nothing changed yet */ m_data = mem; } -EXPORT void RingBufBase::alloc (int size) +EXPORT void RingBufBase::alloc(int size) { - assert (size >= m_len); + assert(size >= m_len); if (size == m_size) return; /* reallocate first when growing */ if (size > m_size) - do_realloc (size); + do_realloc(size); - __sync_add_and_fetch (& misc_bytes_allocated, size - m_size); + __sync_add_and_fetch(&misc_bytes_allocated, size - m_size); int old_size = m_size; int to_end = m_size - m_offset; @@ -67,38 +67,38 @@ EXPORT void RingBufBase::alloc (int size) if (to_end < m_len) { int new_offset = size - to_end; - memmove ((char *) m_data + new_offset, (char *) m_data + m_offset, to_end); + memmove((char *)m_data + new_offset, (char *)m_data + m_offset, to_end); m_offset = new_offset; } /* reallocate last when shrinking */ if (size < old_size) - do_realloc (size); + do_realloc(size); } -EXPORT void RingBufBase::destroy (aud::EraseFunc erase_func) +EXPORT void RingBufBase::destroy(aud::EraseFunc erase_func) { - if (! m_data) + if (!m_data) return; - __sync_sub_and_fetch (& misc_bytes_allocated, m_size); + __sync_sub_and_fetch(&misc_bytes_allocated, m_size); - discard (-1, erase_func); + discard(-1, erase_func); - free (m_data); + free(m_data); m_data = nullptr; m_size = 0; } -EXPORT void RingBufBase::add (int len) +EXPORT void RingBufBase::add(int len) { - assert (len >= 0 && m_len + len <= m_size); + assert(len >= 0 && m_len + len <= m_size); m_len += len; } -EXPORT void RingBufBase::remove (int len) +EXPORT void RingBufBase::remove(int len) { - assert (len >= 0 && len <= m_len); + assert(len >= 0 && len <= m_len); if (len == m_len) m_offset = m_len = 0; @@ -109,54 +109,55 @@ EXPORT void RingBufBase::remove (int len) } } -EXPORT void RingBufBase::copy_in (const void * from, int len, aud::CopyFunc copy_func) +EXPORT void RingBufBase::copy_in(const void * from, int len, + aud::CopyFunc copy_func) { Areas areas; - add (len); - get_areas (m_len - len, len, areas); + add(len); + get_areas(m_len - len, len, areas); if (copy_func) { - copy_func (from, areas.area1, areas.len1); - copy_func ((const char *) from + areas.len1, areas.area2, areas.len2); + copy_func(from, areas.area1, areas.len1); + copy_func((const char *)from + areas.len1, areas.area2, areas.len2); } else { - memcpy (areas.area1, from, areas.len1); - memcpy (areas.area2, (const char *) from + areas.len1, areas.len2); + memcpy(areas.area1, from, areas.len1); + memcpy(areas.area2, (const char *)from + areas.len1, areas.len2); } } -EXPORT void RingBufBase::move_in (void * from, int len, aud::FillFunc fill_func) +EXPORT void RingBufBase::move_in(void * from, int len, aud::FillFunc fill_func) { Areas areas; - add (len); - get_areas (m_len - len, len, areas); + add(len); + get_areas(m_len - len, len, areas); - memcpy (areas.area1, from, areas.len1); - memcpy (areas.area2, (const char *) from + areas.len1, areas.len2); + memcpy(areas.area1, from, areas.len1); + memcpy(areas.area2, (const char *)from + areas.len1, areas.len2); if (fill_func) - fill_func (from, len); + fill_func(from, len); } -EXPORT void RingBufBase::move_out (void * to, int len, aud::EraseFunc erase_func) +EXPORT void RingBufBase::move_out(void * to, int len, aud::EraseFunc erase_func) { Areas areas; - get_areas (0, len, areas); + get_areas(0, len, areas); if (erase_func) - erase_func (to, len); + erase_func(to, len); - memcpy (to, areas.area1, areas.len1); - memcpy ((char *) to + areas.len1, areas.area2, areas.len2); + memcpy(to, areas.area1, areas.len1); + memcpy((char *)to + areas.len1, areas.area2, areas.len2); - remove (len); + remove(len); } -EXPORT void RingBufBase::discard (int len, aud::EraseFunc erase_func) +EXPORT void RingBufBase::discard(int len, aud::EraseFunc erase_func) { - if (! m_data) + if (!m_data) return; if (len < 0) @@ -165,33 +166,33 @@ EXPORT void RingBufBase::discard (int len, aud::EraseFunc erase_func) if (erase_func) { Areas areas; - get_areas (0, len, areas); - erase_func (areas.area1, areas.len1); - erase_func (areas.area2, areas.len2); + get_areas(0, len, areas); + erase_func(areas.area1, areas.len1); + erase_func(areas.area2, areas.len2); } - remove (len); + remove(len); } -EXPORT void RingBufBase::move_in (IndexBase & index, int from, int len) +EXPORT void RingBufBase::move_in(IndexBase & index, int from, int len) { - assert (from >= 0 && from <= index.len ()); - assert (len <= index.len () - from); + assert(from >= 0 && from <= index.len()); + assert(len <= index.len() - from); if (len < 0) - len = index.len () - from; + len = index.len() - from; - move_in ((char *) index.begin () + from, len, nullptr); - index.remove (from, len, nullptr); + move_in((char *)index.begin() + from, len, nullptr); + index.remove(from, len, nullptr); } -EXPORT void RingBufBase::move_out (IndexBase & index, int to, int len) +EXPORT void RingBufBase::move_out(IndexBase & index, int to, int len) { - assert (len <= m_len); + assert(len <= m_len); if (len < 0) len = m_len; - void * ptr = index.insert (to, len); - move_out (ptr, len, nullptr); + void * ptr = index.insert(to, len); + move_out(ptr, len, nullptr); } diff --git a/src/libaudcore/ringbuf.h b/src/libaudcore/ringbuf.h index 5206588..2dd72bd 100644 --- a/src/libaudcore/ringbuf.h +++ b/src/libaudcore/ringbuf.h @@ -38,17 +38,13 @@ class RingBufBase { public: - constexpr RingBufBase () : - m_data (nullptr), - m_size (0), - m_offset (0), - m_len (0) {} - - RingBufBase (RingBufBase && b) : - m_data (b.m_data), - m_size (b.m_size), - m_offset (b.m_offset), - m_len (b.m_len) + constexpr RingBufBase() : m_data(nullptr), m_size(0), m_offset(0), m_len(0) + { + } + + RingBufBase(RingBufBase && b) + : m_data(b.m_data), m_size(b.m_size), m_offset(b.m_offset), + m_len(b.m_len) { b.m_data = nullptr; b.m_size = 0; @@ -57,42 +53,42 @@ public: } // allocated size of the buffer - int size () const - { return m_size; } + int size() const { return m_size; } // number of bytes currently used - int len () const - { return m_len; } + int len() const { return m_len; } // number of bytes that can be read linearly - int linear () const - { return aud::min (m_len, m_size - m_offset); } + int linear() const { return aud::min(m_len, m_size - m_offset); } - void * at (int pos) const - { return (char *) m_data + (m_offset + pos) % m_size; } + void * at(int pos) const + { + return (char *)m_data + (m_offset + pos) % m_size; + } - void alloc (int size); - void destroy (aud::EraseFunc erase_func); + void alloc(int size); + void destroy(aud::EraseFunc erase_func); - void add (int len); // no fill - void remove (int len); // no erase + void add(int len); // no fill + void remove(int len); // no erase - void copy_in (const void * from, int len, aud::CopyFunc copy_func); - void move_in (void * from, int len, aud::FillFunc fill_func); - void move_out (void * to, int len, aud::EraseFunc erase_func); - void discard (int len, aud::EraseFunc erase_func); + void copy_in(const void * from, int len, aud::CopyFunc copy_func); + void move_in(void * from, int len, aud::FillFunc fill_func); + void move_out(void * to, int len, aud::EraseFunc erase_func); + void discard(int len, aud::EraseFunc erase_func); - void move_in (IndexBase & index, int from, int len); - void move_out (IndexBase & index, int to, int len); + void move_in(IndexBase & index, int from, int len); + void move_out(IndexBase & index, int to, int len); private: - struct Areas { - void * area1, * area2; + struct Areas + { + void *area1, *area2; int len1, len2; }; - void get_areas (int pos, int len, Areas & areas); - void do_realloc (int size); + void get_areas(int pos, int len, Areas & areas); + void do_realloc(int size); void * m_data; int m_size, m_offset, m_len; @@ -102,71 +98,75 @@ template class RingBuf : private RingBufBase { public: - constexpr RingBuf () : - RingBufBase () {} - - ~RingBuf () - { destroy (); } - - RingBuf (RingBuf && b) : - RingBufBase (std::move (b)) {} - RingBuf & operator= (RingBuf && b) - { return aud::move_assign (* this, std::move (b)); } - - int size () const - { return cooked (RingBufBase::size ()); } - int len () const - { return cooked (RingBufBase::len ()); } - int linear () const - { return cooked (RingBufBase::linear ()); } - int space () const - { return size () - len (); } - - T & operator[] (int i) - { return * (T *) RingBufBase::at (raw (i)); } - const T & operator[] (int i) const - { return * (const T *) RingBufBase::at (raw (i)); } - - void alloc (int size) - { RingBufBase::alloc (raw (size)); } - void destroy () - { RingBufBase::destroy (aud::erase_func ()); } - - void copy_in (const T * from, int len) - { RingBufBase::copy_in (from, raw (len), aud::copy_func ()); } - void move_in (T * from, int len) - { RingBufBase::move_in (from, raw (len), aud::fill_func ()); } - void move_out (T * to, int len) - { RingBufBase::move_out (to, raw (len), aud::erase_func ()); } - void discard (int len = -1) - { RingBufBase::discard (raw (len), aud::erase_func ()); } - - void move_in (Index & index, int from, int len) - { RingBufBase::move_in (index.base (), raw (from), raw (len)); } - void move_out (Index & index, int to, int len) - { RingBufBase::move_out (index.base (), raw (to), raw (len)); } - - template - T & push (Args && ... args) + constexpr RingBuf() : RingBufBase() {} + + ~RingBuf() { destroy(); } + + RingBuf(RingBuf && b) : RingBufBase(std::move(b)) {} + RingBuf & operator=(RingBuf && b) + { + return aud::move_assign(*this, std::move(b)); + } + + int size() const { return cooked(RingBufBase::size()); } + int len() const { return cooked(RingBufBase::len()); } + int linear() const { return cooked(RingBufBase::linear()); } + int space() const { return size() - len(); } + + T & operator[](int i) { return *(T *)RingBufBase::at(raw(i)); } + const T & operator[](int i) const + { + return *(const T *)RingBufBase::at(raw(i)); + } + + void alloc(int size) { RingBufBase::alloc(raw(size)); } + void destroy() { RingBufBase::destroy(aud::erase_func()); } + + void copy_in(const T * from, int len) + { + RingBufBase::copy_in(from, raw(len), aud::copy_func()); + } + void move_in(T * from, int len) + { + RingBufBase::move_in(from, raw(len), aud::fill_func()); + } + void move_out(T * to, int len) + { + RingBufBase::move_out(to, raw(len), aud::erase_func()); + } + void discard(int len = -1) + { + RingBufBase::discard(raw(len), aud::erase_func()); + } + + void move_in(Index & index, int from, int len) + { + RingBufBase::move_in(index.base(), raw(from), raw(len)); + } + void move_out(Index & index, int to, int len) + { + RingBufBase::move_out(index.base(), raw(to), raw(len)); + } + + template + T & push(Args &&... args) { - add (raw (1)); - return * aud::construct::make (at (raw (len () - 1)), std::forward (args) ...); + add(raw(1)); + return *aud::construct::make(at(raw(len() - 1)), + std::forward(args)...); } - T & head () - { return * (T *) at (raw (0)); } + T & head() { return *(T *)at(raw(0)); } - void pop () + void pop() { - head ().~T (); - remove (raw (1)); + head().~T(); + remove(raw(1)); } private: - static constexpr int raw (int len) - { return len * sizeof (T); } - static constexpr int cooked (int len) - { return len / sizeof (T); } + static constexpr int raw(int len) { return len * sizeof(T); } + static constexpr int cooked(int len) { return len / sizeof(T); } }; #endif // LIBAUDCORE_RINGBUF_H diff --git a/src/libaudcore/runtime.cc b/src/libaudcore/runtime.cc index 382e773..062cc59 100644 --- a/src/libaudcore/runtime.cc +++ b/src/libaudcore/runtime.cc @@ -67,301 +67,299 @@ size_t misc_bytes_allocated; static bool headless_mode; static int instance_number = 1; -#if defined(USE_QT) && ! defined(USE_GTK) -static MainloopType mainloop_type = MainloopType::Qt; -#else +#if defined(USE_GTK) && !defined(USE_QT) static MainloopType mainloop_type = MainloopType::GLib; +#else +static MainloopType mainloop_type = MainloopType::Qt; #endif static aud::array aud_paths; -EXPORT void aud_set_headless_mode (bool headless) - { headless_mode = headless; } -EXPORT bool aud_get_headless_mode () - { return headless_mode; } +EXPORT void aud_set_headless_mode(bool headless) { headless_mode = headless; } +EXPORT bool aud_get_headless_mode() { return headless_mode; } -EXPORT void aud_set_instance (int instance) - { instance_number = instance; } -EXPORT int aud_get_instance () - { return instance_number; } +EXPORT void aud_set_instance(int instance) { instance_number = instance; } +EXPORT int aud_get_instance() { return instance_number; } -EXPORT void aud_set_mainloop_type (MainloopType type) - { mainloop_type = type; } -EXPORT MainloopType aud_get_mainloop_type () - { return mainloop_type; } +EXPORT void aud_set_mainloop_type(MainloopType type) { mainloop_type = type; } +EXPORT MainloopType aud_get_mainloop_type() { return mainloop_type; } -static StringBuf get_path_to_self () +static StringBuf get_path_to_self() { #ifdef __linux__ - StringBuf buf (-1); - int len = readlink ("/proc/self/exe", buf, buf.len ()); + StringBuf buf(-1); + int len = readlink("/proc/self/exe", buf, buf.len()); if (len < 0) { - AUDERR ("Failed to read /proc/self/exe: %s\n", strerror (errno)); - return StringBuf (); + AUDERR("Failed to read /proc/self/exe: %s\n", strerror(errno)); + return StringBuf(); } - if (len == buf.len ()) - throw std::bad_alloc (); + if (len == buf.len()) + throw std::bad_alloc(); - buf.resize (len); + buf.resize(len); return buf; #elif defined _WIN32 - StringBuf buf (-1); - wchar_t * bufw = (wchar_t *) (char *) buf; - int sizew = buf.len () / sizeof (wchar_t); - int lenw = GetModuleFileNameW (nullptr, bufw, sizew); + StringBuf buf(-1); + wchar_t * bufw = (wchar_t *)(char *)buf; + int sizew = buf.len() / sizeof(wchar_t); + int lenw = GetModuleFileNameW(nullptr, bufw, sizew); - if (! lenw) + if (!lenw) { - AUDERR ("GetModuleFileName failed.\n"); - return StringBuf (); + AUDERR("GetModuleFileName failed.\n"); + return StringBuf(); } if (lenw == sizew) - throw std::bad_alloc (); + throw std::bad_alloc(); - buf.resize (lenw * sizeof (wchar_t)); - buf = str_convert (buf, buf.len (), UTF16_NATIVE, "UTF-8"); - return buf.settle (); + buf.resize(lenw * sizeof(wchar_t)); + buf = str_convert(buf, buf.len(), UTF16_NATIVE, "UTF-8"); + return buf.settle(); #elif defined __APPLE__ - StringBuf buf (-1); - uint32_t size = buf.len (); + StringBuf buf(-1); + uint32_t size = buf.len(); - if (_NSGetExecutablePath (buf, & size) < 0) - throw std::bad_alloc (); + if (_NSGetExecutablePath(buf, &size) < 0) + throw std::bad_alloc(); - buf.resize (strlen (buf)); + buf.resize(strlen(buf)); return buf; #else - return StringBuf (); + return StringBuf(); #endif } -static String relocate_path (const char * path, const char * from, const char * to) +static String relocate_path(const char * path, const char * from, + const char * to) { - int oldlen = strlen (from); - int newlen = strlen (to); + int oldlen = strlen(from); + int newlen = strlen(to); if (oldlen && from[oldlen - 1] == G_DIR_SEPARATOR) - oldlen --; + oldlen--; if (newlen && to[newlen - 1] == G_DIR_SEPARATOR) - newlen --; + newlen--; #ifdef _WIN32 - if (strcmp_nocase (path, from, oldlen) || (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR)) + if (strcmp_nocase(path, from, oldlen) || + (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR)) #else - if (strncmp (path, from, oldlen) || (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR)) + if (strncmp(path, from, oldlen) || + (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR)) #endif - return String (path); + return String(path); - return String (str_printf ("%.*s%s", newlen, to, path + oldlen)); + return String(str_printf("%.*s%s", newlen, to, path + oldlen)); } -static void set_default_paths () +static void set_default_paths() { - aud_paths[AudPath::BinDir] = String (INSTALL_BINDIR); - aud_paths[AudPath::DataDir] = String (INSTALL_DATADIR); - aud_paths[AudPath::PluginDir] = String (INSTALL_PLUGINDIR); - aud_paths[AudPath::LocaleDir] = String (INSTALL_LOCALEDIR); - aud_paths[AudPath::DesktopFile] = String (INSTALL_DESKTOPFILE); - aud_paths[AudPath::IconFile] = String (INSTALL_ICONFILE); + aud_paths[AudPath::BinDir] = String(INSTALL_BINDIR); + aud_paths[AudPath::DataDir] = String(INSTALL_DATADIR); + aud_paths[AudPath::PluginDir] = String(INSTALL_PLUGINDIR); + aud_paths[AudPath::LocaleDir] = String(INSTALL_LOCALEDIR); + aud_paths[AudPath::DesktopFile] = String(INSTALL_DESKTOPFILE); + aud_paths[AudPath::IconFile] = String(INSTALL_ICONFILE); } -static void set_install_paths () +static void set_install_paths() { - StringBuf bindir = filename_normalize (str_copy (INSTALL_BINDIR)); - StringBuf datadir = filename_normalize (str_copy (INSTALL_DATADIR)); - StringBuf plugindir = filename_normalize (str_copy (INSTALL_PLUGINDIR)); - StringBuf localedir = filename_normalize (str_copy (INSTALL_LOCALEDIR)); - StringBuf desktopfile = filename_normalize (str_copy (INSTALL_DESKTOPFILE)); - StringBuf iconfile = filename_normalize (str_copy (INSTALL_ICONFILE)); + StringBuf bindir = filename_normalize(str_copy(INSTALL_BINDIR)); + StringBuf datadir = filename_normalize(str_copy(INSTALL_DATADIR)); + StringBuf plugindir = filename_normalize(str_copy(INSTALL_PLUGINDIR)); + StringBuf localedir = filename_normalize(str_copy(INSTALL_LOCALEDIR)); + StringBuf desktopfile = filename_normalize(str_copy(INSTALL_DESKTOPFILE)); + StringBuf iconfile = filename_normalize(str_copy(INSTALL_ICONFILE)); - StringBuf from = str_copy (bindir); + StringBuf from = str_copy(bindir); /* get path to current executable */ - StringBuf to = get_path_to_self (); + StringBuf to = get_path_to_self(); - if (! to) + if (!to) { - set_default_paths (); + set_default_paths(); return; } - to = filename_normalize (std::move (to)); + to = filename_normalize(std::move(to)); - const char * base = last_path_element (to); + const char * base = last_path_element(to); - if (! base) + if (!base) { - set_default_paths (); + set_default_paths(); return; } - cut_path_element (to, base - to); + cut_path_element(to, base - to); /* trim trailing path elements common to old and new paths */ /* at the end, the old and new installation prefixes are left */ - const char * a, * b; - while ((a = last_path_element (from)) && - (b = last_path_element (to)) && + const char *a, *b; + while ((a = last_path_element(from)) && (b = last_path_element(to)) && #ifdef _WIN32 - ! strcmp_nocase (a, b)) + !strcmp_nocase(a, b)) #else - ! strcmp (a, b)) + !strcmp(a, b)) #endif { - cut_path_element (from, a - from); - cut_path_element (to, b - to); + cut_path_element(from, a - from); + cut_path_element(to, b - to); } /* replace old prefix with new one in each path */ - aud_paths[AudPath::BinDir] = relocate_path (bindir, from, to); - aud_paths[AudPath::DataDir] = relocate_path (datadir, from, to); - aud_paths[AudPath::PluginDir] = relocate_path (plugindir, from, to); - aud_paths[AudPath::LocaleDir] = relocate_path (localedir, from, to); - aud_paths[AudPath::DesktopFile] = relocate_path (desktopfile, from, to); - aud_paths[AudPath::IconFile] = relocate_path (iconfile, from, to); + aud_paths[AudPath::BinDir] = relocate_path(bindir, from, to); + aud_paths[AudPath::DataDir] = relocate_path(datadir, from, to); + aud_paths[AudPath::PluginDir] = relocate_path(plugindir, from, to); + aud_paths[AudPath::LocaleDir] = relocate_path(localedir, from, to); + aud_paths[AudPath::DesktopFile] = relocate_path(desktopfile, from, to); + aud_paths[AudPath::IconFile] = relocate_path(iconfile, from, to); } -static void set_config_paths () +static void set_config_paths() { - const char * xdg_config_home = g_get_user_config_dir (); - StringBuf name = (instance_number == 1) ? str_copy ("audacious") : - str_printf ("audacious-%d", instance_number); + const char * xdg_config_home = g_get_user_config_dir(); + StringBuf name = (instance_number == 1) + ? str_copy("audacious") + : str_printf("audacious-%d", instance_number); - aud_paths[AudPath::UserDir] = String (filename_build ({xdg_config_home, name})); - aud_paths[AudPath::PlaylistDir] = String (filename_build - ({aud_paths[AudPath::UserDir], "playlists"})); + aud_paths[AudPath::UserDir] = + String(filename_build({xdg_config_home, name})); + aud_paths[AudPath::PlaylistDir] = + String(filename_build({aud_paths[AudPath::UserDir], "playlists"})); - if (g_mkdir_with_parents (aud_paths[AudPath::PlaylistDir], DIRMODE) < 0) - AUDERR ("Failed to create %s: %s\n", - (const char *) aud_paths[AudPath::PlaylistDir], strerror (errno)); + if (g_mkdir_with_parents(aud_paths[AudPath::PlaylistDir], DIRMODE) < 0) + AUDERR("Failed to create %s: %s\n", + (const char *)aud_paths[AudPath::PlaylistDir], strerror(errno)); #ifdef _WIN32 /* set some UNIX-style environment variables */ - g_setenv ("HOME", g_get_home_dir (), true); - g_setenv ("XDG_CONFIG_HOME", xdg_config_home, true); - g_setenv ("XDG_DATA_HOME", g_get_user_data_dir (), true); - g_setenv ("XDG_CACHE_HOME", g_get_user_cache_dir (), true); + g_setenv("HOME", g_get_home_dir(), true); + g_setenv("XDG_CONFIG_HOME", xdg_config_home, true); + g_setenv("XDG_DATA_HOME", g_get_user_data_dir(), true); + g_setenv("XDG_CACHE_HOME", g_get_user_cache_dir(), true); #endif } -EXPORT const char * aud_get_path (AudPath id) +EXPORT const char * aud_get_path(AudPath id) { - if (! aud_paths[id]) + if (!aud_paths[id]) { if (id <= AudPath::IconFile) - set_install_paths (); + set_install_paths(); else - set_config_paths (); + set_config_paths(); } return aud_paths[id]; } -EXPORT void aud_init_i18n () +EXPORT void aud_init_i18n() { - const char * localedir = aud_get_path (AudPath::LocaleDir); - - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, localedir); - bind_textdomain_codeset (PACKAGE, "UTF-8"); - bindtextdomain (PACKAGE "-plugins", localedir); - bind_textdomain_codeset (PACKAGE "-plugins", "UTF-8"); - textdomain (PACKAGE); + const char * localedir = aud_get_path(AudPath::LocaleDir); + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, localedir); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + bindtextdomain(PACKAGE "-plugins", localedir); + bind_textdomain_codeset(PACKAGE "-plugins", "UTF-8"); + textdomain(PACKAGE); } -EXPORT void aud_init () +EXPORT void aud_init() { - g_thread_pool_set_max_idle_time (100); + g_thread_pool_set_max_idle_time(100); - config_load (); + config_load(); - chardet_init (); - eq_init (); - output_init (); - playlist_init (); + chardet_init(); + eq_init(); + output_init(); + playlist_init(); - start_plugins_one (); + start_plugins_one(); - record_init (); - scanner_init (); - load_playlists (); + record_init(); + scanner_init(); + load_playlists(); } -static void do_autosave (void *) +static void do_autosave(void *) { - hook_call ("config save", nullptr); - save_playlists (false); - plugin_registry_save (); - config_save (); + hook_call("config save", nullptr); + save_playlists(false); + plugin_registry_save(); + config_save(); } -EXPORT void aud_run () +EXPORT void aud_run() { /* playlist_enable_scan() should be after aud_resume(); the intent is to * avoid scanning until the currently playing entry is known, at which time * it can be scanned more efficiently (album art read in the same pass). */ - playlist_enable_scan (true); - playlist_clear_updates (); - start_plugins_two (); + playlist_enable_scan(true); + playlist_clear_updates(); + start_plugins_two(); static QueuedFunc autosave; - autosave.start (AUTOSAVE_INTERVAL, do_autosave, nullptr); + autosave.start(AUTOSAVE_INTERVAL, do_autosave, nullptr); /* calls "config save" before returning */ - interface_run (); + interface_run(); - autosave.stop (); + autosave.stop(); - stop_plugins_two (); - playlist_enable_scan (false); + stop_plugins_two(); + playlist_enable_scan(false); } -EXPORT void aud_cleanup () +EXPORT void aud_cleanup() { - save_playlists (true); + save_playlists(true); - aud_drct_stop (); - playback_stop (true); + aud_drct_stop(); + playback_stop(true); - adder_cleanup (); - scanner_cleanup (); - record_cleanup (); + adder_cleanup(); + scanner_cleanup(); + record_cleanup(); - stop_plugins_one (); + stop_plugins_one(); - art_cleanup (); - chardet_cleanup (); - eq_cleanup (); - output_cleanup (); - playlist_end (); + art_cleanup(); + chardet_cleanup(); + eq_cleanup(); + output_cleanup(); + playlist_end(); - event_queue_cancel_all (); - hook_cleanup (); - timer_cleanup (); + event_queue_cancel_all(); + hook_cleanup(); + timer_cleanup(); - config_save (); - config_cleanup (); + config_save(); + config_cleanup(); } -EXPORT void aud_leak_check () +EXPORT void aud_leak_check() { for (String & path : aud_paths) - path = String (); + path = String(); - string_leak_check (); + string_leak_check(); if (misc_bytes_allocated) - AUDWARN ("Bytes allocated at exit: %ld\n", (long) misc_bytes_allocated); + AUDWARN("Bytes allocated at exit: %ld\n", (long)misc_bytes_allocated); } diff --git a/src/libaudcore/runtime.h b/src/libaudcore/runtime.h index 1a1a352..244eacd 100644 --- a/src/libaudcore/runtime.h +++ b/src/libaudcore/runtime.h @@ -22,7 +22,8 @@ #include -enum class AudPath { +enum class AudPath +{ BinDir, DataDir, PluginDir, @@ -34,25 +35,29 @@ enum class AudPath { count }; -enum class MainloopType { +enum class MainloopType +{ GLib, Qt }; -enum class OutputReset { +enum class OutputReset +{ EffectsOnly, ReopenStream, ResetPlugin }; -enum class OutputStream { +enum class OutputStream +{ AsDecoded, AfterReplayGain, AfterEffects, AfterEqualizer }; -enum class ReplayGainMode { +enum class ReplayGainMode +{ Track, Album, Automatic @@ -60,76 +65,138 @@ enum class ReplayGainMode { namespace audlog { - enum Level { - Debug, - Info, - Warning, - Error - }; +enum Level +{ + Debug, + Info, + Warning, + Error +}; - typedef void (* Handler) (Level level, const char * file, int line, - const char * func, const char * message); +typedef void (*Handler)(Level level, const char * file, int line, + const char * func, const char * message); - void set_stderr_level (Level level); - void subscribe (Handler handler, Level level); - void unsubscribe (Handler handler); +void set_stderr_level(Level level); +void subscribe(Handler handler, Level level); +void unsubscribe(Handler handler); #ifdef _WIN32 - void log (Level level, const char * file, int line, const char * func, - const char * format, ...) __attribute__ ((__format__ (gnu_printf, 5, 6))); +void log(Level level, const char * file, int line, const char * func, + const char * format, ...) + __attribute__((__format__(gnu_printf, 5, 6))); #else - void log (Level level, const char * file, int line, const char * func, - const char * format, ...) __attribute__ ((__format__ (__printf__, 5, 6))); +void log(Level level, const char * file, int line, const char * func, + const char * format, ...) + __attribute__((__format__(__printf__, 5, 6))); #endif - const char * get_level_name (Level level); -} - -#define AUDERR(...) do { audlog::log (audlog::Error, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); } while (0) -#define AUDWARN(...) do { audlog::log (audlog::Warning, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); } while (0) -#define AUDINFO(...) do { audlog::log (audlog::Info, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); } while (0) -#define AUDDBG(...) do { audlog::log (audlog::Debug, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); } while (0) - -const char * aud_get_path (AudPath id); - -void aud_set_headless_mode (bool headless); -bool aud_get_headless_mode (); +const char * get_level_name(Level level); +} // namespace audlog + +#define AUDERR(...) \ + do \ + { \ + audlog::log(audlog::Error, __FILE__, __LINE__, __FUNCTION__, \ + __VA_ARGS__); \ + } while (0) +#define AUDWARN(...) \ + do \ + { \ + audlog::log(audlog::Warning, __FILE__, __LINE__, __FUNCTION__, \ + __VA_ARGS__); \ + } while (0) +#define AUDINFO(...) \ + do \ + { \ + audlog::log(audlog::Info, __FILE__, __LINE__, __FUNCTION__, \ + __VA_ARGS__); \ + } while (0) +#define AUDDBG(...) \ + do \ + { \ + audlog::log(audlog::Debug, __FILE__, __LINE__, __FUNCTION__, \ + __VA_ARGS__); \ + } while (0) + +const char * aud_get_path(AudPath id); + +void aud_set_headless_mode(bool headless); +bool aud_get_headless_mode(); // Note that the UserDir and PlaylistDir paths vary depending on the instance // number. Therefore, calling aud_set_instance() after these paths have been // referenced, or after aud_init(), is an error. -void aud_set_instance (int instance); -int aud_get_instance (); +void aud_set_instance(int instance); +int aud_get_instance(); + +void aud_set_mainloop_type(MainloopType type); +MainloopType aud_get_mainloop_type(); -void aud_set_mainloop_type (MainloopType type); -MainloopType aud_get_mainloop_type (); +void aud_init_i18n(); -void aud_init_i18n (); +void aud_config_set_defaults(const char * section, + const char * const * entries); -void aud_config_set_defaults (const char * section, const char * const * entries); +void aud_set_str(const char * section, const char * name, const char * value); +String aud_get_str(const char * section, const char * name); +void aud_set_bool(const char * section, const char * name, bool value); +bool aud_get_bool(const char * section, const char * name); +void aud_toggle_bool(const char * section, const char * name); +void aud_set_int(const char * section, const char * name, int value); +int aud_get_int(const char * section, const char * name); +void aud_set_double(const char * section, const char * name, double value); +double aud_get_double(const char * section, const char * name); -void aud_set_str (const char * section, const char * name, const char * value); -String aud_get_str (const char * section, const char * name); -void aud_set_bool (const char * section, const char * name, bool value); -bool aud_get_bool (const char * section, const char * name); -void aud_toggle_bool (const char * section, const char * name); -void aud_set_int (const char * section, const char * name, int value); -int aud_get_int (const char * section, const char * name); -void aud_set_double (const char * section, const char * name, double value); -double aud_get_double (const char * section, const char * name); +/* overloads for main ("audacious") config section */ +static inline void aud_set_str(const char * name, const char * value) +{ + aud_set_str(nullptr, name, value); +} +static inline String aud_get_str(const char * name) +{ + return aud_get_str(nullptr, name); +} +static inline void aud_set_bool(const char * name, bool value) +{ + aud_set_bool(nullptr, name, value); +} +static inline bool aud_get_bool(const char * name) +{ + return aud_get_bool(nullptr, name); +} +static inline void aud_toggle_bool(const char * name) +{ + aud_toggle_bool(nullptr, name); +} +static inline void aud_set_int(const char * name, int value) +{ + aud_set_int(nullptr, name, value); +} +static inline int aud_get_int(const char * name) +{ + return aud_get_int(nullptr, name); +} +static inline void aud_set_double(const char * name, double value) +{ + aud_set_double(nullptr, name, value); +} +static inline double aud_get_double(const char * name) +{ + return aud_get_double(nullptr, name); +} -void aud_init (); -void aud_resume (); -void aud_run (); -void aud_quit (); -void aud_cleanup (); +void aud_init(); +void aud_resume(); +void aud_run(); +void aud_quit(); +void aud_cleanup(); -void aud_leak_check (); +void aud_leak_check(); -String aud_history_get (int entry); -void aud_history_add (const char * path); -void aud_history_clear (); +String aud_history_get(int entry); +void aud_history_add(const char * path); +void aud_history_clear(); -void aud_output_reset (OutputReset type); +void aud_output_reset(OutputReset type); #endif diff --git a/src/libaudcore/scanner.cc b/src/libaudcore/scanner.cc index 75cb04a..2ad2ebc 100644 --- a/src/libaudcore/scanner.cc +++ b/src/libaudcore/scanner.cc @@ -19,7 +19,7 @@ #include "scanner.h" -#include /* for GThreadPool */ +#include /* for GThreadPool */ #include "audstrings.h" #include "cue-cache.h" @@ -32,99 +32,97 @@ static GThreadPool * pool; -ScanRequest::ScanRequest (const String & filename, int flags, Callback callback, - PluginHandle * decoder, Tuple && tuple) : - filename (filename), - flags (flags), - callback (callback), - decoder (decoder), - tuple (std::move (tuple)), - ip (nullptr) +ScanRequest::ScanRequest(const String & filename, int flags, Callback callback, + PluginHandle * decoder, Tuple && tuple) + : filename(filename), flags(flags), callback(callback), decoder(decoder), + tuple(std::move(tuple)), ip(nullptr) { /* If this is a cuesheet entry (and it has not already been loaded), capture * a reference to the cache immediately. During a playlist scan, requests * have overlapping lifecycles--each new ScanRequest is created by the * callback of the previous request--so the cached cuesheet persists as long * as consecutive playlist entries reference it. */ - if (! this->tuple.valid () && is_cuesheet_entry (filename)) - cue_cache.capture (new CueCacheRef (strip_subtune (filename))); + if (!this->tuple.valid() && is_cuesheet_entry(filename)) + cue_cache.capture(new CueCacheRef(strip_subtune(filename))); } -void ScanRequest::read_cuesheet_entry () +void ScanRequest::read_cuesheet_entry() { - for (auto & item : cue_cache->load ()) + for (auto & item : cue_cache->load()) { if (item.filename == filename) { decoder = item.decoder; - tuple = item.tuple.ref (); + tuple = item.tuple.ref(); break; } } } -void ScanRequest::run () +void ScanRequest::run() { /* load cuesheet entry (possibly cached) */ if (cue_cache) - read_cuesheet_entry (); + read_cuesheet_entry(); /* for a cuesheet entry, determine the source filename */ - String audio_file = tuple.get_str (Tuple::AudioFile); - if (! audio_file) + String audio_file = tuple.get_str(Tuple::AudioFile); + if (!audio_file) audio_file = filename; - bool need_tuple = (flags & SCAN_TUPLE) && ! tuple.valid (); + bool need_tuple = (flags & SCAN_TUPLE) && !tuple.valid(); bool need_image = (flags & SCAN_IMAGE); - if (! decoder) - decoder = aud_file_find_decoder (audio_file, false, file, & error); - if (! decoder) + if (!decoder) + decoder = aud_file_find_decoder(audio_file, false, file, &error); + if (!decoder) goto err; if (need_tuple || need_image) { - if (! (ip = load_input_plugin (decoder, & error))) + if (!(ip = load_input_plugin(decoder, &error))) goto err; - Index * pimage = need_image ? & image_data : nullptr; - if (! aud_file_read_tag (audio_file, decoder, file, tuple, pimage, & error)) + Tuple dummy_tuple; + /* don't overwrite tuple if already valid (e.g. from a cuesheet) */ + Tuple & rtuple = need_tuple ? tuple : dummy_tuple; + Index * pimage = need_image ? &image_data : nullptr; + if (!aud_file_read_tag(audio_file, decoder, file, rtuple, pimage, + &error)) goto err; - if ((flags & SCAN_IMAGE) && ! image_data.len ()) - image_file = art_search (audio_file); + if (need_image && !image_data.len()) + image_file = art_search(audio_file); } /* rewind/reopen the input file */ if ((flags & SCAN_FILE)) - open_input_file (audio_file, "r", ip, file, & error); + open_input_file(audio_file, "r", ip, file, &error); else { err: /* close file if not needed or if an error occurred */ - file = VFSFile (); + file = VFSFile(); } - callback (this); + callback(this); } -static void scan_worker (void * data, void *) +static void scan_worker(void * data, void *) { - ((ScanRequest *) data)->run (); - delete (ScanRequest *) data; + ((ScanRequest *)data)->run(); + delete (ScanRequest *)data; } -void scanner_init () +void scanner_init() { - pool = g_thread_pool_new (scan_worker, nullptr, SCAN_THREADS, false, nullptr); + pool = + g_thread_pool_new(scan_worker, nullptr, SCAN_THREADS, false, nullptr); } -void scanner_request (ScanRequest * request) +void scanner_request(ScanRequest * request) { - g_thread_pool_push (pool, request, nullptr); + g_thread_pool_push(pool, request, nullptr); } -void scanner_cleanup () -{ - g_thread_pool_free (pool, false, true); -} +void scanner_cleanup() { g_thread_pool_free(pool, false, true); } diff --git a/src/libaudcore/scanner.h b/src/libaudcore/scanner.h index 667afb3..0b6ad30 100644 --- a/src/libaudcore/scanner.h +++ b/src/libaudcore/scanner.h @@ -31,13 +31,13 @@ class PluginHandle; #define SCAN_TUPLE (1 << 0) #define SCAN_IMAGE (1 << 1) -#define SCAN_FILE (1 << 2) +#define SCAN_FILE (1 << 2) #define SCAN_THREADS 2 struct ScanRequest { - typedef void (* Callback) (ScanRequest * request); + typedef void (*Callback)(ScanRequest * request); const String filename; const int flags; @@ -53,19 +53,19 @@ struct ScanRequest String image_file; String error; - ScanRequest (const String & filename, int flags, Callback callback, - PluginHandle * decoder = nullptr, Tuple && tuple = Tuple ()); + ScanRequest(const String & filename, int flags, Callback callback, + PluginHandle * decoder = nullptr, Tuple && tuple = Tuple()); - void run (); + void run(); private: SmartPtr cue_cache; - void read_cuesheet_entry (); + void read_cuesheet_entry(); }; -void scanner_init (); -void scanner_request (ScanRequest * request); -void scanner_cleanup (); +void scanner_init(); +void scanner_request(ScanRequest * request); +void scanner_cleanup(); #endif diff --git a/src/libaudcore/stringbuf.cc b/src/libaudcore/stringbuf.cc index dd923ca..0b50ea2 100644 --- a/src/libaudcore/stringbuf.cc +++ b/src/libaudcore/stringbuf.cc @@ -18,13 +18,14 @@ */ #include -#include #include +#include #include #include #include "objects.h" +#include "threads.h" #ifdef _WIN32 #include @@ -37,109 +38,114 @@ struct StringHeader { - StringHeader * next, * prev; + StringHeader *next, *prev; int len; }; struct StringStack { - static constexpr int Size = 1048576; // 1 MB + static constexpr int Size = 1048576; // 1 MB StringHeader * top; char buf[Size - sizeof top]; }; -static constexpr intptr_t align (intptr_t ptr, intptr_t size) +static constexpr intptr_t align(intptr_t ptr, intptr_t size) { return (ptr + (size - 1)) / size * size; } -static StringHeader * align_after (StringStack * stack, StringHeader * prev_header) +static StringHeader * align_after(StringStack * stack, + StringHeader * prev_header) { char * base; if (prev_header) - base = (char *) prev_header + sizeof (StringHeader) + prev_header->len + 1; + base = + (char *)prev_header + sizeof(StringHeader) + prev_header->len + 1; else base = stack->buf; - return (StringHeader *) align ((intptr_t) base, alignof (StringHeader)); + return (StringHeader *)align((intptr_t)base, alignof(StringHeader)); } static pthread_key_t key; -static pthread_once_t once = PTHREAD_ONCE_INIT; +static std::once_flag once; #ifdef _WIN32 static HANDLE mapping; #endif -static void free_stack (void * stack) +static void free_stack(void * stack) { if (stack) #ifdef _WIN32 - UnmapViewOfFile (stack); + UnmapViewOfFile(stack); #else - munmap (stack, sizeof (StringStack)); + munmap(stack, sizeof(StringStack)); #endif } -static void make_key () +static void make_key() { - pthread_key_create (& key, free_stack); + pthread_key_create(&key, free_stack); #ifdef _WIN32 - mapping = CreateFileMappingW (INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, - 0, sizeof (StringStack), nullptr); + mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, + 0, sizeof(StringStack), nullptr); - if (! mapping) - throw std::bad_alloc (); + if (!mapping) + throw std::bad_alloc(); #endif } -static StringStack * get_stack () +static StringStack * get_stack() { - pthread_once (& once, make_key); + std::call_once(once, make_key); - StringStack * stack = (StringStack *) pthread_getspecific (key); + StringStack * stack = (StringStack *)pthread_getspecific(key); - if (! stack) + if (!stack) { #ifdef _WIN32 - stack = (StringStack *) MapViewOfFile (mapping, FILE_MAP_COPY, 0, 0, sizeof (StringStack)); + stack = (StringStack *)MapViewOfFile(mapping, FILE_MAP_COPY, 0, 0, + sizeof(StringStack)); - if (! stack) - throw std::bad_alloc (); + if (!stack) + throw std::bad_alloc(); #else - stack = (StringStack *) mmap (nullptr, sizeof (StringStack), - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + stack = (StringStack *)mmap(nullptr, sizeof(StringStack), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (stack == MAP_FAILED) - throw std::bad_alloc (); + throw std::bad_alloc(); #endif stack->top = nullptr; - pthread_setspecific (key, stack); + pthread_setspecific(key, stack); } return stack; } -EXPORT void StringBuf::resize (int len) +EXPORT void StringBuf::resize(int len) { - if (! stack) - stack = get_stack (); + if (!stack) + stack = get_stack(); StringHeader * header = nullptr; bool need_alloc = true; if (m_data) { - header = (StringHeader *) (m_data - sizeof (StringHeader)); + header = (StringHeader *)(m_data - sizeof(StringHeader)); /* check if there is enough space in the current location */ - char * limit = header->next ? (char *) header->next : (char *) stack + sizeof (StringStack); + char * limit = header->next ? (char *)header->next + : (char *)stack + sizeof(StringStack); int max_len = limit - 1 - m_data; - if ((len < 0 && ! header->next) || (len >= 0 && len < max_len)) + if ((len < 0 && !header->next) || (len >= 0 && len < max_len)) { m_len = header->len = (len < 0) ? max_len : len; need_alloc = false; @@ -149,13 +155,13 @@ EXPORT void StringBuf::resize (int len) if (need_alloc) { /* allocate a new string at the top of the stack */ - StringHeader * new_header = align_after (stack, stack->top); - char * new_data = (char *) new_header + sizeof (StringHeader); - char * limit = (char *) stack + sizeof (StringStack); + StringHeader * new_header = align_after(stack, stack->top); + char * new_data = (char *)new_header + sizeof(StringHeader); + char * limit = (char *)stack + sizeof(StringStack); int max_len = limit - 1 - new_data; - if (max_len < aud::max (len, 0)) - throw std::bad_alloc (); + if (max_len < aud::max(len, 0)) + throw std::bad_alloc(); int new_len = (len < 0) ? max_len : len; @@ -171,8 +177,8 @@ EXPORT void StringBuf::resize (int len) /* move the old data, if any */ if (m_data) { - int bytes_to_copy = aud::min (m_len, new_len); - memcpy (new_data, m_data, bytes_to_copy); + int bytes_to_copy = aud::min(m_len, new_len); + memcpy(new_data, m_data, bytes_to_copy); if (header->prev) header->prev->next = header->next; @@ -192,11 +198,11 @@ EXPORT void StringBuf::resize (int len) m_data[len] = 0; } -EXPORT StringBuf::~StringBuf () +EXPORT StringBuf::~StringBuf() { if (m_data) { - auto header = (StringHeader *) (m_data - sizeof (StringHeader)); + auto header = (StringHeader *)(m_data - sizeof(StringHeader)); if (header->prev) header->prev->next = header->next; @@ -208,18 +214,18 @@ EXPORT StringBuf::~StringBuf () } } -EXPORT void StringBuf::steal (StringBuf && other) +EXPORT void StringBuf::steal(StringBuf && other) { - (* this = std::move (other)).settle (); + (*this = std::move(other)).settle(); } -EXPORT StringBuf && StringBuf::settle () +EXPORT StringBuf && StringBuf::settle() { if (m_data) { /* collapse any space preceding this string */ - auto header = (StringHeader *) (m_data - sizeof (StringHeader)); - StringHeader * new_header = align_after (stack, header->prev); + auto header = (StringHeader *)(m_data - sizeof(StringHeader)); + StringHeader * new_header = align_after(stack, header->prev); if (new_header != header) { @@ -231,45 +237,45 @@ EXPORT StringBuf && StringBuf::settle () else header->next->prev = new_header; - memmove (new_header, header, sizeof (StringHeader) + m_len + 1); - m_data = (char *) new_header + sizeof (StringHeader); + memmove(new_header, header, sizeof(StringHeader) + m_len + 1); + m_data = (char *)new_header + sizeof(StringHeader); } } - return std::move (* this); + return std::move(*this); } -EXPORT void StringBuf::combine (StringBuf && other) +EXPORT void StringBuf::combine(StringBuf && other) { - if (! other.m_data) + if (!other.m_data) return; - insert (m_len, other.m_data, other.m_len); - other = StringBuf (); - settle (); + insert(m_len, other.m_data, other.m_len); + other = StringBuf(); + settle(); } -EXPORT char * StringBuf::insert (int pos, const char * s, int len) +EXPORT char * StringBuf::insert(int pos, const char * s, int len) { int len0 = m_len; if (pos < 0) pos = len0; if (len < 0) - len = strlen (s); + len = strlen(s); - resize (len0 + len); - memmove (m_data + pos + len, m_data + pos, len0 - pos); + resize(len0 + len); + memmove(m_data + pos + len, m_data + pos, len0 - pos); if (s) - memcpy (m_data + pos, s, len); + memcpy(m_data + pos, s, len); return m_data + pos; } -EXPORT void StringBuf::remove (int pos, int len) +EXPORT void StringBuf::remove(int pos, int len) { int after = m_len - pos - len; - memmove (m_data + pos, m_data + pos + len, after); - resize (pos + after); + memmove(m_data + pos, m_data + pos + len, after); + resize(pos + after); } diff --git a/src/libaudcore/strpool.cc b/src/libaudcore/strpool.cc index c9308d7..96edb99 100644 --- a/src/libaudcore/strpool.cc +++ b/src/libaudcore/strpool.cc @@ -30,48 +30,53 @@ #include -EXPORT char * String::raw_get (const char * str) - { return g_strdup (str); } -EXPORT char * String::raw_ref (const char * str) - { return g_strdup (str); } -EXPORT void String::raw_unref (char * str) - { g_free (str); } +EXPORT char * String::raw_get(const char * str) { return g_strdup(str); } +EXPORT char * String::raw_ref(const char * str) { return g_strdup(str); } +EXPORT void String::raw_unref(char * str) { g_free(str); } -void string_leak_check () {} +void string_leak_check() {} -EXPORT unsigned String::raw_hash (const char * str) - { return str_calc_hash (str); } -EXPORT bool String::raw_equal (const char * str1, const char * str2) - { return ! strcmp_safe (str1, str2); } +EXPORT unsigned String::raw_hash(const char * str) +{ + return str_calc_hash(str); +} +EXPORT bool String::raw_equal(const char * str1, const char * str2) +{ + return !strcmp_safe(str1, str2); +} #else // ! VALGRIND_FRIENDLY struct StrNode : public MultiHash::Node { /* the characters of the string immediately follow the StrNode struct */ - const char * str () const - { return reinterpret_cast (this + 1); } - char * str () - { return reinterpret_cast (this + 1); } + const char * str() const + { + return reinterpret_cast(this + 1); + } + char * str() { return reinterpret_cast(this + 1); } - static const StrNode * of (const char * s) - { return reinterpret_cast (s) - 1; } - static StrNode * of (char * s) - { return reinterpret_cast (s) - 1; } + static const StrNode * of(const char * s) + { + return reinterpret_cast(s) - 1; + } + static StrNode * of(char * s) { return reinterpret_cast(s) - 1; } - static StrNode * create (const char * s) + static StrNode * create(const char * s) { - auto size = sizeof (StrNode) + strlen (s) + 1; - auto node = static_cast (malloc (size)); - if (! node) - throw std::bad_alloc (); + auto size = sizeof(StrNode) + strlen(s) + 1; + auto node = static_cast(malloc(size)); + if (!node) + throw std::bad_alloc(); - strcpy (node->str (), s); + strcpy(node->str(), s); return node; } - bool match (const char * data) const - { return data == str () || ! strcmp (data, str ()); } + bool match(const char * data) const + { + return data == str() || !strcmp(data, str()); + } }; static MultiHash_T strpool_table; @@ -80,32 +85,31 @@ struct Getter { StrNode * node; - StrNode * add (const char * data) + StrNode * add(const char * data) { - node = StrNode::create (data); + node = StrNode::create(data); node->refs = 1; return node; } - bool found (StrNode * node_) + bool found(StrNode * node_) { node = node_; - __sync_fetch_and_add (& node->refs, 1); + __sync_fetch_and_add(&node->refs, 1); return false; } }; struct Remover { - StrNode * add (const char *) - { return nullptr; } + StrNode * add(const char *) { return nullptr; } - bool found (StrNode * node) + bool found(StrNode * node) { - if (! __sync_bool_compare_and_swap (& node->refs, 1, 0)) + if (!__sync_bool_compare_and_swap(&node->refs, 1, 0)) return false; - free (node); + free(node); return true; } }; @@ -115,28 +119,28 @@ struct Remover * In either case, returns the copy. Because this copy may be shared by other * parts of the code, it should not be modified. If is null, simply * returns null with no side effects. */ -EXPORT char * String::raw_get (const char * str) +EXPORT char * String::raw_get(const char * str) { - if (! str) + if (!str) return nullptr; Getter op; - strpool_table.lookup (str, str_calc_hash (str), op); - return op.node->str (); + strpool_table.lookup(str, str_calc_hash(str), op); + return op.node->str(); } /* Increments the reference count of , where is the address of a * string already in the pool. Faster than calling raw_get() a second time. * Returns for convenience. If is null, simply returns null with no * side effects. */ -EXPORT char * String::raw_ref (const char * str_) +EXPORT char * String::raw_ref(const char * str_) { - auto str = const_cast (str_); - if (! str) + auto str = const_cast(str_); + if (!str) return nullptr; - auto node = StrNode::of (str); - __sync_fetch_and_add (& node->refs, 1); + auto node = StrNode::of(str); + __sync_fetch_and_add(&node->refs, 1); return str; } @@ -144,51 +148,52 @@ EXPORT char * String::raw_ref (const char * str_) * string in the pool. If the reference count drops to zero, releases the * memory used by . If is null, simply returns null with no side * effects. */ -EXPORT void String::raw_unref (char * str) +EXPORT void String::raw_unref(char * str) { - if (! str) + if (!str) return; - auto node = StrNode::of (str); + auto node = StrNode::of(str); while (1) { - unsigned refs = __sync_fetch_and_add (& node->refs, 0); + unsigned refs = __sync_fetch_and_add(&node->refs, 0); if (refs > 1) { - if (__sync_bool_compare_and_swap (& node->refs, refs, refs - 1)) + if (__sync_bool_compare_and_swap(&node->refs, refs, refs - 1)) break; } else { Remover op; - int status = strpool_table.lookup (str, node->hash, op); - if (! (status & MultiHash::Found)) - throw std::bad_alloc (); + int status = strpool_table.lookup(str, node->hash, op); + if (!(status & MultiHash::Found)) + throw std::bad_alloc(); if (status & MultiHash::Removed) break; } } } -void string_leak_check () +void string_leak_check() { - strpool_table.iterate ([] (const StrNode * node) { - AUDWARN ("String leaked: %s\n", node->str ()); + strpool_table.iterate([](const StrNode * node) { + AUDWARN("String leaked: %s\n", node->str()); return false; }); } /* Returns the cached hash value of a pooled string (or 0 for null). */ -EXPORT unsigned String::raw_hash (const char * str) +EXPORT unsigned String::raw_hash(const char * str) { - return str ? StrNode::of (str)->hash : 0; + return str ? StrNode::of(str)->hash : 0; } /* Checks whether two pooled strings are equal. Since the pool never contains * duplicate strings, this is a simple pointer comparison and thus much faster - * than strcmp(). null is considered equal to null but not equal to any string. */ -EXPORT bool String::raw_equal (const char * str1, const char * str2) + * than strcmp(). null is considered equal to null but not equal to any string. + */ +EXPORT bool String::raw_equal(const char * str1, const char * str2) { return str1 == str2; } diff --git a/src/libaudcore/templates.h b/src/libaudcore/templates.h index cc1d533..e5f03ec 100644 --- a/src/libaudcore/templates.h +++ b/src/libaudcore/templates.h @@ -1,6 +1,6 @@ /* * templates.h - * Copyright 2014 John Lindgren + * Copyright 2014-2019 John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,72 +29,100 @@ #undef min #undef max -namespace aud { +namespace aud +{ // Utility functions // ================= // minimum of two numbers template -constexpr T min (T a, T b) - { return a < b ? a : b; } +constexpr T min(T a, T b) +{ + return a < b ? a : b; +} // maximum of two numbers template -constexpr T max (T a, T b) - { return a > b ? a : b; } +constexpr T max(T a, T b) +{ + return a > b ? a : b; +} // make sure a number is within the given range template -constexpr T clamp (T x, T low, T high) - { return min (max (x, low), high); } +constexpr T clamp(T x, T low, T high) +{ + return min(max(x, low), high); +} // absolute value template -constexpr T abs (T x) - { return x < 0 ? -x : x; } +constexpr T abs(T x) +{ + return x < 0 ? -x : x; +} // change the sign of x to the sign of s template -constexpr T chsign (T x, T s) - { return (x < 0) ^ (s < 0) ? -x : x; } +constexpr T chsign(T x, T s) +{ + return (x < 0) ^ (s < 0) ? -x : x; +} // integer division with rounding template -constexpr T rdiv (T x, T y) - { return (x + chsign (y / 2, x)) / y; } +constexpr T rdiv(T x, T y) +{ + return (x + chsign(y / 2, x)) / y; +} // convert integer from one scale to another, with rounding template -constexpr T rescale (T x, T old_scale, T new_scale) - { return rdiv (x * new_scale, old_scale); } +constexpr T rescale(T x, T old_scale, T new_scale) +{ + return rdiv(x * new_scale, old_scale); +} // number of characters needed to represent an integer (including minus sign) template -constexpr T n_digits (T x) - { return x < 0 ? 1 + n_digits (-x) : x < 10 ? 1 : 1 + n_digits (x / 10); } +constexpr T n_digits(T x) +{ + return x < 0 ? 1 + n_digits(-x) : x < 10 ? 1 : 1 + n_digits(x / 10); +} // number of elements in an array template -constexpr int n_elems (const T (&) [N]) - { return N; } +constexpr int n_elems(const T (&)[N]) +{ + return N; +} // Casts for storing various data in a void pointer // ================================================ template -inline void * to_ptr (T t) +inline void * to_ptr(T t) { - union { void * v; T t; } u = {nullptr}; - static_assert (sizeof u == sizeof (void *), "Type cannot be stored in a pointer"); - u.t = t; return u.v; + union { + void * v; + T t; + } u = {nullptr}; + static_assert(sizeof u == sizeof(void *), + "Type cannot be stored in a pointer"); + u.t = t; + return u.v; } template -inline T from_ptr (void * v) +inline T from_ptr(void * v) { - union { void * v; T t; } u = {v}; - static_assert (sizeof u == sizeof (void *), "Type cannot be stored in a pointer"); + union { + void * v; + T t; + } u = {v}; + static_assert(sizeof u == sizeof(void *), + "Type cannot be stored in a pointer"); return u.t; } @@ -102,12 +130,12 @@ inline T from_ptr (void * v) // ================================================ template -T & move_assign (T & a, T && b) +T & move_assign(T & a, T && b) { - if (& a != & b) + if (&a != &b) { - a.~T (); - new (& a) T (std::move (b)); + a.~T(); + new (&a) T(std::move(b)); } return a; } @@ -116,23 +144,61 @@ T & move_assign (T & a, T && b) // ================================================================ template -void delete_obj (void * obj) - { (void) sizeof (T); delete (T *) obj; } +void delete_obj(void * obj) +{ + (void)sizeof(T); + delete (T *)obj; +} template -void delete_typed (T * obj) - { (void) sizeof (T); delete obj; } +void delete_typed(T * obj) +{ + (void)sizeof(T); + delete obj; +} + +template +void typed_func(T * obj) +{ + func(obj); +} + +template +static void obj_member(void * obj) +{ + (((T *)obj)->*func)(); +} +template +static void obj_member(void * obj) +{ + (((T *)obj)->*func)(); +} -template -void typed_func (T * obj) - { func (obj); } +// Class which provides scope-based "ownership" of an object +// (similar to std::unique_lock, but more flexible) +// ========================================================= -template -static void obj_member (void * obj) - { (((T *) obj)->* func) (); } -template -static void obj_member (void * obj) - { (((T *) obj)->* func) (); } +template +class owner +{ +public: + explicit owner(T * obj = nullptr) : m_obj(obj) + { + if (m_obj) + (m_obj->*acquire)(); + } + ~owner() + { + if (m_obj) + (m_obj->*release)(); + } + + owner(owner && b) : m_obj(b.m_obj) { b.m_obj = nullptr; } + owner & operator=(owner && b) { return move_assign(*this, std::move(b)); } + +private: + T * m_obj; +}; // Wrapper class allowing enumerations to be used as array indexes; // the enumeration must begin with zero and have a "count" constant @@ -142,54 +208,44 @@ template struct array { // cannot use std::forward here; it is not constexpr until C++14 - template - constexpr array (Args && ... args) : - vals { static_cast (args) ...} {} + template + constexpr array(Args &&... args) : vals{static_cast(args)...} + { + } // Due to GCC bug #63707, the forwarding constructor given above cannot be // used to initialize the array when V is a class with no copy constructor. // As a very limited workaround, provide a second constructor which can be // used to initialize the array to default values in this case. - constexpr array () : - vals () {} - - constexpr const V & operator[] (T t) const - { return vals[(int) t]; } - constexpr const V * begin () const - { return vals; } - constexpr const V * end () const - { return vals + (int) T::count; } - V & operator[] (T t) - { return vals[(int) t]; } - V * begin () - { return vals; } - V * end () - { return vals + (int) T::count; } + constexpr array() : vals() {} + + constexpr const V & operator[](T t) const { return vals[(int)t]; } + constexpr const V * begin() const { return vals; } + constexpr const V * end() const { return vals + (int)T::count; } + V & operator[](T t) { return vals[(int)t]; } + V * begin() { return vals; } + V * end() { return vals + (int)T::count; } private: - V vals[(int) T::count]; + V vals[(int)T::count]; }; // Wrapper class allowing enumerations to be used in range-based for loops // ======================================================================= -template +template struct range { - struct iter { + struct iter + { T v; - constexpr T operator* () const - { return v; } - constexpr bool operator!= (iter other) const - { return v != other.v; } - void operator++ () - { v = (T) ((int) v + 1); } + constexpr T operator*() const { return v; } + constexpr bool operator!=(iter other) const { return v != other.v; } + void operator++() { v = (T)((int)v + 1); } }; - static constexpr iter begin () - { return {first}; } - static constexpr iter end () - { return {(T) ((int) last + 1)}; } + static constexpr iter begin() { return {first}; } + static constexpr iter end() { return {(T)((int)last + 1)}; } }; // Replacement for std::allocator::construct, which also supports aggregate @@ -199,28 +255,36 @@ struct range // class constructor proxy template -struct construct_base { - template - static T * make (void * loc, Args && ... args) - { return new (loc) T (std::forward (args) ...); } +struct construct_base +{ + template + static T * make(void * loc, Args &&... args) + { + return new (loc) T(std::forward(args)...); + } }; // aggregate constructor proxy template -struct construct_base { - template - static T * make (void * loc, Args && ... args) - { return new (loc) T {std::forward (args) ...}; } +struct construct_base +{ + template + static T * make(void * loc, Args &&... args) + { + return new (loc) T{std::forward(args)...}; + } }; // generic constructor proxy template -struct construct { - template - static T * make (void * loc, Args && ... args) +struct construct +{ + template + static T * make(void * loc, Args &&... args) { - constexpr bool aggregate = ! std::is_constructible::value; - return construct_base::make (loc, std::forward (args) ...); + constexpr bool aggregate = !std::is_constructible::value; + return construct_base::make(loc, + std::forward(args)...); } }; @@ -230,25 +294,31 @@ struct construct { // "metaprogramming" string type: each different string is a unique type template -struct metastring { - char data[sizeof... (args) + 1] = {args..., '\0'}; +struct metastring +{ + char data[sizeof...(args) + 1] = {args..., '\0'}; }; // recursive number-printing template, general case (three or more digits) template -struct numeric_builder { - typedef typename numeric_builder::type type; +struct numeric_builder +{ + typedef typename numeric_builder::type type; }; // special case for two digits; minus sign is handled here template -struct numeric_builder<2, x, args...> { - typedef metastring type; +struct numeric_builder<2, x, args...> +{ + typedef metastring < + x<0 ? '-' : '0' + x / 10, '0' + abs(x) % 10, args...> type; }; // special case for one digit (positive numbers only) template -struct numeric_builder<1, x, args...> { +struct numeric_builder<1, x, args...> +{ typedef metastring<'0' + x, args...> type; }; @@ -258,10 +328,10 @@ class numeric_string { private: // generate a unique string type representing this number - typedef typename numeric_builder::type type; + typedef typename numeric_builder::type type; // declare a static string of that type (instantiated later at file scope) - static constexpr type value {}; + static constexpr type value{}; public: // pointer to the instantiated string @@ -276,45 +346,46 @@ constexpr typename numeric_string::type numeric_string::value; // these will be nullptr for basic types (use memset/memcpy instead) // ================================================================= -typedef void (* FillFunc) (void * data, int len); -typedef void (* CopyFunc) (const void * from, void * to, int len); -typedef void (* EraseFunc) (void * data, int len); +typedef void (*FillFunc)(void * data, int len); +typedef void (*CopyFunc)(const void * from, void * to, int len); +typedef void (*EraseFunc)(void * data, int len); template -static constexpr FillFunc fill_func () -{ - return std::is_trivial::value ? (FillFunc) nullptr : - [] (void * data, int len) { - T * iter = (T *) data; - T * end = (T *) ((char *) data + len); - while (iter < end) - new (iter ++) T (); - }; +static constexpr FillFunc fill_func() +{ + return std::is_trivial::value ? (FillFunc) nullptr + : [](void * data, int len) { + T * iter = (T *)data; + T * end = (T *)((char *)data + len); + while (iter < end) + new (iter++) T(); + }; } template -static constexpr CopyFunc copy_func () -{ - return std::is_trivial::value ? (CopyFunc) nullptr : - [] (const void * from, void * to, int len) { - const T * src = (const T *) from; - T * dest = (T *) to; - T * end = (T *) ((char *) to + len); - while (dest < end) - new (dest ++) T (* src ++); - }; +static constexpr CopyFunc copy_func() +{ + return std::is_trivial::value + ? (CopyFunc) nullptr + : [](const void * from, void * to, int len) { + const T * src = (const T *)from; + T * dest = (T *)to; + T * end = (T *)((char *)to + len); + while (dest < end) + new (dest++) T(*src++); + }; } template -static constexpr EraseFunc erase_func () -{ - return std::is_trivial::value ? (EraseFunc) nullptr : - [] (void * data, int len) { - T * iter = (T *) data; - T * end = (T *) ((char *) data + len); - while (iter < end) - (* iter ++).~T (); - }; +static constexpr EraseFunc erase_func() +{ + return std::is_trivial::value ? (EraseFunc) nullptr + : [](void * data, int len) { + T * iter = (T *)data; + T * end = (T *)((char *)data + len); + while (iter < end) + (*iter++).~T(); + }; } } // namespace aud diff --git a/src/libaudcore/tests/test-mainloop.cc b/src/libaudcore/tests/test-mainloop.cc index 384c533..418c7dc 100644 --- a/src/libaudcore/tests/test-mainloop.cc +++ b/src/libaudcore/tests/test-mainloop.cc @@ -19,9 +19,9 @@ #include "mainloop.h" #include "runtime.h" +#include "threads.h" #include -#include #include #include @@ -36,7 +36,7 @@ static QueuedFunc counters[70]; static QueuedFunc timer, delayed; static int count; -static pthread_t main_thread; +static std::thread::id main_thread; static void never_called (void * data) { @@ -46,7 +46,7 @@ static void never_called (void * data) static void count_up (void * data) { - assert (pthread_self () == main_thread); + assert (std::this_thread::get_id () == main_thread); // check that idle calls are run in the same order they were queued assert (count == (int) (size_t) data); @@ -61,7 +61,7 @@ static void count_up (void * data) static void count_down (void * data) { - assert (pthread_self () == main_thread); + assert (std::this_thread::get_id () == main_thread); assert (data == & count); // check that the timer reports being started @@ -84,7 +84,7 @@ static void count_down (void * data) static void check_count (void * data) { - assert (pthread_self () == main_thread); + assert (std::this_thread::get_id () == main_thread); // check relative timing of 10 Hz timer and 250 ms delayed call assert (count == (int) (size_t) data); @@ -92,7 +92,7 @@ static void check_count (void * data) printf ("CHECK: %d\n", count); } -static void * worker (void * data) +static void worker () { // queue some more idle calls from a secondary thread for (int i = 50; i < 70; i ++) @@ -100,8 +100,6 @@ static void * worker (void * data) // queue up a delayed call that should only be called once delayed.queue (250, check_count, (void *) (size_t) 40); - - return nullptr; } int main (int argc, const char * * argv) @@ -109,7 +107,7 @@ int main (int argc, const char * * argv) if (argc >= 2 && ! strcmp (argv[1], "--qt")) use_qt = true; - main_thread = pthread_self (); + main_thread = std::this_thread::get_id (); // queue up a bunch of idle calls for (int i = 0; i < 50; i ++) @@ -129,12 +127,11 @@ int main (int argc, const char * * argv) // queue up a call and then immediately delete the QueuedFunc QueuedFunc ().queue (never_called, nullptr); - pthread_t thread; - pthread_create (& thread, nullptr, worker, nullptr); + auto thread = std::thread (worker); mainloop_run (); - pthread_join (thread, nullptr); + thread.join (); // check that the timer reports being stopped assert (! timer.running ()); diff --git a/src/libaudcore/threads.h b/src/libaudcore/threads.h new file mode 100644 index 0000000..2f13b0c --- /dev/null +++ b/src/libaudcore/threads.h @@ -0,0 +1,100 @@ +/* + * threads.h + * Copyright 2019 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 LIBAUDCORE_THREADS_H +#define LIBAUDCORE_THREADS_H + +#include +#include + +#include +#include +#include + +namespace aud +{ + +/* A wrapper class around TinyLock, encouraging correct usage */ +class spinlock +{ +public: + spinlock() = default; + + /* Not copyable or movable */ + spinlock(const spinlock &) = delete; + spinlock & operator=(const spinlock &) = delete; + + /* Explicit lock/unlock */ + void lock() { tiny_lock(&m_lock); } + void unlock() { tiny_unlock(&m_lock); } + + /* Scope-based lock ownership */ + typedef owner holder; + /* Convenience method for taking ownership of the lock */ + holder take() __attribute__((warn_unused_result)) { return holder(this); } + +private: + TinyLock m_lock = 0; +}; + +/* A wrapper class around TinyRWLock, encouraging correct usage */ +class spinlock_rw +{ +public: + spinlock_rw() = default; + + /* Not copyable or movable */ + spinlock_rw(const spinlock_rw &) = delete; + spinlock_rw & operator=(const spinlock_rw &) = delete; + + /* Explicit lock/unlock */ + void lock_r() { tiny_lock_read(&m_lock); } + void unlock_r() { tiny_unlock_read(&m_lock); } + void lock_w() { tiny_lock_write(&m_lock); } + void unlock_w() { tiny_unlock_write(&m_lock); } + + /* Scope-based lock ownership */ + typedef owner + reader; + typedef owner + writer; + /* Convenience methods for taking ownership of the lock */ + reader read() __attribute__((warn_unused_result)) { return reader(this); } + writer write() __attribute__((warn_unused_result)) { return writer(this); } + +private: + TinyRWLock m_lock = 0; +}; + +/* An alias for std::mutex */ +class mutex : public std::mutex +{ +public: + /* Scope-based lock ownership */ + typedef std::unique_lock holder; + /* Convenience method for taking ownership of the lock */ + holder take() __attribute__((warn_unused_result)) { return holder(*this); } +}; + +/* An alias for std::condition_variable */ +typedef std::condition_variable condvar; + +} // namespace aud + +#endif // LIBAUDCORE_THREADS_H diff --git a/src/libaudcore/timer.cc b/src/libaudcore/timer.cc index 4de6abf..2443f04 100644 --- a/src/libaudcore/timer.cc +++ b/src/libaudcore/timer.cc @@ -18,17 +18,16 @@ */ #include "hook.h" - -#include - #include "index.h" #include "internal.h" #include "mainloop.h" #include "runtime.h" +#include "threads.h" static const aud::array rate_to_ms = {1000, 250, 100, 33}; -struct TimerItem { +struct TimerItem +{ TimerFunc func; void * data; }; @@ -39,7 +38,7 @@ struct TimerList Index items; int use_count = 0; - bool contains (TimerFunc func, void * data) const + bool contains(TimerFunc func, void * data) const { for (auto & item : items) { @@ -50,93 +49,84 @@ struct TimerList return false; } - void check_stop () + void check_stop() { - if (! use_count) + if (!use_count) { - auto is_empty = [] (const TimerItem & item) - { return ! item.func; }; + auto is_empty = [](const TimerItem & item) { return !item.func; }; - items.remove_if (is_empty, true); + items.remove_if(is_empty, true); - if (! items.len () && source.running ()) - source.stop (); + if (!items.len() && source.running()) + source.stop(); } } }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static aud::array lists; -static void timer_run (void * list_) +static void timer_run(void * list_) { - auto & list = * (TimerList *) list_; - pthread_mutex_lock (& mutex); + auto & list = *(TimerList *)list_; + auto mh = mutex.take(); - list.use_count ++; + list.use_count++; /* note: the list may grow (but not shrink) during the call */ - for (int i = 0; i < list.items.len (); i ++) + for (int i = 0; i < list.items.len(); i++) { /* copy locally to prevent race condition */ TimerItem item = list.items[i]; if (item.func) { - pthread_mutex_unlock (& mutex); - item.func (item.data); - pthread_mutex_lock (& mutex); + mh.unlock(); + item.func(item.data); + mh.lock(); } } - list.use_count --; - list.check_stop (); - - pthread_mutex_unlock (& mutex); + list.use_count--; + list.check_stop(); } -EXPORT void timer_add (TimerRate rate, TimerFunc func, void * data) +EXPORT void timer_add(TimerRate rate, TimerFunc func, void * data) { auto & list = lists[rate]; - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! list.contains (func, data)) + if (!list.contains(func, data)) { - list.items.append (func, data); + list.items.append(func, data); - if (! list.source.running ()) - list.source.start (rate_to_ms[rate], timer_run, & list); + if (!list.source.running()) + list.source.start(rate_to_ms[rate], timer_run, &list); } - - pthread_mutex_unlock (& mutex); } -EXPORT void timer_remove (TimerRate rate, TimerFunc func, void * data) +EXPORT void timer_remove(TimerRate rate, TimerFunc func, void * data) { auto & list = lists[rate]; - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); for (TimerItem & item : list.items) { - if (item.func == func && (! data || item.data == data)) + if (item.func == func && (!data || item.data == data)) item.func = nullptr; } - list.check_stop (); - - pthread_mutex_unlock (& mutex); + list.check_stop(); } -void timer_cleanup () +void timer_cleanup() { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); int timers_running = 0; for (TimerList & list : lists) - timers_running += list.items.len (); + timers_running += list.items.len(); if (timers_running) - AUDWARN ("%d timers still registered at exit\n", timers_running); - - pthread_mutex_unlock (& mutex); + AUDWARN("%d timers still registered at exit\n", timers_running); } diff --git a/src/libaudcore/tinylock.cc b/src/libaudcore/tinylock.cc index 873aff1..0424e8b 100644 --- a/src/libaudcore/tinylock.cc +++ b/src/libaudcore/tinylock.cc @@ -19,47 +19,41 @@ #include "tinylock.h" -#ifndef VALGRIND_FRIENDLY - #include #include #define WRITE_BIT (SHRT_MAX + 1) -EXPORT void tiny_lock (TinyLock * lock) +EXPORT void tiny_lock(TinyLock * lock) { - while (__builtin_expect (__sync_lock_test_and_set (lock, 1), 0)) - sched_yield (); + while (__builtin_expect(__sync_lock_test_and_set(lock, 1), 0)) + sched_yield(); } -EXPORT void tiny_unlock (TinyLock * lock) -{ - __sync_lock_release (lock); -} +EXPORT void tiny_unlock(TinyLock * lock) { __sync_lock_release(lock); } -EXPORT void tiny_lock_read (TinyRWLock * lock) +EXPORT void tiny_lock_read(TinyRWLock * lock) { - while (__builtin_expect (__sync_fetch_and_add (lock, 1) & WRITE_BIT, 0)) + while (__builtin_expect(__sync_fetch_and_add(lock, 1) & WRITE_BIT, 0)) { - __sync_fetch_and_sub (lock, 1); - sched_yield (); + __sync_fetch_and_sub(lock, 1); + sched_yield(); } } -EXPORT void tiny_unlock_read (TinyRWLock * lock) +EXPORT void tiny_unlock_read(TinyRWLock * lock) { - __sync_fetch_and_sub (lock, 1); + __sync_fetch_and_sub(lock, 1); } -EXPORT void tiny_lock_write (TinyRWLock * lock) +EXPORT void tiny_lock_write(TinyRWLock * lock) { - while (! __builtin_expect (__sync_bool_compare_and_swap (lock, 0, WRITE_BIT), 1)) - sched_yield (); + while ( + !__builtin_expect(__sync_bool_compare_and_swap(lock, 0, WRITE_BIT), 1)) + sched_yield(); } -EXPORT void tiny_unlock_write (TinyRWLock * lock) +EXPORT void tiny_unlock_write(TinyRWLock * lock) { - __sync_fetch_and_sub (lock, WRITE_BIT); + __sync_fetch_and_sub(lock, WRITE_BIT); } - -#endif /* ! VALGRIND_FRIENDLY */ diff --git a/src/libaudcore/tinylock.h b/src/libaudcore/tinylock.h new file mode 100644 index 0000000..1b16a06 --- /dev/null +++ b/src/libaudcore/tinylock.h @@ -0,0 +1,43 @@ +/* + * tinylock.h + * Copyright 2013 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 LIBAUDCORE_TINYLOCK_H +#define LIBAUDCORE_TINYLOCK_H + +/* + * TinyLock is an extremely low-overhead lock object (in terms of speed and + * memory usage). It makes no guarantees of fair scheduling, however. + * + * Consider using the aud::spinlock wrapper class from threads.h rather than + * using this API directly. + */ + +typedef char TinyLock; + +void tiny_lock(TinyLock * lock); +void tiny_unlock(TinyLock * lock); + +typedef unsigned short TinyRWLock; + +void tiny_lock_read(TinyRWLock * lock); +void tiny_unlock_read(TinyRWLock * lock); +void tiny_lock_write(TinyRWLock * lock); +void tiny_unlock_write(TinyRWLock * lock); + +#endif /* LIBAUDCORE_TINYLOCK_H */ diff --git a/src/libaudcore/tinylock.h.in b/src/libaudcore/tinylock.h.in deleted file mode 100644 index 873af1b..0000000 --- a/src/libaudcore/tinylock.h.in +++ /dev/null @@ -1,56 +0,0 @@ -/* - * tinylock.h - * Copyright 2013 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 LIBAUDCORE_TINYLOCK_H -#define LIBAUDCORE_TINYLOCK_H - -#if @VALGRIND_FRIENDLY@ /* VALGRIND_FRIENDLY */ - -#include - -typedef pthread_mutex_t TinyLock; -typedef pthread_rwlock_t TinyRWLock; - -#define tiny_lock pthread_mutex_lock -#define tiny_unlock pthread_mutex_unlock -#define tiny_lock_read pthread_rwlock_rdlock -#define tiny_unlock_read pthread_rwlock_unlock -#define tiny_lock_write pthread_rwlock_wrlock -#define tiny_unlock_write pthread_rwlock_unlock - -#else /* ! VALGRIND_FRIENDLY */ - -/* TinyLock is an extremely low-overhead lock object (in terms of speed and - * memory usage). It makes no guarantees of fair scheduling, however. */ - -typedef char TinyLock; - -void tiny_lock (TinyLock * lock); -void tiny_unlock (TinyLock * lock); - -typedef unsigned short TinyRWLock; - -void tiny_lock_read (TinyRWLock * lock); -void tiny_unlock_read (TinyRWLock * lock); -void tiny_lock_write (TinyRWLock * lock); -void tiny_unlock_write (TinyRWLock * lock); - -#endif /* ! VALGRIND_FRIENDLY */ - -#endif /* LIBAUDCORE_TINYLOCK_H */ diff --git a/src/libaudcore/tuple-compiler.cc b/src/libaudcore/tuple-compiler.cc index b8d50cd..97198b5 100644 --- a/src/libaudcore/tuple-compiler.cc +++ b/src/libaudcore/tuple-compiler.cc @@ -21,8 +21,8 @@ #include #include -#include #include +#include #include "audstrings.h" #include "runtime.h" @@ -30,7 +30,8 @@ struct Variable { - enum { + enum + { Invalid = 0, Text, Integer, @@ -41,12 +42,13 @@ struct Variable int integer; Tuple::Field field; - bool set (const char * name, bool literal); - bool exists (const Tuple & tuple) const; - Tuple::ValueType get (const Tuple & tuple, String & tmps, int & tmpi) const; + bool set(const char * name, bool literal); + bool exists(const Tuple & tuple) const; + Tuple::ValueType get(const Tuple & tuple, String & tmps, int & tmpi) const; }; -enum class Op { +enum class Op +{ Invalid = 0, Var, Exists, @@ -59,7 +61,8 @@ enum class Op { Empty }; -struct TupleCompiler::Node { +struct TupleCompiler::Node +{ Op op; Variable var1, var2; Index children; @@ -67,26 +70,26 @@ struct TupleCompiler::Node { typedef TupleCompiler::Node Node; -bool Variable::set (const char * name, bool literal) +bool Variable::set(const char * name, bool literal) { - if (g_ascii_isdigit (name[0])) + if (g_ascii_isdigit(name[0])) { type = Integer; - integer = atoi (name); + integer = atoi(name); } else if (literal) { type = Text; - text = String (name); + text = String(name); } else { type = Field; - field = Tuple::field_by_name (name); + field = Tuple::field_by_name(name); if (field < 0) { - AUDWARN ("Invalid variable '%s'.\n", name); + AUDWARN("Invalid variable '%s'.\n", name); return false; } } @@ -94,13 +97,14 @@ bool Variable::set (const char * name, bool literal) return true; } -bool Variable::exists (const Tuple & tuple) const +bool Variable::exists(const Tuple & tuple) const { - g_return_val_if_fail (type == Field, false); - return tuple.get_value_type (field) != Tuple::Empty; + g_return_val_if_fail(type == Field, false); + return tuple.get_value_type(field) != Tuple::Empty; } -Tuple::ValueType Variable::get (const Tuple & tuple, String & tmps, int & tmpi) const +Tuple::ValueType Variable::get(const Tuple & tuple, String & tmps, + int & tmpi) const { switch (type) { @@ -113,14 +117,14 @@ Tuple::ValueType Variable::get (const Tuple & tuple, String & tmps, int & tmpi) return Tuple::Int; case Field: - switch (tuple.get_value_type (field)) + switch (tuple.get_value_type(field)) { case Tuple::String: - tmps = tuple.get_str (field); + tmps = tuple.get_str(field); return Tuple::String; case Tuple::Int: - tmpi = tuple.get_int (field); + tmpi = tuple.get_int(field); return Tuple::Int; default: @@ -128,139 +132,139 @@ Tuple::ValueType Variable::get (const Tuple & tuple, String & tmps, int & tmpi) } default: - g_return_val_if_reached (Tuple::Empty); + g_return_val_if_reached(Tuple::Empty); } } -TupleCompiler::TupleCompiler () {} -TupleCompiler::~TupleCompiler () {} +TupleCompiler::TupleCompiler() {} +TupleCompiler::~TupleCompiler() {} -static StringBuf get_item (const char * & str, char endch, bool & literal) +static StringBuf get_item(const char *& str, char endch, bool & literal) { const char * s = str; - StringBuf buf (-1); + StringBuf buf(-1); char * set = buf; - char * stop = buf + buf.len (); + char * stop = buf + buf.len(); - if (* s == '"') + if (*s == '"') { - if (! literal) + if (!literal) { - buf = StringBuf (); // release space before AUDWARN - AUDWARN ("Unexpected string literal at '%s'.\n", s); - return StringBuf (); + buf = StringBuf(); // release space before AUDWARN + AUDWARN("Unexpected string literal at '%s'.\n", s); + return StringBuf(); } - s ++; + s++; } else literal = false; if (literal) { - while (* s != '"') + while (*s != '"') { - if (* s == '\\') - s ++; + if (*s == '\\') + s++; - if (! * s) + if (!*s) { - buf = StringBuf (); // release space before AUDWARN - AUDWARN ("Unterminated string literal.\n"); - return StringBuf (); + buf = StringBuf(); // release space before AUDWARN + AUDWARN("Unterminated string literal.\n"); + return StringBuf(); } if (set == stop) - throw std::bad_alloc (); + throw std::bad_alloc(); - * set ++ = * s ++; + *set++ = *s++; } - s ++; + s++; } else { - while (g_ascii_isalnum (* s) || * s == '-') + while (g_ascii_isalnum(*s) || *s == '-') { if (set == stop) - throw std::bad_alloc (); + throw std::bad_alloc(); - * set ++ = * s ++; + *set++ = *s++; } } - if (* s != endch) + if (*s != endch) { - buf = StringBuf (); // release space before AUDWARN - AUDWARN ("Expected '%c' at '%s'.\n", endch, s); - return StringBuf (); + buf = StringBuf(); // release space before AUDWARN + AUDWARN("Expected '%c' at '%s'.\n", endch, s); + return StringBuf(); } str = s + 1; - buf.resize (set - buf); + buf.resize(set - buf); return buf; } -static bool compile_expression (Index & nodes, const char * & expression); +static bool compile_expression(Index & nodes, const char *& expression); -static bool parse_construct (Node & node, const char * & c) +static bool parse_construct(Node & node, const char *& c) { bool literal1 = true, literal2 = true; - StringBuf tmps1 = get_item (c, ',', literal1); - if (! tmps1) + StringBuf tmps1 = get_item(c, ',', literal1); + if (!tmps1) return false; - StringBuf tmps2 = get_item (c, ':', literal2); - if (! tmps2) + StringBuf tmps2 = get_item(c, ':', literal2); + if (!tmps2) return false; - if (! node.var1.set (tmps1, literal1)) + if (!node.var1.set(tmps1, literal1)) return false; - if (! node.var2.set (tmps2, literal2)) + if (!node.var2.set(tmps2, literal2)) return false; - return compile_expression (node.children, c); + return compile_expression(node.children, c); } /* Compile format expression into Node tree. */ -static bool compile_expression (Index & nodes, const char * & expression) +static bool compile_expression(Index & nodes, const char *& expression) { const char * c = expression; - while (* c && * c != '}') + while (*c && *c != '}') { - Node & node = nodes.append (); + Node & node = nodes.append(); - if (* c == '$') + if (*c == '$') { /* Expression? */ if (c[1] != '{') { - AUDWARN ("Expected '${' at '%s'.\n", c); + AUDWARN("Expected '${' at '%s'.\n", c); return false; } c += 2; - switch (* c) + switch (*c) { case '?': case '(': - { - if (* c == '?') + { + if (*c == '?') { node.op = Op::Exists; - c ++; + c++; } else { - if (strncmp (c, "(empty)?", 8)) + if (strncmp(c, "(empty)?", 8)) { - AUDWARN ("Expected '(empty)?' at '%s'.\n", c); + AUDWARN("Expected '(empty)?' at '%s'.\n", c); return false; } @@ -269,32 +273,32 @@ static bool compile_expression (Index & nodes, const char * & expression) } bool literal = false; - StringBuf tmps = get_item (c, ':', literal); - if (! tmps) + StringBuf tmps = get_item(c, ':', literal); + if (!tmps) return false; - if (! node.var1.set (tmps, false)) + if (!node.var1.set(tmps, false)) return false; - if (! compile_expression (node.children, c)) + if (!compile_expression(node.children, c)) return false; break; - } + } case '=': case '!': - node.op = (* c == '=') ? Op::Equal : Op::Unequal; + node.op = (*c == '=') ? Op::Equal : Op::Unequal; if (c[1] != '=') { - AUDWARN ("Expected '%c=' at '%s'.\n", c[0], c); + AUDWARN("Expected '%c=' at '%s'.\n", c[0], c); return false; } c += 2; - if (! parse_construct (node, c)) + if (!parse_construct(node, c)) return false; break; @@ -303,81 +307,81 @@ static bool compile_expression (Index & nodes, const char * & expression) case '>': if (c[1] == '=') { - node.op = (* c == '<') ? Op::LessEqual : Op::GreaterEqual; + node.op = (*c == '<') ? Op::LessEqual : Op::GreaterEqual; c += 2; } else { - node.op = (* c == '<') ? Op::Less : Op::Greater; - c ++; + node.op = (*c == '<') ? Op::Less : Op::Greater; + c++; } - if (! parse_construct (node, c)) + if (!parse_construct(node, c)) return false; break; default: - { + { bool literal = false; - StringBuf tmps = get_item (c, '}', literal); - if (! tmps) + StringBuf tmps = get_item(c, '}', literal); + if (!tmps) return false; - c --; + c--; node.op = Op::Var; - if (! node.var1.set (tmps, false)) + if (!node.var1.set(tmps, false)) return false; - } + } } - if (* c != '}') + if (*c != '}') { - AUDWARN ("Expected '}' at '%s'.\n", c); + AUDWARN("Expected '}' at '%s'.\n", c); return false; } - c ++; + c++; } - else if (* c == '{') + else if (*c == '{') { - AUDWARN ("Unexpected '%c' at '%s'.\n", * c, c); + AUDWARN("Unexpected '%c' at '%s'.\n", *c, c); return false; } else { /* Parse raw/literal text */ - StringBuf buf (-1); + StringBuf buf(-1); char * set = buf; - char * stop = buf + buf.len (); + char * stop = buf + buf.len(); - while (* c && * c != '$' && * c != '{' && * c != '}') + while (*c && *c != '$' && *c != '{' && *c != '}') { - if (* c == '\\') + if (*c == '\\') { - c ++; + c++; - if (! * c) + if (!*c) { - buf = StringBuf (); // release space before AUDWARN - AUDWARN ("Incomplete escaped character.\n"); + buf = StringBuf(); // release space before AUDWARN + AUDWARN("Incomplete escaped character.\n"); return false; } } if (set == stop) - throw std::bad_alloc (); + throw std::bad_alloc(); - * set ++ = * c ++; + *set++ = *c++; } - buf.resize (set - buf); + buf.resize(set - buf); node.op = Op::Var; node.var1.type = Variable::Text; - node.var1.text = String (buf); + node.var1.text = String(buf); } } @@ -385,50 +389,48 @@ static bool compile_expression (Index & nodes, const char * & expression) return true; } -bool TupleCompiler::compile (const char * expr) +bool TupleCompiler::compile(const char * expr) { const char * c = expr; Index nodes; - if (! compile_expression (nodes, c)) + if (!compile_expression(nodes, c)) return false; - if (* c) + if (*c) { - AUDWARN ("Unexpected '%c' at '%s'.\n", * c, c); + AUDWARN("Unexpected '%c' at '%s'.\n", *c, c); return false; } - root_nodes = std::move (nodes); + root_nodes = std::move(nodes); return true; } -void TupleCompiler::reset () -{ - root_nodes.clear (); -} +void TupleCompiler::reset() { root_nodes.clear(); } /* Evaluate tuple in given TupleEval expression in given * context and return resulting string. */ -static void eval_expression (const Index & nodes, const Tuple & tuple, StringBuf & out) +static void eval_expression(const Index & nodes, const Tuple & tuple, + StringBuf & out) { for (const Node & node : nodes) { switch (node.op) { case Op::Var: - { + { String tmps; int tmpi; - switch (node.var1.get (tuple, tmps, tmpi)) + switch (node.var1.get(tuple, tmps, tmpi)) { case Tuple::String: - out.insert (-1, tmps); + out.insert(-1, tmps); break; case Tuple::Int: - str_insert_int (out, -1, tmpi); + str_insert_int(out, -1, tmpi); break; default: @@ -436,7 +438,7 @@ static void eval_expression (const Index & nodes, const Tuple & tuple, Str } break; - } + } case Op::Equal: case Op::Unequal: @@ -444,13 +446,13 @@ static void eval_expression (const Index & nodes, const Tuple & tuple, Str case Op::LessEqual: case Op::Greater: case Op::GreaterEqual: - { + { bool result = false; String tmps1, tmps2; int tmpi1 = 0, tmpi2 = 0; - Tuple::ValueType type1 = node.var1.get (tuple, tmps1, tmpi1); - Tuple::ValueType type2 = node.var2.get (tuple, tmps2, tmpi2); + Tuple::ValueType type1 = node.var1.get(tuple, tmps1, tmpi1); + Tuple::ValueType type2 = node.var2.get(tuple, tmps2, tmpi2); if (type1 != Tuple::Empty && type2 != Tuple::Empty) { @@ -459,16 +461,16 @@ static void eval_expression (const Index & nodes, const Tuple & tuple, Str if (type1 == type2) { if (type1 == Tuple::String) - resulti = strcmp (tmps1, tmps2); + resulti = strcmp(tmps1, tmps2); else resulti = tmpi1 - tmpi2; } else { if (type1 == Tuple::Int) - resulti = tmpi1 - atoi (tmps2); + resulti = tmpi1 - atoi(tmps2); else - resulti = atoi (tmps1) - tmpi2; + resulti = atoi(tmps1) - tmpi2; } switch (node.op) @@ -498,57 +500,57 @@ static void eval_expression (const Index & nodes, const Tuple & tuple, Str break; default: - g_warn_if_reached (); + g_warn_if_reached(); } } if (result) - eval_expression (node.children, tuple, out); + eval_expression(node.children, tuple, out); break; - } + } case Op::Exists: - if (node.var1.exists (tuple)) - eval_expression (node.children, tuple, out); + if (node.var1.exists(tuple)) + eval_expression(node.children, tuple, out); break; case Op::Empty: - if (! node.var1.exists (tuple)) - eval_expression (node.children, tuple, out); + if (!node.var1.exists(tuple)) + eval_expression(node.children, tuple, out); break; default: - g_warn_if_reached (); + g_warn_if_reached(); } } } -void TupleCompiler::format (Tuple & tuple) const +void TupleCompiler::format(Tuple & tuple) const { - tuple.unset (Tuple::FormattedTitle); // prevent recursion + tuple.unset(Tuple::FormattedTitle); // prevent recursion - StringBuf buf (0); - eval_expression (root_nodes, tuple, buf); + StringBuf buf(0); + eval_expression(root_nodes, tuple, buf); if (buf[0]) { - tuple.set_str (Tuple::FormattedTitle, buf); + tuple.set_str(Tuple::FormattedTitle, buf); return; } /* formatting failed, try fallbacks */ for (Tuple::Field fallback : {Tuple::Title, Tuple::Basename}) { - String title = tuple.get_str (fallback); + String title = tuple.get_str(fallback); if (title) { - tuple.set_str (Tuple::FormattedTitle, title); + tuple.set_str(Tuple::FormattedTitle, title); return; } } - tuple.set_str (Tuple::FormattedTitle, ""); + tuple.set_str(Tuple::FormattedTitle, ""); } diff --git a/src/libaudcore/tuple-compiler.h b/src/libaudcore/tuple-compiler.h index 88cc21f..3e25faf 100644 --- a/src/libaudcore/tuple-compiler.h +++ b/src/libaudcore/tuple-compiler.h @@ -48,13 +48,13 @@ class TupleCompiler public: struct Node; - TupleCompiler (); - ~TupleCompiler (); + TupleCompiler(); + ~TupleCompiler(); - bool compile (const char * expr); - void reset (); + bool compile(const char * expr); + void reset(); - void format (Tuple & tuple) const; + void format(Tuple & tuple) const; private: Index root_nodes; diff --git a/src/libaudcore/tuple.cc b/src/libaudcore/tuple.cc index 603a475..02dde50 100644 --- a/src/libaudcore/tuple.cc +++ b/src/libaudcore/tuple.cc @@ -1,6 +1,6 @@ /* * tuple.c - * Copyright 2007-2013 William Pitcock, Christian Birchinger, Matti Hämäläinen, + * Copyright 2007-2013 Ariadne Conill, Christian Birchinger, Matti Hämäläinen, * Giacomo Lozito, Eugene Zagidullin, and John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ #include #include -#include /* for g_utf8_validate */ +#include /* for g_utf8_validate */ #include "audio.h" #include "audstrings.h" @@ -32,7 +32,8 @@ #include "tuple.h" #include "vfs.h" -enum { +enum +{ FallbackTitle = Tuple::n_fields, FallbackArtist, FallbackAlbum, @@ -40,17 +41,16 @@ enum { n_private_fields }; -static_assert (n_private_fields <= 64, - "The current tuple implementation is limited to 64 fields"); +static_assert(n_private_fields <= 64, + "The current tuple implementation is limited to 64 fields"); -union TupleVal -{ +union TupleVal { String str; int x; // dummy constructor and destructor - TupleVal () {} - ~TupleVal () {} + TupleVal() {} + ~TupleVal() {} }; /** @@ -59,48 +59,47 @@ union TupleVal */ struct TupleData { - uint64_t setmask; // which fields are present - Index vals; // ordered list of field values + uint64_t setmask; // which fields are present + Index vals; // ordered list of field values - short * subtunes; /**< Array of int containing subtune index numbers. - Can be nullptr if indexing is linear or if - there are no subtunes. */ - short nsubtunes; /**< Number of subtunes, if any. Values greater than 0 - mean that there are subtunes and #subtunes array - may be set. */ + short * subtunes; /**< Array of int containing subtune index numbers. + Can be nullptr if indexing is linear or if + there are no subtunes. */ + short nsubtunes; /**< Number of subtunes, if any. Values greater than 0 + mean that there are subtunes and #subtunes array + may be set. */ short state; int refcount; - TupleData (); - ~TupleData (); + TupleData(); + ~TupleData(); - TupleData (const TupleData & other); - void operator= (const TupleData & other) = delete; + TupleData(const TupleData & other); + void operator=(const TupleData & other) = delete; - bool is_set (int field) const - { return (setmask & bitmask (field)); } + bool is_set(int field) const { return (setmask & bitmask(field)); } - bool is_same (const TupleData & other); + bool is_same(const TupleData & other); - TupleVal * lookup (int field, bool add, bool remove); - void set_int (int field, int x); - void set_str (int field, const char * str); - void set_subtunes (short nsubs, const short * subs); + TupleVal * lookup(int field, bool add, bool remove); + void set_int(int field, int x); + void set_str(int field, const char * str); + void set_subtunes(short nsubs, const short * subs); - static TupleData * ref (TupleData * tuple); - static void unref (TupleData * tuple); + static TupleData * ref(TupleData * tuple); + static void unref(TupleData * tuple); - static TupleData * copy_on_write (TupleData * tuple); + static TupleData * copy_on_write(TupleData * tuple); private: - static constexpr uint64_t bitmask (int n) - { return (uint64_t) 1 << n; } + static constexpr uint64_t bitmask(int n) { return (uint64_t)1 << n; } }; /** Ordered table of basic #Tuple field names and their #ValueType. */ -static const struct { +static const struct +{ const char * name; Tuple::ValueType type; int fallback; @@ -146,15 +145,20 @@ static const struct { {"formatted-title", Tuple::String, -1}, + {"description", Tuple::String, -1}, + {"musicbrainz-id", Tuple::String, -1}, + /* fallbacks */ {nullptr, Tuple::String, -1}, {nullptr, Tuple::String, -1}, {nullptr, Tuple::String, -1}, }; -static_assert (aud::n_elems (field_info) == n_private_fields, "Update field_data"); +static_assert(aud::n_elems(field_info) == n_private_fields, + "Update field_data"); -struct FieldDictEntry { +struct FieldDictEntry +{ const char * name; Tuple::Field field; }; @@ -171,6 +175,7 @@ static const FieldDictEntry field_dict[] = { {"composer", Tuple::Composer}, {"copyright", Tuple::Copyright}, {"date", Tuple::Date}, + {"description", Tuple::Description}, {"file-ext", Tuple::Suffix}, {"file-name", Tuple::Basename}, {"file-path", Tuple::Path}, @@ -183,6 +188,7 @@ static const FieldDictEntry field_dict[] = { {"gain-track-peak", Tuple::TrackPeak}, {"genre", Tuple::Genre}, {"length", Tuple::Length}, + {"musicbrainz-id", Tuple::MusicBrainzID}, {"performer", Tuple::Performer}, {"quality", Tuple::Quality}, {"segment-end", Tuple::EndTime}, @@ -191,15 +197,16 @@ static const FieldDictEntry field_dict[] = { {"subsong-num", Tuple::NumSubtunes}, {"title", Tuple::Title}, {"track-number", Tuple::Track}, - {"year", Tuple::Year} -}; + {"year", Tuple::Year}}; -static_assert (aud::n_elems (field_dict) == Tuple::n_fields, "Update field_dict"); +static_assert(aud::n_elems(field_dict) == Tuple::n_fields, "Update field_dict"); -static constexpr bool is_valid_field (int field) - { return field > Tuple::Invalid && field < Tuple::n_fields; } +static constexpr bool is_valid_field(int field) +{ + return field > Tuple::Invalid && field < Tuple::n_fields; +} -static int bitcount (uint64_t x) +static int bitcount(uint64_t x) { /* algorithm from http://en.wikipedia.org/wiki/Hamming_weight */ x -= (x >> 1) & 0x5555555555555555; @@ -208,77 +215,78 @@ static int bitcount (uint64_t x) return (x * 0x0101010101010101) >> 56; } -static int field_dict_compare (const void * a, const void * b) +static int field_dict_compare(const void * a, const void * b) { - return strcmp (((FieldDictEntry *) a)->name, ((FieldDictEntry *) b)->name); + return strcmp(((FieldDictEntry *)a)->name, ((FieldDictEntry *)b)->name); } -EXPORT Tuple::Field Tuple::field_by_name (const char * name) +EXPORT Tuple::Field Tuple::field_by_name(const char * name) { FieldDictEntry find = {name, Invalid}; - FieldDictEntry * found = (FieldDictEntry *) bsearch (& find, field_dict, - n_fields, sizeof (FieldDictEntry), field_dict_compare); + FieldDictEntry * found = + (FieldDictEntry *)bsearch(&find, field_dict, n_fields, + sizeof(FieldDictEntry), field_dict_compare); return found ? found->field : Invalid; } -EXPORT const char * Tuple::field_get_name (Field field) +EXPORT const char * Tuple::field_get_name(Field field) { - assert (is_valid_field (field)); + assert(is_valid_field(field)); return field_info[field].name; } -EXPORT Tuple::ValueType Tuple::field_get_type (Field field) +EXPORT Tuple::ValueType Tuple::field_get_type(Field field) { - assert (is_valid_field (field)); + assert(is_valid_field(field)); return field_info[field].type; } -TupleVal * TupleData::lookup (int field, bool add, bool remove) +TupleVal * TupleData::lookup(int field, bool add, bool remove) { /* calculate number of preceding fields */ - const uint64_t mask = bitmask (field); - const int pos = bitcount (setmask & (mask - 1)); + const uint64_t mask = bitmask(field); + const int pos = bitcount(setmask & (mask - 1)); if ((setmask & mask)) { if ((add || remove) && field_info[field].type == Tuple::String) - vals[pos].str.~String (); + vals[pos].str.~String(); if (remove) { setmask &= ~mask; - vals.remove (pos, 1); + vals.remove(pos, 1); return nullptr; } - return & vals[pos]; + return &vals[pos]; } - if (! (add || remove) && field_info[field].fallback >= 0) - return lookup (field_info[field].fallback, false, false); + if (!(add || remove) && field_info[field].fallback >= 0) + return lookup(field_info[field].fallback, false, false); - if (! add) + if (!add) return nullptr; setmask |= mask; - vals.insert (pos, 1); - return & vals[pos]; + vals.insert(pos, 1); + return &vals[pos]; } -void TupleData::set_int (int field, int x) +void TupleData::set_int(int field, int x) { - TupleVal * val = lookup (field, true, false); + TupleVal * val = lookup(field, true, false); val->x = x; } -void TupleData::set_str (int field, const char * str) +void TupleData::set_str(int field, const char * str) { - TupleVal * val = lookup (field, true, false); - new (& val->str) String (str); + TupleVal * val = lookup(field, true, false); + new (&val->str) String(str); } -void TupleData::set_subtunes (short nsubs, const short * subs) +void TupleData::set_subtunes(short nsubs, const short * subs) { nsubtunes = nsubs; @@ -288,76 +296,72 @@ void TupleData::set_subtunes (short nsubs, const short * subs) if (nsubs && subs) { subtunes = new short[nsubs]; - memcpy (subtunes, subs, sizeof subtunes[0] * nsubs); + memcpy(subtunes, subs, sizeof subtunes[0] * nsubs); } } -TupleData::TupleData () : - setmask (0), - subtunes (nullptr), - nsubtunes (0), - state (Tuple::Initial), - refcount (1) {} +TupleData::TupleData() + : setmask(0), subtunes(nullptr), nsubtunes(0), state(Tuple::Initial), + refcount(1) +{ +} -TupleData::TupleData (const TupleData & other) : - setmask (other.setmask), - subtunes (nullptr), - nsubtunes (0), - state (other.state), - refcount (1) +TupleData::TupleData(const TupleData & other) + : setmask(other.setmask), subtunes(nullptr), nsubtunes(0), + state(other.state), refcount(1) { - vals.insert (0, other.vals.len ()); + vals.insert(0, other.vals.len()); - auto get = other.vals.begin (); - auto set = vals.begin (); + auto get = other.vals.begin(); + auto set = vals.begin(); - for (int f = 0; f < n_private_fields; f ++) + for (int f = 0; f < n_private_fields; f++) { - if (other.setmask & bitmask (f)) + if (other.setmask & bitmask(f)) { if (field_info[f].type == Tuple::String) - new (& set->str) String (get->str); + new (&set->str) String(get->str); else set->x = get->x; - get ++; - set ++; + get++; + set++; } } - set_subtunes (other.nsubtunes, other.subtunes); + set_subtunes(other.nsubtunes, other.subtunes); } -TupleData::~TupleData () +TupleData::~TupleData() { - auto iter = vals.begin (); + auto iter = vals.begin(); - for (int f = 0; f < n_private_fields; f ++) + for (int f = 0; f < n_private_fields; f++) { - if (setmask & bitmask (f)) + if (setmask & bitmask(f)) { if (field_info[f].type == Tuple::String) - iter->str.~String (); + iter->str.~String(); - iter ++; + iter++; } } delete[] subtunes; } -bool TupleData::is_same (const TupleData & other) +bool TupleData::is_same(const TupleData & other) { if (state != other.state || setmask != other.setmask || - nsubtunes != other.nsubtunes || (! subtunes) != (! other.subtunes)) + nsubtunes != other.nsubtunes || (!subtunes) != (!other.subtunes)) return false; - auto a = vals.begin (); - auto b = other.vals.begin (); + auto a = vals.begin(); + auto b = other.vals.begin(); - for (int f = 0; f < n_private_fields; f ++) + for (int f = 0; f < n_private_fields; f++) { - if (setmask & bitmask (f)) + if (setmask & bitmask(f)) { bool same; @@ -366,211 +370,216 @@ bool TupleData::is_same (const TupleData & other) else same = (a->x = b->x); - if (! same) + if (!same) return false; - a ++; - b ++; + a++; + b++; } } - if (subtunes && memcmp (subtunes, other.subtunes, sizeof subtunes[0] * nsubtunes)) + if (subtunes && + memcmp(subtunes, other.subtunes, sizeof subtunes[0] * nsubtunes)) return false; return true; } -TupleData * TupleData::ref (TupleData * tuple) +TupleData * TupleData::ref(TupleData * tuple) { if (tuple) - __sync_fetch_and_add (& tuple->refcount, 1); + __sync_fetch_and_add(&tuple->refcount, 1); return tuple; } -void TupleData::unref (TupleData * tuple) +void TupleData::unref(TupleData * tuple) { - if (tuple && ! __sync_sub_and_fetch (& tuple->refcount, 1)) + if (tuple && !__sync_sub_and_fetch(&tuple->refcount, 1)) delete tuple; } -TupleData * TupleData::copy_on_write (TupleData * tuple) +TupleData * TupleData::copy_on_write(TupleData * tuple) { - if (! tuple) + if (!tuple) return new TupleData; - if (__sync_fetch_and_add (& tuple->refcount, 0) == 1) + if (__sync_fetch_and_add(&tuple->refcount, 0) == 1) return tuple; - TupleData * copy = new TupleData (* tuple); - unref (tuple); + TupleData * copy = new TupleData(*tuple); + unref(tuple); return copy; } -EXPORT Tuple::~Tuple () -{ - TupleData::unref (data); -} +EXPORT Tuple::~Tuple() { TupleData::unref(data); } -EXPORT bool Tuple::operator== (const Tuple & b) const +EXPORT bool Tuple::operator==(const Tuple & b) const { if (data == b.data) return true; - if (! data || ! b.data) + if (!data || !b.data) return false; - return data->is_same (* b.data); + return data->is_same(*b.data); } -EXPORT Tuple Tuple::ref () const +EXPORT Tuple Tuple::ref() const { Tuple tuple; - tuple.data = TupleData::ref (data); + tuple.data = TupleData::ref(data); return tuple; } -EXPORT Tuple::State Tuple::state () const +EXPORT Tuple::State Tuple::state() const { - return data ? (Tuple::State) data->state : Initial; + return data ? (Tuple::State)data->state : Initial; } -EXPORT void Tuple::set_state (State st) +EXPORT void Tuple::set_state(State st) { - data = TupleData::copy_on_write (data); + data = TupleData::copy_on_write(data); data->state = st; } -EXPORT Tuple::ValueType Tuple::get_value_type (Field field) const +EXPORT Tuple::ValueType Tuple::get_value_type(Field field) const { - assert (is_valid_field (field)); + assert(is_valid_field(field)); const auto & info = field_info[field]; - if (data && (data->is_set (field) || (info.fallback >= 0 && data->is_set (info.fallback)))) + if (data && (data->is_set(field) || + (info.fallback >= 0 && data->is_set(info.fallback)))) return info.type; return Empty; } -EXPORT int Tuple::get_int (Field field) const +EXPORT int Tuple::get_int(Field field) const { - assert (is_valid_field (field) && field_info[field].type == Int); + assert(is_valid_field(field) && field_info[field].type == Int); - TupleVal * val = data ? data->lookup (field, false, false) : nullptr; + TupleVal * val = data ? data->lookup(field, false, false) : nullptr; return val ? val->x : -1; } -EXPORT String Tuple::get_str (Field field) const +EXPORT String Tuple::get_str(Field field) const { - assert (is_valid_field (field) && field_info[field].type == String); + assert(is_valid_field(field) && field_info[field].type == String); - TupleVal * val = data ? data->lookup (field, false, false) : nullptr; - return val ? val->str : ::String (); + TupleVal * val = data ? data->lookup(field, false, false) : nullptr; + return val ? val->str : ::String(); } -EXPORT void Tuple::set_int (Field field, int x) +EXPORT void Tuple::set_int(Field field, int x) { - assert (is_valid_field (field) && field_info[field].type == Int); + assert(is_valid_field(field) && field_info[field].type == Int); - data = TupleData::copy_on_write (data); - data->set_int (field, x); + data = TupleData::copy_on_write(data); + data->set_int(field, x); } -EXPORT void Tuple::set_str (Field field, const char * str) +EXPORT void Tuple::set_str(Field field, const char * str) { - assert (is_valid_field (field) && field_info[field].type == String); + assert(is_valid_field(field) && field_info[field].type == String); - if (! str) + if (!str) { - unset (field); + unset(field); return; } - data = TupleData::copy_on_write (data); + data = TupleData::copy_on_write(data); - if (g_utf8_validate (str, -1, nullptr)) - data->set_str (field, str); + if (g_utf8_validate(str, -1, nullptr)) + data->set_str(field, str); else { - StringBuf utf8 = str_to_utf8 (str, -1); - data->set_str (field, utf8 ? (const char *) utf8 : _("(character encoding error)")); + StringBuf utf8 = str_to_utf8(str, -1); + data->set_str(field, utf8 ? (const char *)utf8 + : _("(character encoding error)")); } } -EXPORT void Tuple::unset (Field field) +EXPORT void Tuple::unset(Field field) { - assert (is_valid_field (field)); + assert(is_valid_field(field)); - if (! data) + if (!data) return; - data = TupleData::copy_on_write (data); - data->lookup (field, false, true); + data = TupleData::copy_on_write(data); + data->lookup(field, false, true); } -EXPORT void Tuple::set_filename (const char * filename) +EXPORT void Tuple::set_filename(const char * filename) { - assert (filename); + assert(filename); - data = TupleData::copy_on_write (data); + data = TupleData::copy_on_write(data); // stdin is handled as a special case - if (! strncmp (filename, "stdin://", 8)) + if (!strncmp(filename, "stdin://", 8)) { - data->set_str (Basename, _("Standard input")); + data->set_str(Basename, _("Standard input")); return; } - const char * base, * ext, * sub; + const char *base, *ext, *sub; int isub; - uri_parse (filename, & base, & ext, & sub, & isub); + uri_parse(filename, &base, &ext, &sub, &isub); if (base > filename) - data->set_str (Path, uri_to_display (str_copy (filename, base - filename))); + data->set_str(Path, + uri_to_display(str_copy(filename, base - filename))); if (ext > base) - data->set_str (Basename, str_to_utf8 (str_decode_percent (base, ext - base))); + data->set_str(Basename, + str_to_utf8(str_decode_percent(base, ext - base))); if (sub > ext + 1) - data->set_str (Suffix, str_to_utf8 (str_decode_percent (ext + 1, sub - ext - 1))); + data->set_str(Suffix, + str_to_utf8(str_decode_percent(ext + 1, sub - ext - 1))); if (sub[0]) - data->set_int (Subtune, isub); + data->set_int(Subtune, isub); } -EXPORT void Tuple::set_format (const char * format, int chans, int rate, int brate) +EXPORT void Tuple::set_format(const char * format, int chans, int rate, + int brate) { if (format) - set_str (Codec, format); + set_str(Codec, format); StringBuf buf; if (chans > 0) { if (chans == 1) - buf = str_copy (_("Mono")); + buf = str_copy(_("Mono")); else if (chans == 2) - buf = str_copy (_("Stereo")); + buf = str_copy(_("Stereo")); else - buf = str_printf (dngettext (PACKAGE, "%d channel", "%d channels", chans), chans); + buf = str_printf( + dngettext(PACKAGE, "%d channel", "%d channels", chans), chans); if (rate > 0) - buf.insert (-1, ", "); + buf.insert(-1, ", "); } if (rate > 0) - str_append_printf (buf, "%d kHz", rate / 1000); + str_append_printf(buf, "%d kHz", rate / 1000); if (buf[0]) - set_str (Quality, buf); + set_str(Quality, buf); if (brate > 0) - set_int (Bitrate, brate); + set_int(Bitrate, brate); } -EXPORT void Tuple::set_subtunes (short n_subtunes, const short * subtunes) +EXPORT void Tuple::set_subtunes(short n_subtunes, const short * subtunes) { - data = TupleData::copy_on_write (data); - data->set_subtunes (n_subtunes, subtunes); + data = TupleData::copy_on_write(data); + data->set_subtunes(n_subtunes, subtunes); } EXPORT short Tuple::get_n_subtunes() const @@ -578,102 +587,102 @@ EXPORT short Tuple::get_n_subtunes() const return data ? data->nsubtunes : 0; } -EXPORT short Tuple::get_nth_subtune (short n) const +EXPORT short Tuple::get_nth_subtune(short n) const { - if (! data || n < 0 || n >= data->nsubtunes) + if (!data || n < 0 || n >= data->nsubtunes) return -1; return data->subtunes ? data->subtunes[n] : 1 + n; } -EXPORT void Tuple::set_gain (Field field, Field unit_field, const char * str) +EXPORT void Tuple::set_gain(Field field, Field unit_field, const char * str) { - set_int (field, lround (str_to_double (str) * 1000000)); - set_int (unit_field, 1000000); + set_int(field, lround(str_to_double(str) * 1000000)); + set_int(unit_field, 1000000); } /* combining this with get_replay_gain() would be cleaner but would * require adding a validity flag to ReplayGainInfo, breaking ABI */ -EXPORT bool Tuple::has_replay_gain () const +EXPORT bool Tuple::has_replay_gain() const { - return get_int (GainDivisor) > 0 && - (data->is_set (AlbumGain) || data->is_set (TrackGain)); + return get_int(GainDivisor) > 0 && + (data->is_set(AlbumGain) || data->is_set(TrackGain)); } -EXPORT ReplayGainInfo Tuple::get_replay_gain () const +EXPORT ReplayGainInfo Tuple::get_replay_gain() const { - ReplayGainInfo gain {}; + ReplayGainInfo gain{}; - if (! data) + if (!data) return gain; - int gain_unit = get_int (GainDivisor); - int peak_unit = get_int (PeakDivisor); + int gain_unit = get_int(GainDivisor); + int peak_unit = get_int(PeakDivisor); if (gain_unit > 0) { - bool have_album = data->is_set (AlbumGain); - bool have_track = data->is_set (TrackGain); + bool have_album = data->is_set(AlbumGain); + bool have_track = data->is_set(TrackGain); if (have_album) - gain.album_gain = get_int (AlbumGain) / (float) gain_unit; + gain.album_gain = get_int(AlbumGain) / (float)gain_unit; if (have_track) - gain.track_gain = get_int (TrackGain) / (float) gain_unit; + gain.track_gain = get_int(TrackGain) / (float)gain_unit; /* fill in missing information if we can */ - if (! have_album && have_track) + if (!have_album && have_track) gain.album_gain = gain.track_gain; - if (have_album && ! have_track) + if (have_album && !have_track) gain.track_gain = gain.album_gain; } if (peak_unit > 0) { - bool have_album = data->is_set (AlbumPeak); - bool have_track = data->is_set (TrackPeak); + bool have_album = data->is_set(AlbumPeak); + bool have_track = data->is_set(TrackPeak); if (have_album) - gain.album_peak = get_int (AlbumPeak) / (float) peak_unit; + gain.album_peak = get_int(AlbumPeak) / (float)peak_unit; if (have_track) - gain.track_peak = get_int (TrackPeak) / (float) peak_unit; + gain.track_peak = get_int(TrackPeak) / (float)peak_unit; /* fill in missing information if we can */ - if (! have_album && have_track) + if (!have_album && have_track) gain.album_peak = gain.track_peak; - if (have_album && ! have_track) + if (have_album && !have_track) gain.track_peak = gain.album_peak; } return gain; } -EXPORT bool Tuple::fetch_stream_info (VFSFile & stream) +EXPORT bool Tuple::fetch_stream_info(VFSFile & stream) { bool updated = false; int value; - ::String val = stream.get_metadata ("track-name"); + ::String val = stream.get_metadata("track-name"); - if (val && val != get_str (Title)) + if (val && val != get_str(Title)) { - set_str (Title, val); + set_str(Title, val); updated = true; } - val = stream.get_metadata ("stream-name"); + val = stream.get_metadata("stream-name"); - if (val && val != get_str (Artist)) + if (val && val != get_str(Artist)) { - set_str (Artist, val); + set_str(Artist, val); updated = true; } - val = stream.get_metadata ("content-bitrate"); - value = val ? atoi (val) / 1000 : 0; + val = stream.get_metadata("content-bitrate"); + value = val ? atoi(val) / 1000 : 0; - if (value && value != get_int (Bitrate)) + if (value && value != get_int(Bitrate)) { - set_int (Bitrate, value); + set_int(Bitrate, value); updated = true; } @@ -684,12 +693,12 @@ EXPORT bool Tuple::fetch_stream_info (VFSFile & stream) * be modified, and the string returned will use the same memory. May return * nullptr. */ -static char * split_folder (char * path, char sep) +static char * split_folder(char * path, char sep) { char * c; - while ((c = strrchr (path, sep))) + while ((c = strrchr(path, sep))) { - * c = 0; + *c = 0; if (c[1]) return c + 1; } @@ -701,86 +710,86 @@ static char * split_folder (char * path, char sep) * "http://some.domain.org/folder/file.mp3" -> "some.domain.org" * "http://some.stream.fm:8000" -> "some.stream.fm" */ -static const char * find_domain (const char * name) +static const char * find_domain(const char * name) { - if (! strncmp (name, "http://", 7)) + if (!strncmp(name, "http://", 7)) return name + 7; - if (! strncmp (name, "https://", 8)) + if (!strncmp(name, "https://", 8)) return name + 8; - if (! strncmp (name, "mms://", 6)) + if (!strncmp(name, "mms://", 6)) return name + 6; return nullptr; } -static StringBuf extract_domain (const char * start) +static StringBuf extract_domain(const char * start) { - StringBuf name = str_copy (start); + StringBuf name = str_copy(start); char * c; - if ((c = strchr (name, '/'))) - name.resize (c - name); - if ((c = strchr (name, ':'))) - name.resize (c - name); - if ((c = strchr (name, '?'))) - name.resize (c - name); + if ((c = strchr(name, '/'))) + name.resize(c - name); + if ((c = strchr(name, ':'))) + name.resize(c - name); + if ((c = strchr(name, '?'))) + name.resize(c - name); return name; } -EXPORT void Tuple::generate_fallbacks () +EXPORT void Tuple::generate_fallbacks() { - if (! data) + if (!data) return; - generate_title (); + generate_title(); - auto artist = get_str (Artist); - auto album = get_str (Album); + auto artist = get_str(Artist); + auto album = get_str(Album); if (artist && album) return; - data = TupleData::copy_on_write (data); + data = TupleData::copy_on_write(data); // use album artist, if present - if (! artist && (artist = get_str (AlbumArtist))) + if (!artist && (artist = get_str(AlbumArtist))) { - data->set_str (FallbackArtist, artist); + data->set_str(FallbackArtist, artist); if (album) return; // nothing left to do } - auto filepath = get_str (Path); - if (! filepath) + auto filepath = get_str(Path); + if (!filepath) return; const char * s; char sep; - if (! strcmp (filepath, "cdda://")) + if (!strcmp(filepath, "cdda://")) { // audio CD: // use "Audio CD" as the album - if (! album) - data->set_str (FallbackAlbum, _("Audio CD")); + if (!album) + data->set_str(FallbackAlbum, _("Audio CD")); } - else if ((s = find_domain (filepath))) + else if ((s = find_domain(filepath))) { // internet URL: // use the domain name as the album - if (! album) - data->set_str (FallbackAlbum, extract_domain (s)); + if (!album) + data->set_str(FallbackAlbum, extract_domain(s)); } else { // any other URI: // use the top two path elements as the artist and album - if ((s = strstr (filepath, "://"))) + if ((s = strstr(filepath, "://"))) { s += 3; sep = '/'; @@ -788,7 +797,7 @@ EXPORT void Tuple::generate_fallbacks () else { #ifdef _WIN32 - if (g_ascii_isalpha (filepath[0]) && filepath[1] == ':') + if (g_ascii_isalpha(filepath[0]) && filepath[1] == ':') s = filepath + 2; else #endif @@ -797,72 +806,75 @@ EXPORT void Tuple::generate_fallbacks () sep = G_DIR_SEPARATOR; } - StringBuf buf = str_copy (s); + StringBuf buf = str_copy(s); - char * first = split_folder (buf, sep); - char * second = (first && first > buf) ? split_folder (buf, sep) : nullptr; + char * first = split_folder(buf, sep); + char * second = + (first && first > buf) ? split_folder(buf, sep) : nullptr; // skip common strings and avoid duplicates - for (auto skip : (const char *[]) {"~", "music", artist, album, get_str (Genre)}) + for (auto skip : + (const char *[]){"~", "music", artist, album, get_str(Genre)}) { - if (first && skip && ! strcmp_nocase (first, skip)) + if (first && skip && !strcmp_nocase(first, skip)) { first = second; second = nullptr; } - if (second && skip && ! strcmp_nocase (second, skip)) + if (second && skip && !strcmp_nocase(second, skip)) second = nullptr; } if (first) { - if (second && ! artist && ! album) + if (second && !artist && !album) { - data->set_str (FallbackArtist, second); - data->set_str (FallbackAlbum, first); + data->set_str(FallbackArtist, second); + data->set_str(FallbackAlbum, first); } else - data->set_str (artist ? FallbackAlbum : FallbackArtist, first); + data->set_str(artist ? FallbackAlbum : FallbackArtist, first); } } } -EXPORT void Tuple::generate_title () +EXPORT void Tuple::generate_title() { - if (! data) + if (!data) return; - auto title = get_str (Title); + auto title = get_str(Title); if (title) return; - data = TupleData::copy_on_write (data); + data = TupleData::copy_on_write(data); - auto filepath = get_str (Path); - if (filepath && ! strcmp (filepath, "cdda://")) + auto filepath = get_str(Path); + if (filepath && !strcmp(filepath, "cdda://")) { // audio CD: // use "Track N" as the title - int subtune = get_int (Subtune); + int subtune = get_int(Subtune); if (subtune >= 0) - data->set_str (FallbackTitle, str_printf (_("Track %d"), subtune)); + data->set_str(FallbackTitle, str_printf(_("Track %d"), subtune)); } else { - auto filename = get_str (Basename); - data->set_str (FallbackTitle, filename ? (const char *) filename : _("(unknown title)")); + auto filename = get_str(Basename); + data->set_str(FallbackTitle, + filename ? (const char *)filename : _("(unknown title)")); } } -EXPORT void Tuple::delete_fallbacks () +EXPORT void Tuple::delete_fallbacks() { - if (! data) + if (!data) return; - data = TupleData::copy_on_write (data); - data->lookup (FallbackTitle, false, true); - data->lookup (FallbackArtist, false, true); - data->lookup (FallbackAlbum, false, true); + data = TupleData::copy_on_write(data); + data->lookup(FallbackTitle, false, true); + data->lookup(FallbackArtist, false, true); + data->lookup(FallbackAlbum, false, true); } diff --git a/src/libaudcore/tuple.h b/src/libaudcore/tuple.h index b7766d6..0ec1ac1 100644 --- a/src/libaudcore/tuple.h +++ b/src/libaudcore/tuple.h @@ -1,6 +1,6 @@ /* * tuple.h - * Copyright 2007-2013 William Pitcock, Christian Birchinger, Matti Hämäläinen, + * Copyright 2007-2013 Ariadne Conill, Christian Birchinger, Matti Hämäläinen, * Giacomo Lozito, Eugene Zagidullin, and John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -39,55 +39,58 @@ public: /* Smart pointer to the actual TupleData struct. * Uses create-on-write and copy-on-write. */ - enum State { - Initial, /* Song info has not yet been read */ - Valid, /* Song info has been successfully read */ - Failed /* Song info could not be read */ + enum State + { + Initial, /* Song info has not yet been read */ + Valid, /* Song info has been successfully read */ + Failed /* Song info could not be read */ }; - enum Field { + enum Field + { Invalid = -1, - Title = 0, /* Song title */ - Artist, /* Song artist */ - Album, /* Album name */ - AlbumArtist, /* Artist for entire album, if different than song artist */ - Comment, /* Freeform comment */ - Genre, /* Song's genre */ - Year, /* Year of production, performance, etc. */ - - Composer, /* Composer, if different than artist */ - Performer, /* Performer, if different than artist */ - Copyright, /* Copyright declaration */ - Date, /* Date of production, performance, etc. */ - - Track, /* Track number */ - Length, /* Track length in milliseconds */ - - Bitrate, /* Bitrate in kilobits (1000 bits)/sec */ - Codec, /* Codec name, such as "Ogg Vorbis" */ - Quality, /* String representing quality, such as "Stereo, 44 kHz" */ - - Basename, /* Base filename, not including the folder path */ - Path, /* Folder path, including the trailing "/" */ - Suffix, /* Filename extension, not including the "." */ - - AudioFile, /* URI of audio file, if different from the nominal URI - * (e.g. for a cuesheet entry, where the nominal URI - * points to the .cue file) */ - - Subtune, /* Index number of subtune */ - NumSubtunes, /* Total number of subtunes in the file */ - - StartTime, /* Playback start point (used for cuesheets) */ - EndTime, /* Playback end point (used for cuesheets) */ - - /* Preserving replay gain information accurately is a challenge since there - * are several differents formats around. We use an integer fraction, with - * the denominator stored in the *Divisor fields. For example, if AlbumGain - * is 512 and GainDivisor is 256, then the album gain is +2 dB. If TrackPeak - * is 787 and PeakDivisor is 1000, then the peak volume is 0.787 in a -1.0 to - * 1.0 range. */ + Title = 0, /* Song title */ + Artist, /* Song artist */ + Album, /* Album name */ + AlbumArtist, /* Artist for entire album, if different than song artist + */ + Comment, /* Freeform comment */ + Genre, /* Song's genre */ + Year, /* Year of production, performance, etc. */ + + Composer, /* Composer, if different than artist */ + Performer, /* Performer, if different than artist */ + Copyright, /* Copyright declaration */ + Date, /* Date of production, performance, etc. */ + + Track, /* Track number */ + Length, /* Track length in milliseconds */ + + Bitrate, /* Bitrate in kilobits (1000 bits)/sec */ + Codec, /* Codec name, such as "Ogg Vorbis" */ + Quality, /* String representing quality, such as "Stereo, 44 kHz" */ + + Basename, /* Base filename, not including the folder path */ + Path, /* Folder path, including the trailing "/" */ + Suffix, /* Filename extension, not including the "." */ + + AudioFile, /* URI of audio file, if different from the nominal URI + * (e.g. for a cuesheet entry, where the nominal URI + * points to the .cue file) */ + + Subtune, /* Index number of subtune */ + NumSubtunes, /* Total number of subtunes in the file */ + + StartTime, /* Playback start point (used for cuesheets) */ + EndTime, /* Playback end point (used for cuesheets) */ + + /* Preserving replay gain information accurately is a challenge since + * there are several differents formats around. We use an integer + * fraction, with the denominator stored in the *Divisor fields. For + * example, if AlbumGain is 512 and GainDivisor is 256, then the album + * gain is +2 dB. If TrackPeak is 787 and PeakDivisor is 1000, then the + * peak volume is 0.787 in a -1.0 to 1.0 range. */ AlbumGain, AlbumPeak, TrackGain, @@ -95,79 +98,80 @@ public: GainDivisor, PeakDivisor, - /* Title formatted for display; input plugins do not need to set this field */ + /* Title formatted for display; input plugins do not need to set this + field */ FormattedTitle, + /* TODO: reorder these at next ABI break! */ + Description, /* Track description */ + MusicBrainzID, /* MusicBrainz identifier */ + n_fields }; - typedef aud::range all_fields; + typedef aud::range all_fields; - enum ValueType { + enum ValueType + { String, Int, Empty }; - static Field field_by_name (const char * name); - static const char * field_get_name (Field field); - static ValueType field_get_type (Field field); + static Field field_by_name(const char * name); + static const char * field_get_name(Field field); + static ValueType field_get_type(Field field); + + constexpr Tuple() : data(nullptr) {} - constexpr Tuple () : - data (nullptr) {} + ~Tuple(); - ~Tuple (); + Tuple(Tuple && b) : data(b.data) { b.data = nullptr; } - Tuple (Tuple && b) : - data (b.data) + Tuple & operator=(Tuple && b) { - b.data = nullptr; + return aud::move_assign(*this, std::move(b)); } - Tuple & operator= (Tuple && b) - { return aud::move_assign (* this, std::move (b)); } - - bool operator== (const Tuple & b) const; - bool operator!= (const Tuple & b) const - { return ! operator== (b); } + bool operator==(const Tuple & b) const; + bool operator!=(const Tuple & b) const { return !operator==(b); } - Tuple ref () const; + Tuple ref() const; /* Gets/sets the state of the song info. Before setting the state to Valid, * you should ensure that, at a minimum, set_filename() has been called. */ - State state () const; - void set_state (State st); + State state() const; + void set_state(State st); /* Returns the value type of a field if set, otherwise Empty. */ - ValueType get_value_type (Field field) const; + ValueType get_value_type(Field field) const; /* Convenience functions */ - bool valid () const - { return state () == Valid; } - bool is_set (Field field) const - { return get_value_type (field) != Empty; } + bool valid() const { return state() == Valid; } + bool is_set(Field field) const { return get_value_type(field) != Empty; } /* Returns the integer value of a field if set, otherwise -1. If you need * to distinguish between a value of -1 and an unset value, use * get_value_type(). */ - int get_int (Field field) const; + int get_int(Field field) const; /* Returns the string value of a field if set, otherwise null. */ - ::String get_str (Field field) const; + ::String get_str(Field field) const; /* Sets a field to the integer value . */ - void set_int (Field field, int x); + void set_int(Field field, int x); /* Sets a field to the string value . If is not valid UTF-8, it * will be converted according to the user's character set detection rules. * Equivalent to unset() if is null. */ - void set_str (Field field, const char * str); + void set_str(Field field, const char * str); /* Clears any value that a field is currently set to. */ - void unset (Field field); + void unset(Field field); - /* Parses the URI and sets Basename, Path, Suffix, and Subtune accordingly. */ - void set_filename (const char * filename); + /* Parses the URI and sets Basename, Path, Suffix, and Subtune + * accordingly. */ + void set_filename(const char * filename); /* Fills in format-related fields (specifically Codec, Quality, * and Bitrate). Plugins should use this function instead of setting @@ -175,44 +179,45 @@ public: * formats. should be a brief description such as "Ogg Vorbis", * "MPEG-1 layer 3", "Audio CD", and so on. is in Hertz. * is in (decimal) kbps. */ - void set_format (const char * format, int channels, int samplerate, int bitrate); + void set_format(const char * format, int channels, int samplerate, + int bitrate); /* In addition to the normal fields, tuples contain an integer array of * subtune ID numbers. This function sets that array. It also sets * NumSubtunes to the value . */ - void set_subtunes (short n_subtunes, const short * subtunes); + void set_subtunes(short n_subtunes, const short * subtunes); /* Returns the length of the subtune array. If the array has not been set, * returns zero. Note that if NumSubtunes is changed after * set_subtunes() is called, this function returns the value * passed to set_subtunes(), not the value of NumSubtunes. */ - short get_n_subtunes () const; + short get_n_subtunes() const; /* Returns the th member of the subtune array. */ - short get_nth_subtune (short n) const; + short get_nth_subtune(short n) const; /* Sets a Replay Gain field pair from a decimal string. */ - void set_gain (Field field, Field unit_field, const char * str); + void set_gain(Field field, Field unit_field, const char * str); /* Returns true if minimal ReplayGainInfo is present. */ - bool has_replay_gain () const; + bool has_replay_gain() const; /* Fills ReplayGainInfo struct from various fields. */ - ReplayGainInfo get_replay_gain () const; + ReplayGainInfo get_replay_gain() const; /* Set various fields based on the ICY metadata of . Returns true * if any fields were changed. */ - bool fetch_stream_info (VFSFile & stream); + bool fetch_stream_info(VFSFile & stream); /* Guesses the song title, artist, and album, if not already set, from the * filename. */ - void generate_fallbacks (); + void generate_fallbacks(); /* Guesses only the song title, if not already set, from the filename. */ - void generate_title (); + void generate_title(); /* Removes guesses made by generate_fallbacks(). This function should be * called, for example, before writing a song tag from the tuple. */ - void delete_fallbacks (); + void delete_fallbacks(); private: TupleData * data; @@ -225,8 +230,7 @@ struct PlaylistAddItem Tuple tuple; PluginHandle * decoder; - PlaylistAddItem copy () const - { return {filename, tuple.ref (), decoder}; } + PlaylistAddItem copy() const { return {filename, tuple.ref(), decoder}; } }; #endif /* LIBAUDCORE_TUPLE_H */ diff --git a/src/libaudcore/util.cc b/src/libaudcore/util.cc index 4d92ded..96390c9 100644 --- a/src/libaudcore/util.cc +++ b/src/libaudcore/util.cc @@ -1,6 +1,6 @@ /* * util.c - * Copyright 2009-2013 John Lindgren and Michał Lipski + * Copyright 2009-2019 John Lindgren and Michał Lipski * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -18,9 +18,10 @@ */ #include "internal.h" +#include "visualizer.h" #include -#include +#include #include #include #include @@ -29,87 +30,91 @@ #include "audstrings.h" #include "runtime.h" +#include "threads.h" -const char * get_home_utf8 () +const char * get_home_utf8() { - static pthread_once_t once = PTHREAD_ONCE_INIT; + static std::once_flag once; static char * home_utf8; - auto init = [] () - { home_utf8 = g_filename_to_utf8 (g_get_home_dir (), -1, nullptr, nullptr, nullptr); }; + auto init = []() { + home_utf8 = + g_filename_to_utf8(g_get_home_dir(), -1, nullptr, nullptr, nullptr); + }; - pthread_once (& once, init); + std::call_once(once, init); return home_utf8; } -bool dir_foreach (const char * path, DirForeachFunc func, void * user) +bool dir_foreach(const char * path, DirForeachFunc func, void * user) { - GDir * dir = g_dir_open (path, 0, nullptr); - if (! dir) + GDir * dir = g_dir_open(path, 0, nullptr); + if (!dir) return false; const char * name; - while ((name = g_dir_read_name (dir))) + while ((name = g_dir_read_name(dir))) { - if (func (filename_build ({path, name}), name, user)) + if (func(filename_build({path, name}), name, user)) break; } - g_dir_close (dir); + g_dir_close(dir); return true; } -String write_temp_file (const void * data, int64_t len) +String write_temp_file(const void * data, int64_t len) { - StringBuf name = filename_build ({g_get_tmp_dir (), "audacious-temp-XXXXXX"}); + StringBuf name = filename_build({g_get_tmp_dir(), "audacious-temp-XXXXXX"}); - int handle = g_mkstemp (name); + int handle = g_mkstemp(name); if (handle < 0) { - AUDERR ("Error creating temporary file: %s\n", strerror (errno)); - return String (); + AUDERR("Error creating temporary file: %s\n", strerror(errno)); + return String(); } while (len) { - int64_t written = write (handle, data, len); + int64_t written = write(handle, data, len); if (written < 0) { - AUDERR ("Error writing %s: %s\n", (const char *) name, strerror (errno)); - close (handle); - return String (); + AUDERR("Error writing %s: %s\n", (const char *)name, + strerror(errno)); + close(handle); + return String(); } - data = (char *) data + written; + data = (char *)data + written; len -= written; } - if (close (handle) < 0) + if (close(handle) < 0) { - AUDERR ("Error closing %s: %s\n", (const char *) name, strerror (errno)); - return String (); + AUDERR("Error closing %s: %s\n", (const char *)name, strerror(errno)); + return String(); } - return String (name); + return String(name); } -bool same_basename (const char * a, const char * b) +bool same_basename(const char * a, const char * b) { - const char * dot_a = strrchr (a, '.'); - const char * dot_b = strrchr (b, '.'); - int len_a = dot_a ? dot_a - a : strlen (a); - int len_b = dot_b ? dot_b - b : strlen (b); + const char * dot_a = strrchr(a, '.'); + const char * dot_b = strrchr(b, '.'); + int len_a = dot_a ? dot_a - a : strlen(a); + int len_b = dot_b ? dot_b - b : strlen(b); - return len_a == len_b && ! strcmp_nocase (a, b, len_a); + return len_a == len_b && !strcmp_nocase(a, b, len_a); } -const char * last_path_element (const char * path) +const char * last_path_element(const char * path) { - const char * slash = strrchr (path, G_DIR_SEPARATOR); + const char * slash = strrchr(path, G_DIR_SEPARATOR); return (slash && slash[1]) ? slash + 1 : nullptr; } -void cut_path_element (char * path, int pos) +void cut_path_element(char * path, int pos) { #ifdef _WIN32 if (pos > 3) @@ -121,31 +126,32 @@ void cut_path_element (char * path, int pos) path[pos] = 0; /* leave [drive letter and] leading slash */ } -bool is_cuesheet_entry (const char * filename) +bool is_cuesheet_entry(const char * filename) { - const char * ext, * sub; - uri_parse (filename, nullptr, & ext, & sub, nullptr); - return sub[0] && sub - ext == 4 && ! strcmp_nocase (ext, ".cue", 4); + const char *ext, *sub; + uri_parse(filename, nullptr, &ext, &sub, nullptr); + return sub[0] && sub - ext == 4 && !strcmp_nocase(ext, ".cue", 4); } -bool is_subtune (const char * filename) +bool is_subtune(const char * filename) { const char * sub; - uri_parse (filename, nullptr, nullptr, & sub, nullptr); + uri_parse(filename, nullptr, nullptr, &sub, nullptr); return sub[0]; } -StringBuf strip_subtune (const char * filename) +StringBuf strip_subtune(const char * filename) { const char * sub; - uri_parse (filename, nullptr, nullptr, & sub, nullptr); - return str_copy (filename, sub - filename); + uri_parse(filename, nullptr, nullptr, &sub, nullptr); + return str_copy(filename, sub - filename); } /* Thomas Wang's 32-bit mix function. See: - * http://web.archive.org/web/20070307172248/http://www.concentric.net/~Ttwang/tech/inthash.htm */ + * http://web.archive.org/web/20070307172248/http://www.concentric.net/~Ttwang/tech/inthash.htm + */ -unsigned int32_hash (unsigned val) +unsigned int32_hash(unsigned val) { val = ~val + (val << 15); val = val ^ (val >> 12); @@ -156,9 +162,42 @@ unsigned int32_hash (unsigned val) return val; } -unsigned ptr_hash (const void * ptr) +unsigned ptr_hash(const void * ptr) +{ + unsigned addr_low = (uint64_t)(uintptr_t)ptr; + unsigned addr_high = (uint64_t)(uintptr_t)ptr >> 32; + return int32_hash(addr_low + addr_high); +} + +EXPORT void Visualizer::compute_log_xscale(float * xscale, int bands) +{ + for (int i = 0; i <= bands; i++) + xscale[i] = powf(256, (float)i / bands) - 0.5f; +} + +EXPORT float Visualizer::compute_freq_band(const float * freq, + const float * xscale, int band, + int bands) { - unsigned addr_low = (uint64_t) (uintptr_t) ptr; - unsigned addr_high = (uint64_t) (uintptr_t) ptr >> 32; - return int32_hash (addr_low + addr_high); + int a = ceilf(xscale[band]); + int b = floorf(xscale[band + 1]); + float n = 0; + + if (b < a) + n += freq[b] * (xscale[band + 1] - xscale[band]); + else + { + if (a > 0) + n += freq[a - 1] * (a - xscale[band]); + for (; a < b; a++) + n += freq[a]; + if (b < 256) + n += freq[b] * (xscale[band + 1] - b); + } + + /* fudge factor to make the graph have the same overall height as a + 12-band one no matter how many bands there are */ + n *= (float)bands / 12; + + return 20 * log10f(n); } diff --git a/src/libaudcore/vfs.cc b/src/libaudcore/vfs.cc index ccbd1aa..2005e54 100644 --- a/src/libaudcore/vfs.cc +++ b/src/libaudcore/vfs.cc @@ -1,6 +1,6 @@ /* * vfs.c - * Copyright 2006-2013 William Pitcock, Daniel Barkalow, Ralf Ertzinger, + * Copyright 2006-2013 Ariadne Conill, Daniel Barkalow, Ralf Ertzinger, * Yoshiki Yazawa, Matti Hämäläinen, and John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -37,24 +37,24 @@ static LocalTransport local_transport; static StdinTransport stdin_transport; -static TransportPlugin * lookup_transport (const char * filename, - String & error, bool * custom_input = nullptr) +static TransportPlugin * lookup_transport(const char * filename, String & error, + bool * custom_input = nullptr) { - StringBuf scheme = uri_get_scheme (filename); + StringBuf scheme = uri_get_scheme(filename); - if (! scheme || ! strcmp (scheme, "file")) - return & local_transport; - if (! strcmp (scheme, "stdin")) - return & stdin_transport; + if (!scheme || !strcmp(scheme, "file")) + return &local_transport; + if (!strcmp(scheme, "stdin")) + return &stdin_transport; - for (PluginHandle * plugin : aud_plugin_list (PluginType::Transport)) + for (PluginHandle * plugin : aud_plugin_list(PluginType::Transport)) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - if (transport_plugin_has_scheme (plugin, scheme)) + if (transport_plugin_has_scheme(plugin, scheme)) { - auto tp = (TransportPlugin *) aud_plugin_get_header (plugin); + auto tp = (TransportPlugin *)aud_plugin_get_header(plugin); if (tp) return tp; } @@ -62,21 +62,21 @@ static TransportPlugin * lookup_transport (const char * filename, if (custom_input) { - for (PluginHandle * plugin : aud_plugin_list (PluginType::Input)) + for (PluginHandle * plugin : aud_plugin_list(PluginType::Input)) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; - if (input_plugin_has_key (plugin, InputKey::Scheme, scheme)) + if (input_plugin_has_key(plugin, InputKey::Scheme, scheme)) { - * custom_input = true; + *custom_input = true; return nullptr; } } } - AUDERR ("Unknown URI scheme: %s://\n", (const char *) scheme); - error = String (_("Unknown URI scheme")); + AUDERR("Unknown URI scheme: %s://\n", (const char *)scheme); + error = String(_("Unknown URI scheme")); return nullptr; } @@ -88,29 +88,29 @@ static TransportPlugin * lookup_transport (const char * filename, * @param mode The preferred access privileges (not guaranteed). * @return On success, a #VFSFile object representing the stream. */ -EXPORT VFSFile::VFSFile (const char * filename, const char * mode) +EXPORT VFSFile::VFSFile(const char * filename, const char * mode) { - auto tp = lookup_transport (filename, m_error); - if (! tp) + auto tp = lookup_transport(filename, m_error); + if (!tp) return; - VFSImpl * impl = tp->fopen (strip_subtune (filename), mode, m_error); - if (! impl) + VFSImpl * impl = tp->fopen(strip_subtune(filename), mode, m_error); + if (!impl) return; /* enable buffering for read-only handles */ - if (mode[0] == 'r' && ! strchr (mode, '+')) - impl = new ProbeBuffer (filename, impl); + if (mode[0] == 'r' && !strchr(mode, '+')) + impl = new ProbeBuffer(filename, impl); - AUDINFO ("<%p> open (mode %s) %s\n", impl, mode, filename); - m_filename = String (filename); - m_impl.capture (impl); + AUDINFO("<%p> open (mode %s) %s\n", impl, mode, filename); + m_filename = String(filename); + m_impl.capture(impl); } -EXPORT VFSFile VFSFile::tmpfile () +EXPORT VFSFile VFSFile::tmpfile() { VFSFile file; - file.m_impl.capture (vfs_tmpfile (file.m_error)); + file.m_impl.capture(vfs_tmpfile(file.m_error)); return file; } @@ -123,12 +123,12 @@ EXPORT VFSFile VFSFile::tmpfile () * @param file #VFSFile object that represents the VFS stream. * @return The number of elements succesfully read. */ -EXPORT int64_t VFSFile::fread (void * ptr, int64_t size, int64_t nmemb) +EXPORT int64_t VFSFile::fread(void * ptr, int64_t size, int64_t nmemb) { - int64_t readed = m_impl->fread (ptr, size, nmemb); + int64_t readed = m_impl->fread(ptr, size, nmemb); - AUDDBG ("<%p> read %" PRId64 " elements of size %" PRId64 " = %" PRId64 "\n", - m_impl.get (), nmemb, size, readed); + AUDDBG("<%p> read %" PRId64 " elements of size %" PRId64 " = %" PRId64 "\n", + m_impl.get(), nmemb, size, readed); return readed; } @@ -142,12 +142,13 @@ EXPORT int64_t VFSFile::fread (void * ptr, int64_t size, int64_t nmemb) * @param file #VFSFile object that represents the VFS stream. * @return The number of elements succesfully written. */ -EXPORT int64_t VFSFile::fwrite (const void * ptr, int64_t size, int64_t nmemb) +EXPORT int64_t VFSFile::fwrite(const void * ptr, int64_t size, int64_t nmemb) { - int64_t written = m_impl->fwrite (ptr, size, nmemb); + int64_t written = m_impl->fwrite(ptr, size, nmemb); - AUDDBG ("<%p> write %" PRId64 " elements of size %" PRId64 " = %" PRId64 "\n", - m_impl.get (), nmemb, size, written); + AUDDBG("<%p> write %" PRId64 " elements of size %" PRId64 " = %" PRId64 + "\n", + m_impl.get(), nmemb, size, written); return written; } @@ -165,16 +166,19 @@ EXPORT int64_t VFSFile::fwrite (const void * ptr, int64_t size, int64_t nmemb) * @param whence Type of the seek: SEEK_CUR, SEEK_SET or SEEK_END. * @return On success, 0. Otherwise, -1. */ -EXPORT int VFSFile::fseek (int64_t offset, VFSSeekType whence) +EXPORT int VFSFile::fseek(int64_t offset, VFSSeekType whence) { - AUDDBG ("<%p> seek to %" PRId64 " from %s\n", m_impl.get (), offset, - whence == VFS_SEEK_CUR ? "current" : whence == VFS_SEEK_SET ? "beginning" : - whence == VFS_SEEK_END ? "end" : "invalid"); - - if (m_impl->fseek (offset, whence) == 0) + AUDDBG("<%p> seek to %" PRId64 " from %s\n", m_impl.get(), offset, + whence == VFS_SEEK_CUR + ? "current" + : whence == VFS_SEEK_SET + ? "beginning" + : whence == VFS_SEEK_END ? "end" : "invalid"); + + if (m_impl->fseek(offset, whence) == 0) return 0; - AUDDBG ("<%p> seek failed!\n", m_impl.get ()); + AUDDBG("<%p> seek failed!\n", m_impl.get()); return -1; } @@ -185,11 +189,11 @@ EXPORT int VFSFile::fseek (int64_t offset, VFSSeekType whence) * @param file #VFSFile object that represents the VFS stream. * @return On success, the current position. Otherwise, -1. */ -EXPORT int64_t VFSFile::ftell () +EXPORT int64_t VFSFile::ftell() { - int64_t told = m_impl->ftell (); + int64_t told = m_impl->ftell(); - AUDDBG ("<%p> tell = %" PRId64 "\n", m_impl.get (), told); + AUDDBG("<%p> tell = %" PRId64 "\n", m_impl.get(), told); return told; } @@ -198,13 +202,14 @@ EXPORT int64_t VFSFile::ftell () * Returns whether or not the VFS stream has reached EOF. * * @param file #VFSFile object that represents the VFS stream. - * @return On success, whether or not the VFS stream is at EOF. Otherwise, false. + * @return On success, whether or not the VFS stream is at EOF. Otherwise, + * false. */ -EXPORT bool VFSFile::feof () +EXPORT bool VFSFile::feof() { - bool eof = m_impl->feof (); + bool eof = m_impl->feof(); - AUDDBG ("<%p> eof = %s\n", m_impl.get (), eof ? "yes" : "no"); + AUDDBG("<%p> eof = %s\n", m_impl.get(), eof ? "yes" : "no"); return eof; } @@ -216,26 +221,26 @@ EXPORT bool VFSFile::feof () * @param length The length to truncate at. * @return On success, 0. Otherwise, -1. */ -EXPORT int VFSFile::ftruncate (int64_t length) +EXPORT int VFSFile::ftruncate(int64_t length) { - AUDDBG ("<%p> truncate to %" PRId64 "\n", m_impl.get (), length); + AUDDBG("<%p> truncate to %" PRId64 "\n", m_impl.get(), length); - if (m_impl->ftruncate (length) == 0) + if (m_impl->ftruncate(length) == 0) return 0; - AUDDBG ("<%p> truncate failed!\n", m_impl.get ()); + AUDDBG("<%p> truncate failed!\n", m_impl.get()); return -1; } -EXPORT int VFSFile::fflush () +EXPORT int VFSFile::fflush() { - AUDDBG ("<%p> flush\n", m_impl.get ()); + AUDDBG("<%p> flush\n", m_impl.get()); - if (m_impl->fflush () == 0) + if (m_impl->fflush() == 0) return 0; - AUDDBG ("<%p> flush failed!\n", m_impl.get ()); + AUDDBG("<%p> flush failed!\n", m_impl.get()); return -1; } @@ -246,11 +251,11 @@ EXPORT int VFSFile::fflush () * @param file #VFSFile object that represents the VFS stream. * @return On success, the size of the file in bytes. Otherwise, -1. */ -EXPORT int64_t VFSFile::fsize () +EXPORT int64_t VFSFile::fsize() { - int64_t size = m_impl->fsize (); + int64_t size = m_impl->fsize(); - AUDDBG ("<%p> size = %" PRId64 "\n", m_impl.get (), size); + AUDDBG("<%p> size = %" PRId64 "\n", m_impl.get(), size); return size; } @@ -262,76 +267,76 @@ EXPORT int64_t VFSFile::fsize () * @param field The string constant field name to get. * @return On success, a copy of the value of the field. Otherwise, nullptr. */ -EXPORT String VFSFile::get_metadata (const char * field) +EXPORT String VFSFile::get_metadata(const char * field) { - return m_impl->get_metadata (field); + return m_impl->get_metadata(field); } -EXPORT void VFSFile::set_limit_to_buffer (bool limit) +EXPORT void VFSFile::set_limit_to_buffer(bool limit) { - auto buffer = dynamic_cast (m_impl.get ()); + auto buffer = dynamic_cast(m_impl.get()); if (buffer) - buffer->set_limit_to_buffer (limit); + buffer->set_limit_to_buffer(limit); else - AUDERR ("<%p> buffering not supported!\n", m_impl.get ()); + AUDERR("<%p> buffering not supported!\n", m_impl.get()); } -EXPORT Index VFSFile::read_all () +EXPORT Index VFSFile::read_all() { constexpr int maxbuf = 16777216; constexpr int pagesize = 4096; Index buf; - int64_t size = fsize (); - int64_t pos = ftell (); + int64_t size = fsize(); + int64_t pos = ftell(); if (size >= 0 && pos >= 0 && pos <= size) { - buf.insert (0, aud::min (size - pos, (int64_t) maxbuf)); - size = fread (buf.begin (), 1, buf.len ()); + buf.insert(0, aud::min(size - pos, (int64_t)maxbuf)); + size = fread(buf.begin(), 1, buf.len()); } else { size = 0; - buf.insert (0, pagesize); + buf.insert(0, pagesize); int64_t readsize; - while ((readsize = fread (& buf[size], 1, buf.len () - size))) + while ((readsize = fread(&buf[size], 1, buf.len() - size))) { size += readsize; - if (size == buf.len ()) + if (size == buf.len()) { - if (buf.len () > maxbuf - pagesize) + if (buf.len() > maxbuf - pagesize) break; - buf.insert (-1, pagesize); + buf.insert(-1, pagesize); } } } - buf.remove (size, -1); + buf.remove(size, -1); return buf; } -EXPORT bool VFSFile::copy_from (VFSFile & source, int64_t size) +EXPORT bool VFSFile::copy_from(VFSFile & source, int64_t size) { constexpr int bufsize = 65536; Index buf; - buf.resize (bufsize); + buf.resize(bufsize); while (size < 0 || size > 0) { int64_t to_read = (size > 0 && size < bufsize) ? size : bufsize; - int64_t readsize = source.fread (buf.begin (), 1, to_read); + int64_t readsize = source.fread(buf.begin(), 1, to_read); if (size > 0) size -= readsize; - if (fwrite (buf.begin (), 1, readsize) != readsize) + if (fwrite(buf.begin(), 1, readsize) != readsize) return false; if (readsize < to_read) @@ -340,80 +345,104 @@ EXPORT bool VFSFile::copy_from (VFSFile & source, int64_t size) /* if a fixed size was requested, return true only if all the data was read. * otherwise, return true only if the end of the source file was reached. */ - return size == 0 || (size < 0 && source.feof ()); + return size == 0 || (size < 0 && source.feof()); } -EXPORT bool VFSFile::replace_with (VFSFile & source) +EXPORT bool VFSFile::replace_with(VFSFile & source) { - if (source.fseek (0, VFS_SEEK_SET) < 0) + if (source.fseek(0, VFS_SEEK_SET) < 0) return false; - if (fseek (0, VFS_SEEK_SET) < 0) + if (fseek(0, VFS_SEEK_SET) < 0) return false; - if (ftruncate (0) < 0) + if (ftruncate(0) < 0) return false; - return copy_from (source, -1); + return copy_from(source, -1); } -EXPORT bool VFSFile::test_file (const char * filename, VFSFileTest test) +EXPORT bool VFSFile::test_file(const char * filename, VFSFileTest test) { - String error; /* discarded */ - return test_file (filename, test, error) == test; + String error; /* discarded */ + return test_file(filename, test, error) == test; } -EXPORT VFSFileTest VFSFile::test_file (const char * filename, VFSFileTest test, String & error) +EXPORT VFSFileTest VFSFile::test_file(const char * filename, VFSFileTest test, + String & error) { bool custom_input = false; - auto tp = lookup_transport (filename, error, & custom_input); + auto tp = lookup_transport(filename, error, &custom_input); /* for URI schemes handled by input plugins, return 0, indicating that we * have no way of testing file attributes */ if (custom_input) - return VFSFileTest (0); + return VFSFileTest(0); /* for unsupported URI schemes, return VFS_NO_ACCESS */ - if (! tp) - return VFSFileTest (test & VFS_NO_ACCESS); + if (!tp) + return VFSFileTest(test & VFS_NO_ACCESS); - return tp->test_file (strip_subtune (filename), test, error); + return tp->test_file(strip_subtune(filename), test, error); } -EXPORT Index VFSFile::read_folder (const char * filename, String & error) +EXPORT Index VFSFile::read_folder(const char * filename, String & error) { - auto tp = lookup_transport (filename, error); - return tp ? tp->read_folder (filename, error) : Index (); + auto tp = lookup_transport(filename, error); + return tp ? tp->read_folder(filename, error) : Index(); } -EXPORT Index VFSFile::read_file (const char * filename, VFSReadOptions options) +EXPORT Index VFSFile::read_file(const char * filename, + VFSReadOptions options) { Index text; - if (! (options & VFS_IGNORE_MISSING) || test_file (filename, VFS_EXISTS)) + if (!(options & VFS_IGNORE_MISSING) || test_file(filename, VFS_EXISTS)) { - VFSFile file (filename, "r"); + VFSFile file(filename, "r"); if (file) - text = file.read_all (); + text = file.read_all(); else - AUDERR ("Cannot open %s for reading: %s\n", filename, file.error ()); + AUDERR("Cannot open %s for reading: %s\n", filename, file.error()); } if ((options & VFS_APPEND_NULL)) - text.append (0); + text.append(0); return text; } -EXPORT bool VFSFile::write_file (const char * filename, const void * data, int64_t len) +EXPORT bool VFSFile::write_file(const char * filename, const void * data, + int64_t len) { bool written = false; - VFSFile file (filename, "w"); + VFSFile file(filename, "w"); if (file) - written = (file.fwrite (data, 1, len) == len && file.fflush () == 0); + written = (file.fwrite(data, 1, len) == len && file.fflush() == 0); else - AUDERR ("Cannot open %s for writing: %s\n", filename, file.error ()); + AUDERR("Cannot open %s for writing: %s\n", filename, file.error()); return written; } + +EXPORT Index VFSFile::supported_uri_schemes() +{ + Index schemes; + + schemes.append("file"); + schemes.append("stdin"); + + for (PluginHandle * plugin : aud_plugin_list(PluginType::Transport)) + { + if (!aud_plugin_get_enabled(plugin)) + continue; + + for (auto s : transport_plugin_get_schemes(plugin)) + schemes.append((const char *)s); + } + + schemes.append(nullptr); + + return schemes; +} diff --git a/src/libaudcore/vfs.h b/src/libaudcore/vfs.h index e7f9ecd..33c5a65 100644 --- a/src/libaudcore/vfs.h +++ b/src/libaudcore/vfs.h @@ -1,6 +1,6 @@ /* * vfs.h - * Copyright 2006-2013 William Pitcock, Daniel Barkalow, Ralf Ertzinger, + * Copyright 2006-2013 Ariadne Conill, Daniel Barkalow, Ralf Ertzinger, * Yoshiki Yazawa, Matti Hämäläinen, and John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -33,21 +33,24 @@ #include #include -enum VFSFileTest { - VFS_IS_REGULAR = (1 << 0), - VFS_IS_SYMLINK = (1 << 1), - VFS_IS_DIR = (1 << 2), +enum VFSFileTest +{ + VFS_IS_REGULAR = (1 << 0), + VFS_IS_SYMLINK = (1 << 1), + VFS_IS_DIR = (1 << 2), VFS_IS_EXECUTABLE = (1 << 3), - VFS_EXISTS = (1 << 4), - VFS_NO_ACCESS = (1 << 5) + VFS_EXISTS = (1 << 4), + VFS_NO_ACCESS = (1 << 5) }; -enum VFSReadOptions { - VFS_APPEND_NULL = (1 << 0), +enum VFSReadOptions +{ + VFS_APPEND_NULL = (1 << 0), VFS_IGNORE_MISSING = (1 << 1) }; -enum VFSSeekType { +enum VFSSeekType +{ VFS_SEEK_SET = 0, VFS_SEEK_CUR = 1, VFS_SEEK_END = 2 @@ -57,18 +60,22 @@ enum VFSSeekType { #include -constexpr int from_vfs_seek_type (VFSSeekType whence) +constexpr int from_vfs_seek_type(VFSSeekType whence) { - return (whence == VFS_SEEK_SET) ? SEEK_SET : - (whence == VFS_SEEK_CUR) ? SEEK_CUR : - (whence == VFS_SEEK_END) ? SEEK_END : -1; + return (whence == VFS_SEEK_SET) + ? SEEK_SET + : (whence == VFS_SEEK_CUR) + ? SEEK_CUR + : (whence == VFS_SEEK_END) ? SEEK_END : -1; } -constexpr VFSSeekType to_vfs_seek_type (int whence) +constexpr VFSSeekType to_vfs_seek_type(int whence) { - return (whence == SEEK_SET) ? VFS_SEEK_SET : - (whence == SEEK_CUR) ? VFS_SEEK_CUR : - (whence == SEEK_END) ? VFS_SEEK_END : (VFSSeekType) -1; + return (whence == SEEK_SET) + ? VFS_SEEK_SET + : (whence == SEEK_CUR) + ? VFS_SEEK_CUR + : (whence == SEEK_END) ? VFS_SEEK_END : (VFSSeekType)-1; } #endif // WANT_VFS_STDIO_COMPAT @@ -86,91 +93,98 @@ constexpr VFSSeekType to_vfs_seek_type (int whence) class LIBAUDCORE_PUBLIC VFSImpl { public: - VFSImpl () {} - virtual ~VFSImpl () {} + VFSImpl() {} + virtual ~VFSImpl() {} - VFSImpl (const VFSImpl &) = delete; - VFSImpl & operator= (const VFSImpl &) = delete; + VFSImpl(const VFSImpl &) = delete; + VFSImpl & operator=(const VFSImpl &) = delete; - virtual int64_t fread (void * ptr, int64_t size, int64_t nmemb) = 0; - virtual int fseek (int64_t offset, VFSSeekType whence) = 0; + virtual int64_t fread(void * ptr, int64_t size, int64_t nmemb) = 0; + virtual int fseek(int64_t offset, VFSSeekType whence) = 0; - virtual int64_t ftell () = 0; - virtual int64_t fsize () = 0; - virtual bool feof () = 0; + virtual int64_t ftell() = 0; + virtual int64_t fsize() = 0; + virtual bool feof() = 0; - virtual int64_t fwrite (const void * ptr, int64_t size, int64_t nmemb) = 0; - virtual int ftruncate (int64_t length) = 0; - virtual int fflush () = 0; + virtual int64_t fwrite(const void * ptr, int64_t size, int64_t nmemb) = 0; + virtual int ftruncate(int64_t length) = 0; + virtual int fflush() = 0; - virtual String get_metadata (const char * field) { return String (); } + virtual String get_metadata(const char * field) { return String(); } }; class VFSFile { public: - VFSFile () {} + VFSFile() {} - VFSFile (const char * filename, VFSImpl * impl) : - m_filename (filename), - m_impl (impl) {} + VFSFile(const char * filename, VFSImpl * impl) + : m_filename(filename), m_impl(impl) + { + } - VFSFile (const char * filename, const char * mode); + VFSFile(const char * filename, const char * mode); /* creates a temporary file (deleted when closed) */ - static VFSFile tmpfile (); + static VFSFile tmpfile(); - explicit operator bool () const - { return (bool) m_impl; } - const char * filename () const - { return m_filename; } - const char * error () const - { return m_error; } + explicit operator bool() const { return (bool)m_impl; } + const char * filename() const { return m_filename; } + const char * error() const { return m_error; } /* basic operations */ - int64_t fread (void * ptr, int64_t size, int64_t nmemb) __attribute__ ((warn_unused_result)); - int fseek (int64_t offset, VFSSeekType whence) __attribute__ ((warn_unused_result)); + int64_t fread(void * ptr, int64_t size, int64_t nmemb) + __attribute__((warn_unused_result)); + int fseek(int64_t offset, VFSSeekType whence) + __attribute__((warn_unused_result)); - int64_t ftell (); - int64_t fsize (); - bool feof (); + int64_t ftell(); + int64_t fsize(); + bool feof(); - int64_t fwrite (const void * ptr, int64_t size, int64_t nmemb) __attribute__ ((warn_unused_result)); - int ftruncate (int64_t length) __attribute__ ((warn_unused_result)); - int fflush () __attribute__ ((warn_unused_result)); + int64_t fwrite(const void * ptr, int64_t size, int64_t nmemb) + __attribute__((warn_unused_result)); + int ftruncate(int64_t length) __attribute__((warn_unused_result)); + int fflush() __attribute__((warn_unused_result)); /* used to read e.g. ICY metadata */ - String get_metadata (const char * field); + String get_metadata(const char * field); /* the VFS layer buffers up to 256 KB of data at the beginning of files * opened in read-only mode; this function disallows reading outside the * buffered region (useful for probing the file type) */ - void set_limit_to_buffer (bool limit); + void set_limit_to_buffer(bool limit); /* utility functions */ /* reads the entire file into memory (limited to 16 MB) */ - Index read_all (); + Index read_all(); /* reads data from another open file and appends it to this one */ - bool copy_from (VFSFile & source, int64_t size = -1); + bool copy_from(VFSFile & source, int64_t size = -1); /* overwrites the entire file with the contents of another */ - bool replace_with (VFSFile & source); + bool replace_with(VFSFile & source); /* tests certain attributes of a file without opening it. * the 2-argument version returns true if all requested tests passed. - * the 3-argument version returns a bitmask indicating which tests passed. */ - static bool test_file (const char * filename, VFSFileTest test); - static VFSFileTest test_file (const char * filename, VFSFileTest test, String & error); + * the 3-argument version returns a bitmask indicating which tests passed. + */ + static bool test_file(const char * filename, VFSFileTest test); + static VFSFileTest test_file(const char * filename, VFSFileTest test, + String & error); /* returns a sorted list of folder entries (as full URIs) */ - static Index read_folder (const char * filename, String & error); + static Index read_folder(const char * filename, String & error); /* convenience functions to read/write entire files */ - static Index read_file (const char * filename, VFSReadOptions options); - static bool write_file (const char * filename, const void * data, int64_t len); + static Index read_file(const char * filename, VFSReadOptions options); + static bool write_file(const char * filename, const void * data, + int64_t len); + + /* returns a list of supported URI schemes */ + static Index supported_uri_schemes(); private: String m_filename, m_error; diff --git a/src/libaudcore/vfs_async.cc b/src/libaudcore/vfs_async.cc index 8939236..3c22910 100644 --- a/src/libaudcore/vfs_async.cc +++ b/src/libaudcore/vfs_async.cc @@ -1,6 +1,6 @@ /* * vfs_async.cc - * Copyright 2010-2014 William Pitcock and John Lindgren + * Copyright 2010-2014 Ariadne Conill and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -17,75 +17,77 @@ * the use of this software. */ -#include - +#include "vfs_async.h" #include "list.h" #include "mainloop.h" +#include "threads.h" #include "vfs.h" -#include "vfs_async.h" struct QueuedData : public ListNode { const String filename; - const VFSConsumer cons_f; - void * const user; - - pthread_t thread; + const VFSConsumer2 cons_f; + std::thread thread; Index buf; - QueuedData (const char * filename, VFSConsumer cons_f, void * user) : - filename (filename), - cons_f (cons_f), - user (user) {} + QueuedData(const char * filename, VFSConsumer2 cons_f) + : filename(filename), cons_f(cons_f) + { + } }; static QueuedFunc queued_func; static List queue; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; -static void send_data (void *) +static void send_data(void *) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); QueuedData * data; - while ((data = queue.head ())) + while ((data = queue.head())) { - queue.remove (data); + queue.remove(data); - pthread_mutex_unlock (& mutex); + mh.unlock(); - pthread_join (data->thread, nullptr); - data->cons_f (data->filename, data->buf, data->user); + data->thread.join(); + data->cons_f(data->filename, data->buf); delete data; - pthread_mutex_lock (& mutex); + mh.lock(); } - - pthread_mutex_unlock (& mutex); } -static void * read_worker (void * data0) +static void read_worker(QueuedData * data) { - auto data = (QueuedData *) data0; - - VFSFile file (data->filename, "r"); + VFSFile file(data->filename, "r"); if (file) - data->buf = file.read_all (); + data->buf = file.read_all(); - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! queue.head ()) - queued_func.queue (send_data, nullptr); + if (!queue.head()) + queued_func.queue(send_data, nullptr); - queue.append (data); + queue.append(data); +} - pthread_mutex_unlock (& mutex); - return nullptr; +EXPORT void vfs_async_file_get_contents(const char * filename, + VFSConsumer2 cons_f) +{ + auto data = new QueuedData(filename, cons_f); + data->thread = std::thread(read_worker, data); } -EXPORT void vfs_async_file_get_contents (const char * filename, VFSConsumer cons_f, void * user) +EXPORT void vfs_async_file_get_contents(const char * filename, + VFSConsumer cons_f, void * user) { - auto data = new QueuedData (filename, cons_f, user); - pthread_create (& data->thread, nullptr, read_worker, data); + auto functor = [cons_f, user](const char * filename, + const Index & buf) { + cons_f(filename, buf, user); + }; + + vfs_async_file_get_contents(filename, functor); } diff --git a/src/libaudcore/vfs_async.h b/src/libaudcore/vfs_async.h index b77f88b..5969555 100644 --- a/src/libaudcore/vfs_async.h +++ b/src/libaudcore/vfs_async.h @@ -1,6 +1,6 @@ /* * vfs_async.c - * Copyright 2010 William Pitcock + * Copyright 2010 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,10 +20,17 @@ #ifndef LIBAUDCORE_VFS_ASYNC_H #define LIBAUDCORE_VFS_ASYNC_H +#include #include -typedef void (* VFSConsumer) (const char * filename, const Index & buf, void * user); +using VFSConsumer2 = + std::function & buf)>; +void vfs_async_file_get_contents(const char * filename, VFSConsumer2 cons_f); -void vfs_async_file_get_contents (const char * filename, VFSConsumer cons_f, void * user); +/* old version -- remove this at next hard API break */ +typedef void (*VFSConsumer)(const char * filename, const Index & buf, + void * user); +void vfs_async_file_get_contents(const char * filename, VFSConsumer cons_f, + void * user); #endif diff --git a/src/libaudcore/vfs_local.cc b/src/libaudcore/vfs_local.cc index 7af685f..d21d3c0 100644 --- a/src/libaudcore/vfs_local.cc +++ b/src/libaudcore/vfs_local.cc @@ -36,9 +36,10 @@ #define ftello ftello64 #endif -#define perror(s) AUDERR ("%s: %s\n", (const char *) (s), strerror (errno)) +#define perror(s) AUDERR("%s: %s\n", (const char *)(s), strerror(errno)) -enum LocalOp { +enum LocalOp +{ OP_NONE, OP_READ, OP_WRITE @@ -47,26 +48,25 @@ enum LocalOp { class LocalFile : public VFSImpl { public: - LocalFile (const char * path, FILE * stream) : - m_path (path), - m_stream (stream), - m_cached_pos (0), - m_cached_size (-1), - m_last_op (OP_NONE) {} + LocalFile(const char * path, FILE * stream) + : m_path(path), m_stream(stream), m_cached_pos(0), m_cached_size(-1), + m_last_op(OP_NONE) + { + } - ~LocalFile (); + ~LocalFile(); protected: - int64_t fread (void * ptr, int64_t size, int64_t nmemb); - int fseek (int64_t offset, VFSSeekType whence); + int64_t fread(void * ptr, int64_t size, int64_t nmemb); + int fseek(int64_t offset, VFSSeekType whence); - int64_t ftell (); - int64_t fsize (); - bool feof (); + int64_t ftell(); + int64_t fsize(); + bool feof(); - int64_t fwrite (const void * ptr, int64_t size, int64_t nmemb); - int ftruncate (int64_t length); - int fflush (); + int64_t fwrite(const void * ptr, int64_t size, int64_t nmemb); + int ftruncate(int64_t length); + int fflush(); private: String m_path; @@ -76,31 +76,32 @@ private: LocalOp m_last_op; }; -VFSImpl * LocalTransport::fopen (const char * uri, const char * mode, String & error) +VFSImpl * LocalTransport::fopen(const char * uri, const char * mode, + String & error) { - StringBuf path = uri_to_filename (uri); + StringBuf path = uri_to_filename(uri); - if (! path) + if (!path) { - error = String (_("Invalid file name")); + error = String(_("Invalid file name")); return nullptr; } const char * suffix = ""; #ifdef _WIN32 - if (! strchr (mode, 'b')) /* binary mode (Windows) */ + if (!strchr(mode, 'b')) /* binary mode (Windows) */ suffix = "b"; #else - if (! strchr (mode, 'e')) /* close on exec (POSIX) */ + if (!strchr(mode, 'e')) /* close on exec (POSIX) */ suffix = "e"; #endif - StringBuf mode2 = str_concat ({mode, suffix}); + StringBuf mode2 = str_concat({mode, suffix}); - FILE * stream = ::g_fopen (path, mode2); + FILE * stream = ::g_fopen(path, mode2); - if (! stream) + if (!stream) { int errsave = errno; @@ -109,73 +110,74 @@ VFSImpl * LocalTransport::fopen (const char * uri, const char * mode, String & e * 2) UTF-8 filesystem mounted on legacy system */ if (errsave == ENOENT) { - StringBuf path2 = uri_to_filename (uri, false); - if (path2 && strcmp (path, path2)) - stream = ::g_fopen (path2, mode2); + StringBuf path2 = uri_to_filename(uri, false); + if (path2 && strcmp(path, path2)) + stream = ::g_fopen(path2, mode2); } - if (! stream) + if (!stream) { - perror (path); - error = String (strerror (errsave)); + perror(path); + error = String(strerror(errsave)); return nullptr; } } - return new LocalFile (path, stream); + return new LocalFile(path, stream); } -VFSImpl * StdinTransport::fopen (const char * uri, const char * mode, String & error) +VFSImpl * StdinTransport::fopen(const char * uri, const char * mode, + String & error) { - if (mode[0] != 'r' || strchr (mode, '+')) + if (mode[0] != 'r' || strchr(mode, '+')) { - error = String (_("Invalid access mode")); + error = String(_("Invalid access mode")); return nullptr; } - return new LocalFile ("(stdin)", stdin); + return new LocalFile("(stdin)", stdin); } -VFSImpl * vfs_tmpfile (String & error) +VFSImpl * vfs_tmpfile(String & error) { - FILE * stream = tmpfile (); + FILE * stream = tmpfile(); - if (! stream) + if (!stream) { int errsave = errno; - perror ("(tmpfile)"); - error = String (strerror (errsave)); + perror("(tmpfile)"); + error = String(strerror(errsave)); return nullptr; } - return new LocalFile ("(tmpfile)", stream); + return new LocalFile("(tmpfile)", stream); } -LocalFile::~LocalFile () +LocalFile::~LocalFile() { // do not close stdin - if (m_stream != stdin && fclose (m_stream) < 0) - perror (m_path); + if (m_stream != stdin && fclose(m_stream) < 0) + perror(m_path); } -int64_t LocalFile::fread (void * ptr, int64_t size, int64_t nitems) +int64_t LocalFile::fread(void * ptr, int64_t size, int64_t nitems) { if (m_last_op == OP_WRITE) { - if (::fflush (m_stream) < 0) + if (::fflush(m_stream) < 0) { - perror (m_path); + perror(m_path); return 0; } } m_last_op = OP_READ; - clearerr (m_stream); + clearerr(m_stream); - int64_t result = ::fread (ptr, size, nitems, m_stream); - if (result < nitems && ferror (m_stream)) - perror (m_path); + int64_t result = ::fread(ptr, size, nitems, m_stream); + if (result < nitems && ferror(m_stream)) + perror(m_path); if (m_cached_pos >= 0) m_cached_pos += size * result; @@ -183,41 +185,41 @@ int64_t LocalFile::fread (void * ptr, int64_t size, int64_t nitems) return result; } -int64_t LocalFile::fwrite (const void * ptr, int64_t size, int64_t nitems) +int64_t LocalFile::fwrite(const void * ptr, int64_t size, int64_t nitems) { if (m_last_op == OP_READ) { - if (::fflush (m_stream) < 0) + if (::fflush(m_stream) < 0) { - perror (m_path); + perror(m_path); return 0; } } m_last_op = OP_WRITE; - clearerr (m_stream); + clearerr(m_stream); - int64_t result = ::fwrite (ptr, size, nitems, m_stream); - if (result < nitems && ferror (m_stream)) - perror (m_path); + int64_t result = ::fwrite(ptr, size, nitems, m_stream); + if (result < nitems && ferror(m_stream)) + perror(m_path); if (m_cached_pos >= 0) m_cached_pos += size * result; if (m_cached_size >= 0 && m_cached_pos >= 0) - m_cached_size = aud::max (m_cached_size, m_cached_pos); + m_cached_size = aud::max(m_cached_size, m_cached_pos); else m_cached_size = -1; return result; } -int LocalFile::fseek (int64_t offset, VFSSeekType whence) +int LocalFile::fseek(int64_t offset, VFSSeekType whence) { - int result = fseeko (m_stream, offset, from_vfs_seek_type (whence)); + int result = fseeko(m_stream, offset, from_vfs_seek_type(whence)); if (result < 0) - perror (m_path); + perror(m_path); if (result == 0) { @@ -234,33 +236,30 @@ int LocalFile::fseek (int64_t offset, VFSSeekType whence) return result; } -int64_t LocalFile::ftell () +int64_t LocalFile::ftell() { if (m_cached_pos < 0) - m_cached_pos = ftello (m_stream); + m_cached_pos = ftello(m_stream); return m_cached_pos; } -bool LocalFile::feof () -{ - return ::feof (m_stream); -} +bool LocalFile::feof() { return ::feof(m_stream); } -int LocalFile::ftruncate (int64_t length) +int LocalFile::ftruncate(int64_t length) { if (m_last_op != OP_NONE) { - if (::fflush (m_stream) < 0) + if (::fflush(m_stream) < 0) { - perror (m_path); + perror(m_path); return -1; } } - int result = ::ftruncate (fileno (m_stream), length); + int result = ::ftruncate(fileno(m_stream), length); if (result < 0) - perror (m_path); + perror(m_path); if (result == 0) { @@ -271,14 +270,14 @@ int LocalFile::ftruncate (int64_t length) return result; } -int LocalFile::fflush () +int LocalFile::fflush() { if (m_last_op != OP_WRITE) return 0; - int result = ::fflush (m_stream); + int result = ::fflush(m_stream); if (result < 0) - perror (m_path); + perror(m_path); if (result == 0) m_last_op = OP_NONE; @@ -286,7 +285,7 @@ int LocalFile::fflush () return result; } -int64_t LocalFile::fsize () +int64_t LocalFile::fsize() { // size of stdin is unknown if (m_stream == stdin) @@ -294,21 +293,21 @@ int64_t LocalFile::fsize () if (m_cached_size < 0) { - int64_t saved_pos = ftell (); + int64_t saved_pos = ftell(); if (saved_pos < 0) goto ERR; - if (fseek (0, VFS_SEEK_END) < 0) + if (fseek(0, VFS_SEEK_END) < 0) goto ERR; m_last_op = OP_NONE; m_cached_pos = -1; - int64_t length = ftello (m_stream); + int64_t length = ftello(m_stream); if (length < 0) goto ERR; - if (fseek (saved_pos, VFS_SEEK_SET) < 0) + if (fseek(saved_pos, VFS_SEEK_SET) < 0) goto ERR; m_cached_pos = saved_pos; @@ -318,17 +317,18 @@ int64_t LocalFile::fsize () return m_cached_size; ERR: - perror (m_path); + perror(m_path); return -1; } -VFSFileTest LocalTransport::test_file (const char * uri, VFSFileTest test, String & error) +VFSFileTest LocalTransport::test_file(const char * uri, VFSFileTest test, + String & error) { - StringBuf path = uri_to_filename (uri); - if (! path) + StringBuf path = uri_to_filename(uri); + if (!path) { - error = String (_("Invalid file name")); - return VFSFileTest (test & VFS_NO_ACCESS); + error = String(_("Invalid file name")); + return VFSFileTest(test & VFS_NO_ACCESS); } int passed = 0; @@ -338,32 +338,33 @@ VFSFileTest LocalTransport::test_file (const char * uri, VFSFileTest test, Strin #ifdef S_ISLNK if (test & VFS_IS_SYMLINK) { - if (g_lstat (path, & st) < 0) + if (g_lstat(path, &st) < 0) { - error = String (strerror (errno)); + error = String(strerror(errno)); passed |= VFS_NO_ACCESS; goto out; } - if (S_ISLNK (st.st_mode)) + if (S_ISLNK(st.st_mode)) passed |= VFS_IS_SYMLINK; else need_stat = false; } #endif - if (test & (VFS_IS_REGULAR | VFS_IS_DIR | VFS_IS_EXECUTABLE | VFS_EXISTS | VFS_NO_ACCESS)) + if (test & (VFS_IS_REGULAR | VFS_IS_DIR | VFS_IS_EXECUTABLE | VFS_EXISTS | + VFS_NO_ACCESS)) { - if (need_stat && g_stat (path, & st) < 0) + if (need_stat && g_stat(path, &st) < 0) { - error = String (strerror (errno)); + error = String(strerror(errno)); passed |= VFS_NO_ACCESS; goto out; } - if (S_ISREG (st.st_mode)) + if (S_ISREG(st.st_mode)) passed |= VFS_IS_REGULAR; - if (S_ISDIR (st.st_mode)) + if (S_ISDIR(st.st_mode)) passed |= VFS_IS_DIR; if (st.st_mode & S_IXUSR) passed |= VFS_IS_EXECUTABLE; @@ -372,34 +373,34 @@ VFSFileTest LocalTransport::test_file (const char * uri, VFSFileTest test, Strin } out: - return VFSFileTest (test & passed); + return VFSFileTest(test & passed); } -Index LocalTransport::read_folder (const char * uri, String & error) +Index LocalTransport::read_folder(const char * uri, String & error) { Index entries; - StringBuf path = uri_to_filename (uri); - if (! path) + StringBuf path = uri_to_filename(uri); + if (!path) { - error = String (_("Invalid file name")); + error = String(_("Invalid file name")); return entries; } GError * gerr = nullptr; - GDir * folder = g_dir_open (path, 0, & gerr); - if (! folder) + GDir * folder = g_dir_open(path, 0, &gerr); + if (!folder) { - error = String (gerr->message); - g_error_free (gerr); + error = String(gerr->message); + g_error_free(gerr); return entries; } const char * name; - while ((name = g_dir_read_name (folder))) - entries.append (String (filename_to_uri (filename_build ({path, name})))); + while ((name = g_dir_read_name(folder))) + entries.append(String(filename_to_uri(filename_build({path, name})))); - g_dir_close (folder); + g_dir_close(folder); return entries; } diff --git a/src/libaudcore/vfs_local.h b/src/libaudcore/vfs_local.h index 071c0d9..e5a9a1c 100644 --- a/src/libaudcore/vfs_local.h +++ b/src/libaudcore/vfs_local.h @@ -25,21 +25,22 @@ class LocalTransport : public TransportPlugin { public: - constexpr LocalTransport () : TransportPlugin (PluginInfo (), nullptr) {} + constexpr LocalTransport() : TransportPlugin(PluginInfo(), nullptr) {} - VFSImpl * fopen (const char * filename, const char * mode, String & error); - VFSFileTest test_file (const char * filename, VFSFileTest test, String & error); - Index read_folder (const char * filename, String & error); + VFSImpl * fopen(const char * filename, const char * mode, String & error); + VFSFileTest test_file(const char * filename, VFSFileTest test, + String & error); + Index read_folder(const char * filename, String & error); }; class StdinTransport : public TransportPlugin { public: - constexpr StdinTransport () : TransportPlugin (PluginInfo (), nullptr) {} + constexpr StdinTransport() : TransportPlugin(PluginInfo(), nullptr) {} - VFSImpl * fopen (const char * filename, const char * mode, String & error); + VFSImpl * fopen(const char * filename, const char * mode, String & error); }; -VFSImpl * vfs_tmpfile (String & error); +VFSImpl * vfs_tmpfile(String & error); #endif /* LIBAUDCORE_VFS_LOCAL_H */ diff --git a/src/libaudcore/vis-runner.cc b/src/libaudcore/vis-runner.cc index 4f142ca..dde486a 100644 --- a/src/libaudcore/vis-runner.cc +++ b/src/libaudcore/vis-runner.cc @@ -20,7 +20,6 @@ #include "internal.h" #include -#include #include #include @@ -28,26 +27,27 @@ #include "list.h" #include "mainloop.h" #include "output.h" +#include "threads.h" #define INTERVAL 33 /* milliseconds */ #define FRAMES_PER_NODE 512 struct VisNode : public ListNode { - VisNode (int channels, int time) : - channels (channels), - time (time), - data (new float[channels * FRAMES_PER_NODE]) {} + VisNode(int channels, int time) + : channels(channels), time(time), + data(new float[channels * FRAMES_PER_NODE]) + { + } - ~VisNode () - { delete[] data; } + ~VisNode() { delete[] data; } const int channels; int time; float * data; }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static aud::mutex mutex; static bool enabled = false; static bool playing = false, paused = false; static VisNode * current_node = nullptr; @@ -56,23 +56,20 @@ static List vis_list; static List vis_pool; static QueuedFunc queued_clear; -static void send_audio (void *) +static void send_audio(void *) { /* call before locking mutex to avoid deadlock */ - int outputted = output_get_raw_time (); + int outputted = output_get_raw_time(); - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! enabled || ! playing || paused) - { - pthread_mutex_unlock (& mutex); + if (!enabled || !playing || paused) return; - } VisNode * node = nullptr; VisNode * next; - while ((next = vis_list.head ())) + while ((next = vis_list.head())) { /* If we are considering a node, stop searching and use it if it is the * most recent (that is, the next one is in the future). Otherwise, @@ -82,80 +79,72 @@ static void send_audio (void *) break; if (node) - vis_pool.prepend (node); + vis_pool.prepend(node); node = next; - vis_list.remove (node); + vis_list.remove(node); } - pthread_mutex_unlock (& mutex); - - if (! node) + if (!node) return; - vis_send_audio (node->data, node->channels); + mh.unlock(); + vis_send_audio(node->data, node->channels); + mh.lock(); - pthread_mutex_lock (& mutex); - vis_pool.prepend (node); - pthread_mutex_unlock (& mutex); + vis_pool.prepend(node); } -static void send_clear (void *) -{ - vis_send_clear (); -} +static void send_clear(void *) { vis_send_clear(); } -static void flush_locked () +static void flush(aud::mutex::holder &) { delete current_node; current_node = nullptr; - vis_list.clear (); - vis_pool.clear (); + vis_list.clear(); + vis_pool.clear(); if (enabled) - queued_clear.queue (send_clear, nullptr); + queued_clear.queue(send_clear, nullptr); } -void vis_runner_flush () +void vis_runner_flush() { - pthread_mutex_lock (& mutex); - flush_locked (); - pthread_mutex_unlock (& mutex); + auto mh = mutex.take(); + flush(mh); } -static void start_stop_locked (bool new_playing, bool new_paused) +static void start_stop(aud::mutex::holder & mh, bool new_playing, + bool new_paused) { playing = new_playing; paused = new_paused; - queued_clear.stop (); + queued_clear.stop(); - if (! enabled || ! playing) - flush_locked (); + if (!enabled || !playing) + flush(mh); - if (enabled && playing && ! paused) - timer_add (TimerRate::Hz30, send_audio); + if (enabled && playing && !paused) + timer_add(TimerRate::Hz30, send_audio); else - timer_remove (TimerRate::Hz30, send_audio); + timer_remove(TimerRate::Hz30, send_audio); } -void vis_runner_start_stop (bool new_playing, bool new_paused) +void vis_runner_start_stop(bool new_playing, bool new_paused) { - pthread_mutex_lock (& mutex); - start_stop_locked (new_playing, new_paused); - pthread_mutex_unlock (& mutex); + auto mh = mutex.take(); + start_stop(mh, new_playing, new_paused); } -void vis_runner_pass_audio (int time, const Index & data, int channels, int rate) +void vis_runner_pass_audio(int time, const Index & data, int channels, + int rate) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); - if (! enabled || ! playing) - { - pthread_mutex_unlock (& mutex); + if (!enabled || !playing) return; - } /* We can build a single node from multiple calls; we can also build * multiple nodes from the same call. If current_node is present, it was @@ -166,7 +155,7 @@ void vis_runner_pass_audio (int time, const Index & data, int channels, i while (1) { if (current_node) - assert (current_node->channels == channels); + assert(current_node->channels == channels); else { int node_time = time; @@ -178,27 +167,27 @@ void vis_runner_pass_audio (int time, const Index & data, int channels, i * queue, we are at the beginning of the song or had an underrun, * and we want to copy the earliest audio data we have. */ - VisNode * tail = vis_list.tail (); + VisNode * tail = vis_list.tail(); if (tail) node_time = tail->time + INTERVAL; - at = channels * (int) ((int64_t) (node_time - time) * rate / 1000); + at = channels * (int)((int64_t)(node_time - time) * rate / 1000); if (at < 0) at = 0; - if (at >= data.len ()) + if (at >= data.len()) break; - current_node = vis_pool.head (); + current_node = vis_pool.head(); if (current_node) { - assert (current_node->channels == channels); - vis_pool.remove (current_node); + assert(current_node->channels == channels); + vis_pool.remove(current_node); current_node->time = node_time; } else - current_node = new VisNode (channels, node_time); + current_node = new VisNode(channels, node_time); current_frames = 0; } @@ -208,24 +197,23 @@ void vis_runner_pass_audio (int time, const Index & data, int channels, i * wait for more data to be passed in the next call. If we do fill the * node, we loop and start building a new one. */ - int copy = aud::min (data.len () - at, channels * (FRAMES_PER_NODE - current_frames)); - memcpy (current_node->data + channels * current_frames, & data[at], sizeof (float) * copy); + int copy = aud::min(data.len() - at, + channels * (FRAMES_PER_NODE - current_frames)); + memcpy(current_node->data + channels * current_frames, &data[at], + sizeof(float) * copy); current_frames += copy / channels; if (current_frames < FRAMES_PER_NODE) break; - vis_list.append (current_node); + vis_list.append(current_node); current_node = nullptr; } - - pthread_mutex_unlock (& mutex); } -void vis_runner_enable (bool enable) +void vis_runner_enable(bool enable) { - pthread_mutex_lock (& mutex); + auto mh = mutex.take(); enabled = enable; - start_stop_locked (playing, paused); - pthread_mutex_unlock (& mutex); + start_stop(mh, playing, paused); } diff --git a/src/libaudcore/visualization.cc b/src/libaudcore/visualization.cc index 2f7a768..1122658 100644 --- a/src/libaudcore/visualization.cc +++ b/src/libaudcore/visualization.cc @@ -31,60 +31,58 @@ static Index visualizers; static int running = false; static int num_enabled = 0; -EXPORT void aud_visualizer_add (Visualizer * vis) +EXPORT void aud_visualizer_add(Visualizer * vis) { - visualizers.append (vis); + visualizers.append(vis); - num_enabled ++; + num_enabled++; if (num_enabled == 1) - vis_runner_enable (true); + vis_runner_enable(true); } -EXPORT void aud_visualizer_remove (Visualizer * vis) +EXPORT void aud_visualizer_remove(Visualizer * vis) { int num_disabled = 0; - auto is_match = [&] (Visualizer * vis2) - { + auto is_match = [&](Visualizer * vis2) { if (vis2 != vis) return false; - num_disabled ++; + num_disabled++; return true; }; - visualizers.remove_if (is_match, true); + visualizers.remove_if(is_match, true); num_enabled -= num_disabled; - if (! num_enabled) - vis_runner_enable (false); + if (!num_enabled) + vis_runner_enable(false); } -void vis_send_clear () +void vis_send_clear() { for (Visualizer * vis : visualizers) - vis->clear (); + vis->clear(); } -static void pcm_to_mono (const float * data, float * mono, int channels) +static void pcm_to_mono(const float * data, float * mono, int channels) { if (channels == 1) - memcpy (mono, data, sizeof (float) * 512); + memcpy(mono, data, sizeof(float) * 512); else { float * set = mono; - while (set < & mono[512]) + while (set < &mono[512]) { - * set ++ = (data[0] + data[1]) / 2; + *set++ = (data[0] + data[1]) / 2; data += channels; } } } -void vis_send_audio (const float * data, int channels) +void vis_send_audio(const float * data, int channels) { - auto is_active = [] (int type_mask) - { + auto is_active = [](int type_mask) { for (Visualizer * vis : visualizers) { if ((vis->type_mask & type_mask)) @@ -97,83 +95,83 @@ void vis_send_audio (const float * data, int channels) float mono[512]; float freq[256]; - if (is_active (Visualizer::MonoPCM | Visualizer::Freq)) - pcm_to_mono (data, mono, channels); - if (is_active (Visualizer::Freq)) - calc_freq (mono, freq); + if (is_active(Visualizer::MonoPCM | Visualizer::Freq)) + pcm_to_mono(data, mono, channels); + if (is_active(Visualizer::Freq)) + calc_freq(mono, freq); for (Visualizer * vis : visualizers) { if ((vis->type_mask & Visualizer::MonoPCM)) - vis->render_mono_pcm (mono); + vis->render_mono_pcm(mono); if ((vis->type_mask & Visualizer::MultiPCM)) - vis->render_multi_pcm (data, channels); + vis->render_multi_pcm(data, channels); if ((vis->type_mask & Visualizer::Freq)) - vis->render_freq (freq); + vis->render_freq(freq); } } -static bool vis_load (PluginHandle * plugin) +static bool vis_load(PluginHandle * plugin) { - AUDINFO ("Activating %s.\n", aud_plugin_get_name (plugin)); - VisPlugin * header = (VisPlugin *) aud_plugin_get_header (plugin); - if (! header) + AUDINFO("Activating %s.\n", aud_plugin_get_name(plugin)); + VisPlugin * header = (VisPlugin *)aud_plugin_get_header(plugin); + if (!header) return false; - aud_visualizer_add (header); + aud_visualizer_add(header); return true; } -static void vis_unload (PluginHandle * plugin) +static void vis_unload(PluginHandle * plugin) { - AUDINFO ("Deactivating %s.\n", aud_plugin_get_name (plugin)); - VisPlugin * header = (VisPlugin *) aud_plugin_get_header (plugin); - if (! header) + AUDINFO("Deactivating %s.\n", aud_plugin_get_name(plugin)); + VisPlugin * header = (VisPlugin *)aud_plugin_get_header(plugin); + if (!header) return; - header->clear (); - aud_visualizer_remove (header); + header->clear(); + aud_visualizer_remove(header); } -void vis_activate (bool activate) +void vis_activate(bool activate) { - if (! activate == ! running) + if (!activate == !running) return; - for (PluginHandle * plugin : aud_plugin_list (PluginType::Vis)) + for (PluginHandle * plugin : aud_plugin_list(PluginType::Vis)) { - if (! aud_plugin_get_enabled (plugin)) + if (!aud_plugin_get_enabled(plugin)) continue; if (activate) - vis_load (plugin); + vis_load(plugin); else - vis_unload (plugin); + vis_unload(plugin); } running = activate; } -bool vis_plugin_start (PluginHandle * plugin) +bool vis_plugin_start(PluginHandle * plugin) { - VisPlugin * vp = (VisPlugin *) aud_plugin_get_header (plugin); - if (! vp || ! vp->init ()) + VisPlugin * vp = (VisPlugin *)aud_plugin_get_header(plugin); + if (!vp || !vp->init()) return false; if (running) - vis_load (plugin); + vis_load(plugin); return true; } -void vis_plugin_stop (PluginHandle * plugin) +void vis_plugin_stop(PluginHandle * plugin) { - VisPlugin * vp = (VisPlugin *) aud_plugin_get_header (plugin); - if (! vp) + VisPlugin * vp = (VisPlugin *)aud_plugin_get_header(plugin); + if (!vp) return; if (running) - vis_unload (plugin); + vis_unload(plugin); - vp->cleanup (); + vp->cleanup(); } diff --git a/src/libaudcore/visualizer.h b/src/libaudcore/visualizer.h index 5c825e6..1a82bd7 100644 --- a/src/libaudcore/visualizer.h +++ b/src/libaudcore/visualizer.h @@ -25,27 +25,32 @@ class LIBAUDCORE_PUBLIC Visualizer { public: - enum { + enum + { MonoPCM = (1 << 0), MultiPCM = (1 << 1), Freq = (1 << 2) }; const int type_mask; - constexpr Visualizer (int type_mask) : - type_mask (type_mask) {} + constexpr Visualizer(int type_mask) : type_mask(type_mask) {} /* reset internal state and clear display */ - virtual void clear () = 0; + virtual void clear() = 0; /* 512 frames of a single-channel PCM signal */ - virtual void render_mono_pcm (const float * pcm) {} + virtual void render_mono_pcm(const float * pcm) {} /* 512 frames of an interleaved multi-channel PCM signal */ - virtual void render_multi_pcm (const float * pcm, int channels) {} + virtual void render_multi_pcm(const float * pcm, int channels) {} /* intensity of frequencies 1/512, 2/512, ..., 256/512 of sample rate */ - virtual void render_freq (const float * freq) {} + virtual void render_freq(const float * freq) {} + + /* common math for rendering a frequency graph (see util.cc) */ + static void compute_log_xscale(float * xscale, int bands); + static float compute_freq_band(const float * freq, const float * xscale, + int band, int bands); }; #endif /* LIBAUDCORE_VISUALIZER_H */ diff --git a/src/libaudgui/Makefile b/src/libaudgui/Makefile index c0589ce..081bd01 100644 --- a/src/libaudgui/Makefile +++ b/src/libaudgui/Makefile @@ -1,6 +1,6 @@ SHARED_LIB = ${LIB_PREFIX}audgui${LIB_SUFFIX} LIB_MAJOR = 5 -LIB_MINOR = 0 +LIB_MINOR = 1 SRCS = about.cc \ confirm.cc \ @@ -52,7 +52,9 @@ CPPFLAGS := -I.. -I../.. \ CFLAGS += ${LIB_CFLAGS} -LIBS := -L../libaudcore -laudcore \ +LIB_LDFLAGS := -L../libaudcore $(LIB_LDFLAGS) + +LIBS := -laudcore \ ${LIBS} -lm \ ${GLIB_LIBS} \ ${GTK_LIBS} diff --git a/src/libaudgui/eq-preset.cc b/src/libaudgui/eq-preset.cc index 159fef9..cdffa77 100644 --- a/src/libaudgui/eq-preset.cc +++ b/src/libaudgui/eq-preset.cc @@ -20,8 +20,10 @@ #include #include +#include #include #include +#include #include #include "internal.h" @@ -65,11 +67,16 @@ static void select_all (void *, bool selected) item.selected = selected; } +static void activate_preset (const EqualizerPreset & preset) +{ + aud_eq_apply_preset (preset); + aud_set_bool ("equalizer_active", true); +} + static void activate_row (void *, int row) { g_return_if_fail (row >= 0 && row < preset_list.len ()); - aud_eq_apply_preset (preset_list[row].preset); - aud_set_bool (nullptr, "equalizer_active", true); + activate_preset (preset_list[row].preset); } static void focus_change (void *, int row) @@ -124,6 +131,30 @@ static int find_by_name (const char * name) return -1; } +static const EqualizerPreset * find_one_selected () +{ + const EqualizerPreset * preset = nullptr; + + for (PresetItem & item : preset_list) + { + if (item.selected) + { + if (preset) + { + preset = nullptr; + break; + } + + preset = & item.preset; + } + } + + if (! preset) + aud_ui_show_error (_("Please select one preset to export.")); + + return preset; +} + static void text_changed () { const char * name = gtk_entry_get_text ((GtkEntry *) entry); @@ -186,6 +217,20 @@ static void revert_changes () gtk_widget_set_sensitive (revert, false); } +static void do_save_file (void) +{ + auto preset = find_one_selected (); + if (preset) + eq_preset_save_file (* preset); +} + +static void do_save_eqf (void) +{ + auto preset = find_one_selected (); + if (preset) + eq_preset_save_eqf (* preset); +} + static void cleanup_eq_preset_window () { // also hide the preset browser window @@ -209,14 +254,12 @@ static GtkWidget * create_menu_bar () { static const AudguiMenuItem import_items[] = { MenuCommand (N_("Preset File ..."), nullptr, 0, (GdkModifierType) 0, eq_preset_load_file), - MenuCommand (N_("EQF File ..."), nullptr, 0, (GdkModifierType) 0, eq_preset_load_eqf), - MenuSep (), - MenuCommand (N_("Winamp Presets ..."), nullptr, 0, (GdkModifierType) 0, eq_preset_import_winamp) + MenuCommand (N_("EQF File ..."), nullptr, 0, (GdkModifierType) 0, eq_preset_load_eqf) }; static const AudguiMenuItem export_items[] = { - MenuCommand (N_("Preset File ..."), nullptr, 0, (GdkModifierType) 0, eq_preset_save_file), - MenuCommand (N_("EQF File ..."), nullptr, 0, (GdkModifierType) 0, eq_preset_save_eqf) + MenuCommand (N_("Preset File ..."), nullptr, 0, (GdkModifierType) 0, do_save_file), + MenuCommand (N_("EQF File ..."), nullptr, 0, (GdkModifierType) 0, do_save_eqf) }; static const AudguiMenuItem menus[] = { @@ -309,8 +352,17 @@ static void merge_presets (const Index & presets) preset_list.remove_if (is_duplicate); } + /* deselect existing presets */ + for (auto & item : preset_list) + item.selected = false; + + /* append and select new presets */ for (const EqualizerPreset & preset : presets) - preset_list.append (preset, false); + preset_list.append (preset, true); + + /* if a single preset was imported, activate it */ + if (presets.len () == 1) + activate_preset (presets[0]); } EXPORT void audgui_import_eq_presets (const Index & presets) @@ -322,6 +374,7 @@ EXPORT void audgui_import_eq_presets (const Index & presets) audgui_list_delete_rows (list, 0, preset_list.len ()); merge_presets (presets); audgui_list_insert_rows (list, 0, preset_list.len ()); + audgui_list_set_focus (list, preset_list.len () - 1); changes_made = true; gtk_widget_set_sensitive (revert, true); diff --git a/src/libaudgui/equalizer.cc b/src/libaudgui/equalizer.cc index 207f8a7..a6d6640 100644 --- a/src/libaudgui/equalizer.cc +++ b/src/libaudgui/equalizer.cc @@ -31,7 +31,7 @@ static void on_off_cb (GtkToggleButton * on_off) { - aud_set_bool (nullptr, "equalizer_active", gtk_toggle_button_get_active (on_off)); + aud_set_bool ("equalizer_active", gtk_toggle_button_get_active (on_off)); } static void on_off_update (void *, GtkWidget * on_off) @@ -61,7 +61,7 @@ static void slider_moved (GtkRange * slider) double value = round (gtk_range_get_value (slider)); if (band == -1) - aud_set_double (nullptr, "equalizer_preamp", value); + aud_set_double ("equalizer_preamp", value); else aud_eq_set_band (band, value); } @@ -99,7 +99,7 @@ static void set_slider (GtkWidget * slider, double value) static void update_sliders (void *, GtkWidget * window) { GtkWidget * preamp = (GtkWidget *) g_object_get_data ((GObject *) window, "preamp"); - set_slider (preamp, aud_get_double (nullptr, "equalizer_preamp")); + set_slider (preamp, aud_get_double ("equalizer_preamp")); double values[AUD_EQ_NBANDS]; aud_eq_get_bands (values); diff --git a/src/libaudgui/images.gresource.xml b/src/libaudgui/images.gresource.xml index 2a5dacf..83441eb 100644 --- a/src/libaudgui/images.gresource.xml +++ b/src/libaudgui/images.gresource.xml @@ -51,6 +51,7 @@ media-skip-backward.svg media-skip-forward.svg multimedia-volume-control.svg + preferences-desktop-font.svg preferences-system.svg process-stop.svg system-run.svg diff --git a/src/libaudgui/infopopup.cc b/src/libaudgui/infopopup.cc index bdefdd5..8de01c9 100644 --- a/src/libaudgui/infopopup.cc +++ b/src/libaudgui/infopopup.cc @@ -1,6 +1,6 @@ /* * infopopup.c - * Copyright 2006-2012 William Pitcock, Giacomo Lozito, John Lindgren, and + * Copyright 2006-2012 Ariadne Conill, Giacomo Lozito, John Lindgren, and * Thomas Lange * * Redistribution and use in source and binary forms, with or without @@ -91,7 +91,7 @@ static void infopopup_progress_cb (void *) time = aud_drct_get_time (); } - if (aud_get_bool (nullptr, "filepopup_showprogressbar") && filename && + if (aud_get_bool ("filepopup_showprogressbar") && filename && current_file && ! strcmp (filename, current_file) && length > 0) { gtk_progress_bar_set_fraction ((GtkProgressBar *) widgets.progress, time / (float) length); @@ -109,32 +109,14 @@ static void infopopup_realized (GtkWidget * widget) infopopup_move_to_mouse (widget); } -/* borrowed from the gtkui infoarea */ static gboolean infopopup_draw_bg (GtkWidget * widget) { - double r = 1, g = 1, b = 1; - - /* In a dark theme, try to match the tone of the base color */ - auto & c = (gtk_widget_get_style (widget))->base[GTK_STATE_NORMAL]; - int v = aud::max (aud::max (c.red, c.green), c.blue); - - if (v >= 10*256 && v < 80*256) - { - r = (double)c.red / v; - g = (double)c.green / v; - b = (double)c.blue / v; - } - GtkAllocation alloc; gtk_widget_get_allocation (widget, & alloc); cairo_t * cr = gdk_cairo_create (gtk_widget_get_window (widget)); - - cairo_pattern_t * gradient = cairo_pattern_create_linear (0, 0, 0, alloc.height); - cairo_pattern_add_color_stop_rgb (gradient, 0, 0.25 * r, 0.25 * g, 0.25 * b); - cairo_pattern_add_color_stop_rgb (gradient, 0.5, 0.15 * r, 0.15 * g, 0.15 * b); - cairo_pattern_add_color_stop_rgb (gradient, 0.5, 0.1 * r, 0.1 * g, 0.1 * b); - cairo_pattern_add_color_stop_rgb (gradient, 1, 0, 0, 0); + auto & c = (gtk_widget_get_style (widget))->base[GTK_STATE_NORMAL]; + cairo_pattern_t * gradient = audgui_dark_bg_gradient (c, alloc.height); cairo_set_source (cr, gradient); cairo_rectangle (cr, 0, 0, alloc.width, alloc.height); diff --git a/src/libaudgui/infowin.cc b/src/libaudgui/infowin.cc index 8f62856..63bb3fa 100644 --- a/src/libaudgui/infowin.cc +++ b/src/libaudgui/infowin.cc @@ -1,6 +1,6 @@ /* * infowin.c - * Copyright 2006-2013 William Pitcock, Tomasz Moń, Eugene Zagidullin, + * Copyright 2006-2013 Ariadne Conill, Tomasz Moń, Eugene Zagidullin, * John Lindgren, and Thomas Lange * * Redistribution and use in source and binary forms, with or without @@ -65,7 +65,7 @@ static struct { GtkWidget * image; GtkWidget * codec[3]; GtkWidget * apply; - GtkWidget * clear; + GtkWidget * autofill; GtkWidget * ministatus; } widgets; @@ -192,7 +192,7 @@ static void set_field_int_from_entry (Tuple & tuple, Tuple::Field field, GtkWidg tuple.unset (field); } -static void entry_changed (GtkEditable * editable) +static void entry_changed () { if (can_write) gtk_widget_set_sensitive (widgets.apply, true); @@ -201,12 +201,12 @@ static void entry_changed (GtkEditable * editable) static void ministatus_display_message (const char * text) { gtk_label_set_text ((GtkLabel *) widgets.ministatus, text); - gtk_widget_hide (widgets.clear); + gtk_widget_hide (widgets.autofill); gtk_widget_show (widgets.ministatus); ministatus_timer.queue (AUDGUI_STATUS_TIMEOUT, [] (void *) { gtk_widget_hide (widgets.ministatus); - gtk_widget_show (widgets.clear); + gtk_widget_show (widgets.autofill); }, nullptr); } @@ -231,11 +231,9 @@ static void infowin_update_tuple () ministatus_display_message (_("Save error")); } -static void infowin_next () +static void infowin_select_entry (int entry) { - int entry = current_entry + 1; - - if (entry < current_playlist.n_entries ()) + if (entry >= 0 && entry < current_playlist.n_entries ()) { current_playlist.select_all (false); current_playlist.select_entry (entry, true); @@ -246,6 +244,16 @@ static void infowin_next () audgui_infowin_hide (); } +static void infowin_prev () +{ + infowin_select_entry (current_entry - 1); +} + +static void infowin_next () +{ + infowin_select_entry (current_entry + 1); +} + static void genre_fill (GtkWidget * combo) { GList * list = nullptr; @@ -262,9 +270,9 @@ static void genre_fill (GtkWidget * combo) g_list_free (list); } -static void clear_toggled (GtkToggleButton * toggle) +static void autofill_toggled (GtkToggleButton * toggle) { - aud_set_bool ("audgui", "clear_song_fields", gtk_toggle_button_get_active (toggle)); + aud_set_bool ("audgui", "clear_song_fields", ! gtk_toggle_button_get_active (toggle)); } static void infowin_display_image (const char * filename) @@ -386,16 +394,15 @@ static void create_infowin () gtk_table_attach ((GtkTable *) main_grid, bottom_hbox, 0, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); - widgets.clear = gtk_check_button_new_with_mnemonic - (_("Clea_r fields when moving to next song")); + widgets.autofill = gtk_check_button_new_with_mnemonic (_("_Auto-fill empty fields")); - gtk_toggle_button_set_active ((GtkToggleButton *) widgets.clear, - aud_get_bool ("audgui", "clear_song_fields")); - g_signal_connect (widgets.clear, "toggled", (GCallback) clear_toggled, nullptr); + gtk_toggle_button_set_active ((GtkToggleButton *) widgets.autofill, + ! aud_get_bool ("audgui", "clear_song_fields")); + g_signal_connect (widgets.autofill, "toggled", (GCallback) autofill_toggled, nullptr); - gtk_widget_set_no_show_all (widgets.clear, true); - gtk_widget_show (widgets.clear); - gtk_box_pack_start ((GtkBox *) bottom_hbox, widgets.clear, false, false, 0); + gtk_widget_set_no_show_all (widgets.autofill, true); + gtk_widget_show (widgets.autofill); + gtk_box_pack_start ((GtkBox *) bottom_hbox, widgets.autofill, false, false, 0); widgets.ministatus = small_label_new (nullptr); gtk_widget_set_no_show_all (widgets.ministatus, true); @@ -407,12 +414,16 @@ static void create_infowin () GtkWidget * close_button = audgui_button_new (_("_Close"), "window-close", (AudguiCallback) audgui_infowin_hide, nullptr); + GtkWidget * prev_button = audgui_button_new (_("_Previous"), "go-previous", + (AudguiCallback) infowin_prev, nullptr); + GtkWidget * next_button = audgui_button_new (_("_Next"), "go-next", (AudguiCallback) infowin_next, nullptr); gtk_box_pack_end ((GtkBox *) bottom_hbox, close_button, false, false, 0); - gtk_box_pack_end ((GtkBox *) bottom_hbox, next_button, false, false, 0); gtk_box_pack_end ((GtkBox *) bottom_hbox, widgets.apply, false, false, 0); + gtk_box_pack_end ((GtkBox *) bottom_hbox, next_button, false, false, 0); + gtk_box_pack_end ((GtkBox *) bottom_hbox, prev_button, false, false, 0); audgui_destroy_on_escape (infowin); g_signal_connect (infowin, "destroy", (GCallback) infowin_destroyed, nullptr); diff --git a/src/libaudgui/init.cc b/src/libaudgui/init.cc index c3d3a76..36ad24d 100644 --- a/src/libaudgui/init.cc +++ b/src/libaudgui/init.cc @@ -361,7 +361,9 @@ EXPORT void audgui_init () hook_associate ("playlist set playing", playlist_set_playing_cb, nullptr); hook_associate ("playlist position", playlist_position_cb, nullptr); +#ifndef _WIN32 gtk_window_set_default_icon_name ("audacious"); +#endif } EXPORT void audgui_cleanup () diff --git a/src/libaudgui/libaudgui-gtk.h b/src/libaudgui/libaudgui-gtk.h index f98ba27..e0b321b 100644 --- a/src/libaudgui/libaudgui-gtk.h +++ b/src/libaudgui/libaudgui-gtk.h @@ -88,4 +88,8 @@ GtkWidget * audgui_dialog_new (GtkMessageType type, const char * title, const char * text, GtkWidget * button1, GtkWidget * button2); void audgui_dialog_add_widget (GtkWidget * dialog, GtkWidget * widget); +cairo_pattern_t * audgui_dark_bg_gradient (const GdkColor & base, int height); +void audgui_vis_bar_color (const GdkColor & hue, int bar, int n_bars, + float & r, float & g, float & b); + #endif diff --git a/src/libaudgui/playlists.cc b/src/libaudgui/playlists.cc index 6f00008..37c693a 100644 --- a/src/libaudgui/playlists.cc +++ b/src/libaudgui/playlists.cc @@ -64,7 +64,7 @@ static void finish_job (void * data) ImportExportJob * job = (ImportExportJob *) data; Playlist::GetMode mode = Playlist::Wait; - if (aud_get_bool (nullptr, "metadata_on_play")) + if (aud_get_bool ("metadata_on_play")) mode = Playlist::NoWait; if (job->list.exists ()) diff --git a/src/libaudgui/prefs-widget.cc b/src/libaudgui/prefs-widget.cc index c240ece..7fba25f 100644 --- a/src/libaudgui/prefs-widget.cc +++ b/src/libaudgui/prefs-widget.cc @@ -1,6 +1,6 @@ /* * prefs-widget.c - * Copyright 2007-2014 Tomasz Moń, William Pitcock, and John Lindgren + * Copyright 2007-2014 Tomasz Moń, Ariadne Conill, and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/libaudgui/prefs-window.cc b/src/libaudgui/prefs-window.cc index bf839a2..aa81891 100644 --- a/src/libaudgui/prefs-window.cc +++ b/src/libaudgui/prefs-window.cc @@ -1,6 +1,6 @@ /* * prefs-window.cc - * Copyright 2006-2014 William Pitcock, Tomasz Moń, Michael Färber, and + * Copyright 2006-2014 Ariadne Conill, Tomasz Moń, Michael Färber, and * John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -107,6 +107,7 @@ static const TitleFieldTag title_field_tags[] = { { N_("File name") , "${file-name}" }, { N_("File path") , "${file-path}" }, { N_("Date") , "${date}" }, + { N_("Description") , "${description}" }, { N_("Year") , "${year}" }, { N_("Comment") , "${comment}" }, { N_("Codec") , "${codec}" }, @@ -268,6 +269,16 @@ static const PreferencesWidget connectivity_page_widgets[] = { WidgetCheck (N_("Use authentication with proxy"), WidgetBool (0, "use_proxy_auth")), WidgetTable ({{proxy_auth_elements}}, + WIDGET_CHILD), + WidgetCheck (N_("Use SOCKS proxy"), + WidgetBool (0, "socks_proxy")), + WidgetRadio (N_("SOCKS v4a"), + WidgetInt (0, "socks_type"), + {0}, + WIDGET_CHILD), + WidgetRadio (N_("SOCKS v5"), + WidgetInt (0, "socks_type"), + {1}, WIDGET_CHILD) }; @@ -350,7 +361,14 @@ static const PreferencesWidget advanced_page_widgets[] = { WidgetCheck (N_("Do not load metadata for songs until played"), WidgetBool (0, "metadata_on_play")), WidgetCheck (N_("Probe content of files with no recognized file name extension"), - WidgetBool (0, "slow_probe")) + WidgetBool (0, "slow_probe")), + WidgetLabel (N_("Miscellaneous")), + WidgetSpin (N_("Step forward/backward by:"), + WidgetInt (0, "step_size"), + {1, 60, 1, N_("seconds")}), + WidgetSpin (N_("Adjust volume by:"), + WidgetInt (0, "volume_delta"), + {1, 25, 1, N_("percent")}) }; #define TITLESTRING_NPRESETS 8 @@ -454,7 +472,7 @@ static void update_titlestring_cbox (GtkComboBox * cbox, const char * format) static void on_titlestring_entry_changed (GtkEntry * entry, GtkComboBox * cbox) { const char * format = gtk_entry_get_text (entry); - aud_set_str (nullptr, "generic_title_format", format); + aud_set_str ("generic_title_format", format); update_titlestring_cbox (cbox, format); } @@ -536,7 +554,7 @@ static void create_titlestring_widgets (GtkWidget * * cbox, GtkWidget * * entry) * entry = gtk_entry_new (); - String format = aud_get_str (nullptr, "generic_title_format"); + String format = aud_get_str ("generic_title_format"); update_titlestring_cbox ((GtkComboBox *) * cbox, format); gtk_entry_set_text ((GtkEntry *) * entry, format); diff --git a/src/libaudgui/preset-browser.cc b/src/libaudgui/preset-browser.cc index 5b5c78d..c67b3f2 100644 --- a/src/libaudgui/preset-browser.cc +++ b/src/libaudgui/preset-browser.cc @@ -26,25 +26,28 @@ #include #include -#include #include #include -typedef void (* FilebrowserCallback) (const char * filename); +typedef void (* PresetAction) (const char * filename, const EqualizerPreset * preset); static void browser_response (GtkWidget * dialog, int response, void * data) { if (response == GTK_RESPONSE_ACCEPT) { CharPtr filename (gtk_file_chooser_get_uri ((GtkFileChooser *) dialog)); - ((FilebrowserCallback) data) (filename); + auto preset = (const EqualizerPreset *) + g_object_get_data ((GObject *) dialog, "eq-preset"); + + ((PresetAction) data) (filename, preset); } gtk_widget_destroy (dialog); } static void show_preset_browser (const char * title, gboolean save, - const char * default_filename, FilebrowserCallback callback) + const char * default_filename, PresetAction callback, + const EqualizerPreset * preset) { GtkWidget * browser = gtk_file_chooser_dialog_new (title, nullptr, save ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN, _("Cancel"), @@ -56,87 +59,74 @@ static void show_preset_browser (const char * title, gboolean save, if (default_filename) gtk_file_chooser_set_current_name ((GtkFileChooser *) browser, default_filename); + if (preset) + g_object_set_data_full ((GObject *) browser, "eq-preset", + new EqualizerPreset (* preset), aud::delete_obj); + g_signal_connect (browser, "response", (GCallback) browser_response, (void *) callback); audgui_show_unique_window (AUDGUI_PRESET_BROWSER_WINDOW, browser); } -static void do_load_file (const char * filename) +static void do_load_file (const char * filename, const EqualizerPreset *) { - EqualizerPreset preset; + Index presets; + presets.append (); VFSFile file (filename, "r"); - if (! file || ! aud_load_preset_file (preset, file)) + if (! file || ! aud_load_preset_file (presets[0], file)) return; - aud_eq_apply_preset (preset); + audgui_import_eq_presets (presets); } void eq_preset_load_file () { - show_preset_browser (_("Load Preset File"), false, nullptr, do_load_file); + show_preset_browser (_("Load Preset File"), false, nullptr, do_load_file, nullptr); } -static void do_load_eqf (const char * filename) +static void do_load_eqf (const char * filename, const EqualizerPreset *) { VFSFile file (filename, "r"); if (! file) return; - Index presets = aud_import_winamp_presets (file); - - if (presets.len ()) - aud_eq_apply_preset (presets[0]); + audgui_import_eq_presets (aud_import_winamp_presets (file)); } void eq_preset_load_eqf () { - show_preset_browser (_("Load EQF File"), false, nullptr, do_load_eqf); + show_preset_browser (_("Load EQF File"), false, nullptr, do_load_eqf, nullptr); } -static void do_save_file (const char * filename) +static void do_save_file (const char * filename, const EqualizerPreset * preset) { - EqualizerPreset preset; - aud_eq_update_preset (preset); + g_return_if_fail (preset); VFSFile file (filename, "w"); if (file) - aud_save_preset_file (preset, file); + aud_save_preset_file (* preset, file); } -void eq_preset_save_file () +void eq_preset_save_file (const EqualizerPreset & preset) { - show_preset_browser (_("Save Preset File"), true, _(".preset"), do_save_file); + StringBuf name = str_concat ({preset.name, ".preset"}); + show_preset_browser (_("Save Preset File"), true, name, do_save_file, & preset); } -static void do_save_eqf (const char * filename) +static void do_save_eqf (const char * filename, const EqualizerPreset * preset) { - VFSFile file (filename, "w"); - if (! file) - return; + g_return_if_fail (preset); - EqualizerPreset preset = EqualizerPreset (); - preset.name = String ("Preset1"); - - aud_eq_update_preset (preset); - aud_export_winamp_preset (preset, file); -} - -void eq_preset_save_eqf () -{ - show_preset_browser (_("Save EQF File"), true, _(".eqf"), do_save_eqf); -} - -static void do_import_winamp (const char * filename) -{ - VFSFile file (filename, "r"); + VFSFile file (filename, "w"); if (! file) return; - audgui_import_eq_presets (aud_import_winamp_presets (file)); + aud_export_winamp_preset (* preset, file); } -void eq_preset_import_winamp () +void eq_preset_save_eqf (const EqualizerPreset & preset) { - show_preset_browser (_("Import Winamp Presets"), false, nullptr, do_import_winamp); + StringBuf name = str_concat ({preset.name, ".eqf"}); + show_preset_browser (_("Save EQF File"), true, name, do_save_eqf, & preset); } diff --git a/src/libaudgui/preset-browser.h b/src/libaudgui/preset-browser.h index b2d6796..3d6a9ce 100644 --- a/src/libaudgui/preset-browser.h +++ b/src/libaudgui/preset-browser.h @@ -20,10 +20,11 @@ #ifndef AUDGUI_PRESET_BROWSER_H #define AUDGUI_PRESET_BROWSER_H +#include + void eq_preset_load_file (); void eq_preset_load_eqf (); -void eq_preset_save_file (); -void eq_preset_save_eqf (); -void eq_preset_import_winamp (); +void eq_preset_save_file (const EqualizerPreset & preset); +void eq_preset_save_eqf (const EqualizerPreset & preset); #endif // AUDGUI_PRESET_BROWSER_H diff --git a/src/libaudgui/url-opener.cc b/src/libaudgui/url-opener.cc index 6c5c5cd..c994b7a 100644 --- a/src/libaudgui/url-opener.cc +++ b/src/libaudgui/url-opener.cc @@ -38,7 +38,7 @@ static void open_cb (void * entry) else aud_drct_pl_add (text, -1); - if (aud_get_bool (nullptr, "save_url_history")) + if (aud_get_bool ("save_url_history")) aud_history_add (text); } diff --git a/src/libaudgui/util.cc b/src/libaudgui/util.cc index 2994c89..72cd9c5 100644 --- a/src/libaudgui/util.cc +++ b/src/libaudgui/util.cc @@ -190,8 +190,8 @@ EXPORT GtkWidget * audgui_file_entry_new (GtkFileChooserAction action, const cha GtkWidget * entry = gtk_entry_new (); auto data = new FileEntryData {action, String (title)}; - auto destroy_cb = [] (void * data) { delete (FileEntryData *) data; }; - g_object_set_data_full ((GObject *) entry, "file-entry-data", data, destroy_cb); + g_object_set_data_full ((GObject *) entry, "file-entry-data", data, + aud::delete_obj); gtk_entry_set_icon_from_icon_name ((GtkEntry *) entry, GTK_ENTRY_ICON_SECONDARY, "document-open"); @@ -303,3 +303,92 @@ EXPORT void audgui_simple_message (GtkWidget * * widget, GtkMessageType type, gtk_widget_show_all (* widget); } } + +EXPORT cairo_pattern_t * audgui_dark_bg_gradient (const GdkColor & base, int height) +{ + float r = 1, g = 1, b = 1; + + /* in a dark theme, try to match the tone of the base color */ + int v = aud::max (aud::max (base.red, base.green), base.blue); + + if (v >= 10*256 && v < 80*256) + { + r = (float) base.red / v; + g = (float) base.green / v; + b = (float) base.blue / v; + } + + cairo_pattern_t * gradient = cairo_pattern_create_linear (0, 0, 0, height); + cairo_pattern_add_color_stop_rgb (gradient, 0, 0.16 * r, 0.16 * g, 0.16 * b); + cairo_pattern_add_color_stop_rgb (gradient, 0.45, 0.11 * r, 0.11 * g, 0.11 * b); + cairo_pattern_add_color_stop_rgb (gradient, 0.55, 0.06 * r, 0.06 * g, 0.06 * b); + cairo_pattern_add_color_stop_rgb (gradient, 1, 0.09 * r, 0.09 * g, 0.09 * b); + return gradient; +} + +static void rgb_to_hsv (float r, float g, float b, float * h, float * s, float * v) +{ + float max = aud::max (aud::max (r, g), b); + float min = aud::min (aud::min (r, g), b); + + * v = max; + + if (max == min) + { + * h = 0; + * s = 0; + return; + } + + if (r == max) + * h = 1 + (g - b) / (max - min); + else if (g == max) + * h = 3 + (b - r) / (max - min); + else + * h = 5 + (r - g) / (max - min); + + * s = (max - min) / max; +} + +static void hsv_to_rgb (float h, float s, float v, float * r, float * g, float * b) +{ + for (; h >= 2; h -= 2) + { + float * p = r; + r = g; + g = b; + b = p; + } + + if (h < 1) + { + * r = 1; + * g = 0; + * b = 1 - h; + } + else + { + * r = 1; + * g = h - 1; + * b = 0; + } + + * r = v * (1 - s * (1 - * r)); + * g = v * (1 - s * (1 - * g)); + * b = v * (1 - s * (1 - * b)); +} + +EXPORT void audgui_vis_bar_color (const GdkColor & hue, int bar, int n_bars, + float & r, float & g, float & b) +{ + float h, s, v; + rgb_to_hsv (hue.red / 65535.0, hue.green / 65535.0, hue.blue / 65535.0, & h, & s, & v); + + if (s < 0.1) /* monochrome theme? use blue instead */ + h = 4.6; + + s = 1 - 0.9 * bar / (n_bars - 1); + v = 0.75 + 0.25 * bar / (n_bars - 1); + + hsv_to_rgb (h, s, v, & r, & g, & b); +} diff --git a/src/libaudqt/Makefile b/src/libaudqt/Makefile index fa9e7bf..bd3ef16 100644 --- a/src/libaudqt/Makefile +++ b/src/libaudqt/Makefile @@ -1,12 +1,16 @@ SHARED_LIB = ${LIB_PREFIX}audqt${LIB_SUFFIX} LIB_MAJOR = 2 -LIB_MINOR = 1 +LIB_MINOR = 2 SRCS = about-qt.cc \ art-qt.cc \ audqt.cc \ + colorbutton.cc \ + eq-preset-qt.cc \ equalizer-qt.cc \ + file-entry.cc \ fileopener.cc \ + font-entry.cc \ images.cc \ infopopup-qt.cc \ infowin-qt.cc \ @@ -23,13 +27,16 @@ SRCS = about-qt.cc \ queue-manager-qt.cc \ url-opener-qt.cc \ util-qt.cc \ + treeview.cc \ volumebutton.cc -INCLUDES = export.h \ +INCLUDES = colorbutton.h \ + export.h \ iface.h \ info-widget.h \ libaudqt.h \ - menu.h + menu.h \ + treeview.h include ../../buildsys.mk include ../../extra.mk @@ -45,7 +52,9 @@ CPPFLAGS := -I.. -I../.. \ CFLAGS += ${LIB_CFLAGS} -LIBS := -L../libaudcore -laudcore \ +LIB_LDFLAGS := -L../libaudcore $(LIB_LDFLAGS) + +LIBS := -laudcore \ ${LIBS} -lm \ ${QT_LIBS} diff --git a/src/libaudqt/about-qt.cc b/src/libaudqt/about-qt.cc index fe0a9de..4496e59 100644 --- a/src/libaudqt/about-qt.cc +++ b/src/libaudqt/about-qt.cc @@ -1,6 +1,6 @@ /* * about.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,79 +30,81 @@ #include "libaudqt.h" -static QTabWidget * buildCreditsNotebook (QWidget * parent) +static QTabWidget * buildCreditsNotebook(QWidget * parent) { - const char * data_dir = aud_get_path (AudPath::DataDir); + const char * data_dir = aud_get_path(AudPath::DataDir); const char * titles[2] = {N_("Credits"), N_("License")}; const char * filenames[2] = {"AUTHORS", "COPYING"}; - auto tabs = new QTabWidget (parent); - tabs->setDocumentMode (true); - tabs->setMinimumSize (6 * audqt::sizes.OneInch, 2 * audqt::sizes.OneInch); + auto tabs = new QTabWidget(parent); + tabs->setDocumentMode(true); + tabs->setMinimumSize(6 * audqt::sizes.OneInch, 2 * audqt::sizes.OneInch); - for (int i = 0; i < 2; i ++) + for (int i = 0; i < 2; i++) { - auto text = VFSFile::read_file (filename_build ({data_dir, filenames[i]}), VFS_APPEND_NULL); - auto edit = new QPlainTextEdit (text.begin (), parent); - edit->setReadOnly (true); - edit->setFrameStyle (QFrame::NoFrame); - tabs->addTab (edit, _(titles[i])); + auto text = VFSFile::read_file(filename_build({data_dir, filenames[i]}), + VFS_APPEND_NULL); + auto edit = new QPlainTextEdit(text.begin(), parent); + edit->setReadOnly(true); + edit->setFrameStyle(QFrame::NoFrame); + tabs->addTab(edit, _(titles[i])); } return tabs; } -static QDialog * buildAboutWindow () +static QDialog * buildAboutWindow() { - const char * about_text = "Audacious " VERSION "
" COPYRIGHT; + const char * about_text = + "Audacious " VERSION "
" COPYRIGHT; const char * website = "https://audacious-media-player.org"; auto window = new QDialog; - window->setWindowTitle (_("About Audacious")); + window->setWindowTitle(_("About Audacious")); - auto logo = new QLabel (window); - int logo_size = audqt::to_native_dpi (400); - logo->setPixmap (QIcon (":/about-logo.svg").pixmap (logo_size, logo_size)); - logo->setAlignment (Qt::AlignHCenter); + auto logo = new QLabel(window); + int logo_size = audqt::to_native_dpi(400); + logo->setPixmap(QIcon(":/about-logo.svg").pixmap(logo_size, logo_size)); + logo->setAlignment(Qt::AlignHCenter); - auto text = new QLabel (about_text, window); - text->setAlignment (Qt::AlignHCenter); + auto text = new QLabel(about_text, window); + text->setAlignment(Qt::AlignHCenter); - auto anchor = QString ("%1").arg (website); - auto link_label = new QLabel (anchor, window); - link_label->setAlignment (Qt::AlignHCenter); - link_label->setOpenExternalLinks (true); + auto anchor = QString("%1").arg(website); + auto link_label = new QLabel(anchor, window); + link_label->setAlignment(Qt::AlignHCenter); + link_label->setOpenExternalLinks(true); - auto layout = audqt::make_vbox (window); - layout->addSpacing (audqt::sizes.EightPt); - layout->addWidget (logo); - layout->addWidget (text); - layout->addWidget (link_label); - layout->addWidget (buildCreditsNotebook (window)); + auto layout = audqt::make_vbox(window); + layout->addSpacing(audqt::sizes.EightPt); + layout->addWidget(logo); + layout->addWidget(text); + layout->addWidget(link_label); + layout->addWidget(buildCreditsNotebook(window)); return window; } static QDialog * s_aboutwin = nullptr; -namespace audqt { +namespace audqt +{ -EXPORT void aboutwindow_show () +EXPORT void aboutwindow_show() { - if (! s_aboutwin) + if (!s_aboutwin) { - s_aboutwin = buildAboutWindow (); - s_aboutwin->setAttribute (Qt::WA_DeleteOnClose); + s_aboutwin = buildAboutWindow(); + s_aboutwin->setAttribute(Qt::WA_DeleteOnClose); - QObject::connect (s_aboutwin, & QObject::destroyed, [] () { - s_aboutwin = nullptr; - }); + QObject::connect(s_aboutwin, &QObject::destroyed, + []() { s_aboutwin = nullptr; }); } - window_bring_to_front (s_aboutwin); + window_bring_to_front(s_aboutwin); } -EXPORT void aboutwindow_hide () +EXPORT void aboutwindow_hide() { if (s_aboutwin) delete s_aboutwin; diff --git a/src/libaudqt/art-qt.cc b/src/libaudqt/art-qt.cc index 3327d91..3c3bad9 100644 --- a/src/libaudqt/art-qt.cc +++ b/src/libaudqt/art-qt.cc @@ -1,6 +1,6 @@ /* * art.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -18,9 +18,9 @@ */ #include -#include #include #include +#include #include #include @@ -28,48 +28,55 @@ #include #include -namespace audqt { +namespace audqt +{ -EXPORT QImage art_request (const char * filename, bool * queued) +EXPORT QImage art_request(const char * filename, bool * queued) { - AudArtPtr art = aud_art_request (filename, AUD_ART_DATA, queued); + AudArtPtr art = aud_art_request(filename, AUD_ART_DATA, queued); - auto data = art.data (); - return data ? QImage::fromData ((const uchar *) data->begin (), data->len ()) : QImage (); + auto data = art.data(); + return data ? QImage::fromData((const uchar *)data->begin(), data->len()) + : QImage(); } -EXPORT QPixmap art_scale (const QImage & image, unsigned int w, unsigned int h, bool want_hidpi) +EXPORT QPixmap art_scale(const QImage & image, unsigned int w, unsigned int h, + bool want_hidpi) { // return original image if requested size is zero, // or original size is smaller than requested size - if ((w == 0 && h == 0) || ((unsigned) image.width () <= w && (unsigned) image.height () <= h)) - return QPixmap::fromImage (image); + if ((w == 0 && h == 0) || + ((unsigned)image.width() <= w && (unsigned)image.height() <= h)) + return QPixmap::fromImage(image); - qreal r = want_hidpi ? qApp->devicePixelRatio () : 1; - auto pixmap = QPixmap::fromImage (image.scaled (w * r, h * r, - Qt::KeepAspectRatio, Qt::SmoothTransformation)); + qreal r = want_hidpi ? qApp->devicePixelRatio() : 1; + auto pixmap = QPixmap::fromImage(image.scaled( + w * r, h * r, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - pixmap.setDevicePixelRatio (r); + pixmap.setDevicePixelRatio(r); return pixmap; } -EXPORT QPixmap art_request (const char * filename, unsigned int w, unsigned int h, bool want_hidpi) +EXPORT QPixmap art_request(const char * filename, unsigned int w, + unsigned int h, bool want_hidpi) { - auto img = art_request (filename); - if (! img.isNull ()) - return art_scale (img, w, h, want_hidpi); + auto img = art_request(filename); + if (!img.isNull()) + return art_scale(img, w, h, want_hidpi); - unsigned size = to_native_dpi (48); - return get_icon ("audio-x-generic").pixmap (aud::min (w, size), aud::min (h, size)); + unsigned size = to_native_dpi(48); + return get_icon("audio-x-generic") + .pixmap(aud::min(w, size), aud::min(h, size)); } -EXPORT QPixmap art_request_current (unsigned int w, unsigned int h, bool want_hidpi) +EXPORT QPixmap art_request_current(unsigned int w, unsigned int h, + bool want_hidpi) { - String filename = aud_drct_get_filename (); - if (! filename) - return QPixmap (); + String filename = aud_drct_get_filename(); + if (!filename) + return QPixmap(); - return art_request (filename, w, h, want_hidpi); + return art_request(filename, w, h, want_hidpi); } } // namespace audqt diff --git a/src/libaudqt/audqt.cc b/src/libaudqt/audqt.cc index 0677b96..c81eb20 100644 --- a/src/libaudqt/audqt.cc +++ b/src/libaudqt/audqt.cc @@ -1,6 +1,6 @@ /* * util.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,7 +31,8 @@ #include "libaudqt-internal.h" #include "libaudqt.h" -namespace audqt { +namespace audqt +{ static int init_count; @@ -41,124 +42,160 @@ static PixelMargins margins_local; EXPORT const PixelSizes & sizes = sizes_local; EXPORT const PixelMargins & margins = margins_local; -EXPORT void init () +EXPORT void init() { - if (init_count ++) + if (init_count++) return; static char app_name[] = "audacious"; static int dummy_argc = 1; static char * dummy_argv[] = {app_name, nullptr}; - auto qapp = new QApplication (dummy_argc, dummy_argv); + auto qapp = new QApplication(dummy_argc, dummy_argv); - qapp->setAttribute (Qt::AA_UseHighDpiPixmaps); + qapp->setAttribute(Qt::AA_UseHighDpiPixmaps); #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) - qapp->setAttribute (Qt::AA_ForceRasterWidgets); + qapp->setAttribute(Qt::AA_ForceRasterWidgets); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) - qapp->setAttribute (Qt::AA_UseStyleSheetPropagationInWidgetStyles); + qapp->setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); #endif - qapp->setApplicationName (_("Audacious")); - if (qapp->windowIcon ().isNull ()) - qapp->setWindowIcon (audqt::get_icon (app_name)); + qapp->setApplicationName(_("Audacious")); + if (qapp->windowIcon().isNull()) + qapp->setWindowIcon(audqt::get_icon(app_name)); + + qapp->setQuitOnLastWindowClosed(false); + + auto desktop = qapp->desktop(); + sizes_local.OneInch = + aud::max(96, (desktop->logicalDpiX() + desktop->logicalDpiY()) / 2); + sizes_local.TwoPt = aud::rescale(2, 72, sizes_local.OneInch); + sizes_local.FourPt = aud::rescale(4, 72, sizes_local.OneInch); + sizes_local.EightPt = aud::rescale(8, 72, sizes_local.OneInch); + + margins_local.TwoPt = + QMargins(sizes.TwoPt, sizes.TwoPt, sizes.TwoPt, sizes.TwoPt); + margins_local.FourPt = + QMargins(sizes.FourPt, sizes.FourPt, sizes.FourPt, sizes.FourPt); + margins_local.EightPt = + QMargins(sizes.EightPt, sizes.EightPt, sizes.EightPt, sizes.EightPt); + +#ifdef Q_OS_MAC // Mac-specific font tweaks + QApplication::setFont(QApplication::font("QSmallFont"), "QDialog"); + QApplication::setFont(QApplication::font("QSmallFont"), "QTreeView"); + QApplication::setFont(QApplication::font("QTipLabel"), "QStatusBar"); +#endif - qapp->setQuitOnLastWindowClosed (false); + log_init(); +} - auto desktop = qapp->desktop (); - sizes_local.OneInch = aud::max (96, (desktop->logicalDpiX () + desktop->logicalDpiY ()) / 2); - sizes_local.TwoPt = aud::rescale (2, 72, sizes_local.OneInch); - sizes_local.FourPt = aud::rescale (4, 72, sizes_local.OneInch); - sizes_local.EightPt = aud::rescale (8, 72, sizes_local.OneInch); +EXPORT void run() { qApp->exec(); } - margins_local.TwoPt = QMargins (sizes.TwoPt, sizes.TwoPt, sizes.TwoPt, sizes.TwoPt); - margins_local.FourPt = QMargins (sizes.FourPt, sizes.FourPt, sizes.FourPt, sizes.FourPt); - margins_local.EightPt = QMargins (sizes.EightPt, sizes.EightPt, sizes.EightPt, sizes.EightPt); +EXPORT void quit() { qApp->quit(); } -#ifdef Q_OS_MAC // Mac-specific font tweaks - QApplication::setFont (QApplication::font ("QSmallFont"), "QDialog"); - QApplication::setFont (QApplication::font ("QSmallFont"), "QTreeView"); - QApplication::setFont (QApplication::font ("QTipLabel"), "QStatusBar"); -#endif +EXPORT void cleanup() +{ + if (--init_count) + return; - log_init (); -} + aboutwindow_hide(); + eq_presets_hide(); + equalizer_hide(); + infopopup_hide_now(); + infowin_hide(); + log_inspector_hide(); + prefswin_hide(); + queue_manager_hide(); -EXPORT void run () -{ - qApp->exec (); + log_cleanup(); + + delete qApp; } -EXPORT void quit () +EXPORT QIcon get_icon(const char * name) { - qApp->quit (); + auto icon = QIcon::fromTheme(name); + + if (icon.isNull()) + icon = QIcon(QString(":/") + name + ".svg"); + + return icon; } -EXPORT void cleanup () +EXPORT QGradientStops dark_bg_gradient(const QColor & base) { - if (-- init_count) - return; + constexpr int s[4] = {40, 28, 16, 24}; + + QColor c[4]; + for (int i = 0; i < 4; i++) + c[i] = QColor(s[i], s[i], s[i]); - aboutwindow_hide (); - equalizer_hide (); - infopopup_hide_now (); - infowin_hide (); - log_inspector_hide (); - prefswin_hide (); - queue_manager_hide (); + /* in a dark theme, try to match the tone of the base color */ + int v = base.value(); + if (v >= 10 && v < 80) + { + int r = base.red(), g = base.green(), b = base.blue(); - log_cleanup (); + for (int i = 0; i < 4; i++) + { + c[i] = QColor(r * s[i] / v, g * s[i] / v, b * s[i] / v); + } + } - delete qApp; + return {{0, c[0]}, {0.45, c[1]}, {0.55, c[2]}, {1, c[3]}}; } -EXPORT QIcon get_icon (const char * name) +EXPORT QColor vis_bar_color(const QColor & hue, int bar, int n_bars) { - auto icon = QIcon::fromTheme (name); + qreal h, s, v; + hue.getHsvF(&h, &s, &v); - if (icon.isNull ()) - icon = QIcon (QString (":/") + name + ".svg"); + if (s < 0.1) /* monochrome? use blue instead */ + h = 0.67; - return icon; + s = 1 - 0.9 * bar / (n_bars - 1); + v = 0.75 + 0.25 * bar / (n_bars - 1); + + return QColor::fromHsvF(h, s, v); } -EXPORT QHBoxLayout * make_hbox (QWidget * parent, int spacing) +EXPORT QHBoxLayout * make_hbox(QWidget * parent, int spacing) { - auto layout = new QHBoxLayout (parent); - layout->setContentsMargins (0, 0, 0, 0); - layout->setSpacing (spacing); + auto layout = new QHBoxLayout(parent); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(spacing); return layout; } -EXPORT QVBoxLayout * make_vbox (QWidget * parent, int spacing) +EXPORT QVBoxLayout * make_vbox(QWidget * parent, int spacing) { - auto layout = new QVBoxLayout (parent); - layout->setContentsMargins (0, 0, 0, 0); - layout->setSpacing (spacing); + auto layout = new QVBoxLayout(parent); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(spacing); return layout; } -EXPORT void enable_layout (QLayout * layout, bool enabled) +EXPORT void enable_layout(QLayout * layout, bool enabled) { - int count = layout->count (); - for (int i = 0; i < count; i ++) + int count = layout->count(); + for (int i = 0; i < count; i++) { - auto item = layout->itemAt (i); - if (QLayout * layout2 = item->layout ()) - enable_layout (layout2, enabled); - if (QWidget * widget = item->widget ()) - widget->setEnabled (enabled); + auto item = layout->itemAt(i); + if (QLayout * layout2 = item->layout()) + enable_layout(layout2, enabled); + if (QWidget * widget = item->widget()) + widget->setEnabled(enabled); } } -EXPORT void clear_layout (QLayout * layout) +EXPORT void clear_layout(QLayout * layout) { - while (QLayoutItem * item = layout->takeAt (0)) + while (QLayoutItem * item = layout->takeAt(0)) { - if (QLayout * layout2 = item->layout ()) - clear_layout (layout2); - if (QWidget * widget = item->widget ()) + if (QLayout * layout2 = item->layout()) + clear_layout(layout2); + if (QWidget * widget = item->widget()) delete widget; delete item; @@ -166,42 +203,43 @@ EXPORT void clear_layout (QLayout * layout) } /* the goal is to force a window to come to the front on any Qt platform */ -EXPORT void window_bring_to_front (QWidget * window) +EXPORT void window_bring_to_front(QWidget * window) { - window->show (); + window->show(); - Qt::WindowStates state = window->windowState (); + Qt::WindowStates state = window->windowState(); state &= ~Qt::WindowMinimized; state |= Qt::WindowActive; - window->setWindowState (state); - window->raise (); - window->activateWindow (); + window->setWindowState(state); + window->raise(); + window->activateWindow(); } -EXPORT void simple_message (const char * title, const char * text) +EXPORT void simple_message(const char * title, const char * text) { - simple_message (title, text, QMessageBox::NoIcon); + simple_message(title, text, QMessageBox::NoIcon); } -EXPORT void simple_message (const char * title, const char * text, QMessageBox::Icon icon) +EXPORT void simple_message(const char * title, const char * text, + QMessageBox::Icon icon) { - auto msgbox = new QMessageBox (icon, title, text, QMessageBox::Close); - msgbox->button (QMessageBox::Close)->setText (translate_str (N_("_Close"))); - msgbox->setAttribute (Qt::WA_DeleteOnClose); - msgbox->show (); + auto msgbox = new QMessageBox(icon, title, text, QMessageBox::Close); + msgbox->button(QMessageBox::Close)->setText(translate_str(N_("_Close"))); + msgbox->setAttribute(Qt::WA_DeleteOnClose); + msgbox->show(); } /* translate GTK+ accelerators and also handle dgettext() */ -EXPORT QString translate_str (const char * str, const char * domain) +EXPORT QString translate_str(const char * str, const char * domain) { /* handle null and empty strings */ - if (! str || ! str[0]) - return QString (str); + if (!str || !str[0]) + return QString(str); /* translate the GTK+ accelerator (_) into a Qt accelerator (&) */ - return QString (dgettext (domain, str)).replace ('_', '&'); + return QString(dgettext(domain, str)).replace('_', '&'); } } // namespace audqt diff --git a/src/libaudqt/colorbutton.cc b/src/libaudqt/colorbutton.cc new file mode 100644 index 0000000..a3d631a --- /dev/null +++ b/src/libaudqt/colorbutton.cc @@ -0,0 +1,62 @@ +/* + * colorbutton.h + * Copyright 2019 Ariadne Conill + * + * 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 "colorbutton.h" +#include "libaudqt.h" + +#include +#include + +namespace audqt +{ + +ColorButton::ColorButton(QWidget * parent) : QPushButton(parent) +{ + connect(this, &QPushButton::clicked, [this]() { + auto dialog = findChild(); + if (!dialog) + { + dialog = new QColorDialog(m_color, this); + dialog->setAttribute(Qt::WA_DeleteOnClose); + connect(dialog, &QColorDialog::colorSelected, this, + &ColorButton::setColor); + } + + window_bring_to_front(dialog); + }); +} + +void ColorButton::setColor(const QColor & color) +{ + if (color != m_color) + { + m_color = color; + update(); + + onColorChanged(); + } +} + +void ColorButton::paintEvent(QPaintEvent * event) +{ + QPushButton::paintEvent(event); + QPainter(this).fillRect(rect() - margins.FourPt, m_color); +} + +} // namespace audqt diff --git a/src/libaudqt/colorbutton.h b/src/libaudqt/colorbutton.h new file mode 100644 index 0000000..da8803b --- /dev/null +++ b/src/libaudqt/colorbutton.h @@ -0,0 +1,52 @@ +/* + * colorbutton.h + * Copyright 2019 Ariadne Conill + * + * 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 LIBAUDQT_COLORBUTTON_H +#define LIBAUDQT_COLORBUTTON_H + +#include "libaudqt/export.h" + +#include +#include + +namespace audqt +{ + +class LIBAUDQT_PUBLIC ColorButton : public QPushButton +{ +public: + ColorButton(QWidget * parent = nullptr); + ~ColorButton(){}; + + void setColor(const QColor &); + + QColor color() const { return m_color; } + +protected: + virtual void onColorChanged(){}; + +private: + void paintEvent(QPaintEvent *) override; + + QColor m_color; +}; + +} // namespace audqt + +#endif diff --git a/src/libaudqt/eq-preset-qt.cc b/src/libaudqt/eq-preset-qt.cc new file mode 100644 index 0000000..33f2196 --- /dev/null +++ b/src/libaudqt/eq-preset-qt.cc @@ -0,0 +1,414 @@ +/* + * eq-preset-qt.cc + * Copyright 2018 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 "libaudqt.h" +#include "treeview.h" + +#include +#include +#include +#include +#include +#include + +#include "libaudcore/audstrings.h" +#include "libaudcore/equalizer.h" +#include "libaudcore/i18n.h" +#include "libaudcore/interface.h" +#include "libaudcore/runtime.h" +#include "libaudcore/vfs.h" + +namespace audqt +{ + +class PresetItem : public QStandardItem +{ +public: + explicit PresetItem(const EqualizerPreset & preset) + : QStandardItem((const char *)preset.name), preset(preset) + { + } + + const EqualizerPreset preset; +}; + +class PresetModel : public QStandardItemModel +{ +public: + explicit PresetModel(QObject * parent) : QStandardItemModel(0, 1, parent) {} + + void load_all(); + void save_all(); + + QModelIndex add_preset(const EqualizerPreset & preset); + QModelIndex add_preset(const char * name); + void apply_preset(int row); + + const EqualizerPreset * preset_at(int row) const + { + auto pitem = static_cast(item(row)); + return pitem ? &pitem->preset : nullptr; + } + + bool removeRows(int row, int count, + const QModelIndex & parent = QModelIndex()) override + { + bool removed = QStandardItemModel::removeRows(row, count, parent); + m_changed = m_changed || removed; + return removed; + } + +private: + bool m_changed = false; +}; + +void PresetModel::load_all() +{ + clear(); + + auto presets = aud_eq_read_presets("eq.preset"); + for (const EqualizerPreset & preset : presets) + appendRow(new PresetItem(preset)); + + m_changed = false; +} + +void PresetModel::save_all() +{ + if (!m_changed) + return; + + Index presets; + for (int row = 0; row < rowCount(); row++) + presets.append(*preset_at(row)); + + presets.sort([](const EqualizerPreset & a, const EqualizerPreset & b) { + return strcmp(a.name, b.name); + }); + + aud_eq_write_presets(presets, "eq.preset"); + m_changed = false; +} + +QModelIndex PresetModel::add_preset(const EqualizerPreset & preset) +{ + int insert_idx = rowCount(); + for (int row = 0; row < rowCount(); row++) + { + if (preset_at(row)->name == preset.name) + { + insert_idx = row; + break; + } + } + + setItem(insert_idx, new PresetItem(preset)); + m_changed = true; + + return index(insert_idx, 0); +} + +QModelIndex PresetModel::add_preset(const char * name) +{ + EqualizerPreset preset{String(name)}; + aud_eq_update_preset(preset); + return add_preset(preset); +} + +void PresetModel::apply_preset(int row) +{ + auto preset = preset_at(row); + if (!preset) + return; + + aud_eq_apply_preset(*preset); + aud_set_bool("equalizer_active", true); +} + +class PresetView : public TreeView +{ +public: + PresetView(QPushButton * export_btn) : m_export_btn(export_btn) + { + setEditTriggers(QTreeView::NoEditTriggers); + setHeaderHidden(true); + setIndentation(0); + setSelectionMode(QTreeView::ExtendedSelection); + setUniformRowHeights(true); + + auto pmodel = new PresetModel(this); + pmodel->load_all(); + setModel(pmodel); + } + + PresetModel * pmodel() const { return static_cast(model()); } + + void add_imported(const Index & presets); + + const EqualizerPreset * preset_for_export() const + { + auto idxs = selectionModel()->selectedIndexes(); + if (idxs.size() != 1) + return nullptr; + + return pmodel()->preset_at(idxs[0].row()); + } + +protected: + void activate(const QModelIndex & index) override + { + pmodel()->apply_preset(index.row()); + } + + void selectionChanged(const QItemSelection & selected, + const QItemSelection & deselected) override + { + TreeView::selectionChanged(selected, deselected); + + auto idxs = selectionModel()->selectedIndexes(); + m_export_btn->setEnabled(idxs.size() == 1); + } + +private: + QPushButton * m_export_btn; +}; + +void PresetView::add_imported(const Index & presets) +{ + QItemSelection sel; + for (auto & preset : presets) + { + auto idx = pmodel()->add_preset(preset); + sel.select(idx, idx); + } + + selectionModel()->select(sel, QItemSelectionModel::Clear | + QItemSelectionModel::SelectCurrent); + + if (presets.len() == 1) + { + aud_eq_apply_preset(presets[0]); + aud_set_bool("equalizer_active", true); + } +} + +static Index import_file(const char * filename) +{ + VFSFile file(filename, "r"); + if (!file) + return Index(); + + if (str_has_suffix_nocase(filename, ".eqf") || + str_has_suffix_nocase(filename, ".q1")) + { + return aud_import_winamp_presets(file); + } + + /* assume everything else is a native preset file */ + Index presets; + presets.append(); + + if (!aud_load_preset_file(presets[0], file)) + presets.clear(); + + return presets; +} + +static bool export_file(const char * filename, const EqualizerPreset & preset) +{ + VFSFile file(filename, "w"); + if (!file) + return false; + + if (str_has_suffix_nocase(filename, ".eqf") || + str_has_suffix_nocase(filename, ".q1")) + { + return aud_export_winamp_preset(preset, file); + } + + /* assume everything else is a native preset file */ + return aud_save_preset_file(preset, file); +} + +static const char * name_filter = N_("Preset files (*.preset *.eqf *.q1)"); + +static void show_import_dialog(QDialog * parent, PresetView * view) +{ + auto dialog = new QFileDialog(parent, _("Load Preset File")); + + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setFileMode(QFileDialog::ExistingFile); + dialog->setLabelText(QFileDialog::Accept, _("Load")); + dialog->setNameFilter(_(name_filter)); + + QObject::connect(dialog, &QFileDialog::accepted, [dialog, view]() { + auto urls = dialog->selectedUrls(); + if (urls.size() != 1) + return; + + auto filename = urls[0].toEncoded(); + auto presets = import_file(filename); + + if (presets.len()) + { + view->add_imported(presets); + dialog->deleteLater(); + } + else + { + aud_ui_show_error( + str_printf(_("Error loading %s."), filename.constData())); + } + }); + + window_bring_to_front(dialog); +} + +static void show_export_dialog(QDialog * parent, const EqualizerPreset & preset) +{ + auto dialog = new QFileDialog(parent, _("Save Preset File")); + + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setAcceptMode(QFileDialog::AcceptSave); + dialog->setFileMode(QFileDialog::AnyFile); + dialog->setLabelText(QFileDialog::Accept, _("Save")); + dialog->setNameFilter(_(name_filter)); + + /* TODO: replace other illegal characters on Win32 */ + auto safe = + QString(preset.name).replace(QLatin1Char('/'), QLatin1Char('_')); + dialog->selectFile(safe + ".preset"); + + QObject::connect(dialog, &QFileDialog::accepted, [dialog, preset]() { + auto urls = dialog->selectedUrls(); + if (urls.size() != 1) + return; + + auto filename = urls[0].toEncoded(); + + if (export_file(filename, preset)) + dialog->deleteLater(); + else + aud_ui_show_error( + str_printf(_("Error saving %s."), filename.constData())); + }); + + window_bring_to_front(dialog); +} + +static QDialog * create_preset_win() +{ + auto win = new QDialog; + win->setAttribute(Qt::WA_DeleteOnClose); + win->setWindowTitle(_("Equalizer Presets")); + win->setContentsMargins(margins.TwoPt); + + auto edit = new QLineEdit; + auto save_btn = new QPushButton(_("Save Preset")); + save_btn->setIcon(get_icon("document-save")); + save_btn->setDisabled(true); + + auto hbox = make_hbox(nullptr); + hbox->addWidget(edit); + hbox->addWidget(save_btn); + + auto import_btn = new QPushButton(_("Import")); + import_btn->setIcon(get_icon("document-open")); + + auto export_btn = new QPushButton(_("Export")); + export_btn->setIcon(get_icon("document-save")); + + auto view = new PresetView(export_btn); + + auto hbox2 = make_hbox(nullptr); + hbox2->addWidget(import_btn); + hbox2->addWidget(export_btn); + hbox2->addStretch(1); + + auto revert_btn = new QPushButton(_("Revert Changes")); + revert_btn->setIcon(get_icon("edit-undo")); + revert_btn->setDisabled(true); + + auto close_btn = new QPushButton(_("Close")); + close_btn->setIcon(get_icon("window-close")); + + auto hbox3 = make_hbox(nullptr); + hbox3->addWidget(revert_btn); + hbox3->addStretch(1); + hbox3->addWidget(close_btn); + + auto vbox = make_vbox(win); + vbox->addLayout(hbox); + vbox->addWidget(view); + vbox->addLayout(hbox2); + vbox->addLayout(hbox3); + + auto pmodel = view->pmodel(); + + QObject::connect(edit, &QLineEdit::textChanged, + [save_btn](const QString & text) { + save_btn->setEnabled(!text.isEmpty()); + }); + + QObject::connect(save_btn, &QPushButton::clicked, + [view, pmodel, edit, revert_btn]() { + auto added = pmodel->add_preset(edit->text().toUtf8()); + view->setCurrentIndex(added); + revert_btn->setDisabled(false); + }); + + QObject::connect(import_btn, &QPushButton::clicked, + [win, view]() { show_import_dialog(win, view); }); + + QObject::connect(export_btn, &QPushButton::clicked, [win, view]() { + auto preset = view->preset_for_export(); + if (preset != nullptr) + show_export_dialog(win, *preset); + }); + + QObject::connect(pmodel, &PresetModel::rowsRemoved, + [revert_btn]() { revert_btn->setDisabled(false); }); + + QObject::connect(revert_btn, &QPushButton::clicked, [pmodel, revert_btn]() { + pmodel->load_all(); + revert_btn->setDisabled(true); + }); + + QObject::connect(close_btn, &QPushButton::clicked, win, + &QObject::deleteLater); + + QObject::connect(win, &QObject::destroyed, + [pmodel]() { pmodel->save_all(); }); + + return win; +} + +static QPointer s_preset_win; + +EXPORT void eq_presets_show() +{ + if (!s_preset_win) + s_preset_win = create_preset_win(); + + window_bring_to_front(s_preset_win); +} + +EXPORT void eq_presets_hide() { delete s_preset_win; } + +} // namespace audqt diff --git a/src/libaudqt/equalizer-qt.cc b/src/libaudqt/equalizer-qt.cc index 01907ce..e603c94 100644 --- a/src/libaudqt/equalizer-qt.cc +++ b/src/libaudqt/equalizer-qt.cc @@ -1,6 +1,6 @@ /* * equalizer.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,29 +38,31 @@ class VLabel : public QLabel { public: - VLabel (const QString & text, QWidget * parent = nullptr) : - QLabel (text, parent) {} + VLabel(const QString & text, QWidget * parent = nullptr) + : QLabel(text, parent) + { + } - QSize minimumSizeHint () const + QSize minimumSizeHint() const { - QSize s = QLabel::minimumSizeHint (); - return QSize (s.height (), s.width ()); + QSize s = QLabel::minimumSizeHint(); + return QSize(s.height(), s.width()); } - QSize sizeHint () const + QSize sizeHint() const { - QSize s = QLabel::sizeHint (); - return QSize (s.height (), s.width ()); + QSize s = QLabel::sizeHint(); + return QSize(s.height(), s.width()); } - void paintEvent (QPaintEvent *) + void paintEvent(QPaintEvent *) { - QPainter p (this); - p.rotate (270); + QPainter p(this); + p.rotate(270); - QRect box (-height (), 0, height (), width ()); - style ()->drawItemText (& p, box, (int) alignment (), palette (), - isEnabled (), text (), QPalette::Foreground); + QRect box(-height(), 0, height(), width()); + style()->drawItemText(&p, box, (int)alignment(), palette(), isEnabled(), + text(), QPalette::Foreground); } }; @@ -68,24 +71,23 @@ class EqualizerSlider : public QWidget public: QSlider slider; - EqualizerSlider (const char * label, QWidget * parent) : - QWidget (parent), - slider (Qt::Vertical) + EqualizerSlider(const char * label, QWidget * parent) + : QWidget(parent), slider(Qt::Vertical) { - slider.setMinimumHeight (audqt::sizes.OneInch); - slider.setRange (-AUD_EQ_MAX_GAIN, AUD_EQ_MAX_GAIN); - slider.setTickInterval (AUD_EQ_MAX_GAIN >> 1); - slider.setTickPosition (QSlider::TicksBothSides); + slider.setMinimumHeight(audqt::sizes.OneInch); + slider.setRange(-AUD_EQ_MAX_GAIN, AUD_EQ_MAX_GAIN); + slider.setTickInterval(AUD_EQ_MAX_GAIN >> 1); + slider.setTickPosition(QSlider::TicksBothSides); - auto layout = audqt::make_vbox (this); - auto value_label = new QLabel ("0"); + auto layout = audqt::make_vbox(this); + auto value_label = new QLabel("0"); - layout->addWidget (new VLabel (label, this), 1, Qt::AlignCenter); - layout->addWidget (& slider, 0, Qt::AlignCenter); - layout->addWidget (value_label, 0, Qt::AlignCenter); + layout->addWidget(new VLabel(label, this), 1, Qt::AlignCenter); + layout->addWidget(&slider, 0, Qt::AlignCenter); + layout->addWidget(value_label, 0, Qt::AlignCenter); - connect (& slider, & QSlider::valueChanged, [value_label] (int value) { - value_label->setText (QString::number (value)); + connect(&slider, &QSlider::valueChanged, [value_label](int value) { + value_label->setText(QString::number(value)); }); } }; @@ -93,119 +95,128 @@ public: class EqualizerWindow : public QDialog { public: - EqualizerWindow (); + EqualizerWindow(); private: QCheckBox m_onoff_checkbox; EqualizerSlider * m_preamp_slider; EqualizerSlider * m_sliders[AUD_EQ_NBANDS]; - void updateActive (); - void updatePreamp (); - void updateBands (); + void updateActive(); + void updatePreamp(); + void updateBands(); - const HookReceiver - hook1 {"set equalizer_active", this, & EqualizerWindow::updateActive}, - hook2 {"set equalizer_preamp", this, & EqualizerWindow::updatePreamp}, - hook3 {"set equalizer_bands", this, & EqualizerWindow::updateBands}; + const HookReceiver hook1{"set equalizer_active", this, + &EqualizerWindow::updateActive}, + hook2{"set equalizer_preamp", this, &EqualizerWindow::updatePreamp}, + hook3{"set equalizer_bands", this, &EqualizerWindow::updateBands}; }; -EqualizerWindow::EqualizerWindow () : - m_onoff_checkbox (audqt::translate_str (N_("_Enable"))) +EqualizerWindow::EqualizerWindow() + : m_onoff_checkbox(audqt::translate_str(N_("_Enable"))) { - const char * const names[AUD_EQ_NBANDS] = {N_("31 Hz"), N_("63 Hz"), - N_("125 Hz"), N_("250 Hz"), N_("500 Hz"), N_("1 kHz"), N_("2 kHz"), - N_("4 kHz"), N_("8 kHz"), N_("16 kHz")}; + const char * const names[AUD_EQ_NBANDS] = { + N_("31 Hz"), N_("63 Hz"), N_("125 Hz"), N_("250 Hz"), N_("500 Hz"), + N_("1 kHz"), N_("2 kHz"), N_("4 kHz"), N_("8 kHz"), N_("16 kHz")}; - auto slider_container = new QWidget (this); - auto slider_layout = audqt::make_hbox (slider_container, audqt::sizes.TwoPt); + auto slider_container = new QWidget(this); + auto slider_layout = audqt::make_hbox(slider_container, audqt::sizes.TwoPt); - m_preamp_slider = new EqualizerSlider (_("Preamp"), this); - slider_layout->addWidget (m_preamp_slider); + m_preamp_slider = new EqualizerSlider(_("Preamp"), this); + slider_layout->addWidget(m_preamp_slider); - auto line = new QFrame (this); - line->setFrameShape (QFrame::VLine); - line->setFrameShadow (QFrame::Sunken); - slider_layout->addWidget (line); + auto line = new QFrame(this); + line->setFrameShape(QFrame::VLine); + line->setFrameShadow(QFrame::Sunken); + slider_layout->addWidget(line); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) + for (int i = 0; i < AUD_EQ_NBANDS; i++) { - m_sliders[i] = new EqualizerSlider (_(names[i]), this); - slider_layout->addWidget (m_sliders[i]); + m_sliders[i] = new EqualizerSlider(_(names[i]), this); + slider_layout->addWidget(m_sliders[i]); } - auto layout = audqt::make_vbox (this); - layout->setSizeConstraint (QLayout::SetFixedSize); - layout->addWidget (& m_onoff_checkbox); - layout->addWidget (slider_container); + auto zero_button = new QPushButton(_("Reset to Zero"), this); + auto preset_button = new QPushButton(_("Presets ..."), this); - setWindowTitle (_("Equalizer")); - setContentsMargins (audqt::margins.EightPt); + auto hbox = audqt::make_hbox(nullptr); + hbox->addWidget(&m_onoff_checkbox); + hbox->addStretch(1); + hbox->addWidget(zero_button); + hbox->addWidget(preset_button); - m_onoff_checkbox.setFocus (); + auto layout = audqt::make_vbox(this); + layout->setSizeConstraint(QLayout::SetFixedSize); + layout->addLayout(hbox); + layout->addWidget(slider_container); - updateActive (); - updatePreamp (); - updateBands (); + setWindowTitle(_("Equalizer")); + setContentsMargins(audqt::margins.EightPt); - connect (& m_onoff_checkbox, & QCheckBox::stateChanged, [] (int state) { - aud_set_bool (nullptr, "equalizer_active", (state == Qt::Checked)); - }); + m_onoff_checkbox.setFocus(); - connect (& m_preamp_slider->slider, & QSlider::valueChanged, [] (int value) { - aud_set_int (nullptr, "equalizer_preamp", value); + updateActive(); + updatePreamp(); + updateBands(); + + connect(&m_onoff_checkbox, &QCheckBox::stateChanged, [](int state) { + aud_set_bool("equalizer_active", (state == Qt::Checked)); }); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) + connect(zero_button, &QPushButton::clicked, + []() { aud_eq_apply_preset(EqualizerPreset()); }); + + connect(preset_button, &QPushButton::clicked, audqt::eq_presets_show); + + connect(&m_preamp_slider->slider, &QSlider::valueChanged, + [](int value) { aud_set_int("equalizer_preamp", value); }); + + for (int i = 0; i < AUD_EQ_NBANDS; i++) { - connect (& m_sliders[i]->slider, & QSlider::valueChanged, [i] (int value) { - aud_eq_set_band (i, value); - }); + connect(&m_sliders[i]->slider, &QSlider::valueChanged, + [i](int value) { aud_eq_set_band(i, value); }); } } -void EqualizerWindow::updateActive () +void EqualizerWindow::updateActive() { - bool active = aud_get_bool (nullptr, "equalizer_active"); - m_onoff_checkbox.setCheckState (active ? Qt::Checked : Qt::Unchecked); + bool active = aud_get_bool("equalizer_active"); + m_onoff_checkbox.setCheckState(active ? Qt::Checked : Qt::Unchecked); } -void EqualizerWindow::updatePreamp () +void EqualizerWindow::updatePreamp() { - m_preamp_slider->slider.setValue (aud_get_int (nullptr, "equalizer_preamp")); + m_preamp_slider->slider.setValue(aud_get_int("equalizer_preamp")); } -void EqualizerWindow::updateBands () +void EqualizerWindow::updateBands() { double values[AUD_EQ_NBANDS]; - aud_eq_get_bands (values); + aud_eq_get_bands(values); - for (int i = 0; i < AUD_EQ_NBANDS; i ++) - m_sliders[i]->slider.setValue (values[i]); + for (int i = 0; i < AUD_EQ_NBANDS; i++) + m_sliders[i]->slider.setValue(values[i]); } static EqualizerWindow * s_equalizer = nullptr; -namespace audqt { +namespace audqt +{ -EXPORT void equalizer_show () +EXPORT void equalizer_show() { - if (! s_equalizer) + if (!s_equalizer) { s_equalizer = new EqualizerWindow; - s_equalizer->setAttribute (Qt::WA_DeleteOnClose); + s_equalizer->setAttribute(Qt::WA_DeleteOnClose); - QObject::connect (s_equalizer, & QObject::destroyed, [] () { - s_equalizer = nullptr; - }); + QObject::connect(s_equalizer, &QObject::destroyed, + []() { s_equalizer = nullptr; }); } - window_bring_to_front (s_equalizer); + window_bring_to_front(s_equalizer); } -EXPORT void equalizer_hide () -{ - delete s_equalizer; -} +EXPORT void equalizer_hide() { delete s_equalizer; } } // namespace audqt diff --git a/src/libaudqt/export.h b/src/libaudqt/export.h index 457e848..8662a73 100644 --- a/src/libaudqt/export.h +++ b/src/libaudqt/export.h @@ -21,13 +21,13 @@ #define LIBAUDQT_EXPORT_H #ifdef _WIN32 - #ifdef LIBAUDQT_BUILD - #define LIBAUDQT_PUBLIC __declspec(dllexport) - #else - #define LIBAUDQT_PUBLIC __declspec(dllimport) - #endif +#ifdef LIBAUDQT_BUILD +#define LIBAUDQT_PUBLIC __declspec(dllexport) #else - #define LIBAUDQT_PUBLIC __attribute__ ((visibility ("default"))) +#define LIBAUDQT_PUBLIC __declspec(dllimport) +#endif +#else +#define LIBAUDQT_PUBLIC __attribute__((visibility("default"))) #endif #endif // LIBAUDQT_EXPORT_H diff --git a/src/libaudqt/file-entry.cc b/src/libaudqt/file-entry.cc new file mode 100644 index 0000000..9c04068 --- /dev/null +++ b/src/libaudqt/file-entry.cc @@ -0,0 +1,128 @@ +/* + * file-entry.cc + * Copyright 2018 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 "libaudqt.h" + +#include +#include +#include + +#include +#include + +namespace audqt +{ + +class FileEntry : public QLineEdit +{ +public: + FileEntry(QWidget * parent, const char * title, + QFileDialog::FileMode file_mode, + QFileDialog::AcceptMode accept_mode) + : QLineEdit(parent), m_title(title), m_file_mode(file_mode), + m_accept_mode(accept_mode), + m_action(get_icon("document-open"), _("Browse"), nullptr) + { + addAction(&m_action, TrailingPosition); + connect(&m_action, &QAction::triggered, this, &FileEntry::show_dialog); + } + +private: + QFileDialog * create_dialog(); + void show_dialog(); + + const QString m_title; + const QFileDialog::FileMode m_file_mode; + const QFileDialog::AcceptMode m_accept_mode; + + QAction m_action; + QPointer m_dialog; +}; + +QFileDialog * FileEntry::create_dialog() +{ + auto dialog = new QFileDialog(this, m_title); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setFileMode(m_file_mode); + dialog->setAcceptMode(m_accept_mode); + + String uri = file_entry_get_uri(this); + if (uri) + { + // As of Qt 5.11, selectUrl() works fine with the built-in Qt dialog + // but has no effect on the GTK-based dialog. As a workaround, try to + // get a local file path and use selectFile() instead. + StringBuf local = uri_to_filename(uri); + if (local) + dialog->selectFile((const char *)local); + else + dialog->selectUrl(QUrl((const char *)uri)); + } + + QObject::connect(dialog, &QFileDialog::accepted, [this, dialog]() { + auto urls = dialog->selectedUrls(); + if (urls.length() == 1) + file_entry_set_uri(this, urls[0].toEncoded().constData()); + }); + + return dialog; +} + +void FileEntry::show_dialog() +{ + if (!m_dialog) + m_dialog = create_dialog(); + + window_bring_to_front(m_dialog); +} + +EXPORT QLineEdit * file_entry_new(QWidget * parent, const char * title, + QFileDialog::FileMode file_mode, + QFileDialog::AcceptMode accept_mode) +{ + return new FileEntry(parent, title, file_mode, accept_mode); +} + +EXPORT String file_entry_get_uri(QLineEdit * entry) +{ + QByteArray text = entry->text().toUtf8(); + + if (text.isEmpty()) + return String(); + else if (strstr(text, "://")) + return String(text); + else + return String(filename_to_uri( + filename_normalize(filename_expand(str_copy(text))))); +} + +EXPORT void file_entry_set_uri(QLineEdit * entry, const char * uri) +{ + if (!uri || !uri[0]) + { + entry->clear(); + return; + } + + StringBuf path = uri_to_filename(uri, false); + entry->setText(path ? filename_contract(std::move(path)) : uri); + entry->end(false); +} + +} // namespace audqt diff --git a/src/libaudqt/fileopener.cc b/src/libaudqt/fileopener.cc index dc5691f..1ab1e29 100644 --- a/src/libaudqt/fileopener.cc +++ b/src/libaudqt/fileopener.cc @@ -26,110 +26,100 @@ #include -namespace audqt { +namespace audqt +{ static aud::array s_dialogs; -static void import_playlist (Playlist playlist, const String & filename) +static void import_playlist(Playlist playlist, const String & filename) { - playlist.set_filename (filename); - playlist.remove_all_entries (); - playlist.insert_entry (0, filename, Tuple (), false); + playlist.set_filename(filename); + playlist.remove_all_entries(); + playlist.insert_entry(0, filename, Tuple(), false); } -static void export_playlist (Playlist playlist, const String & filename) +static void export_playlist(Playlist playlist, const String & filename) { Playlist::GetMode mode = Playlist::Wait; - if (aud_get_bool (nullptr, "metadata_on_play")) + if (aud_get_bool("metadata_on_play")) mode = Playlist::NoWait; - playlist.set_filename (filename); - playlist.save_to_file (filename, mode); + playlist.set_filename(filename); + playlist.save_to_file(filename, mode); } -EXPORT void fileopener_show (FileMode mode) +EXPORT void fileopener_show(FileMode mode) { - QFileDialog * & dialog = s_dialogs[mode]; + QFileDialog *& dialog = s_dialogs[mode]; - if (! dialog) + if (!dialog) { - static constexpr aud::array titles { - N_("Open Files"), - N_("Open Folder"), - N_("Add Files"), - N_("Add Folder"), - N_("Import Playlist"), - N_("Export Playlist") - }; - - static constexpr aud::array labels { - N_("Open"), - N_("Open"), - N_("Add"), - N_("Add"), - N_("Import"), - N_("Export") - }; - - static constexpr aud::array modes { - QFileDialog::ExistingFiles, - QFileDialog::Directory, - QFileDialog::ExistingFiles, - QFileDialog::Directory, - QFileDialog::ExistingFile, - QFileDialog::AnyFile - }; - - String path = aud_get_str ("audgui", "filesel_path"); - dialog = new QFileDialog (nullptr, _(titles[mode]), QString (path)); - - dialog->setAttribute (Qt::WA_DeleteOnClose); - dialog->setFileMode (modes[mode]); - dialog->setLabelText (QFileDialog::Accept, _(labels[mode])); + static constexpr aud::array titles{ + N_("Open Files"), N_("Open Folder"), N_("Add Files"), + N_("Add Folder"), N_("Import Playlist"), N_("Export Playlist")}; + + static constexpr aud::array labels{ + N_("Open"), N_("Open"), N_("Add"), + N_("Add"), N_("Import"), N_("Export")}; + + static constexpr aud::array modes{ + QFileDialog::ExistingFiles, QFileDialog::Directory, + QFileDialog::ExistingFiles, QFileDialog::Directory, + QFileDialog::ExistingFile, QFileDialog::AnyFile}; + + String path = aud_get_str("audgui", "filesel_path"); + dialog = new QFileDialog(nullptr, _(titles[mode]), QString(path)); + + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setFileMode(modes[mode]); + dialog->setLabelText(QFileDialog::Accept, _(labels[mode])); if (mode == FileMode::ExportPlaylist) - dialog->setAcceptMode (QFileDialog::AcceptSave); - - QObject::connect (dialog, & QFileDialog::directoryEntered, [] (const QString & path) - { aud_set_str ("audgui", "filesel_path", path.toUtf8 ().constData ()); }); - - auto playlist = Playlist::active_playlist (); - - QObject::connect (dialog, & QFileDialog::accepted, [dialog, mode, playlist] () - { - Index files; - for (const QUrl & url : dialog->selectedUrls ()) - files.append (String (url.toEncoded ().constData ())); - - switch (mode) - { - case FileMode::Add: - case FileMode::AddFolder: - aud_drct_pl_add_list (std::move (files), -1); - break; - case FileMode::Open: - case FileMode::OpenFolder: - aud_drct_pl_open_list (std::move (files)); - break; - case FileMode::ImportPlaylist: - if (files.len () == 1) - import_playlist (playlist, files[0].filename); - break; - case FileMode::ExportPlaylist: - if (files.len () == 1) - export_playlist (playlist, files[0].filename); - break; - default: - /* not reached */ - break; - } - }); - - QObject::connect (dialog, & QObject::destroyed, [& dialog] () - { dialog = nullptr; }); + dialog->setAcceptMode(QFileDialog::AcceptSave); + + QObject::connect(dialog, &QFileDialog::directoryEntered, + [](const QString & path) { + aud_set_str("audgui", "filesel_path", + path.toUtf8().constData()); + }); + + auto playlist = Playlist::active_playlist(); + + QObject::connect( + dialog, &QFileDialog::accepted, [dialog, mode, playlist]() { + Index files; + for (const QUrl & url : dialog->selectedUrls()) + files.append(String(url.toEncoded().constData())); + + switch (mode) + { + case FileMode::Add: + case FileMode::AddFolder: + aud_drct_pl_add_list(std::move(files), -1); + break; + case FileMode::Open: + case FileMode::OpenFolder: + aud_drct_pl_open_list(std::move(files)); + break; + case FileMode::ImportPlaylist: + if (files.len() == 1) + import_playlist(playlist, files[0].filename); + break; + case FileMode::ExportPlaylist: + if (files.len() == 1) + export_playlist(playlist, files[0].filename); + break; + default: + /* not reached */ + break; + } + }); + + QObject::connect(dialog, &QObject::destroyed, + [&dialog]() { dialog = nullptr; }); } - window_bring_to_front (dialog); + window_bring_to_front(dialog); } } // namespace audqt diff --git a/src/libaudqt/font-entry.cc b/src/libaudqt/font-entry.cc new file mode 100644 index 0000000..95b4ff5 --- /dev/null +++ b/src/libaudqt/font-entry.cc @@ -0,0 +1,167 @@ +/* + * font-entry.cc + * Copyright 2015 John Lindgren + * Copyright 2019 Ariadne Conill + * + * 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 "libaudqt.h" + +#include +#include +#include +#include + +#include +#include + +namespace audqt +{ + +class FontEntry : public QLineEdit +{ +public: + FontEntry(QWidget * parent = nullptr, const char * font = nullptr) + : QLineEdit(parent), + m_action(get_icon("preferences-desktop-font"), _("Set Font"), nullptr) + { + addAction(&m_action, TrailingPosition); + connect(&m_action, &QAction::triggered, this, &FontEntry::show_dialog); + + if (font) + setText(font); + + end(false); + } + +private: + void show_dialog(); + + QAction m_action; + QPointer m_dialog; +}; + +/* parse a subset of Pango font descriptions */ +EXPORT QFont qfont_from_string(const char * name) +{ + auto family = str_copy(name); + int size = 0; + QFont::Weight weight = QFont::Normal; + QFont::Style style = QFont::StyleNormal; + QFont::Stretch stretch = QFont::Unstretched; + + while (1) + { + /* check for attributes */ + bool attr_found = false; + const char * space = strrchr(family, ' '); + + if (space) + { + const char * attr = space + 1; + int num = str_to_int(attr); + + attr_found = true; + + if (num > 0) + size = num; + else if (!strcmp(attr, "Light")) + weight = QFont::Light; + else if (!strcmp(attr, "Bold")) + weight = QFont::Bold; + else if (!strcmp(attr, "Oblique")) + style = QFont::StyleOblique; + else if (!strcmp(attr, "Italic")) + style = QFont::StyleItalic; + else if (!strcmp(attr, "Condensed")) + stretch = QFont::Condensed; + else if (!strcmp(attr, "Expanded")) + stretch = QFont::Expanded; + else + attr_found = false; + } + + if (!attr_found) + { + QFont font((const char *)family); + + if (size > 0) + font.setPointSize(size); + if (weight != QFont::Normal) + font.setWeight(weight); + if (style != QFont::StyleNormal) + font.setStyle(style); + if (stretch != QFont::Unstretched) + font.setStretch(stretch); + + return font; + } + + family.resize(space - family); + } +} + +EXPORT StringBuf qfont_to_string(const QFont & font) +{ + StringBuf font_str = str_copy(font.family().toUtf8()); + + auto weight = font.weight(); + auto style = font.style(); + auto stretch = font.stretch(); + + if (weight == QFont::Light) + font_str.insert(-1, " Light"); + else if (weight == QFont::Bold) + font_str.insert(-1, " Bold"); + + if (style == QFont::StyleOblique) + font_str.insert(-1, " Oblique"); + else if (style == QFont::StyleItalic) + font_str.insert(-1, " Italic"); + + if (stretch == QFont::Condensed) + font_str.insert(-1, " Condensed"); + else if (stretch == QFont::Expanded) + font_str.insert(-1, " Expanded"); + + str_append_printf(font_str, " %d", font.pointSize()); + + return font_str; +} + +void FontEntry::show_dialog() +{ + if (!m_dialog) + { + m_dialog = new QFontDialog(this); + + QObject::connect(m_dialog, &QFontDialog::fontSelected, + [this](const QFont & font) { + setText((const char *)qfont_to_string(font)); + end(false); + }); + } + + m_dialog->setCurrentFont(qfont_from_string(text().toUtf8())); + window_bring_to_front(m_dialog); +} + +EXPORT QLineEdit * font_entry_new(QWidget * parent, const char * font) +{ + return new FontEntry(parent, font); +} + +} // namespace audqt diff --git a/src/libaudqt/iface.h b/src/libaudqt/iface.h index fe36766..99b0ff4 100644 --- a/src/libaudqt/iface.h +++ b/src/libaudqt/iface.h @@ -1,6 +1,6 @@ /* * iface.h - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,29 +25,37 @@ #include #include -namespace audqt { +namespace audqt +{ class LIBAUDQT_PUBLIC QtIfacePlugin : public IfacePlugin { public: - constexpr QtIfacePlugin (PluginInfo info) : IfacePlugin (info) {} - - void show_about_window () { aboutwindow_show (); } - void hide_about_window () { aboutwindow_hide (); } - - void show_filebrowser (bool open) - { fileopener_show (open ? FileMode::Open : FileMode::Add); } - - void hide_filebrowser () {} - void show_jump_to_song () {} - void hide_jump_to_song () {} - void show_prefs_window () { prefswin_show (); } - void hide_prefs_window () { prefswin_hide (); } - - void plugin_menu_add (AudMenuID id, void func (), const char * name, const char * icon) - { menu_add (id, func, name, icon); } - void plugin_menu_remove (AudMenuID id, void func ()) - { menu_remove (id, func); } + constexpr QtIfacePlugin(PluginInfo info) : IfacePlugin(info) {} + + void show_about_window() { aboutwindow_show(); } + void hide_about_window() { aboutwindow_hide(); } + + void show_filebrowser(bool open) + { + fileopener_show(open ? FileMode::Open : FileMode::Add); + } + + void hide_filebrowser() {} + void show_jump_to_song() {} + void hide_jump_to_song() {} + void show_prefs_window() { prefswin_show(); } + void hide_prefs_window() { prefswin_hide(); } + + void plugin_menu_add(AudMenuID id, void func(), const char * name, + const char * icon) + { + menu_add(id, func, name, icon); + } + void plugin_menu_remove(AudMenuID id, void func()) + { + menu_remove(id, func); + } }; } // namespace audqt diff --git a/src/libaudqt/images.qrc b/src/libaudqt/images.qrc index 93c2ebd..a5f18ef 100644 --- a/src/libaudqt/images.qrc +++ b/src/libaudqt/images.qrc @@ -50,6 +50,7 @@ ../../images/media-skip-backward.svg ../../images/media-skip-forward.svg ../../images/multimedia-volume-control.svg + ../../images/preferences-desktop-font.svg ../../images/preferences-system.svg ../../images/process-stop.svg ../../images/system-run.svg diff --git a/src/libaudqt/info-widget.cc b/src/libaudqt/info-widget.cc index c1eb083..0baa2fd 100644 --- a/src/libaudqt/info-widget.cc +++ b/src/libaudqt/info-widget.cc @@ -1,7 +1,7 @@ /* * info-widget.h * Copyright 2006-2017 René Bertin, Thomas Lange, John Lindgren, - * William Pitcock, Tomasz Moń, and Eugene Zagidullin + * Ariadne Conill, Tomasz Moń, and Eugene Zagidullin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -19,32 +19,40 @@ */ #include "info-widget.h" -#include "libaudqt.h" #include "libaudqt-internal.h" +#include "libaudqt.h" #include +#include +#include #include #include +#include #include -namespace audqt { +namespace audqt +{ -struct TupleFieldMap { +struct TupleFieldMap +{ const char * name; Tuple::Field field; bool editable; }; +static const char * varied_str = N_(""); + static const TupleFieldMap tuple_field_map[] = { {N_("Metadata"), Tuple::Invalid, false}, + {N_("Title"), Tuple::Title, true}, {N_("Artist"), Tuple::Artist, true}, {N_("Album"), Tuple::Album, true}, - {N_("Title"), Tuple::Title, true}, + {N_("Album Artist"), Tuple::AlbumArtist, true}, {N_("Track Number"), Tuple::Track, true}, {N_("Genre"), Tuple::Genre, true}, {N_("Comment"), Tuple::Comment, true}, - {N_("Album Artist"), Tuple::AlbumArtist, true}, + {N_("Description"), Tuple::Description, true}, {N_("Composer"), Tuple::Composer, true}, {N_("Performer"), Tuple::Performer, true}, {N_("Recording Year"), Tuple::Year, true}, @@ -56,160 +64,356 @@ static const TupleFieldMap tuple_field_map[] = { {N_("Codec"), Tuple::Codec, false}, {N_("Quality"), Tuple::Quality, false}, {N_("Bitrate"), Tuple::Bitrate, false}, -}; + {N_("MusicBrainz ID"), Tuple::MusicBrainzID, false}}; + +static const TupleFieldMap * to_field_map(const QModelIndex & index) +{ + int row = index.row(); + if (row < 0 || row >= aud::n_elems(tuple_field_map)) + return nullptr; + + return &tuple_field_map[row]; +} + +static QModelIndex sibling_field_index(const QModelIndex & current, + int direction) +{ + QModelIndex index = current; + + while (1) + { + index = index.sibling(index.row() + direction, index.column()); + auto map = to_field_map(index); + + if (!map) + return QModelIndex(); + if (map->field != Tuple::Invalid) + return index; + } +} + +static QString tuple_field_to_str(const Tuple & tuple, Tuple::Field field) +{ + switch (tuple.get_value_type(field)) + { + case Tuple::String: + return QString(tuple.get_str(field)); + case Tuple::Int: + return QString::number(tuple.get_int(field)); + default: + return QString(); + } +} + +static void tuple_field_set_from_str(Tuple & tuple, Tuple::Field field, + const QString & str) +{ + if (str.isEmpty()) + tuple.unset(field); + else if (Tuple::field_get_type(field) == Tuple::String) + tuple.set_str(field, str.toUtf8()); + else + tuple.set_int(field, str.toInt()); +} + +static bool tuple_field_is_same(const Tuple & a, const Tuple & b, + Tuple::Field field) +{ + auto a_type = a.get_value_type(field); + if (a_type != b.get_value_type(field)) + return false; + + switch (a_type) + { + case Tuple::String: + return (a.get_str(field) == b.get_str(field)); + case Tuple::Int: + return (a.get_int(field) == b.get_int(field)); + default: + return true; + } +} + +static void tuple_field_copy(Tuple & dest, const Tuple & src, + Tuple::Field field) +{ + switch (src.get_value_type(field)) + { + case Tuple::String: + dest.set_str(field, src.get_str(field)); + break; + case Tuple::Int: + dest.set_int(field, src.get_int(field)); + break; + default: + dest.unset(field); + break; + } +} class InfoModel : public QAbstractTableModel { public: - InfoModel (QObject * parent = nullptr) : - QAbstractTableModel (parent) {} + enum + { + Col_Name = 0, + Col_Value = 1 + }; + + InfoModel(QObject * parent = nullptr) : QAbstractTableModel(parent) {} + + int rowCount(const QModelIndex &) const override + { + return aud::n_elems(tuple_field_map); + } + int columnCount(const QModelIndex &) const override { return 2; } - int rowCount (const QModelIndex & parent = QModelIndex ()) const - { return aud::n_elems (tuple_field_map); } - int columnCount (const QModelIndex & parent = QModelIndex ()) const - { return 2; } + QVariant data(const QModelIndex & index, int role) const override; + bool setData(const QModelIndex & index, const QVariant & value, + int role) override; + Qt::ItemFlags flags(const QModelIndex & index) const override; - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); - Qt::ItemFlags flags (const QModelIndex & index) const; + void setItems(Index && items) + { + m_items = std::move(items); + revertTupleData(); + } - void setTupleData (const Tuple & tuple, String filename, PluginHandle * plugin) + void linkEnabled(QWidget * widget) { - m_tuple = tuple.ref (); - m_filename = filename; - m_plugin = plugin; - m_dirty = false; + widget->setEnabled(m_changed_mask != 0); + m_linked_widgets.append(widget); } - bool updateFile () const; + void revertTupleData(); + bool updateFile() const; private: + void updateEnabled() + { + for (auto & widget : m_linked_widgets) + { + if (widget) + widget->setEnabled(m_changed_mask != 0); + } + } + + /* set of filenames, original tuples, decoders */ + Index m_items; + /* local (possibly edited) tuple */ Tuple m_tuple; - String m_filename; - PluginHandle * m_plugin = nullptr; - bool m_dirty = false; + /* bitmask of fields which vary between tuples and will be preserved */ + uint64_t m_varied_mask = 0; + /* bitmask of fields which have been edited */ + uint64_t m_changed_mask = 0; + /* list of widgets to enable when edits have been made */ + QList> m_linked_widgets; }; -EXPORT InfoWidget::InfoWidget (QWidget * parent) : - QTreeView (parent), - m_model (new InfoModel (this)) +EXPORT InfoWidget::InfoWidget(QWidget * parent) + : QTreeView(parent), m_model(new InfoModel(this)) { - setModel (m_model); - header ()->hide (); - setIndentation (0); - resizeColumnToContents (0); - setContextMenuPolicy (Qt::CustomContextMenu); + setModel(m_model); + header()->hide(); + setIndentation(0); + resizeColumnToContents(0); + setContextMenuPolicy(Qt::CustomContextMenu); + + connect(this, &QWidget::customContextMenuRequested, + [this](const QPoint & pos) { + auto index = indexAt(pos); + if (index.column() != InfoModel::Col_Value) + return; + auto text = m_model->data(index, Qt::DisplayRole).toString(); + if (!text.isEmpty()) + show_copy_context_menu(this, mapToGlobal(pos), text); + }); +} - connect (this, & QWidget::customContextMenuRequested, [this] (const QPoint & pos) - { - auto index = indexAt (pos); - if (index.column () != 1) - return; - auto text = m_model->data (index, Qt::DisplayRole).toString (); - if (! text.isEmpty ()) - show_copy_context_menu (this, mapToGlobal (pos), text); - }); +EXPORT InfoWidget::~InfoWidget() {} + +EXPORT void InfoWidget::fillInfo(const char * filename, const Tuple & tuple, + PluginHandle * decoder, bool updating_enabled) +{ + Index items; + items.append(String(filename), tuple.ref(), decoder); + fillInfo(std::move(items), updating_enabled); +} + +EXPORT void InfoWidget::fillInfo(Index && items, + bool updating_enabled) +{ + m_model->setItems(std::move(items)); + reset(); + + setEditTriggers(updating_enabled ? QAbstractItemView::AllEditTriggers + : QAbstractItemView::NoEditTriggers); + + auto initial_index = m_model->index(1 /* title */, InfoModel::Col_Value); + setCurrentIndex(initial_index); +} + +EXPORT void InfoWidget::linkEnabled(QWidget * widget) +{ + m_model->linkEnabled(widget); } -EXPORT InfoWidget::~InfoWidget () +EXPORT void InfoWidget::revertInfo() { + m_model->revertTupleData(); + reset(); } -EXPORT void InfoWidget::fillInfo (const char * filename, const Tuple & tuple, - PluginHandle * decoder, bool updating_enabled) +EXPORT bool InfoWidget::updateFile() { return m_model->updateFile(); } + +void InfoWidget::keyPressEvent(QKeyEvent * event) { - m_model->setTupleData (tuple, String (filename), decoder); - reset (); - setEditTriggers (updating_enabled ? QAbstractItemView::SelectedClicked : QAbstractItemView::NoEditTriggers); + if (event->type() == QEvent::KeyPress && + (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)) + { + auto index = sibling_field_index(currentIndex(), + (event->key() == Qt::Key_Up) ? -1 : 1); + if (index.isValid()) + setCurrentIndex(index); + + event->accept(); + return; + } + + QTreeView::keyPressEvent(event); } -EXPORT bool InfoWidget::updateFile () +void InfoModel::revertTupleData() { - return m_model->updateFile (); + m_tuple = (m_items.len() > 0) ? m_items[0].tuple.ref() : Tuple(); + m_varied_mask = 0; + m_changed_mask = 0; + + for (auto & item : m_items) + { + for (auto field : Tuple::all_fields()) + { + if (!tuple_field_is_same(item.tuple, m_tuple, field)) + m_varied_mask |= (uint64_t)1 << (int)field; + } + } + + updateEnabled(); } -bool InfoModel::updateFile () const +bool InfoModel::updateFile() const { - if (! m_dirty) + if (m_changed_mask == 0) return true; - return aud_file_write_tuple (m_filename, m_plugin, m_tuple); + int n_saved = 0; + + for (auto & item : m_items) + { + auto new_tuple = item.tuple.ref(); + + for (auto field : Tuple::all_fields()) + { + uint64_t mask = ((uint64_t)1 << (int)field); + if ((m_changed_mask & mask) != 0) + tuple_field_copy(new_tuple, m_tuple, field); + } + + if (aud_file_write_tuple(item.filename, item.decoder, new_tuple)) + n_saved++; + } + + return (n_saved == m_items.len()); } -bool InfoModel::setData (const QModelIndex & index, const QVariant & value, int role) +bool InfoModel::setData(const QModelIndex & index, const QVariant & value, + int role) { if (role != Qt::EditRole) return false; - Tuple::Field field_id = tuple_field_map [index.row ()].field; - if (field_id == Tuple::Invalid) + auto map = to_field_map(index); + if (!map || map->field == Tuple::Invalid) return false; - m_dirty = true; + uint64_t mask = ((uint64_t)1 << (int)map->field); + auto str = value.toString(); - auto t = Tuple::field_get_type (field_id); - auto str = value.toString (); + /* prevent accidental overwrite of varied values */ + if ((m_varied_mask & mask) != 0 && str == _(varied_str)) + return false; - if (str.isEmpty ()) - m_tuple.unset (field_id); - else if (t == Tuple::String) - m_tuple.set_str (field_id, str.toUtf8 ()); - else /* t == Tuple::Int */ - m_tuple.set_int (field_id, str.toInt ()); + if ((m_varied_mask & mask) != 0 || + str != tuple_field_to_str(m_tuple, map->field)) + { + tuple_field_set_from_str(m_tuple, map->field, str); + m_varied_mask &= ~mask; + m_changed_mask |= mask; + updateEnabled(); + } - emit dataChanged (index, index, {role}); + emit dataChanged(index, index, {role}); return true; } -QVariant InfoModel::data (const QModelIndex & index, int role) const +QVariant InfoModel::data(const QModelIndex & index, int role) const { - Tuple::Field field_id = tuple_field_map [index.row ()].field; + auto map = to_field_map(index); + if (!map) + return QVariant(); + + uint64_t mask = 0; + if (map->field != Tuple::Invalid) + mask = ((uint64_t)1 << (int)map->field); if (role == Qt::DisplayRole || role == Qt::EditRole) { - if (index.column () == 0) - return translate_str (tuple_field_map [index.row ()].name); - else if (index.column () == 1) + if (index.column() == InfoModel::Col_Name) + return translate_str(map->name); + else if (index.column() == InfoModel::Col_Value) { - if (field_id == Tuple::Invalid) - return QVariant (); - - switch (m_tuple.get_value_type (field_id)) - { - case Tuple::String: - return QString (m_tuple.get_str (field_id)); - case Tuple::Int: - /* convert to string so Qt allows clearing the field */ - return QString::number (m_tuple.get_int (field_id)); - default: - return QVariant (); - } + if (map->field == Tuple::Invalid) + return QVariant(); + + if ((m_varied_mask & mask) != 0) + return QString(_(varied_str)); + + return tuple_field_to_str(m_tuple, map->field); } } else if (role == Qt::FontRole) { - if (field_id == Tuple::Invalid) + if ((index.column() == Col_Name && map->field == Tuple::Invalid) || + (index.column() == Col_Value && (m_changed_mask & mask) != 0)) + { + QFont f; + f.setBold(true); + return f; + } + else if (index.column() == Col_Value && (m_varied_mask & mask) != 0) { QFont f; - f.setBold (true); + f.setItalic(true); return f; } - return QVariant (); + + return QVariant(); } - return QVariant (); + return QVariant(); } -Qt::ItemFlags InfoModel::flags (const QModelIndex & index) const +Qt::ItemFlags InfoModel::flags(const QModelIndex & index) const { - if (index.column () == 1) + if (index.column() == InfoModel::Col_Value) { - auto & t = tuple_field_map [index.row ()]; + auto map = to_field_map(index); - if (t.field == Tuple::Invalid) + if (!map || map->field == Tuple::Invalid) return Qt::ItemNeverHasChildren; - else if (t.editable) - return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; + else if (map->editable) + return Qt::ItemIsSelectable | Qt::ItemIsEditable | + Qt::ItemIsEnabled; return Qt::ItemIsEnabled; } diff --git a/src/libaudqt/info-widget.h b/src/libaudqt/info-widget.h index 80e0483..40f3d2d 100644 --- a/src/libaudqt/info-widget.h +++ b/src/libaudqt/info-widget.h @@ -1,6 +1,6 @@ /* * info-widget.h - * Copyright 2006-2014 William Pitcock, Tomasz Moń, Eugene Zagidullin, + * Copyright 2006-2014 Ariadne Conill, Tomasz Moń, Eugene Zagidullin, * John Lindgren, and Thomas Lange * * Redistribution and use in source and binary forms, with or without @@ -22,24 +22,33 @@ #define LIBAUDQT_INFO_WIDGET_H #include +#include #include +struct PlaylistAddItem; class PluginHandle; class Tuple; -namespace audqt { +namespace audqt +{ class InfoModel; class LIBAUDQT_PUBLIC InfoWidget : public QTreeView { public: - InfoWidget (QWidget * parent = nullptr); - ~InfoWidget (); - - void fillInfo (const char * filename, const Tuple & tuple, - PluginHandle * decoder, bool updating_enabled); - bool updateFile (); + InfoWidget(QWidget * parent = nullptr); + ~InfoWidget(); + + void fillInfo(const char * filename, const Tuple & tuple, + PluginHandle * decoder, bool updating_enabled); + void fillInfo(Index && items, bool updating_enabled); + void linkEnabled(QWidget * widget); + void revertInfo(); + bool updateFile(); + +protected: + void keyPressEvent(QKeyEvent * event) override; private: InfoModel * m_model; diff --git a/src/libaudqt/infopopup-qt.cc b/src/libaudqt/infopopup-qt.cc index de6d7b7..30c1e39 100644 --- a/src/libaudqt/infopopup-qt.cc +++ b/src/libaudqt/infopopup-qt.cc @@ -23,31 +23,32 @@ #include #include -#include "libaudqt.h" #include "libaudqt-internal.h" +#include "libaudqt.h" #include #include #include #include -namespace audqt { +namespace audqt +{ class InfoPopup : public PopupWidget { public: - InfoPopup (const String & filename, const Tuple & tuple); + InfoPopup(const String & filename, const Tuple & tuple); private: - void add_field (int row, const char * field, const char * value); - void add_fields (const Tuple & tuple); - void art_ready (const char * filename); - void finish_loading (); + void add_field(int row, const char * field, const char * value); + void add_fields(const Tuple & tuple); + void art_ready(const char * filename); + void finish_loading(); - void paintEvent (QPaintEvent *) override; + void paintEvent(QPaintEvent *) override; - HookReceiver art_ready_hook - {"art ready", this, & InfoPopup::art_ready}; + HookReceiver art_ready_hook{"art ready", this, + &InfoPopup::art_ready}; const String m_filename; const QGradientStops m_stops; @@ -57,165 +58,141 @@ private: bool m_queued = false; }; -static QGradientStops get_stops (const QColor & base) -{ - QColor mid = QColor (64, 64, 64); - QColor dark = QColor (38, 38, 38); - QColor darker = QColor (26, 26, 26); - - /* In a dark theme, try to match the tone of the base color */ - int v = base.value (); - if (v >= 10 && v < 80) - { - int r = base.red (), g = base.green (), b = base.blue (); - mid = QColor (r * 64 / v, g * 64 / v, b * 64 / v); - dark = QColor (r * 38 / v, g * 38 / v, b * 38 / v); - darker = QColor (r * 26 / v, g * 26 / v, b * 26 / v); - } - - return { - {0, mid}, - {0.499, dark}, - {0.5, darker}, - {1, Qt::black} - }; -} - -InfoPopup::InfoPopup (const String & filename, const Tuple & tuple) : - m_filename (filename), - m_stops (get_stops (palette ().color (QPalette::Window))) +InfoPopup::InfoPopup(const String & filename, const Tuple & tuple) + : m_filename(filename), + m_stops(dark_bg_gradient(palette().color(QPalette::Window))) { - setWindowFlags (Qt::ToolTip); + setWindowFlags(Qt::ToolTip); - m_hbox.setMargin (sizes.TwoPt); - m_hbox.setSpacing (sizes.FourPt); - setLayout (& m_hbox); + m_hbox.setMargin(sizes.TwoPt); + m_hbox.setSpacing(sizes.FourPt); + setLayout(&m_hbox); - m_grid.setMargin (0); - m_grid.setHorizontalSpacing (sizes.FourPt); - m_grid.setVerticalSpacing (0); - m_hbox.addLayout (& m_grid); + m_grid.setMargin(0); + m_grid.setHorizontalSpacing(sizes.FourPt); + m_grid.setVerticalSpacing(0); + m_hbox.addLayout(&m_grid); - add_fields (tuple); - finish_loading (); + add_fields(tuple); + finish_loading(); } -void InfoPopup::add_fields (const Tuple & tuple) +void InfoPopup::add_fields(const Tuple & tuple) { - String title = tuple.get_str (Tuple::Title); - String artist = tuple.get_str (Tuple::Artist); - String album = tuple.get_str (Tuple::Album); - String genre = tuple.get_str (Tuple::Genre); - - int year = tuple.get_int (Tuple::Year); - int track = tuple.get_int (Tuple::Track); - int length = tuple.get_int (Tuple::Length); + String title = tuple.get_str(Tuple::Title); + String artist = tuple.get_str(Tuple::Artist); + String album = tuple.get_str(Tuple::Album); + String genre = tuple.get_str(Tuple::Genre); + + int year = tuple.get_int(Tuple::Year); + int track = tuple.get_int(Tuple::Track); + int length = tuple.get_int(Tuple::Length); int row = 0; if (title) - add_field (row ++, _("Title"), title); + add_field(row++, _("Title"), title); if (artist) - add_field (row ++, _("Artist"), artist); + add_field(row++, _("Artist"), artist); if (album) - add_field (row ++, _("Album"), album); + add_field(row++, _("Album"), album); if (genre) - add_field (row ++, _("Genre"), genre); + add_field(row++, _("Genre"), genre); if (year > 0) - add_field (row ++, _("Year"), int_to_str (year)); + add_field(row++, _("Year"), int_to_str(year)); if (track > 0) - add_field (row ++, _("Track"), int_to_str (track)); + add_field(row++, _("Track"), int_to_str(track)); if (length > 0) - add_field (row ++, _("Length"), str_format_time (length)); + add_field(row++, _("Length"), str_format_time(length)); } -void InfoPopup::add_field (int row, const char * field, const char * value) +void InfoPopup::add_field(int row, const char * field, const char * value) { - auto header = new QLabel (this); - header->setTextFormat (Qt::RichText); - header->setText (QString ("%1").arg (field)); - m_grid.addWidget (header, row, 0, Qt::AlignRight); - - auto label = new QLabel (this); - header->setTextFormat (Qt::RichText); - auto html = QString (value).toHtmlEscaped (); - label->setText (QString ("%1").arg (html)); - m_grid.addWidget (label, row, 1, Qt::AlignLeft); + auto header = new QLabel(this); + header->setTextFormat(Qt::RichText); + header->setText( + QString("%1").arg(field)); + m_grid.addWidget(header, row, 0, Qt::AlignRight); + + auto label = new QLabel(this); + header->setTextFormat(Qt::RichText); + auto html = QString(value).toHtmlEscaped(); + label->setText(QString("%1").arg(html)); + m_grid.addWidget(label, row, 1, Qt::AlignLeft); } -void InfoPopup::art_ready (const char * filename) +void InfoPopup::art_ready(const char * filename) { - if (m_queued && strcmp (filename, m_filename) == 0) - finish_loading (); + if (m_queued && strcmp(filename, m_filename) == 0) + finish_loading(); } -void InfoPopup::finish_loading () +void InfoPopup::finish_loading() { - QImage image = art_request (m_filename, & m_queued); + QImage image = art_request(m_filename, &m_queued); - if (! image.isNull ()) + if (!image.isNull()) { - auto label = new QLabel (this); - label->setPixmap (art_scale (image, sizes.OneInch, sizes.OneInch)); - m_hbox.insertWidget (0, label); + auto label = new QLabel(this); + label->setPixmap(art_scale(image, sizes.OneInch, sizes.OneInch)); + m_hbox.insertWidget(0, label); } - if (! m_queued) - show (); + if (!m_queued) + show(); } -void InfoPopup::paintEvent (QPaintEvent *) +void InfoPopup::paintEvent(QPaintEvent *) { - QLinearGradient grad (0, 0, 0, height ()); - grad.setStops (m_stops); + QLinearGradient grad(0, 0, 0, height()); + grad.setStops(m_stops); - QPainter p (this); - p.fillRect (rect (), grad); + QPainter p(this); + p.fillRect(rect(), grad); } static InfoPopup * s_infopopup; -static void infopopup_show (const String & filename, const Tuple & tuple) +static void infopopup_show(const String & filename, const Tuple & tuple) { if (s_infopopup) - s_infopopup->deleteLater (); + s_infopopup->deleteLater(); - s_infopopup = new InfoPopup (filename, tuple); + s_infopopup = new InfoPopup(filename, tuple); - QObject::connect (s_infopopup, & QObject::destroyed, [] () { - s_infopopup = nullptr; - }); + QObject::connect(s_infopopup, &QObject::destroyed, + []() { s_infopopup = nullptr; }); } -EXPORT void infopopup_show (Playlist playlist, int entry) +EXPORT void infopopup_show(Playlist playlist, int entry) { - String filename = playlist.entry_filename (entry); - Tuple tuple = playlist.entry_tuple (entry); + String filename = playlist.entry_filename(entry); + Tuple tuple = playlist.entry_tuple(entry); - if (filename && tuple.valid ()) - infopopup_show (filename, tuple); + if (filename && tuple.valid()) + infopopup_show(filename, tuple); } -EXPORT void infopopup_show_current () +EXPORT void infopopup_show_current() { - auto playlist = Playlist::playing_playlist (); - if (playlist == Playlist ()) - playlist = Playlist::active_playlist (); + auto playlist = Playlist::playing_playlist(); + if (playlist == Playlist()) + playlist = Playlist::active_playlist(); - int position = playlist.get_position (); + int position = playlist.get_position(); if (position >= 0) - infopopup_show (playlist, position); + infopopup_show(playlist, position); } -EXPORT void infopopup_hide () +EXPORT void infopopup_hide() { /* This function can be called from an enter/leave event, and Qt does not * like widgets being deleted from such events. This is debatably a bug in * Qt, but deleteLater() is an effective workaround. */ if (s_infopopup) - s_infopopup->deleteLater (); + s_infopopup->deleteLater(); } -void infopopup_hide_now () +void infopopup_hide_now() { /* On exit, we really do want to delete the widget immediately. */ delete s_infopopup; diff --git a/src/libaudqt/infowin-qt.cc b/src/libaudqt/infowin-qt.cc index 2f4161c..853e0cc 100644 --- a/src/libaudqt/infowin-qt.cc +++ b/src/libaudqt/infowin-qt.cc @@ -1,6 +1,6 @@ /* * infowin.cc - * Copyright 2006-2014 William Pitcock, Tomasz Moń, Eugene Zagidullin, + * Copyright 2006-2014 Ariadne Conill, Tomasz Moń, Eugene Zagidullin, * John Lindgren, and Thomas Lange * * Redistribution and use in source and binary forms, with or without @@ -26,8 +26,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -40,10 +40,11 @@ #include #include "info-widget.h" -#include "libaudqt.h" #include "libaudqt-internal.h" +#include "libaudqt.h" -namespace audqt { +namespace audqt +{ /* This class remedies some of the deficiencies of QLabel (such as lack * of proper wrapping). It can be expanded and/or made more visible if @@ -51,47 +52,43 @@ namespace audqt { class TextWidget : public QWidget { public: - TextWidget () - { - m_doc.setDefaultFont (font ()); - } + TextWidget() { m_doc.setDefaultFont(font()); } - void setText (const QString & text) + void setText(const QString & text) { - m_doc.setPlainText (text); - updateGeometry (); + m_doc.setPlainText(text); + updateGeometry(); } - void setWidth (int width) + void setWidth(int width) { - m_doc.setTextWidth (width); - updateGeometry (); + m_doc.setTextWidth(width); + updateGeometry(); } protected: - QSize sizeHint () const override + QSize sizeHint() const override { - qreal width = m_doc.idealWidth (); - qreal height = m_doc.size ().height (); - return QSize (ceil (width), ceil (height)); + qreal width = m_doc.idealWidth(); + qreal height = m_doc.size().height(); + return QSize(ceil(width), ceil(height)); } - QSize minimumSizeHint () const override - { return sizeHint (); } + QSize minimumSizeHint() const override { return sizeHint(); } - void changeEvent (QEvent * event) override + void changeEvent(QEvent * event) override { - if (event->type () == QEvent::FontChange) + if (event->type() == QEvent::FontChange) { - m_doc.setDefaultFont (font ()); - updateGeometry (); + m_doc.setDefaultFont(font()); + updateGeometry(); } } - void paintEvent (QPaintEvent * event) override + void paintEvent(QPaintEvent * event) override { - QPainter painter (this); - m_doc.drawContents (& painter); + QPainter painter(this); + m_doc.drawContents(&painter); } private: @@ -101,140 +98,202 @@ private: class InfoWindow : public QDialog { public: - InfoWindow (QWidget * parent = nullptr); + InfoWindow(QWidget * parent = nullptr); - void fillInfo (const char * filename, const Tuple & tuple, - PluginHandle * decoder, bool updating_enabled); + void fillInfo(Index && items, bool updating_enabled); private: String m_filename; QLabel m_image; TextWidget m_uri_label; InfoWidget m_infowidget; + QPushButton * m_save_btn; - void displayImage (const char * filename); + void displayImage(const char * filename); - const HookReceiver - art_hook {"art ready", this, & InfoWindow::displayImage}; + const HookReceiver art_hook{ + "art ready", this, &InfoWindow::displayImage}; }; -InfoWindow::InfoWindow (QWidget * parent) : QDialog (parent) +InfoWindow::InfoWindow(QWidget * parent) : QDialog(parent) { - setWindowTitle (_("Song Info")); - setContentsMargins (margins.TwoPt); - - m_image.setAlignment (Qt::AlignCenter); - m_uri_label.setWidth (2 * audqt::sizes.OneInch); - m_uri_label.setContextMenuPolicy (Qt::CustomContextMenu); - - connect (& m_uri_label, & QWidget::customContextMenuRequested, [this] (const QPoint & pos) { - show_copy_context_menu (this, m_uri_label.mapToGlobal (pos), QString (m_filename)); + setWindowTitle(_("Song Info")); + setContentsMargins(margins.TwoPt); + + m_image.setAlignment(Qt::AlignCenter); + m_uri_label.setWidth(2 * audqt::sizes.OneInch); + m_uri_label.setContextMenuPolicy(Qt::CustomContextMenu); + + connect(&m_uri_label, &QWidget::customContextMenuRequested, + [this](const QPoint & pos) { + show_copy_context_menu(this, m_uri_label.mapToGlobal(pos), + QString(m_filename)); + }); + + auto left_vbox = make_vbox(nullptr); + left_vbox->addWidget(&m_image); + left_vbox->addWidget(&m_uri_label); + left_vbox->setStretch(0, 1); + left_vbox->setStretch(1, 0); + + auto hbox = make_hbox(nullptr); + hbox->addLayout(left_vbox); + hbox->addWidget(&m_infowidget); + + auto vbox = make_vbox(this); + vbox->addLayout(hbox); + + auto bbox = + new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Close | + QDialogButtonBox::Reset, + this); + + m_save_btn = bbox->button(QDialogButtonBox::Save); + auto close_btn = bbox->button(QDialogButtonBox::Close), + revert_btn = bbox->button(QDialogButtonBox::Reset); + + close_btn->setText(translate_str(N_("_Close"))); + revert_btn->setText(translate_str(N_("_Revert"))); + + m_infowidget.linkEnabled(m_save_btn); + m_infowidget.linkEnabled(revert_btn); + + vbox->addWidget(bbox); + + connect(bbox, &QDialogButtonBox::accepted, [this]() { + if (m_infowidget.updateFile()) + deleteLater(); + else + aud_ui_show_error(str_printf(_("Error writing tag(s)."))); }); - auto left_vbox = make_vbox (nullptr); - left_vbox->addWidget (& m_image); - left_vbox->addWidget (& m_uri_label); - left_vbox->setStretch (0, 1); - left_vbox->setStretch (1, 0); - - auto hbox = make_hbox (nullptr); - hbox->addLayout (left_vbox); - hbox->addWidget (& m_infowidget); - - auto vbox = make_vbox (this); - vbox->addLayout (hbox); - - auto bbox = new QDialogButtonBox (QDialogButtonBox::Save | QDialogButtonBox::Close, this); - bbox->button (QDialogButtonBox::Save)->setText (translate_str (N_("_Save"))); - bbox->button (QDialogButtonBox::Close)->setText (translate_str (N_("_Close"))); - vbox->addWidget (bbox); - - connect (bbox, & QDialogButtonBox::accepted, [this] () { - m_infowidget.updateFile (); - deleteLater (); - }); - - connect (bbox, & QDialogButtonBox::rejected, this, & QObject::deleteLater); + connect(bbox, &QDialogButtonBox::rejected, this, &QObject::deleteLater); + connect(revert_btn, &QPushButton::clicked, &m_infowidget, + &InfoWidget::revertInfo); } -void InfoWindow::fillInfo (const char * filename, const Tuple & tuple, - PluginHandle * decoder, bool updating_enabled) +void InfoWindow::fillInfo(Index && items, + bool updating_enabled) { - m_filename = String (filename); - m_uri_label.setText ((QString) uri_to_display (filename)); - displayImage (filename); - m_infowidget.fillInfo (filename, tuple, decoder, updating_enabled); + if (items.len() == 1) + { + m_filename = String(items[0].filename); + m_uri_label.setText((QString)uri_to_display(m_filename)); + displayImage(m_filename); + m_save_btn->setText(translate_str(N_("_Save"))); + } + else + { + m_filename = String(); + m_uri_label.setText( + translate_str(N_("%1 files selected")).arg(items.len())); + m_image.setPixmap( + get_icon("audio-x-generic").pixmap(to_native_dpi(48))); + m_save_btn->setText( + translate_str(N_("_Save %1 files")).arg(items.len())); + } + + m_infowidget.fillInfo(std::move(items), updating_enabled); } -void InfoWindow::displayImage (const char * filename) +void InfoWindow::displayImage(const char * filename) { - if (! strcmp_safe (filename, m_filename)) - m_image.setPixmap (art_request (filename, 2 * sizes.OneInch, 2 * sizes.OneInch)); + if (!strcmp_safe(filename, m_filename)) + m_image.setPixmap( + art_request(filename, 2 * sizes.OneInch, 2 * sizes.OneInch)); } static InfoWindow * s_infowin = nullptr; -static void show_infowin (const char * filename, - const Tuple & tuple, PluginHandle * decoder, bool can_write) +static void show_infowin(Index && items, bool can_write) { - if (! s_infowin) + if (!s_infowin) { s_infowin = new InfoWindow; - s_infowin->setAttribute (Qt::WA_DeleteOnClose); + s_infowin->setAttribute(Qt::WA_DeleteOnClose); - QObject::connect (s_infowin, & QObject::destroyed, [] () { - s_infowin = nullptr; - }); + QObject::connect(s_infowin, &QObject::destroyed, + []() { s_infowin = nullptr; }); } - s_infowin->fillInfo (filename, tuple, decoder, can_write); - s_infowin->resize (6 * sizes.OneInch, 3 * sizes.OneInch); - window_bring_to_front (s_infowin); + s_infowin->fillInfo(std::move(items), can_write); + s_infowin->resize(6 * sizes.OneInch, 3 * sizes.OneInch); + window_bring_to_front(s_infowin); } -EXPORT void infowin_show (Playlist playlist, int entry) +static void fetch_entry(Playlist playlist, int entry, + Index & items, bool & can_write) { - String filename = playlist.entry_filename (entry); - if (! filename) + String filename = playlist.entry_filename(entry); + if (!filename) return; String error; - PluginHandle * decoder = playlist.entry_decoder (entry, Playlist::Wait, & error); - Tuple tuple = decoder ? playlist.entry_tuple (entry, Playlist::Wait, & error) : Tuple (); + PluginHandle * decoder = + playlist.entry_decoder(entry, Playlist::Wait, &error); + Tuple tuple = + decoder ? playlist.entry_tuple(entry, Playlist::Wait, &error) : Tuple(); - if (decoder && tuple.valid () && ! aud_custom_infowin (filename, decoder)) + if (decoder && tuple.valid()) { /* cuesheet entries cannot be updated */ - bool can_write = aud_file_can_write_tuple (filename, decoder) && - ! tuple.is_set (Tuple::StartTime); + can_write = (can_write && aud_file_can_write_tuple(filename, decoder) && + !tuple.is_set(Tuple::StartTime)); - tuple.delete_fallbacks (); - show_infowin (filename, tuple, decoder, can_write); + tuple.delete_fallbacks(); + items.append(filename, std::move(tuple), decoder); } - else - infowin_hide (); if (error) - aud_ui_show_error (str_printf (_("Error opening %s:\n%s"), - (const char *) filename, (const char *) error)); + aud_ui_show_error(str_printf(_("Error opening %s:\n%s"), + (const char *)filename, + (const char *)error)); } -EXPORT void infowin_show_current () +EXPORT void infowin_show(Playlist playlist, int entry) { - auto playlist = Playlist::playing_playlist (); - if (playlist == Playlist ()) - playlist = Playlist::active_playlist (); + Index items; + bool can_write = true; - int position = playlist.get_position (); - if (position < 0) - return; + fetch_entry(playlist, entry, items, can_write); - infowin_show (playlist, position); + if (items.len()) + show_infowin(std::move(items), can_write); + else + infowin_hide(); } -EXPORT void infowin_hide () +EXPORT void infowin_show_selected(Playlist playlist) { - delete s_infowin; + Index items; + bool can_write = true; + + int n_entries = playlist.n_entries(); + for (int entry = 0; entry < n_entries; entry++) + { + if (playlist.entry_selected(entry)) + fetch_entry(playlist, entry, items, can_write); + } + + if (items.len()) + show_infowin(std::move(items), can_write); + else + infowin_hide(); } +EXPORT void infowin_show_current() +{ + auto playlist = Playlist::playing_playlist(); + if (playlist == Playlist()) + playlist = Playlist::active_playlist(); + + int position = playlist.get_position(); + if (position < 0) + return; + + infowin_show(playlist, position); +} + +EXPORT void infowin_hide() { delete s_infowin; } + } // namespace audqt diff --git a/src/libaudqt/libaudqt-internal.h b/src/libaudqt/libaudqt-internal.h index 19dded2..3dd1398 100644 --- a/src/libaudqt/libaudqt-internal.h +++ b/src/libaudqt/libaudqt-internal.h @@ -26,28 +26,29 @@ class QPoint; class QScreen; class QString; -namespace audqt { +namespace audqt +{ /* infopopup.cc */ -void infopopup_hide_now (); +void infopopup_hide_now(); /* log-inspector.cc */ -void log_init (); -void log_cleanup (); +void log_init(); +void log_cleanup(); /* util-qt.cc */ class PopupWidget : public QWidget { public: - PopupWidget (QWidget * parent = nullptr); + PopupWidget(QWidget * parent = nullptr); protected: - bool eventFilter (QObject *, QEvent * e) override; - void showEvent (QShowEvent *) override; + bool eventFilter(QObject *, QEvent * e) override; + void showEvent(QShowEvent *) override; }; -void show_copy_context_menu (QWidget * parent, const QPoint & global_pos, - const QString & text_to_copy); +void show_copy_context_menu(QWidget * parent, const QPoint & global_pos, + const QString & text_to_copy); } // namespace audqt diff --git a/src/libaudqt/libaudqt.h b/src/libaudqt/libaudqt.h index e2a23de..54f902d 100644 --- a/src/libaudqt/libaudqt.h +++ b/src/libaudqt/libaudqt.h @@ -1,6 +1,6 @@ /* * libaudqt.h - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,19 +20,20 @@ #ifndef LIBAUDQT_H #define LIBAUDQT_H +#include #include #include #include #include -class QIcon; -class QLayout; class QBoxLayout; class QHBoxLayout; -class QVBoxLayout; - +class QIcon; +class QLayout; +class QLineEdit; class QPixmap; class QToolButton; +class QVBoxLayout; class QWidget; enum class PluginType; @@ -40,9 +41,11 @@ class Playlist; class PluginHandle; struct PreferencesWidget; -namespace audqt { +namespace audqt +{ -enum class FileMode { +enum class FileMode +{ Open, OpenFolder, Add, @@ -52,14 +55,16 @@ enum class FileMode { count }; -struct PixelSizes { +struct PixelSizes +{ int OneInch; int TwoPt; int FourPt; int EightPt; }; -struct PixelMargins { +struct PixelMargins +{ QMargins TwoPt; QMargins FourPt; QMargins EightPt; @@ -68,94 +73,124 @@ struct PixelMargins { struct MenuItem; /* about.cc */ -void aboutwindow_show (); -void aboutwindow_hide (); +void aboutwindow_show(); +void aboutwindow_hide(); /* playlist-management.cc */ -void playlist_show_rename (Playlist playlist); -void playlist_confirm_delete (Playlist playlist); +void playlist_show_rename(Playlist playlist); +void playlist_confirm_delete(Playlist playlist); /* equalizer.cc */ -void equalizer_show (); -void equalizer_hide (); +void equalizer_show(); +void equalizer_hide(); + +/* eq-preset-qt.cc */ +void eq_presets_show(); +void eq_presets_hide(); /* fileopener.cc */ -void fileopener_show (FileMode mode); +void fileopener_show(FileMode mode); /* url-opener.cc */ -void urlopener_show (bool open); - -/* util.cc */ +void urlopener_show(bool open); +/* audqt.cc */ extern const PixelSizes & sizes; extern const PixelMargins & margins; -static inline int to_native_dpi (int x) - { return aud::rescale (x, 96, sizes.OneInch); } -static inline int to_portable_dpi (int x) - { return aud::rescale (x, sizes.OneInch, 96); } +static inline int to_native_dpi(int x) +{ + return aud::rescale(x, 96, sizes.OneInch); +} +static inline int to_portable_dpi(int x) +{ + return aud::rescale(x, sizes.OneInch, 96); +} -void init (); -void run (); -void quit (); -void cleanup (); +void init(); +void run(); +void quit(); +void cleanup(); -QIcon get_icon (const char * name); +QIcon get_icon(const char * name); -QHBoxLayout * make_hbox (QWidget * parent, int spacing = sizes.FourPt); -QVBoxLayout * make_vbox (QWidget * parent, int spacing = sizes.FourPt); +QGradientStops dark_bg_gradient(const QColor & base); +QColor vis_bar_color(const QColor & hue, int bar, int n_bars); -void enable_layout (QLayout * layout, bool enabled); -void clear_layout (QLayout * layout); -void window_bring_to_front (QWidget * win); -void simple_message (const char * title, const char * text); -void simple_message (const char * title, const char * text, QMessageBox::Icon icon); -QString translate_str (const char * str, const char * domain); +QHBoxLayout * make_hbox(QWidget * parent, int spacing = sizes.FourPt); +QVBoxLayout * make_vbox(QWidget * parent, int spacing = sizes.FourPt); + +void enable_layout(QLayout * layout, bool enabled); +void clear_layout(QLayout * layout); +void window_bring_to_front(QWidget * win); +void simple_message(const char * title, const char * text); +void simple_message(const char * title, const char * text, + QMessageBox::Icon icon); +QString translate_str(const char * str, const char * domain); #ifdef PACKAGE -static inline QString translate_str (const char * str) - { return translate_str (str, PACKAGE); } +static inline QString translate_str(const char * str) +{ + return translate_str(str, PACKAGE); +} #endif +/* file-entry.cc */ +QLineEdit * file_entry_new(QWidget * parent, const char * title, + QFileDialog::FileMode file_mode, + QFileDialog::AcceptMode accept_mode); +String file_entry_get_uri(QLineEdit * entry); +void file_entry_set_uri(QLineEdit * entry, const char * uri); + +/* font-entry.cc */ +QLineEdit * font_entry_new(QWidget * parent, const char * font); +QFont qfont_from_string(const char * name); +StringBuf qfont_to_string(const QFont & font); + /* prefs-builder.cc */ -void prefs_populate (QBoxLayout * layout, ArrayRef widgets, const char * domain); +void prefs_populate(QBoxLayout * layout, ArrayRef widgets, + const char * domain); /* prefs-plugin.cc */ -void plugin_about (PluginHandle * ph); -void plugin_prefs (PluginHandle * ph); +void plugin_about(PluginHandle * ph); +void plugin_prefs(PluginHandle * ph); /* prefs-window.cc */ -void prefswin_show (); -void prefswin_hide (); -void prefswin_show_page (int id, bool show = true); -void prefswin_show_plugin_page (PluginType type); +void prefswin_show(); +void prefswin_hide(); +void prefswin_show_page(int id, bool show = true); +void prefswin_show_plugin_page(PluginType type); /* log-inspector.cc */ -void log_inspector_show (); -void log_inspector_hide (); +void log_inspector_show(); +void log_inspector_hide(); /* art-qt.cc */ -QImage art_request (const char * filename, bool * queued = nullptr); -QPixmap art_scale (const QImage & image, unsigned int w, unsigned int h, bool want_hidpi = true); -QPixmap art_request (const char * filename, unsigned int w, unsigned int h, bool want_hidpi = true); -QPixmap art_request_current (unsigned int w, unsigned int h, bool want_hidpi = true); +QImage art_request(const char * filename, bool * queued = nullptr); +QPixmap art_scale(const QImage & image, unsigned int w, unsigned int h, + bool want_hidpi = true); +QPixmap art_request(const char * filename, unsigned int w, unsigned int h, + bool want_hidpi = true); +QPixmap art_request_current(unsigned int w, unsigned int h, + bool want_hidpi = true); /* infopopup-qt.cc */ -void infopopup_show (Playlist playlist, int entry); -void infopopup_show_current (); -void infopopup_hide (); +void infopopup_show(Playlist playlist, int entry); +void infopopup_show_current(); +void infopopup_hide(); /* infowin.cc */ -void infowin_show (Playlist playlist, int entry); -void infowin_show_current (); -void infowin_hide (); +void infowin_show(Playlist playlist, int entry); +void infowin_show_selected(Playlist playlist); +void infowin_show_current(); +void infowin_hide(); /* queue-manager.cc */ -void queue_manager_show (); -void queue_manager_hide (); +void queue_manager_show(); +void queue_manager_hide(); /* volumebutton.cc */ -QToolButton * volume_button_new (QWidget * parent = nullptr); +QToolButton * volume_button_new(QWidget * parent = nullptr); } // namespace audqt diff --git a/src/libaudqt/log-inspector.cc b/src/libaudqt/log-inspector.cc index e582a29..460c178 100644 --- a/src/libaudqt/log-inspector.cc +++ b/src/libaudqt/log-inspector.cc @@ -1,6 +1,6 @@ /* * log-inspector.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -17,17 +17,17 @@ * the use of this software. */ -#include "libaudqt.h" #include "libaudqt-internal.h" +#include "libaudqt.h" #include #include #include #include #include -#include #include #include +#include #include #include @@ -38,16 +38,19 @@ #define LOGENTRY_MAX 1024 -namespace audqt { +namespace audqt +{ -enum LogEntryColumn { +enum LogEntryColumn +{ Level, Function, Message, Count }; -struct LogEntry { +struct LogEntry +{ audlog::Level level; String function; String message; @@ -56,220 +59,228 @@ struct LogEntry { class LogEntryModel : public QAbstractListModel { public: - LogEntryModel (QObject * parent = nullptr) : - QAbstractListModel (parent) {} + LogEntryModel(QObject * parent = nullptr) : QAbstractListModel(parent) {} + + void cleanup(); - void cleanup (); protected: - int rowCount (const QModelIndex & parent = QModelIndex ()) const - { return m_entries.len (); } - int columnCount (const QModelIndex & parent = QModelIndex ()) const - { return LogEntryColumn::Count; } + int rowCount(const QModelIndex & parent = QModelIndex()) const + { + return m_entries.len(); + } + int columnCount(const QModelIndex & parent = QModelIndex()) const + { + return LogEntryColumn::Count; + } - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; private: RingBuf m_entries; - void addEntry (const LogEntry * entry); - HookReceiver - log_hook {"audqt log entry", this, & LogEntryModel::addEntry}; + void addEntry(const LogEntry * entry); + HookReceiver log_hook{ + "audqt log entry", this, &LogEntryModel::addEntry}; }; -void LogEntryModel::cleanup () +void LogEntryModel::cleanup() { - if (m_entries.len () > 0) + if (m_entries.len() > 0) { - beginRemoveRows (QModelIndex (), 0, m_entries.len () - 1); - m_entries.destroy (); - endRemoveRows (); + beginRemoveRows(QModelIndex(), 0, m_entries.len() - 1); + m_entries.destroy(); + endRemoveRows(); } } /* log entry model */ -void LogEntryModel::addEntry (const LogEntry * entry) +void LogEntryModel::addEntry(const LogEntry * entry) { - if (! m_entries.space ()) + if (!m_entries.space()) { - if (m_entries.len () < LOGENTRY_MAX) - m_entries.alloc (aud::max (16, 2 * m_entries.len ())); + if (m_entries.len() < LOGENTRY_MAX) + m_entries.alloc(aud::max(16, 2 * m_entries.len())); else { - beginRemoveRows (QModelIndex (), 0, 0); - m_entries.pop (); - endRemoveRows (); + beginRemoveRows(QModelIndex(), 0, 0); + m_entries.pop(); + endRemoveRows(); } } - beginInsertRows (QModelIndex (), m_entries.len (), m_entries.len ()); - m_entries.push (* entry); - endInsertRows (); + beginInsertRows(QModelIndex(), m_entries.len(), m_entries.len()); + m_entries.push(*entry); + endInsertRows(); } -QVariant LogEntryModel::data (const QModelIndex & index, int role) const +QVariant LogEntryModel::data(const QModelIndex & index, int role) const { - int row = index.row (); - if (row < 0 || row >= m_entries.len ()) - return QVariant (); + int row = index.row(); + if (row < 0 || row >= m_entries.len()) + return QVariant(); auto & e = m_entries[row]; if (role == Qt::DisplayRole) { - switch (index.column ()) + switch (index.column()) { - case LogEntryColumn::Level: return QString (audlog::get_level_name (e.level)); - case LogEntryColumn::Function: return QString (e.function); - case LogEntryColumn::Message: return QString (e.message); + case LogEntryColumn::Level: + return QString(audlog::get_level_name(e.level)); + case LogEntryColumn::Function: + return QString(e.function); + case LogEntryColumn::Message: + return QString(e.message); } } - return QVariant (); + return QVariant(); } -QVariant LogEntryModel::headerData (int section, Qt::Orientation orientation, int role) const +QVariant LogEntryModel::headerData(int section, Qt::Orientation orientation, + int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { - case LogEntryColumn::Level: return QString (_("Level")); - case LogEntryColumn::Function: return QString (_("Function")); - case LogEntryColumn::Message: return QString (_("Message")); + case LogEntryColumn::Level: + return QString(_("Level")); + case LogEntryColumn::Function: + return QString(_("Function")); + case LogEntryColumn::Message: + return QString(_("Message")); } } - return QVariant (); + return QVariant(); } /* static model */ static SmartPtr s_model; static audlog::Level s_level = audlog::Warning; -static void log_handler (audlog::Level level, const char * file, int line, - const char * func, const char * message) +static void log_handler(audlog::Level level, const char * file, int line, + const char * func, const char * message) { - auto messages = str_list_to_index (message, "\n"); + auto messages = str_list_to_index(message, "\n"); for (auto & message : messages) { auto entry = new LogEntry; entry->level = level; - entry->function = String (str_printf ("%s (%s:%d)", func, file, line)); - entry->message = std::move (message); + entry->function = String(str_printf("%s (%s:%d)", func, file, line)); + entry->message = std::move(message); - event_queue ("audqt log entry", entry, aud::delete_obj); + event_queue("audqt log entry", entry, aud::delete_obj); } } -void log_init () +void log_init() { - s_model.capture (new LogEntryModel); - audlog::subscribe (log_handler, s_level); + s_model.capture(new LogEntryModel); + audlog::subscribe(log_handler, s_level); } -void log_cleanup () +void log_cleanup() { - audlog::unsubscribe (log_handler); - event_queue_cancel ("audqt log entry"); - s_model.clear (); + audlog::unsubscribe(log_handler); + event_queue_cancel("audqt log entry"); + s_model.clear(); } /* log entry inspector */ class LogEntryInspector : public QDialog { public: - LogEntryInspector (QWidget * parent = nullptr); + LogEntryInspector(QWidget * parent = nullptr); private: QComboBox m_level_combobox; - void setLogLevel (audlog::Level level); + void setLogLevel(audlog::Level level); }; -LogEntryInspector::LogEntryInspector (QWidget * parent) : - QDialog (parent) +LogEntryInspector::LogEntryInspector(QWidget * parent) : QDialog(parent) { - setWindowTitle (_("Log Inspector")); - setContentsMargins (margins.TwoPt); + setWindowTitle(_("Log Inspector")); + setContentsMargins(margins.TwoPt); - auto view = new QTreeView (this); - view->setModel (s_model.get ()); + auto view = new QTreeView(this); + view->setModel(s_model.get()); - view->setAllColumnsShowFocus (true); - view->setIndentation (0); - view->setUniformRowHeights (true); - view->scrollToBottom (); + view->setAllColumnsShowFocus(true); + view->setIndentation(0); + view->setUniformRowHeights(true); + view->scrollToBottom(); - m_level_combobox.addItem (_("Debug"), audlog::Debug); - m_level_combobox.addItem (_("Info"), audlog::Info); - m_level_combobox.addItem (_("Warning"), audlog::Warning); - m_level_combobox.addItem (_("Error"), audlog::Error); + m_level_combobox.addItem(_("Debug"), audlog::Debug); + m_level_combobox.addItem(_("Info"), audlog::Info); + m_level_combobox.addItem(_("Warning"), audlog::Warning); + m_level_combobox.addItem(_("Error"), audlog::Error); - m_level_combobox.setCurrentIndex (s_level); + m_level_combobox.setCurrentIndex(s_level); - QObject::connect (& m_level_combobox, - static_cast (&QComboBox::currentIndexChanged), - [this] (int idx) { setLogLevel ((audlog::Level) idx); }); + QObject::connect( + &m_level_combobox, + static_cast(&QComboBox::currentIndexChanged), + [this](int idx) { setLogLevel((audlog::Level)idx); }); - auto btnbox = new QDialogButtonBox (this); + auto btnbox = new QDialogButtonBox(this); - auto btn1 = btnbox->addButton (translate_str (N_("Cl_ear")), QDialogButtonBox::ActionRole); - btn1->setIcon (audqt::get_icon ("edit-clear-all")); - btn1->setAutoDefault (false); - QObject::connect (btn1, & QPushButton::clicked, [] () { - s_model.get ()->cleanup (); - }); + auto btn1 = btnbox->addButton(translate_str(N_("Cl_ear")), + QDialogButtonBox::ActionRole); + btn1->setIcon(audqt::get_icon("edit-clear-all")); + btn1->setAutoDefault(false); + QObject::connect(btn1, &QPushButton::clicked, + []() { s_model.get()->cleanup(); }); - auto btn2 = btnbox->addButton (QDialogButtonBox::Close); - btn2->setText (translate_str (N_("_Close"))); - btn2->setAutoDefault (false); - QObject::connect (btn2, & QPushButton::clicked, this, & QDialog::close); + auto btn2 = btnbox->addButton(QDialogButtonBox::Close); + btn2->setText(translate_str(N_("_Close"))); + btn2->setAutoDefault(false); + QObject::connect(btn2, &QPushButton::clicked, this, &QDialog::close); - auto hbox = make_hbox (nullptr); - hbox->addWidget (new QLabel (_("Log Level:"), this)); - hbox->addWidget (& m_level_combobox); - hbox->addWidget (btnbox); + auto hbox = make_hbox(nullptr); + hbox->addWidget(new QLabel(_("Log Level:"), this)); + hbox->addWidget(&m_level_combobox); + hbox->addWidget(btnbox); - auto vbox = make_vbox (this); - vbox->addWidget (view); - vbox->addLayout (hbox); + auto vbox = make_vbox(this); + vbox->addWidget(view); + vbox->addLayout(hbox); - resize (6 * sizes.OneInch, 3 * sizes.OneInch); + resize(6 * sizes.OneInch, 3 * sizes.OneInch); } static LogEntryInspector * s_inspector = nullptr; -void LogEntryInspector::setLogLevel (audlog::Level level) +void LogEntryInspector::setLogLevel(audlog::Level level) { s_level = level; - audlog::unsubscribe (log_handler); - audlog::subscribe (log_handler, level); + audlog::unsubscribe(log_handler); + audlog::subscribe(log_handler, level); - m_level_combobox.setCurrentIndex (level); + m_level_combobox.setCurrentIndex(level); } -EXPORT void log_inspector_show () +EXPORT void log_inspector_show() { - if (! s_inspector) + if (!s_inspector) { s_inspector = new LogEntryInspector; - s_inspector->setAttribute (Qt::WA_DeleteOnClose); + s_inspector->setAttribute(Qt::WA_DeleteOnClose); - QObject::connect (s_inspector, & QObject::destroyed, [] () { - s_inspector = nullptr; - }); + QObject::connect(s_inspector, &QObject::destroyed, + []() { s_inspector = nullptr; }); } - window_bring_to_front (s_inspector); + window_bring_to_front(s_inspector); } -EXPORT void log_inspector_hide () -{ - delete s_inspector; -} +EXPORT void log_inspector_hide() { delete s_inspector; } } // namespace audqt diff --git a/src/libaudqt/menu-qt.cc b/src/libaudqt/menu-qt.cc index 2ce34de..ca08ece 100644 --- a/src/libaudqt/menu-qt.cc +++ b/src/libaudqt/menu-qt.cc @@ -1,6 +1,6 @@ /* * menu.h - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,104 +28,109 @@ #include #include -namespace audqt { +namespace audqt +{ class MenuAction : public QAction { public: - MenuAction (const MenuItem & item, const char * domain, QWidget * parent); + MenuAction(const MenuItem & item, const char * domain, QWidget * parent); private: - void toggle (bool checked); - void update (); + void toggle(bool checked); + void update(); const MenuItem & m_item; SmartPtr> m_hook; }; -MenuAction::MenuAction (const MenuItem & item, const char * domain, QWidget * parent) : - QAction (parent), - m_item (item) +MenuAction::MenuAction(const MenuItem & item, const char * domain, + QWidget * parent) + : QAction(parent), m_item(item) { if (item.sep) { - setSeparator (true); + setSeparator(true); return; } - setText (translate_str (item.text.name, domain)); + setText(translate_str(item.text.name, domain)); if (item.cfg.name) { - setCheckable (true); - setChecked (aud_get_bool (item.cfg.sect, item.cfg.name)); + setCheckable(true); + setChecked(aud_get_bool(item.cfg.sect, item.cfg.name)); - QObject::connect (this, & QAction::toggled, this, & MenuAction::toggle); + QObject::connect(this, &QAction::toggled, this, &MenuAction::toggle); if (item.cfg.hook) - m_hook.capture (new HookReceiver (item.cfg.hook, this, & MenuAction::update)); + m_hook.capture(new HookReceiver(item.cfg.hook, this, + &MenuAction::update)); } else if (item.func) - QObject::connect (this, & QAction::triggered, item.func); + QObject::connect(this, &QAction::triggered, item.func); else if (item.items.len) - setMenu (menu_build (item.items, domain, parent)); + setMenu(menu_build(item.items, domain, parent)); else if (item.submenu) - setMenu (item.submenu ()); + setMenu(item.submenu()); #ifndef Q_OS_MAC - if (item.text.icon && QIcon::hasThemeIcon (item.text.icon)) - setIcon (audqt::get_icon (item.text.icon)); + if (item.text.icon && QIcon::hasThemeIcon(item.text.icon)) + setIcon(audqt::get_icon(item.text.icon)); #endif if (item.text.shortcut) - setShortcut (QString (item.text.shortcut)); + setShortcut(QString(item.text.shortcut)); if (parent) - parent->addAction (this); + parent->addAction(this); } -void MenuAction::toggle (bool checked) +void MenuAction::toggle(bool checked) { - if (aud_get_bool (m_item.cfg.sect, m_item.cfg.name) != checked) + if (aud_get_bool(m_item.cfg.sect, m_item.cfg.name) != checked) { - aud_set_bool (m_item.cfg.sect, m_item.cfg.name, checked); + aud_set_bool(m_item.cfg.sect, m_item.cfg.name, checked); if (m_item.func) - m_item.func (); + m_item.func(); } } -void MenuAction::update () +void MenuAction::update() { - setChecked (aud_get_bool (m_item.cfg.sect, m_item.cfg.name)); + setChecked(aud_get_bool(m_item.cfg.sect, m_item.cfg.name)); } -EXPORT QAction * menu_action (const MenuItem & menu_item, const char * domain, QWidget * parent) +EXPORT QAction * menu_action(const MenuItem & menu_item, const char * domain, + QWidget * parent) { - return new MenuAction (menu_item, domain, parent); + return new MenuAction(menu_item, domain, parent); } -EXPORT QMenu * menu_build (ArrayRef menu_items, const char * domain, QWidget * parent) +EXPORT QMenu * menu_build(ArrayRef menu_items, const char * domain, + QWidget * parent) { - QMenu * m = new QMenu (parent); + QMenu * m = new QMenu(parent); for (auto & it : menu_items) - m->addAction (new MenuAction (it, domain, parent)); + m->addAction(new MenuAction(it, domain, parent)); return m; } -EXPORT QMenuBar * menubar_build (ArrayRef menu_items, const char * domain, QWidget * parent) +EXPORT QMenuBar * menubar_build(ArrayRef menu_items, + const char * domain, QWidget * parent) { #ifdef Q_OS_MAC - QMenuBar * m = new QMenuBar (nullptr); + QMenuBar * m = new QMenuBar(nullptr); #else - QMenuBar * m = new QMenuBar (parent); - m->setContextMenuPolicy (Qt::PreventContextMenu); + QMenuBar * m = new QMenuBar(parent); + m->setContextMenuPolicy(Qt::PreventContextMenu); #endif for (auto & it : menu_items) - m->addAction (new MenuAction (it, domain, parent)); + m->addAction(new MenuAction(it, domain, parent)); return m; } diff --git a/src/libaudqt/menu.h b/src/libaudqt/menu.h index 3478291..b93daa3 100644 --- a/src/libaudqt/menu.h +++ b/src/libaudqt/menu.h @@ -1,6 +1,6 @@ /* * menu.h - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,25 +31,29 @@ class QWidget; enum class AudMenuID; -namespace audqt { +namespace audqt +{ -typedef void (* MenuFunc) (); +typedef void (*MenuFunc)(); -struct MenuItemText { +struct MenuItemText +{ const char * name; const char * icon; const char * shortcut; }; -struct MenuItemConfig { +struct MenuItemConfig +{ const char * sect; const char * name; const char * hook; }; -struct MenuItem { +struct MenuItem +{ MenuItemText text; - void (* func) (); + void (*func)(); /* for toggle items */ MenuItemConfig cfg; @@ -58,39 +62,60 @@ struct MenuItem { ArrayRef items; /* for custom submenus */ - QMenu * (* submenu) (); + QMenu * (*submenu)(); /* for separators */ bool sep; }; -constexpr MenuItem MenuCommand (MenuItemText text, MenuFunc func) - { return {text, func}; } -constexpr MenuItem MenuToggle (MenuItemText text, MenuItemConfig cfg, MenuFunc func = nullptr) - { return {text, func, cfg}; } -constexpr MenuItem MenuSub (MenuItemText text, ArrayRef items) - { return {text, nullptr, {}, items}; } -constexpr MenuItem MenuSub (MenuItemText text, QMenu * (* submenu) ()) - { return {text, nullptr, {}, nullptr, submenu}; } -constexpr MenuItem MenuSep () - { return {{}, nullptr, {}, nullptr, nullptr, true}; } +constexpr MenuItem MenuCommand(MenuItemText text, MenuFunc func) +{ + return {text, func}; +} +constexpr MenuItem MenuToggle(MenuItemText text, MenuItemConfig cfg, + MenuFunc func = nullptr) +{ + return {text, func, cfg}; +} +constexpr MenuItem MenuSub(MenuItemText text, ArrayRef items) +{ + return {text, nullptr, {}, items}; +} +constexpr MenuItem MenuSub(MenuItemText text, QMenu * (*submenu)()) +{ + return {text, nullptr, {}, nullptr, submenu}; +} +constexpr MenuItem MenuSep() +{ + return {{}, nullptr, {}, nullptr, nullptr, true}; +} /* menu.cc */ -QAction * menu_action (const MenuItem & menu_item, const char * domain, QWidget * parent = nullptr); -QMenu * menu_build (ArrayRef menu_items, const char * domain, QWidget * parent = nullptr); -QMenuBar * menubar_build (ArrayRef menu_items, const char * domain, QWidget * parent = nullptr); +QAction * menu_action(const MenuItem & menu_item, const char * domain, + QWidget * parent = nullptr); +QMenu * menu_build(ArrayRef menu_items, const char * domain, + QWidget * parent = nullptr); +QMenuBar * menubar_build(ArrayRef menu_items, const char * domain, + QWidget * parent = nullptr); #ifdef PACKAGE -static inline QMenu * menu_build (ArrayRef menu_items, QWidget * parent = nullptr) - { return menu_build (menu_items, PACKAGE, parent); } -static inline QMenuBar * menubar_build (ArrayRef menu_items, QWidget * parent = nullptr) - { return menubar_build (menu_items, PACKAGE, parent); } +static inline QMenu * menu_build(ArrayRef menu_items, + QWidget * parent = nullptr) +{ + return menu_build(menu_items, PACKAGE, parent); +} +static inline QMenuBar * menubar_build(ArrayRef menu_items, + QWidget * parent = nullptr) +{ + return menubar_build(menu_items, PACKAGE, parent); +} #endif /* plugin-menu.cc */ -QMenu * menu_get_by_id (AudMenuID id); -void menu_add (AudMenuID id, MenuFunc func, const char * name, const char * icon); -void menu_remove (AudMenuID id, MenuFunc func); +QMenu * menu_get_by_id(AudMenuID id); +void menu_add(AudMenuID id, MenuFunc func, const char * name, + const char * icon); +void menu_remove(AudMenuID id, MenuFunc func); } // namespace audqt diff --git a/src/libaudqt/meson.build b/src/libaudqt/meson.build new file mode 100644 index 0000000..6aff2c9 --- /dev/null +++ b/src/libaudqt/meson.build @@ -0,0 +1,58 @@ +libaudqt_sources = [ + 'about-qt.cc', + 'art-qt.cc', + 'audqt.cc', + 'colorbutton.cc', + 'eq-preset-qt.cc', + 'equalizer-qt.cc', + 'file-entry.cc', + 'fileopener.cc', + 'font-entry.cc', + 'infopopup-qt.cc', + 'infowin-qt.cc', + 'info-widget.cc', + 'log-inspector.cc', + 'menu-qt.cc', + 'playlist-management.cc', + 'plugin-menu-qt.cc', + 'prefs-builder.cc', + 'prefs-plugin.cc', + 'prefs-widget-qt.cc', + 'prefs-window-qt.cc', + 'prefs-pluginlist-model.cc', + 'queue-manager-qt.cc', + 'url-opener-qt.cc', + 'util-qt.cc', + 'treeview.cc', + 'volumebutton.cc' +] + + +libaudqt_headers = [ + 'colorbutton.h', + 'export.h', + 'iface.h', + 'info-widget.h', + 'libaudqt.h', + 'menu.h', + 'treeview.h' +] + + +images_src = qt5.preprocess(qresources: 'images.qrc') + + +install_headers(libaudqt_headers, subdir: 'libaudqt') + + +libaudqt_lib = library('audqt', + libaudqt_sources, + images_src, + cpp_args: ['-DLIBAUDQT_BUILD'], + include_directories: [src_inc], + dependencies: [qt_dep], + link_with: [libaudcore_lib], + soversion: '2', + version: '2.2.0', + install: true +) diff --git a/src/libaudqt/playlist-management.cc b/src/libaudqt/playlist-management.cc index c6e0899..d373801 100644 --- a/src/libaudqt/playlist-management.cc +++ b/src/libaudqt/playlist-management.cc @@ -1,6 +1,6 @@ /* * playlist-management.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,101 +20,87 @@ #include "libaudqt.h" #include -#include -#include -#include -#include +#include #include -#include #include #include -#include #include +#include -namespace audqt { - -static QDialog * buildRenameDialog (Playlist playlist) +namespace audqt { - auto dialog = new QDialog; - auto prompt = new QLabel (_("What would you like to call this playlist?"), dialog); - auto entry = new QLineEdit ((const char *) playlist.get_title (), dialog); - auto rename = new QPushButton (translate_str (N_("_Rename")), dialog); - auto cancel = new QPushButton (translate_str (N_("_Cancel")), dialog); - - auto buttonbox = new QDialogButtonBox (dialog); - buttonbox->addButton (rename, QDialogButtonBox::AcceptRole); - buttonbox->addButton (cancel, QDialogButtonBox::RejectRole); - - QObject::connect (buttonbox, & QDialogButtonBox::accepted, [dialog, entry, playlist] () { - playlist.set_title (entry->text ().toUtf8 ()); - dialog->close (); - }); - QObject::connect (buttonbox, & QDialogButtonBox::rejected, dialog, & QDialog::close); - - auto layout = make_vbox (dialog); - layout->addWidget (prompt); - layout->addWidget (entry); - layout->addStretch (1); - layout->addWidget (buttonbox); - - dialog->setWindowTitle (_("Rename Playlist")); - dialog->setContentsMargins (margins.EightPt); - - entry->selectAll (); +static QDialog * buildRenameDialog(Playlist playlist) +{ + auto dialog = new QInputDialog; + dialog->setInputMode(QInputDialog::TextInput); + dialog->setWindowTitle(_("Rename Playlist")); + dialog->setLabelText(_("What would you like to call this playlist?")); + dialog->setOkButtonText(translate_str(N_("_Rename"))); + dialog->setCancelButtonText(translate_str(N_("_Cancel"))); + dialog->setTextValue((const char *)playlist.get_title()); + + QObject::connect(dialog, &QInputDialog::textValueSelected, + [dialog, playlist](const QString & text) { + playlist.set_title(text.toUtf8()); + dialog->close(); + }); return dialog; } -static QDialog * buildDeleteDialog (Playlist playlist) +static QDialog * buildDeleteDialog(Playlist playlist) { auto dialog = new QMessageBox; - auto skip_prompt = new QCheckBox (translate_str (N_("_Don’t ask again")), dialog); - auto remove = new QPushButton (translate_str (N_("_Remove")), dialog); - auto cancel = new QPushButton (translate_str (N_("_Cancel")), dialog); - - dialog->setIcon (QMessageBox::Question); - dialog->setWindowTitle (_("Remove Playlist")); - dialog->setText ((const char *) str_printf (_("Do you want to permanently remove “%s”?"), - (const char *) playlist.get_title ())); - dialog->setCheckBox (skip_prompt); - dialog->addButton (remove, QMessageBox::AcceptRole); - dialog->addButton (cancel, QMessageBox::RejectRole); - - remove->setIcon (audqt::get_icon ("edit-delete")); - cancel->setIcon (audqt::get_icon ("process-stop")); - - QObject::connect (skip_prompt, & QCheckBox::stateChanged, [] (int state) { - aud_set_bool ("audgui", "no_confirm_playlist_delete", (state == Qt::Checked)); + auto skip_prompt = + new QCheckBox(translate_str(N_("_Don’t ask again")), dialog); + auto remove = new QPushButton(translate_str(N_("_Remove")), dialog); + auto cancel = new QPushButton(translate_str(N_("_Cancel")), dialog); + + dialog->setIcon(QMessageBox::Question); + dialog->setWindowTitle(_("Remove Playlist")); + dialog->setText( + (const char *)str_printf(_("Do you want to permanently remove “%s”?"), + (const char *)playlist.get_title())); + dialog->setCheckBox(skip_prompt); + dialog->addButton(remove, QMessageBox::AcceptRole); + dialog->addButton(cancel, QMessageBox::RejectRole); + + remove->setIcon(audqt::get_icon("edit-delete")); + cancel->setIcon(audqt::get_icon("process-stop")); + + QObject::connect(skip_prompt, &QCheckBox::stateChanged, [](int state) { + aud_set_bool("audgui", "no_confirm_playlist_delete", + (state == Qt::Checked)); }); - QObject::connect (remove, & QPushButton::clicked, [dialog, playlist] () { - playlist.remove_playlist (); - dialog->close (); + QObject::connect(remove, &QPushButton::clicked, [dialog, playlist]() { + playlist.remove_playlist(); + dialog->close(); }); return dialog; } -EXPORT void playlist_show_rename (Playlist playlist) +EXPORT void playlist_show_rename(Playlist playlist) { - auto dialog = buildRenameDialog (playlist); - dialog->setAttribute (Qt::WA_DeleteOnClose); - dialog->show (); + auto dialog = buildRenameDialog(playlist); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); } -EXPORT void playlist_confirm_delete (Playlist playlist) +EXPORT void playlist_confirm_delete(Playlist playlist) { - if (aud_get_bool ("audgui", "no_confirm_playlist_delete")) + if (aud_get_bool("audgui", "no_confirm_playlist_delete")) { - playlist.remove_playlist (); + playlist.remove_playlist(); return; } - auto dialog = buildDeleteDialog (playlist); - dialog->setAttribute (Qt::WA_DeleteOnClose); - dialog->show (); + auto dialog = buildDeleteDialog(playlist); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); } } // namespace audqt diff --git a/src/libaudqt/plugin-menu-qt.cc b/src/libaudqt/plugin-menu-qt.cc index 344ad7e..a886258 100644 --- a/src/libaudqt/plugin-menu-qt.cc +++ b/src/libaudqt/plugin-menu-qt.cc @@ -1,6 +1,6 @@ /* * plugin-menu.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,9 +26,11 @@ #include #include -namespace audqt { +namespace audqt +{ -struct ItemData { +struct ItemData +{ MenuItem item; SmartPtr action; }; @@ -36,57 +38,54 @@ struct ItemData { static aud::array> items; static aud::array menus; -static void show_prefs () -{ - prefswin_show_plugin_page (PluginType::General); -} +static void show_prefs() { prefswin_show_plugin_page(PluginType::General); } MenuItem default_menu_items[] = { - MenuCommand ({N_("_Plugins ..."), "preferences-system"}, show_prefs), + MenuCommand({N_("_Plugins ..."), "preferences-system"}, show_prefs), }; -void menu_rebuild (AudMenuID id) +void menu_rebuild(AudMenuID id) { if (menus[id]) - menus[id]->clear (); + menus[id]->clear(); else - menus[id] = new QMenu (_("Services")); + menus[id] = new QMenu(_("Services")); for (auto & item : items[id]) { - item.action.capture (menu_action (item.item, nullptr)); - menus[id]->addAction (item.action.get ()); + item.action.capture(menu_action(item.item, nullptr)); + menus[id]->addAction(item.action.get()); } - if (! menus[id]->isEmpty ()) - menus[id]->addAction (menu_action (MenuSep (), PACKAGE, menus[id])); + if (!menus[id]->isEmpty()) + menus[id]->addAction(menu_action(MenuSep(), PACKAGE, menus[id])); for (auto & item : default_menu_items) - menus[id]->addAction (menu_action (item, PACKAGE, menus[id])); + menus[id]->addAction(menu_action(item, PACKAGE, menus[id])); } -EXPORT QMenu * menu_get_by_id (AudMenuID id) +EXPORT QMenu * menu_get_by_id(AudMenuID id) { - if (! menus[id]) - menu_rebuild (id); + if (!menus[id]) + menu_rebuild(id); return menus[id]; } -EXPORT void menu_add (AudMenuID id, MenuFunc func, const char * name, const char * icon) +EXPORT void menu_add(AudMenuID id, MenuFunc func, const char * name, + const char * icon) { - items[id].append (MenuCommand ({name, icon}, func)); + items[id].append(MenuCommand({name, icon}, func)); menu_rebuild(id); } -EXPORT void menu_remove (AudMenuID id, MenuFunc func) +EXPORT void menu_remove(AudMenuID id, MenuFunc func) { - auto is_match = [func] (ItemData & item) - { return item.item.func == func; }; + auto is_match = [func](ItemData & item) { return item.item.func == func; }; - if (items[id].remove_if (is_match, true)) - menu_rebuild (id); + if (items[id].remove_if(is_match, true)) + menu_rebuild(id); } } // namespace audqt diff --git a/src/libaudqt/prefs-builder.cc b/src/libaudqt/prefs-builder.cc index 2bcdd24..ca9d111 100644 --- a/src/libaudqt/prefs-builder.cc +++ b/src/libaudqt/prefs-builder.cc @@ -1,6 +1,6 @@ /* * prefs-builder.cc - * Copyright 2014 William Pitcock and John Lindgren + * Copyright 2014 Ariadne Conill and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,9 +28,11 @@ #include #include -namespace audqt { +namespace audqt +{ -void prefs_populate (QBoxLayout * layout, ArrayRef widgets, const char * domain) +void prefs_populate(QBoxLayout * layout, ArrayRef widgets, + const char * domain) { /* layout prior to header label */ QBoxLayout * orig_layout = layout; @@ -46,27 +48,27 @@ void prefs_populate (QBoxLayout * layout, ArrayRef widgets, c { if (w.child) { - if (! parent_layout) + if (!parent_layout) { /* save prior layouts */ parent_layout = layout; parent_orig_layout = orig_layout; /* create new layout for child widgets */ - if (dynamic_cast (parent_layout)) - layout = make_hbox (nullptr, sizes.TwoPt); + if (dynamic_cast(parent_layout)) + layout = make_hbox(nullptr, sizes.TwoPt); else { - layout = make_vbox (nullptr, sizes.TwoPt); - layout->setContentsMargins (sizes.EightPt, 0, 0, 0); + layout = make_vbox(nullptr, sizes.TwoPt); + layout->setContentsMargins(sizes.EightPt, 0, 0, 0); } - parent_layout->addLayout (layout); + parent_layout->addLayout(layout); orig_layout = layout; if (parent_widget) - parent_widget->set_child_layout (layout); + parent_widget->set_child_layout(layout); } } else @@ -83,28 +85,28 @@ void prefs_populate (QBoxLayout * layout, ArrayRef widgets, c /* enable/disable child widgets */ if (parent_widget) - parent_widget->update_from_cfg (); + parent_widget->update_from_cfg(); parent_widget = nullptr; } if (w.type != PreferencesWidget::RadioButton) radio_btn_group[w.child] = nullptr; - if (! w.child) + if (!w.child) radio_btn_group[true] = nullptr; switch (w.type) { case PreferencesWidget::Button: - layout->addWidget (new ButtonWidget (& w, domain)); + layout->addWidget(new ButtonWidget(&w, domain)); break; case PreferencesWidget::CheckButton: { - auto checkbox = new BooleanWidget (& w, domain); - layout->addWidget (checkbox); + auto checkbox = new BooleanWidget(&w, domain); + layout->addWidget(checkbox); - if (! w.child) + if (!w.child) parent_widget = checkbox; break; @@ -112,23 +114,23 @@ void prefs_populate (QBoxLayout * layout, ArrayRef widgets, c case PreferencesWidget::Label: { - auto label = new QLabel (translate_str (w.label, domain)); + auto label = new QLabel(translate_str(w.label, domain)); - if (strstr (w.label, "")) + if (strstr(w.label, "")) { /* extra spacing above a header */ - if (orig_layout->itemAt (0)) - orig_layout->addSpacing (sizes.EightPt); + if (orig_layout->itemAt(0)) + orig_layout->addSpacing(sizes.EightPt); - orig_layout->addWidget (label); + orig_layout->addWidget(label); /* create indented layout below header */ - layout = make_vbox (nullptr, sizes.TwoPt); - layout->setContentsMargins (sizes.EightPt, 0, 0, 0); - orig_layout->addLayout (layout); + layout = make_vbox(nullptr, sizes.TwoPt); + layout->setContentsMargins(sizes.EightPt, 0, 0, 0); + orig_layout->addLayout(layout); } else - layout->addWidget (label); + layout->addWidget(label); break; } @@ -137,88 +139,94 @@ void prefs_populate (QBoxLayout * layout, ArrayRef widgets, c switch (w.cfg.type) { case WidgetConfig::Int: - layout->addWidget (new IntegerWidget (& w, domain)); + layout->addWidget(new IntegerWidget(&w, domain)); break; case WidgetConfig::Float: - layout->addWidget (new DoubleWidget (& w, domain)); + layout->addWidget(new DoubleWidget(&w, domain)); break; default: - AUDDBG ("encountered unhandled configuration type %d for PreferencesWidget::SpinButton\n", w.cfg.type); + AUDDBG("encountered unhandled configuration type %d for " + "PreferencesWidget::SpinButton\n", + w.cfg.type); break; } break; case PreferencesWidget::Entry: - /* TODO: implement file chooser */ + layout->addWidget(new StringWidget(&w, domain)); + break; + case PreferencesWidget::FileEntry: - layout->addWidget (new StringWidget (& w, domain)); + layout->addWidget(new FileWidget(&w, domain)); + break; + + case PreferencesWidget::FontButton: + layout->addWidget(new FontWidget(&w, domain)); break; case PreferencesWidget::RadioButton: { - if (! radio_btn_group[w.child]) + if (!radio_btn_group[w.child]) radio_btn_group[w.child] = new QButtonGroup; - auto radio_btn = new RadioButtonWidget (& w, domain, radio_btn_group[w.child]); - layout->addWidget (radio_btn); + auto radio_btn = + new RadioButtonWidget(&w, domain, radio_btn_group[w.child]); + layout->addWidget(radio_btn); - if (! w.child) + if (!w.child) parent_widget = radio_btn; break; } - case PreferencesWidget::FontButton: - /* XXX: unimplemented */ - AUDDBG ("font buttons are unimplemented\n"); - break; - case PreferencesWidget::ComboBox: - layout->addWidget (new ComboBoxWidget (& w, domain)); + layout->addWidget(new ComboBoxWidget(&w, domain)); break; case PreferencesWidget::CustomQt: if (w.data.populate) - layout->addWidget ((QWidget *) w.data.populate ()); + layout->addWidget((QWidget *)w.data.populate()); break; /* layout widgets follow */ case PreferencesWidget::Box: - layout->addWidget (new BoxWidget (& w, domain, - (bool) dynamic_cast (layout))); + layout->addWidget(new BoxWidget( + &w, domain, (bool)dynamic_cast(layout))); break; case PreferencesWidget::Table: - layout->addWidget (new TableWidget (& w, domain)); + layout->addWidget(new TableWidget(&w, domain)); break; case PreferencesWidget::Notebook: - layout->addWidget (new NotebookWidget (& w, domain)); + layout->addWidget(new NotebookWidget(&w, domain)); break; case PreferencesWidget::Separator: { QFrame * f = new QFrame; - f->setFrameShape (w.data.separator.horizontal ? QFrame::HLine : QFrame::VLine); - f->setFrameShadow (QFrame::Sunken); + f->setFrameShape(w.data.separator.horizontal ? QFrame::HLine + : QFrame::VLine); + f->setFrameShadow(QFrame::Sunken); - layout->addSpacing (sizes.FourPt); - layout->addWidget (f); - layout->addSpacing (sizes.FourPt); + layout->addSpacing(sizes.FourPt); + layout->addWidget(f); + layout->addSpacing(sizes.FourPt); break; } /* stub handler */ default: - AUDDBG ("invoked stub handler for PreferencesWidget type %d\n", w.type); + AUDDBG("invoked stub handler for PreferencesWidget type %d\n", + w.type); break; } } /* enable/disable child widgets */ if (parent_widget) - parent_widget->update_from_cfg (); + parent_widget->update_from_cfg(); } } // namespace audqt diff --git a/src/libaudqt/prefs-plugin.cc b/src/libaudqt/prefs-plugin.cc index 03fa53d..473d9bc 100644 --- a/src/libaudqt/prefs-plugin.cc +++ b/src/libaudqt/prefs-plugin.cc @@ -1,6 +1,6 @@ /* * prefs-plugin.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,39 +31,42 @@ #include "libaudqt.h" -namespace audqt { +namespace audqt +{ -EXPORT void plugin_about (PluginHandle * ph) +EXPORT void plugin_about(PluginHandle * ph) { - Plugin * header = (Plugin *) aud_plugin_get_header (ph); + Plugin * header = (Plugin *)aud_plugin_get_header(ph); - if (! header) + if (!header) return; const char * name = header->info.name; const char * text = header->info.about; - if (! text) + if (!text) return; if (header->info.domain) { - name = dgettext (header->info.domain, name); - text = dgettext (header->info.domain, text); + name = dgettext(header->info.domain, name); + text = dgettext(header->info.domain, text); } - AUDDBG ("name = %s\n", name); + AUDDBG("name = %s\n", name); - simple_message (str_printf (_("About %s"), name), text, QMessageBox::Information); + simple_message(str_printf(_("About %s"), name), text, + QMessageBox::Information); } -struct ConfigWindow { +struct ConfigWindow +{ PluginHandle * ph; QDialog * root; }; static Index config_windows; -static ConfigWindow * find_config_window (PluginHandle * ph) +static ConfigWindow * find_config_window(PluginHandle * ph) { for (ConfigWindow * cw : config_windows) { @@ -74,78 +77,82 @@ static ConfigWindow * find_config_window (PluginHandle * ph) return nullptr; } -EXPORT void plugin_prefs (PluginHandle * ph) +EXPORT void plugin_prefs(PluginHandle * ph) { - ConfigWindow * cw = find_config_window (ph); + ConfigWindow * cw = find_config_window(ph); if (cw && cw->root) { - window_bring_to_front (cw->root); + window_bring_to_front(cw->root); return; } - Plugin * header = (Plugin *) aud_plugin_get_header (ph); - if (! header) + Plugin * header = (Plugin *)aud_plugin_get_header(ph); + if (!header) return; const PluginPreferences * p = header->info.prefs; - if (! p) + if (!p) return; - if (! cw) + if (!cw) { - cw = new ConfigWindow {ph}; - config_windows.append (cw); + cw = new ConfigWindow{ph}; + config_windows.append(cw); } cw->root = new QDialog; - cw->root->setAttribute (Qt::WA_DeleteOnClose); - cw->root->setContentsMargins (margins.FourPt); + cw->root->setAttribute(Qt::WA_DeleteOnClose); + cw->root->setContentsMargins(margins.FourPt); if (p->init) - p->init (); + p->init(); - QObject::connect (cw->root, & QObject::destroyed, [p, cw] () { + QObject::connect(cw->root, &QObject::destroyed, [p, cw]() { if (p->cleanup) - p->cleanup (); + p->cleanup(); cw->root = nullptr; }); const char * name = header->info.name; if (header->info.domain) - name = dgettext (header->info.domain, name); + name = dgettext(header->info.domain, name); - cw->root->setWindowTitle ((const char *) str_printf(_("%s Settings"), name)); + cw->root->setWindowTitle((const char *)str_printf(_("%s Settings"), name)); - auto vbox = make_vbox (cw->root, sizes.TwoPt); - prefs_populate (vbox, p->widgets, header->info.domain); - vbox->addStretch (1); + auto vbox = make_vbox(cw->root, sizes.TwoPt); + prefs_populate(vbox, p->widgets, header->info.domain); + vbox->addStretch(1); QDialogButtonBox * bbox = new QDialogButtonBox; if (p->apply) { - bbox->setStandardButtons (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - bbox->button (QDialogButtonBox::Ok)->setText (translate_str (N_("_Set"))); - bbox->button (QDialogButtonBox::Cancel)->setText (translate_str (N_("_Cancel"))); - - QObject::connect (bbox, & QDialogButtonBox::accepted, [p, cw] () { - p->apply (); - cw->root->deleteLater (); + bbox->setStandardButtons(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel); + bbox->button(QDialogButtonBox::Ok)->setText(translate_str(N_("_Set"))); + bbox->button(QDialogButtonBox::Cancel) + ->setText(translate_str(N_("_Cancel"))); + + QObject::connect(bbox, &QDialogButtonBox::accepted, [p, cw]() { + p->apply(); + cw->root->deleteLater(); }); } else { - bbox->setStandardButtons (QDialogButtonBox::Close); - bbox->button (QDialogButtonBox::Close)->setText (translate_str (N_("_Close"))); + bbox->setStandardButtons(QDialogButtonBox::Close); + bbox->button(QDialogButtonBox::Close) + ->setText(translate_str(N_("_Close"))); } - QObject::connect (bbox, & QDialogButtonBox::rejected, cw->root, & QObject::deleteLater); + QObject::connect(bbox, &QDialogButtonBox::rejected, cw->root, + &QObject::deleteLater); - vbox->addWidget (bbox); + vbox->addWidget(bbox); - window_bring_to_front (cw->root); + window_bring_to_front(cw->root); } } // namespace audqt diff --git a/src/libaudqt/prefs-pluginlist-model.cc b/src/libaudqt/prefs-pluginlist-model.cc index ea82f43..df6fd4a 100644 --- a/src/libaudqt/prefs-pluginlist-model.cc +++ b/src/libaudqt/prefs-pluginlist-model.cc @@ -1,6 +1,6 @@ /* * prefs-pluginlist-model.cc - * Copyright 2014-2017 John Lindgren and William Pitcock + * Copyright 2014-2017 John Lindgren and Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,23 +26,24 @@ #include #include -namespace audqt { +namespace audqt +{ -struct PluginCategory { +struct PluginCategory +{ PluginType type; const char * name; }; static const PluginCategory categories[] = { - { PluginType::General, N_("General") }, - { PluginType::Effect, N_("Effect") }, - { PluginType::Vis, N_("Visualization") }, - { PluginType::Input, N_("Input") }, - { PluginType::Playlist, N_("Playlist") }, - { PluginType::Transport, N_("Transport") } -}; + {PluginType::General, N_("General")}, + {PluginType::Effect, N_("Effect")}, + {PluginType::Vis, N_("Visualization")}, + {PluginType::Input, N_("Input")}, + {PluginType::Playlist, N_("Playlist")}, + {PluginType::Transport, N_("Transport")}}; -static constexpr int n_categories = aud::n_elems (categories); +static constexpr int n_categories = aud::n_elems(categories); // The model hierarchy is as follows: // @@ -55,136 +56,139 @@ static constexpr int n_categories = aud::n_elems (categories); // + Effect plugin ... // + More categories ... -QModelIndex PluginListModel::index (int row, int column, const QModelIndex & parent) const +QModelIndex PluginListModel::index(int row, int column, + const QModelIndex & parent) const { // is parent the root node? - if (! parent.isValid ()) - return createIndex (row, column, nullptr); + if (!parent.isValid()) + return createIndex(row, column, nullptr); // is parent a plugin node? - if (parent.internalPointer () != nullptr) - return QModelIndex (); + if (parent.internalPointer() != nullptr) + return QModelIndex(); // parent must be a category node - int cat = parent.row (); + int cat = parent.row(); if (cat < 0 || cat >= n_categories) - return QModelIndex (); + return QModelIndex(); - auto & list = aud_plugin_list (categories[cat].type); - if (row < 0 || row >= list.len ()) - return QModelIndex (); + auto & list = aud_plugin_list(categories[cat].type); + if (row < 0 || row >= list.len()) + return QModelIndex(); - return createIndex (row, column, list[row]); + return createIndex(row, column, list[row]); } // for a plugin node, return the category node // for all other nodes, return an invalid index -QModelIndex PluginListModel::parent (const QModelIndex & child) const +QModelIndex PluginListModel::parent(const QModelIndex & child) const { - auto p = pluginForIndex (child); - return p ? indexForType (aud_plugin_get_type (p)) : QModelIndex (); + auto p = pluginForIndex(child); + return p ? indexForType(aud_plugin_get_type(p)) : QModelIndex(); } // retrieve the PluginHandle from a plugin node -PluginHandle * PluginListModel::pluginForIndex (const QModelIndex & index) const +PluginHandle * PluginListModel::pluginForIndex(const QModelIndex & index) const { - return (PluginHandle *) index.internalPointer (); + return (PluginHandle *)index.internalPointer(); } // look up the category node for a given plugin type -QModelIndex PluginListModel::indexForType (PluginType type) const +QModelIndex PluginListModel::indexForType(PluginType type) const { - for (int cat = 0; cat < n_categories; cat ++) + for (int cat = 0; cat < n_categories; cat++) { if (categories[cat].type == type) - return createIndex (cat, 0, nullptr); + return createIndex(cat, 0, nullptr); } - return QModelIndex (); + return QModelIndex(); } -int PluginListModel::rowCount (const QModelIndex & parent) const +int PluginListModel::rowCount(const QModelIndex & parent) const { // for the root node, return the # of categories - if (! parent.isValid ()) + if (!parent.isValid()) return n_categories; // for a plugin node, return 0 (no children) - if (parent.internalPointer () != nullptr) + if (parent.internalPointer() != nullptr) return 0; // for a category node, return the # of plugins - int cat = parent.row (); + int cat = parent.row(); if (cat < 0 || cat >= n_categories) return 0; - return aud_plugin_list (categories[cat].type).len (); + return aud_plugin_list(categories[cat].type).len(); } -int PluginListModel::columnCount (const QModelIndex & parent) const +int PluginListModel::columnCount(const QModelIndex & parent) const { return NumColumns; } -QVariant PluginListModel::data (const QModelIndex & index, int role) const +QVariant PluginListModel::data(const QModelIndex & index, int role) const { - auto p = pluginForIndex (index); + auto p = pluginForIndex(index); - if (! p) // category node? + if (!p) // category node? { - if (role != Qt::DisplayRole || index.column () != 0) - return QVariant (); + if (role != Qt::DisplayRole || index.column() != 0) + return QVariant(); - int cat = index.row (); + int cat = index.row(); if (cat < 0 || cat >= n_categories) - return QVariant (); + return QVariant(); - return QString (_(categories[cat].name)); + return QString(_(categories[cat].name)); } - bool enabled = aud_plugin_get_enabled (p); + bool enabled = aud_plugin_get_enabled(p); - switch (index.column ()) + switch (index.column()) { case NameColumn: if (role == Qt::DisplayRole) - return QString (aud_plugin_get_name (p)); + return QString(aud_plugin_get_name(p)); if (role == Qt::CheckStateRole) return enabled ? Qt::Checked : Qt::Unchecked; break; case AboutColumn: - if (role == Qt::DecorationRole && enabled && aud_plugin_has_about (p)) - return audqt::get_icon ("dialog-information"); + if (role == Qt::DecorationRole && enabled && aud_plugin_has_about(p)) + return audqt::get_icon("dialog-information"); break; case SettingsColumn: - if (role == Qt::DecorationRole && enabled && aud_plugin_has_configure (p)) - return audqt::get_icon ("preferences-system"); + if (role == Qt::DecorationRole && enabled && + aud_plugin_has_configure(p)) + return audqt::get_icon("preferences-system"); break; } - return QVariant (); + return QVariant(); } -bool PluginListModel::setData (const QModelIndex &index, const QVariant &value, int role) +bool PluginListModel::setData(const QModelIndex & index, const QVariant & value, + int role) { if (role != Qt::CheckStateRole) return false; - auto p = pluginForIndex (index); - if (! p) + auto p = pluginForIndex(index); + if (!p) return false; - aud_plugin_enable (p, value.toUInt () != Qt::Unchecked); - emit dataChanged (index, index.sibling (index.row (), NumColumns - 1)); + aud_plugin_enable(p, value.toUInt() != Qt::Unchecked); + emit dataChanged(index, index.sibling(index.row(), NumColumns - 1)); return true; } -Qt::ItemFlags PluginListModel::flags (const QModelIndex & index) const +Qt::ItemFlags PluginListModel::flags(const QModelIndex & index) const { return (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); } diff --git a/src/libaudqt/prefs-pluginlist-model.h b/src/libaudqt/prefs-pluginlist-model.h index adb0130..74438a9 100644 --- a/src/libaudqt/prefs-pluginlist-model.h +++ b/src/libaudqt/prefs-pluginlist-model.h @@ -1,6 +1,6 @@ /* * prefs-pluginlist-model.h - * Copyright 2014-2017 John Lindgren and William Pitcock + * Copyright 2014-2017 John Lindgren and Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,12 +25,14 @@ enum class PluginType; class PluginHandle; -namespace audqt { +namespace audqt +{ class PluginListModel : public QAbstractItemModel { public: - enum { + enum + { NameColumn, AboutColumn, SettingsColumn, @@ -38,20 +40,20 @@ public: NumColumns }; - PluginListModel (QObject * parent) : QAbstractItemModel (parent) {} + PluginListModel(QObject * parent) : QAbstractItemModel(parent) {} - QModelIndex index (int row, int column, const QModelIndex & parent) const; - QModelIndex parent (const QModelIndex & child) const; + QModelIndex index(int row, int column, const QModelIndex & parent) const; + QModelIndex parent(const QModelIndex & child) const; - PluginHandle * pluginForIndex (const QModelIndex & index) const; - QModelIndex indexForType (PluginType type) const; + PluginHandle * pluginForIndex(const QModelIndex & index) const; + QModelIndex indexForType(PluginType type) const; - int rowCount (const QModelIndex & parent) const; - int columnCount (const QModelIndex & parent) const; + int rowCount(const QModelIndex & parent) const; + int columnCount(const QModelIndex & parent) const; - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - bool setData (const QModelIndex & index, const QVariant & value, int role); - Qt::ItemFlags flags (const QModelIndex & parent) const; + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + bool setData(const QModelIndex & index, const QVariant & value, int role); + Qt::ItemFlags flags(const QModelIndex & parent) const; }; } // namespace audqt diff --git a/src/libaudqt/prefs-widget-qt.cc b/src/libaudqt/prefs-widget-qt.cc index c67280f..1a21b06 100644 --- a/src/libaudqt/prefs-widget-qt.cc +++ b/src/libaudqt/prefs-widget-qt.cc @@ -1,6 +1,6 @@ /* * prefs-widget.cc - * Copyright 2007-2014 Tomasz Moń, William Pitcock, and John Lindgren + * Copyright 2007-2014 Tomasz Moń, Ariadne Conill, and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -17,8 +17,8 @@ * the use of this software. */ -#include "prefs-widget.h" #include "libaudqt.h" +#include "prefs-widget.h" #include #include @@ -33,215 +33,291 @@ #include #include -namespace audqt { +namespace audqt +{ -HookableWidget::HookableWidget (const PreferencesWidget * parent, const char * domain) : - m_parent (parent), m_domain (domain) +HookableWidget::HookableWidget(const PreferencesWidget * parent, + const char * domain) + : m_parent(parent), m_domain(domain) { if (m_parent->cfg.hook) - hook.capture (new HookReceiver - {m_parent->cfg.hook, this, & HookableWidget::update_from_cfg}); + hook.capture(new HookReceiver{ + m_parent->cfg.hook, this, &HookableWidget::update_from_cfg}); } -void HookableWidget::update_from_cfg () +void HookableWidget::update_from_cfg() { m_updating = true; - update (); + update(); m_updating = false; } /* button */ -ButtonWidget::ButtonWidget (const PreferencesWidget * parent, const char * domain) : - QPushButton (translate_str (parent->label, domain)) +ButtonWidget::ButtonWidget(const PreferencesWidget * parent, + const char * domain) + : QPushButton(translate_str(parent->label, domain)) { - QObject::connect (this, & QPushButton::clicked, parent->data.button.callback); + setAutoDefault(false); + QObject::connect(this, &QPushButton::clicked, parent->data.button.callback); } /* boolean widget (checkbox) */ -BooleanWidget::BooleanWidget (const PreferencesWidget * parent, const char * domain) : - QCheckBox (translate_str (parent->label, domain)), - ParentWidget (parent, domain) +BooleanWidget::BooleanWidget(const PreferencesWidget * parent, + const char * domain) + : QCheckBox(translate_str(parent->label, domain)), + ParentWidget(parent, domain) { - update (); + update(); - QObject::connect (this, & QCheckBox::stateChanged, [this] (int state) { + QObject::connect(this, &QCheckBox::stateChanged, [this](int state) { if (m_updating) return; - m_parent->cfg.set_bool (state != Qt::Unchecked); + m_parent->cfg.set_bool(state != Qt::Unchecked); if (m_child_layout) - enable_layout (m_child_layout, state != Qt::Unchecked); + enable_layout(m_child_layout, state != Qt::Unchecked); }); } -void BooleanWidget::update () +void BooleanWidget::update() { - bool on = m_parent->cfg.get_bool (); - setCheckState (on ? Qt::Checked : Qt::Unchecked); + bool on = m_parent->cfg.get_bool(); + setCheckState(on ? Qt::Checked : Qt::Unchecked); if (m_child_layout) - enable_layout (m_child_layout, on); + enable_layout(m_child_layout, on); } /* integer (radio button) */ -RadioButtonWidget::RadioButtonWidget (const PreferencesWidget * parent, - const char * domain, QButtonGroup * btn_group) : - QRadioButton (translate_str (parent->label, domain)), - ParentWidget (parent, domain) +RadioButtonWidget::RadioButtonWidget(const PreferencesWidget * parent, + const char * domain, + QButtonGroup * btn_group) + : QRadioButton(translate_str(parent->label, domain)), + ParentWidget(parent, domain) { if (btn_group) - btn_group->addButton (this, parent->data.radio_btn.value); + btn_group->addButton(this, parent->data.radio_btn.value); - update (); + update(); - QObject::connect (this, & QAbstractButton::toggled, [this] (bool checked) { + QObject::connect(this, &QAbstractButton::toggled, [this](bool checked) { if (m_updating) return; if (checked) - m_parent->cfg.set_int (m_parent->data.radio_btn.value); + m_parent->cfg.set_int(m_parent->data.radio_btn.value); if (m_child_layout) - enable_layout (m_child_layout, checked); + enable_layout(m_child_layout, checked); }); } -void RadioButtonWidget::update () +void RadioButtonWidget::update() { - bool checked = (m_parent->cfg.get_int () == m_parent->data.radio_btn.value); + bool checked = (m_parent->cfg.get_int() == m_parent->data.radio_btn.value); if (checked) - setChecked (true); + setChecked(true); if (m_child_layout) - enable_layout (m_child_layout, checked); + enable_layout(m_child_layout, checked); } /* integer (spinbox) */ -IntegerWidget::IntegerWidget (const PreferencesWidget * parent, const char * domain) : - HookableWidget (parent, domain), - m_spinner (new QSpinBox) +IntegerWidget::IntegerWidget(const PreferencesWidget * parent, + const char * domain) + : HookableWidget(parent, domain), m_spinner(new QSpinBox) { - auto layout = make_hbox (this); + auto layout = make_hbox(this); if (parent->label) - layout->addWidget (new QLabel (translate_str (parent->label, domain))); + layout->addWidget(new QLabel(translate_str(parent->label, domain))); - m_spinner->setRange ((int) m_parent->data.spin_btn.min, (int) m_parent->data.spin_btn.max); - m_spinner->setSingleStep ((int) m_parent->data.spin_btn.step); - layout->addWidget (m_spinner); + m_spinner->setRange((int)m_parent->data.spin_btn.min, + (int)m_parent->data.spin_btn.max); + m_spinner->setSingleStep((int)m_parent->data.spin_btn.step); + layout->addWidget(m_spinner); if (parent->data.spin_btn.right_label) - layout->addWidget (new QLabel (translate_str (parent->data.spin_btn.right_label, domain))); + layout->addWidget(new QLabel( + translate_str(parent->data.spin_btn.right_label, domain))); - layout->addStretch (1); + layout->addStretch(1); - update (); + update(); /* - * Qt has two different valueChanged signals for spin boxes. So we have to do an explicit - * cast to the type of the correct valueChanged signal. --kaniini. + * Qt has two different valueChanged signals for spin boxes. So we have to + * do an explicit cast to the type of the correct valueChanged signal. + * --kaniini. */ - void (QSpinBox::* signal) (int) = & QSpinBox::valueChanged; - QObject::connect (m_spinner, signal, [this] (int value) { - if (! m_updating) - m_parent->cfg.set_int (value); + void (QSpinBox::*signal)(int) = &QSpinBox::valueChanged; + QObject::connect(m_spinner, signal, [this](int value) { + if (!m_updating) + m_parent->cfg.set_int(value); }); } -void IntegerWidget::update () -{ - m_spinner->setValue (m_parent->cfg.get_int ()); -} +void IntegerWidget::update() { m_spinner->setValue(m_parent->cfg.get_int()); } /* double (spinbox) */ -DoubleWidget::DoubleWidget (const PreferencesWidget * parent, const char * domain) : - HookableWidget (parent, domain), - m_spinner (new QDoubleSpinBox) +DoubleWidget::DoubleWidget(const PreferencesWidget * parent, + const char * domain) + : HookableWidget(parent, domain), m_spinner(new QDoubleSpinBox) { - auto layout = make_hbox (this); + auto layout = make_hbox(this); if (parent->label) - layout->addWidget (new QLabel (translate_str (parent->label, domain))); + layout->addWidget(new QLabel(translate_str(parent->label, domain))); - auto decimals_for = [] (double step) - { return aud::max (0, -(int) floor (log10 (step) + 0.01)); }; + auto decimals_for = [](double step) { + return aud::max(0, -(int)floor(log10(step) + 0.01)); + }; - m_spinner->setDecimals (decimals_for (m_parent->data.spin_btn.step)); - m_spinner->setRange (m_parent->data.spin_btn.min, m_parent->data.spin_btn.max); - m_spinner->setSingleStep (m_parent->data.spin_btn.step); - layout->addWidget (m_spinner); + m_spinner->setDecimals(decimals_for(m_parent->data.spin_btn.step)); + m_spinner->setRange(m_parent->data.spin_btn.min, + m_parent->data.spin_btn.max); + m_spinner->setSingleStep(m_parent->data.spin_btn.step); + layout->addWidget(m_spinner); if (parent->data.spin_btn.right_label) - layout->addWidget (new QLabel (translate_str (parent->data.spin_btn.right_label, domain))); + layout->addWidget(new QLabel( + translate_str(parent->data.spin_btn.right_label, domain))); - layout->addStretch (1); + layout->addStretch(1); - update (); + update(); - void (QDoubleSpinBox::* signal) (double) = & QDoubleSpinBox::valueChanged; - QObject::connect (m_spinner, signal, [this] (double value) { - if (! m_updating) - m_parent->cfg.set_float (value); + void (QDoubleSpinBox::*signal)(double) = &QDoubleSpinBox::valueChanged; + QObject::connect(m_spinner, signal, [this](double value) { + if (!m_updating) + m_parent->cfg.set_float(value); }); } -void DoubleWidget::update () -{ - m_spinner->setValue (m_parent->cfg.get_float ()); -} +void DoubleWidget::update() { m_spinner->setValue(m_parent->cfg.get_float()); } /* string (lineedit) */ -StringWidget::StringWidget (const PreferencesWidget * parent, const char * domain) : - HookableWidget (parent, domain), - m_lineedit (new QLineEdit) +StringWidget::StringWidget(const PreferencesWidget * parent, + const char * domain) + : HookableWidget(parent, domain), m_lineedit(new QLineEdit) { - auto layout = make_hbox (this); + auto layout = make_hbox(this); if (parent->label) - layout->addWidget (new QLabel (translate_str (parent->label, domain))); + layout->addWidget(new QLabel(translate_str(parent->label, domain))); if (parent->type == PreferencesWidget::Entry && parent->data.entry.password) - m_lineedit->setEchoMode (QLineEdit::Password); + m_lineedit->setEchoMode(QLineEdit::Password); - layout->addWidget (m_lineedit, 1); + layout->addWidget(m_lineedit, 1); - update (); + update(); - QObject::connect (m_lineedit, & QLineEdit::textChanged, [this] (const QString & value) { - if (! m_updating) - m_parent->cfg.set_string (value.toUtf8 ()); - }); + QObject::connect(m_lineedit, &QLineEdit::textChanged, + [this](const QString & value) { + if (!m_updating) + m_parent->cfg.set_string(value.toUtf8()); + }); } -void StringWidget::update () +void StringWidget::update() { - m_lineedit->setText ((const char *) m_parent->cfg.get_string ()); + m_lineedit->setText((const char *)m_parent->cfg.get_string()); +} + +/* file widget (audqt::FileEntry) */ +FileWidget::FileWidget(const PreferencesWidget * parent, const char * domain) + : HookableWidget(parent, domain) +{ + QFileDialog::FileMode file_mode; + const char * title; + + switch (parent->data.file_entry.mode) + { + default: + case FileSelectMode::File: + file_mode = QFileDialog::ExistingFile; + title = _("Choose File"); + break; + case FileSelectMode::Folder: + file_mode = QFileDialog::Directory; + title = _("Choose Folder"); + break; + } + + m_lineedit = + file_entry_new(this, title, file_mode, QFileDialog::AcceptOpen); + + auto layout = make_hbox(this); + + if (parent->label) + layout->addWidget(new QLabel(translate_str(parent->label, domain))); + + layout->addWidget(m_lineedit, 1); + + update(); + + QObject::connect( + m_lineedit, &QLineEdit::textChanged, [this](const QString &) { + if (!m_updating) + m_parent->cfg.set_string(file_entry_get_uri(m_lineedit)); + }); +} + +void FileWidget::update() +{ + file_entry_set_uri(m_lineedit, m_parent->cfg.get_string()); +} + +/* font widget (audqt::FontEntry) */ +FontWidget::FontWidget(const PreferencesWidget * parent, const char * domain) + : HookableWidget(parent, domain), m_lineedit(font_entry_new(this, nullptr)) +{ + auto layout = make_hbox(this); + + if (parent->label) + layout->addWidget(new QLabel(translate_str(parent->label, domain))); + + layout->addWidget(m_lineedit, 1); + + update(); + + QObject::connect(m_lineedit, &QLineEdit::textChanged, + [this](const QString & value) { + if (!m_updating) + m_parent->cfg.set_string(value.toUtf8()); + }); +} + +void FontWidget::update() +{ + m_lineedit->setText((const char *)m_parent->cfg.get_string()); } /* combo box widget (string or int) */ -ComboBoxWidget::ComboBoxWidget (const PreferencesWidget * parent, const char * domain) : - HookableWidget (parent, domain), - m_combobox (new QComboBox) +ComboBoxWidget::ComboBoxWidget(const PreferencesWidget * parent, + const char * domain) + : HookableWidget(parent, domain), m_combobox(new QComboBox) { - auto layout = make_hbox (this); + auto layout = make_hbox(this); if (parent->label) - layout->addWidget (new QLabel (translate_str (parent->label, domain))); + layout->addWidget(new QLabel(translate_str(parent->label, domain))); - layout->addWidget (m_combobox); - layout->addStretch (1); + layout->addWidget(m_combobox); + layout->addStretch(1); - update (); + update(); - void (QComboBox::* signal) (int) = & QComboBox::currentIndexChanged; - QObject::connect (m_combobox, signal, [this] (int idx) { + void (QComboBox::*signal)(int) = &QComboBox::currentIndexChanged; + QObject::connect(m_combobox, signal, [this](int idx) { if (m_updating) return; - QVariant data = m_combobox->itemData (idx); + QVariant data = m_combobox->itemData(idx); switch (m_parent->cfg.type) { case WidgetConfig::Int: - m_parent->cfg.set_int (data.toInt ()); + m_parent->cfg.set_int(data.toInt()); break; case WidgetConfig::String: - m_parent->cfg.set_string (data.toString ().toUtf8 ()); + m_parent->cfg.set_string(data.toString().toUtf8()); break; default: break; @@ -249,25 +325,25 @@ ComboBoxWidget::ComboBoxWidget (const PreferencesWidget * parent, const char * d }); } -void ComboBoxWidget::update () +void ComboBoxWidget::update() { ArrayRef items = m_parent->data.combo.elems; if (m_parent->data.combo.fill) - items = m_parent->data.combo.fill (); + items = m_parent->data.combo.fill(); - m_combobox->clear (); + m_combobox->clear(); /* add combobox items */ switch (m_parent->cfg.type) { case WidgetConfig::Int: for (const ComboItem & item : items) - m_combobox->addItem (dgettext (m_domain, item.label), item.num); + m_combobox->addItem(dgettext(m_domain, item.label), item.num); break; case WidgetConfig::String: for (const ComboItem & item : items) - m_combobox->addItem (dgettext (m_domain, item.label), item.str); + m_combobox->addItem(dgettext(m_domain, item.label), item.str); break; default: break; @@ -278,13 +354,13 @@ void ComboBoxWidget::update () { case WidgetConfig::Int: { - int num = m_parent->cfg.get_int (); + int num = m_parent->cfg.get_int(); - for (int i = 0; i < items.len; i ++) + for (int i = 0; i < items.len; i++) { if (items.data[i].num == num) { - m_combobox->setCurrentIndex (i); + m_combobox->setCurrentIndex(i); break; } } @@ -293,13 +369,13 @@ void ComboBoxWidget::update () } case WidgetConfig::String: { - String str = m_parent->cfg.get_string (); + String str = m_parent->cfg.get_string(); - for (int i = 0; i < items.len; i ++) + for (int i = 0; i < items.len; i++) { - if (! strcmp_safe (items.data[i].str, str)) + if (!strcmp_safe(items.data[i].str, str)) { - m_combobox->setCurrentIndex (i); + m_combobox->setCurrentIndex(i); break; } } @@ -312,40 +388,43 @@ void ComboBoxWidget::update () } /* layout widgets */ -BoxWidget::BoxWidget (const PreferencesWidget * parent, const char * domain, bool horizontal_layout) +BoxWidget::BoxWidget(const PreferencesWidget * parent, const char * domain, + bool horizontal_layout) { QBoxLayout * layout; if (parent->data.box.horizontal) - layout = make_hbox (this, sizes.TwoPt); + layout = make_hbox(this, sizes.TwoPt); else - layout = make_vbox (this, sizes.TwoPt); + layout = make_vbox(this, sizes.TwoPt); - prefs_populate (layout, parent->data.box.widgets, domain); + prefs_populate(layout, parent->data.box.widgets, domain); - /* only add stretch if the orientation does not match the enclosing layout */ + /* only add stretch if the orientation does not match the enclosing layout + */ if (parent->data.box.horizontal != horizontal_layout) - layout->addStretch (1); + layout->addStretch(1); } -TableWidget::TableWidget (const PreferencesWidget * parent, const char * domain) +TableWidget::TableWidget(const PreferencesWidget * parent, const char * domain) { // TODO: proper table layout - auto layout = make_vbox (this, sizes.TwoPt); - prefs_populate (layout, parent->data.table.widgets, domain); + auto layout = make_vbox(this, sizes.TwoPt); + prefs_populate(layout, parent->data.table.widgets, domain); } -NotebookWidget::NotebookWidget (const PreferencesWidget * parent, const char * domain) +NotebookWidget::NotebookWidget(const PreferencesWidget * parent, + const char * domain) { for (const NotebookTab & tab : parent->data.notebook.tabs) { - auto widget = new QWidget (this); - widget->setContentsMargins (margins.FourPt); + auto widget = new QWidget(this); + widget->setContentsMargins(margins.FourPt); - auto layout = make_vbox (widget, sizes.TwoPt); - prefs_populate (layout, tab.widgets, domain); - layout->addStretch (1); + auto layout = make_vbox(widget, sizes.TwoPt); + prefs_populate(layout, tab.widgets, domain); + layout->addStretch(1); - addTab (widget, translate_str (tab.name, domain)); + addTab(widget, translate_str(tab.name, domain)); } } diff --git a/src/libaudqt/prefs-widget.h b/src/libaudqt/prefs-widget.h index 773945a..e796ae7 100644 --- a/src/libaudqt/prefs-widget.h +++ b/src/libaudqt/prefs-widget.h @@ -1,6 +1,6 @@ /* * prefs-widget.cc - * Copyright 2007-2014 Tomasz Moń, William Pitcock, and John Lindgren + * Copyright 2007-2014 Tomasz Moń, Ariadne Conill, and John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,8 +20,8 @@ #ifndef LIBAUDQT_PREFS_WIDGET_H #define LIBAUDQT_PREFS_WIDGET_H -#include #include +#include #include #include @@ -35,30 +35,20 @@ class QDoubleSpinBox; class QLineEdit; class QSpinBox; -namespace audqt { - -/* - * basic idea is this. create classes which wrap the PreferencesWidgets. - * Each should have it's own get(), set() and widget() methods. those are the - * functions that we really care about. - * get() and set() allow for introspection and manipulation of the underlying - * objects. they also handle pinging the plugin which owns the PreferencesWidget, - * i.e. calling PreferencesWidget::callback(). - * widget() builds the actual Qt side of the widget, hooks up the relevant signals - * to slots, etc. the result of widget() is not const as it is linked into a - * layout manager or shown or whatever. - */ +namespace audqt +{ /* base class which provides plumbing for hooks. */ -class HookableWidget { +class HookableWidget +{ public: - void update_from_cfg (); + void update_from_cfg(); protected: - HookableWidget (const PreferencesWidget * parent, const char * domain); + HookableWidget(const PreferencesWidget * parent, const char * domain); - virtual ~HookableWidget () {} - virtual void update () {} + virtual ~HookableWidget() {} + virtual void update() {} const PreferencesWidget * const m_parent; const char * const m_domain; @@ -69,93 +59,134 @@ private: }; /* shared class which allows disabling child widgets */ -class ParentWidget : public HookableWidget { +class ParentWidget : public HookableWidget +{ public: - void set_child_layout (QLayout * layout) - { m_child_layout = layout; } + void set_child_layout(QLayout * layout) { m_child_layout = layout; } protected: - ParentWidget (const PreferencesWidget * parent, const char * domain) : - HookableWidget (parent, domain) {} + ParentWidget(const PreferencesWidget * parent, const char * domain) + : HookableWidget(parent, domain) + { + } QLayout * m_child_layout = nullptr; }; /* button widget */ -class ButtonWidget : public QPushButton { +class ButtonWidget : public QPushButton +{ public: - ButtonWidget (const PreferencesWidget * parent, const char * domain); + ButtonWidget(const PreferencesWidget * parent, const char * domain); }; /* boolean widget (checkbox) */ -class BooleanWidget : public QCheckBox, public ParentWidget { +class BooleanWidget : public QCheckBox, public ParentWidget +{ public: - BooleanWidget (const PreferencesWidget * parent, const char * domain); + BooleanWidget(const PreferencesWidget * parent, const char * domain); + private: - void update (); + void update(); }; /* integer widget (spinner) */ -class IntegerWidget : public QWidget, HookableWidget { +class IntegerWidget : public QWidget, HookableWidget +{ public: - IntegerWidget (const PreferencesWidget * parent, const char * domain); + IntegerWidget(const PreferencesWidget * parent, const char * domain); + private: - void update (); + void update(); QSpinBox * m_spinner; }; /* integer widget (radio button) */ -class RadioButtonWidget : public QRadioButton, public ParentWidget { +class RadioButtonWidget : public QRadioButton, public ParentWidget +{ public: - RadioButtonWidget (const PreferencesWidget * parent, const char * domain, - QButtonGroup * btn_group); + RadioButtonWidget(const PreferencesWidget * parent, const char * domain, + QButtonGroup * btn_group); + private: - void update (); + void update(); }; /* double widget (spinner) */ -class DoubleWidget : public QWidget, HookableWidget { +class DoubleWidget : public QWidget, HookableWidget +{ public: - DoubleWidget (const PreferencesWidget * parent, const char * domain); + DoubleWidget(const PreferencesWidget * parent, const char * domain); + private: - void update (); + void update(); QDoubleSpinBox * m_spinner; }; /* string widget (lineedit) */ -class StringWidget : public QWidget, HookableWidget { +class StringWidget : public QWidget, HookableWidget +{ public: - StringWidget (const PreferencesWidget * parent, const char * domain); + StringWidget(const PreferencesWidget * parent, const char * domain); + private: - void update (); + void update(); + QLineEdit * m_lineedit; +}; + +/* file widget (audqt::FileEntry) */ +class FileWidget : public QWidget, HookableWidget +{ +public: + FileWidget(const PreferencesWidget * parent, const char * domain); + +private: + void update(); + QLineEdit * m_lineedit; +}; + +/* font widget (audqt::FontEntry) */ +class FontWidget : public QWidget, HookableWidget +{ +public: + FontWidget(const PreferencesWidget * parent, const char * domain); + +private: + void update(); QLineEdit * m_lineedit; }; /* combo box (string or int) */ -class ComboBoxWidget : public QWidget, HookableWidget { +class ComboBoxWidget : public QWidget, HookableWidget +{ public: - ComboBoxWidget (const PreferencesWidget * parent, const char * domain); + ComboBoxWidget(const PreferencesWidget * parent, const char * domain); + private: - void update (); + void update(); QComboBox * m_combobox; }; /* box container widget */ -class BoxWidget : public QWidget { +class BoxWidget : public QWidget +{ public: - BoxWidget (const PreferencesWidget * parent, const char * domain, bool horizontal_layout); + BoxWidget(const PreferencesWidget * parent, const char * domain, + bool horizontal_layout); }; /* table container widget */ -class TableWidget : public QWidget { +class TableWidget : public QWidget +{ public: - TableWidget (const PreferencesWidget * parent, const char * domain); + TableWidget(const PreferencesWidget * parent, const char * domain); }; /* notebook widget */ -class NotebookWidget : public QTabWidget { +class NotebookWidget : public QTabWidget +{ public: - NotebookWidget (const PreferencesWidget * parent, const char * domain); + NotebookWidget(const PreferencesWidget * parent, const char * domain); }; } // namespace audqt diff --git a/src/libaudqt/prefs-window-qt.cc b/src/libaudqt/prefs-window-qt.cc index 42f5798..8f72ba4 100644 --- a/src/libaudqt/prefs-window-qt.cc +++ b/src/libaudqt/prefs-window-qt.cc @@ -1,6 +1,6 @@ /* * prefs-window.cc - * Copyright 2006-2014 William Pitcock, Tomasz Moń, Michael Färber, and + * Copyright 2006-2014 Ariadne Conill, Tomasz Moń, Michael Färber, and * John Lindgren * * Redistribution and use in source and binary forms, with or without @@ -54,74 +54,93 @@ #include "libaudqt.h" #include "prefs-pluginlist-model.h" -namespace audqt { +namespace audqt +{ class PrefsWindow : public QDialog { public: - static PrefsWindow * get_instance () { - if (! instance) - (void) new PrefsWindow; + static PrefsWindow * get_instance() + { + if (!instance) + (void)new PrefsWindow; return instance; } - static void destroy_instance () { + static void destroy_instance() + { if (instance) delete instance; } - static ArrayRef get_output_combo () { - return {instance->output_combo_elements.begin (), - instance->output_combo_elements.len ()}; + static ArrayRef get_output_combo() + { + return {instance->output_combo_elements.begin(), + instance->output_combo_elements.len()}; } static int output_combo_selected; - static void output_combo_changed () { instance->output_change (); } + static void output_combo_changed() { instance->output_change(); } - static void * get_output_config_button () { return instance->output_config_button; } - static void * get_output_about_button () { return instance->output_about_button; } + static void * get_output_config_button() + { + return instance->output_config_button; + } + static void * get_output_about_button() + { + return instance->output_about_button; + } - static void * get_record_checkbox () { return instance->record_checkbox; } - static void * get_record_config_button () { return instance->record_config_button; } - static void * get_record_about_button () { return instance->record_about_button; } + static void * get_record_checkbox() { return instance->record_checkbox; } + static void * get_record_config_button() + { + return instance->record_config_button; + } + static void * get_record_about_button() + { + return instance->record_about_button; + } private: static PrefsWindow * instance; - PrefsWindow (); - ~PrefsWindow () { instance = nullptr; } + PrefsWindow(); + ~PrefsWindow() { instance = nullptr; } Index output_combo_elements; - QPushButton * output_config_button, * output_about_button; + QPushButton *output_config_button, *output_about_button; QCheckBox * record_checkbox; - QPushButton * record_config_button, * record_about_button; + QPushButton *record_config_button, *record_about_button; - void output_setup (); - void output_change (); + void output_setup(); + void output_change(); - void record_setup (); - void record_update (); + void record_setup(); + void record_update(); - const HookReceiver - record_hook {"enable record", this, & PrefsWindow::record_update}; + const HookReceiver record_hook{"enable record", this, + &PrefsWindow::record_update}; }; /* static data */ PrefsWindow * PrefsWindow::instance = nullptr; int PrefsWindow::output_combo_selected; -struct Category { +struct Category +{ const char * icon; const char * name; }; -struct TitleFieldTag { +struct TitleFieldTag +{ const char * name; const char * tag; }; -enum { +enum +{ CATEGORY_APPEARANCE = 0, CATEGORY_AUDIO, CATEGORY_NETWORK, @@ -133,255 +152,219 @@ enum { }; static const Category categories[] = { - { "applications-graphics", N_("Appearance") }, - { "audio-volume-medium", N_("Audio") }, - { "applications-internet", N_("Network") }, - { "audio-x-generic", N_("Playlist")} , - { "dialog-information", N_("Song Info") }, - { "applications-system", N_("Plugins") }, - { "preferences-system", N_("Advanced") } -}; + {"applications-graphics", N_("Appearance")}, + {"audio-volume-medium", N_("Audio")}, + {"applications-internet", N_("Network")}, + {"audio-x-generic", N_("Playlist")}, + {"dialog-information", N_("Song Info")}, + {"applications-system", N_("Plugins")}, + {"preferences-system", N_("Advanced")}}; static const TitleFieldTag title_field_tags[] = { - { N_("Artist") , "${artist}" }, - { N_("Album") , "${album}" }, - { N_("Album artist"), "${album-artist}" }, - { N_("Title") , "${title}" }, - { N_("Track number"), "${track-number}" }, - { N_("Genre") , "${genre}" }, - { N_("File name") , "${file-name}" }, - { N_("File path") , "${file-path}" }, - { N_("Date") , "${date}" }, - { N_("Year") , "${year}" }, - { N_("Comment") , "${comment}" }, - { N_("Codec") , "${codec}" }, - { N_("Quality") , "${quality}" } -}; + {N_("Artist"), "${artist}"}, + {N_("Album"), "${album}"}, + {N_("Album artist"), "${album-artist}"}, + {N_("Title"), "${title}"}, + {N_("Track number"), "${track-number}"}, + {N_("Genre"), "${genre}"}, + {N_("File name"), "${file-name}"}, + {N_("File path"), "${file-path}"}, + {N_("Date"), "${date}"}, + {N_("Description"), "${description}"}, + {N_("Year"), "${year}"}, + {N_("Comment"), "${comment}"}, + {N_("Codec"), "${codec}"}, + {N_("Quality"), "${quality}"}}; static const ComboItem chardet_detector_presets[] = { - ComboItem (N_("None"), ""), - ComboItem (N_("Arabic"), GUESS_REGION_AR), - ComboItem (N_("Baltic"), GUESS_REGION_BL), - ComboItem (N_("Chinese"), GUESS_REGION_CN), - ComboItem (N_("Greek"), GUESS_REGION_GR), - ComboItem (N_("Hebrew"), GUESS_REGION_HW), - ComboItem (N_("Japanese"), GUESS_REGION_JP), - ComboItem (N_("Korean"), GUESS_REGION_KR), - ComboItem (N_("Polish"), GUESS_REGION_PL), - ComboItem (N_("Russian"), GUESS_REGION_RU), - ComboItem (N_("Taiwanese"), GUESS_REGION_TW), - ComboItem (N_("Turkish"), GUESS_REGION_TR) -}; + ComboItem(N_("None"), ""), + ComboItem(N_("Arabic"), GUESS_REGION_AR), + ComboItem(N_("Baltic"), GUESS_REGION_BL), + ComboItem(N_("Chinese"), GUESS_REGION_CN), + ComboItem(N_("Greek"), GUESS_REGION_GR), + ComboItem(N_("Hebrew"), GUESS_REGION_HW), + ComboItem(N_("Japanese"), GUESS_REGION_JP), + ComboItem(N_("Korean"), GUESS_REGION_KR), + ComboItem(N_("Polish"), GUESS_REGION_PL), + ComboItem(N_("Russian"), GUESS_REGION_RU), + ComboItem(N_("Taiwanese"), GUESS_REGION_TW), + ComboItem(N_("Turkish"), GUESS_REGION_TR)}; static const ComboItem bitdepth_elements[] = { - ComboItem (N_("Automatic"), -1), - ComboItem ("16", 16), - ComboItem ("24", 24), - ComboItem ("32", 32), - ComboItem (N_("Floating point"), 0) -}; + ComboItem(N_("Automatic"), -1), ComboItem("16", 16), ComboItem("24", 24), + ComboItem("32", 32), ComboItem(N_("Floating point"), 0)}; static const ComboItem record_elements[] = { - ComboItem (N_("As decoded"), (int) OutputStream::AsDecoded), - ComboItem (N_("After applying ReplayGain"), (int) OutputStream::AfterReplayGain), - ComboItem (N_("After applying effects"), (int) OutputStream::AfterEffects), - ComboItem (N_("After applying equalization"), (int) OutputStream::AfterEqualizer) -}; + ComboItem(N_("As decoded"), (int)OutputStream::AsDecoded), + ComboItem(N_("After applying ReplayGain"), + (int)OutputStream::AfterReplayGain), + ComboItem(N_("After applying effects"), (int)OutputStream::AfterEffects), + ComboItem(N_("After applying equalization"), + (int)OutputStream::AfterEqualizer)}; static const ComboItem replaygainmode_elements[] = { - ComboItem (N_("Track"), (int) ReplayGainMode::Track), - ComboItem (N_("Album"), (int) ReplayGainMode::Album), - ComboItem (N_("Based on shuffle"), (int) ReplayGainMode::Automatic) -}; + ComboItem(N_("Track"), (int)ReplayGainMode::Track), + ComboItem(N_("Album"), (int)ReplayGainMode::Album), + ComboItem(N_("Based on shuffle"), (int)ReplayGainMode::Automatic)}; static Index iface_combo_elements; static int iface_combo_selected; static QWidget * iface_prefs_box; -static ArrayRef iface_combo_fill (); -static void iface_combo_changed (); -static void * iface_create_prefs_box (); +static ArrayRef iface_combo_fill(); +static void iface_combo_changed(); +static void * iface_create_prefs_box(); static const PreferencesWidget appearance_page_widgets[] = { - WidgetCombo (N_("Interface:"), - WidgetInt (iface_combo_selected, iface_combo_changed), - {0, iface_combo_fill}), - WidgetSeparator ({true}), - WidgetCustomQt (iface_create_prefs_box) -}; + WidgetCombo(N_("Interface:"), + WidgetInt(iface_combo_selected, iface_combo_changed), + {0, iface_combo_fill}), + WidgetSeparator({true}), WidgetCustomQt(iface_create_prefs_box)}; -static void output_bit_depth_changed (); +static void output_bit_depth_changed(); static const PreferencesWidget output_combo_widgets[] = { - WidgetCombo (N_("Output plugin:"), - WidgetInt (PrefsWindow::output_combo_selected, - PrefsWindow::output_combo_changed, - "audqt update output combo"), - {0, PrefsWindow::get_output_combo}), - WidgetCustomQt (PrefsWindow::get_output_config_button), - WidgetCustomQt (PrefsWindow::get_output_about_button) -}; + WidgetCombo(N_("Output plugin:"), + WidgetInt(PrefsWindow::output_combo_selected, + PrefsWindow::output_combo_changed, + "audqt update output combo"), + {0, PrefsWindow::get_output_combo}), + WidgetCustomQt(PrefsWindow::get_output_config_button), + WidgetCustomQt(PrefsWindow::get_output_about_button)}; static const PreferencesWidget record_buttons[] = { - WidgetCustomQt (PrefsWindow::get_record_config_button), - WidgetCustomQt (PrefsWindow::get_record_about_button) -}; + WidgetCustomQt(PrefsWindow::get_record_config_button), + WidgetCustomQt(PrefsWindow::get_record_about_button)}; static const PreferencesWidget gain_table[] = { - WidgetSpin (N_("Amplify all files:"), - WidgetFloat (0, "replay_gain_preamp"), - {-15, 15, 0.1, N_("dB")}), - WidgetSpin (N_("Amplify untagged files:"), - WidgetFloat (0, "default_gain"), - {-15, 15, 0.1, N_("dB")}) -}; + WidgetSpin(N_("Amplify all files:"), WidgetFloat(0, "replay_gain_preamp"), + {-15, 15, 0.1, N_("dB")}), + WidgetSpin(N_("Amplify untagged files:"), WidgetFloat(0, "default_gain"), + {-15, 15, 0.1, N_("dB")})}; static const PreferencesWidget audio_page_widgets[] = { - WidgetLabel (N_("Output Settings")), - WidgetBox ({{output_combo_widgets}, true}), - WidgetCombo (N_("Bit depth:"), - WidgetInt (0, "output_bit_depth", output_bit_depth_changed), - {{bitdepth_elements}}), - WidgetSpin (N_("Buffer size:"), - WidgetInt (0, "output_buffer_size"), - {100, 10000, 1000, N_("ms")}), - WidgetCheck (N_("Soft clipping"), - WidgetBool (0, "soft_clipping")), - WidgetCheck (N_("Use software volume control (not recommended)"), - WidgetBool (0, "software_volume_control")), - WidgetLabel (N_("Recording Settings")), - WidgetCustomQt (PrefsWindow::get_record_checkbox), - WidgetBox ({{record_buttons}, true}, - WIDGET_CHILD), - WidgetCombo (N_("Record stream:"), - WidgetInt (0, "record_stream"), - {{record_elements}}), - WidgetLabel (N_("ReplayGain")), - WidgetCheck (N_("Enable ReplayGain"), - WidgetBool (0, "enable_replay_gain")), - WidgetCombo (N_("Mode:"), - WidgetInt (0, "replay_gain_mode"), - {{replaygainmode_elements}}, - WIDGET_CHILD), - WidgetCheck (N_("Prevent clipping (recommended)"), - WidgetBool (0, "enable_clipping_prevention"), - WIDGET_CHILD), - WidgetTable ({{gain_table}}, - WIDGET_CHILD) -}; + WidgetLabel(N_("Output Settings")), + WidgetBox({{output_combo_widgets}, true}), + WidgetCombo(N_("Bit depth:"), + WidgetInt(0, "output_bit_depth", output_bit_depth_changed), + {{bitdepth_elements}}), + WidgetSpin(N_("Buffer size:"), WidgetInt(0, "output_buffer_size"), + {100, 10000, 1000, N_("ms")}), + WidgetCheck(N_("Soft clipping"), WidgetBool(0, "soft_clipping")), + WidgetCheck(N_("Use software volume control (not recommended)"), + WidgetBool(0, "software_volume_control")), + WidgetLabel(N_("Recording Settings")), + WidgetCustomQt(PrefsWindow::get_record_checkbox), + WidgetBox({{record_buttons}, true}, WIDGET_CHILD), + WidgetCombo(N_("Record stream:"), WidgetInt(0, "record_stream"), + {{record_elements}}), + WidgetLabel(N_("ReplayGain")), + WidgetCheck(N_("Enable ReplayGain"), WidgetBool(0, "enable_replay_gain")), + WidgetCombo(N_("Mode:"), WidgetInt(0, "replay_gain_mode"), + {{replaygainmode_elements}}, WIDGET_CHILD), + WidgetCheck(N_("Prevent clipping (recommended)"), + WidgetBool(0, "enable_clipping_prevention"), WIDGET_CHILD), + WidgetTable({{gain_table}}, WIDGET_CHILD)}; static const PreferencesWidget proxy_host_port_elements[] = { - WidgetEntry (N_("Proxy hostname:"), - WidgetString (0, "proxy_host")), - WidgetEntry (N_("Proxy port:"), - WidgetString (0, "proxy_port")) -}; + WidgetEntry(N_("Proxy hostname:"), WidgetString(0, "proxy_host")), + WidgetEntry(N_("Proxy port:"), WidgetString(0, "proxy_port"))}; static const PreferencesWidget proxy_auth_elements[] = { - WidgetEntry (N_("Proxy username:"), - WidgetString (0, "proxy_user")), - WidgetEntry (N_("Proxy password:"), - WidgetString (0, "proxy_pass"), - {true}) -}; + WidgetEntry(N_("Proxy username:"), WidgetString(0, "proxy_user")), + WidgetEntry(N_("Proxy password:"), WidgetString(0, "proxy_pass"), {true})}; static const PreferencesWidget connectivity_page_widgets[] = { - WidgetLabel (N_("Network Settings")), - WidgetSpin (N_("Buffer size:"), - WidgetInt (0, "net_buffer_kb"), - {16, 1024, 16, N_("KiB")}), - WidgetLabel (N_("Proxy Configuration")), - WidgetCheck (N_("Enable proxy usage"), - WidgetBool (0, "use_proxy")), - WidgetTable ({{proxy_host_port_elements}}, - WIDGET_CHILD), - WidgetCheck (N_("Use authentication with proxy"), - WidgetBool (0, "use_proxy_auth")), - WidgetTable ({{proxy_auth_elements}}, - WIDGET_CHILD) -}; + WidgetLabel(N_("Network Settings")), + WidgetSpin(N_("Buffer size:"), WidgetInt(0, "net_buffer_kb"), + {16, 1024, 16, N_("KiB")}), + WidgetLabel(N_("Proxy Configuration")), + WidgetCheck(N_("Enable proxy usage"), WidgetBool(0, "use_proxy")), + WidgetTable({{proxy_host_port_elements}}, WIDGET_CHILD), + WidgetCheck(N_("Use authentication with proxy"), + WidgetBool(0, "use_proxy_auth")), + WidgetTable({{proxy_auth_elements}}, WIDGET_CHILD), + WidgetCheck(N_("Use SOCKS proxy"), WidgetBool(0, "socks_proxy")), + WidgetRadio(N_("SOCKS v4a"), WidgetInt(0, "socks_type"), {0}, WIDGET_CHILD), + WidgetRadio(N_("SOCKS v5"), WidgetInt(0, "socks_type"), {1}, WIDGET_CHILD)}; static const PreferencesWidget chardet_elements[] = { - WidgetCombo (N_("Auto character encoding detector for:"), - WidgetString (0, "chardet_detector"), - {{chardet_detector_presets}}), - WidgetEntry (N_("Fallback character encodings:"), - WidgetString (0, "chardet_fallback")) -}; + WidgetCombo(N_("Auto character encoding detector for:"), + WidgetString(0, "chardet_detector"), + {{chardet_detector_presets}}), + WidgetEntry(N_("Fallback character encodings:"), + WidgetString(0, "chardet_fallback"))}; -static void send_title_change (); -static void * create_titlestring_table (); +static void send_title_change(); +static void * create_titlestring_table(); static const PreferencesWidget playlist_page_widgets[] = { - WidgetLabel (N_("Behavior")), - WidgetCheck (N_("Resume playback on startup"), - WidgetBool (0, "resume_playback_on_startup")), - WidgetCheck (N_("Pause instead of resuming immediately"), - WidgetBool (0, "always_resume_paused"), - WIDGET_CHILD), - WidgetCheck (N_("Advance when the current song is deleted"), - WidgetBool (0, "advance_on_delete")), - WidgetCheck (N_("Clear the playlist when opening files"), - WidgetBool (0, "clear_playlist")), - WidgetCheck (N_("Open files in a temporary playlist"), - WidgetBool (0, "open_to_temporary")), - WidgetLabel (N_("Song Display")), - WidgetCheck (N_("Show song numbers"), - WidgetBool (0, "show_numbers_in_pl", send_title_change)), - WidgetCheck (N_("Show leading zeroes (02:00 vs. 2:00)"), - WidgetBool (0, "leading_zero", send_title_change)), - WidgetCheck (N_("Show hours separately (1:30:00 vs. 90:00)"), - WidgetBool (0, "show_hours", send_title_change)), - WidgetCustomQt (create_titlestring_table), - WidgetLabel (N_("Export")), - WidgetCheck (N_("Use relative paths when possible"), - WidgetBool (0, "export_relative_paths")) -}; + WidgetLabel(N_("Behavior")), + WidgetCheck(N_("Resume playback on startup"), + WidgetBool(0, "resume_playback_on_startup")), + WidgetCheck(N_("Pause instead of resuming immediately"), + WidgetBool(0, "always_resume_paused"), WIDGET_CHILD), + WidgetCheck(N_("Advance when the current song is deleted"), + WidgetBool(0, "advance_on_delete")), + WidgetCheck(N_("Clear the playlist when opening files"), + WidgetBool(0, "clear_playlist")), + WidgetCheck(N_("Open files in a temporary playlist"), + WidgetBool(0, "open_to_temporary")), + WidgetLabel(N_("Song Display")), + WidgetCheck(N_("Show song numbers"), + WidgetBool(0, "show_numbers_in_pl", send_title_change)), + WidgetCheck(N_("Show leading zeroes (02:00 vs. 2:00)"), + WidgetBool(0, "leading_zero", send_title_change)), + WidgetCheck(N_("Show hours separately (1:30:00 vs. 90:00)"), + WidgetBool(0, "show_hours", send_title_change)), + WidgetCustomQt(create_titlestring_table), + WidgetLabel(N_("Export")), + WidgetCheck(N_("Use relative paths when possible"), + WidgetBool(0, "export_relative_paths"))}; static const PreferencesWidget song_info_page_widgets[] = { - WidgetLabel (N_("Album Art")), - WidgetLabel (N_("Search for images matching these words (comma-separated):")), - WidgetEntry (0, WidgetString (0, "cover_name_include")), - WidgetLabel (N_("Exclude images matching these words (comma-separated):")), - WidgetEntry (0, WidgetString (0, "cover_name_exclude")), - WidgetCheck (N_("Search for images matching song file name"), - WidgetBool (0, "use_file_cover")), - WidgetCheck (N_("Search recursively"), - WidgetBool (0, "recurse_for_cover")), - WidgetSpin (N_("Search depth:"), - WidgetInt (0, "recurse_for_cover_depth"), - {0, 100, 1}, - WIDGET_CHILD), - WidgetLabel (N_("Popup Information")), - WidgetCheck (N_("Show popup information"), - WidgetBool (0, "show_filepopup_for_tuple")), - WidgetSpin (N_("Popup delay (tenths of a second):"), - WidgetInt (0, "filepopup_delay"), - {0, 100, 1}, - WIDGET_CHILD), - WidgetCheck (N_("Show time scale for current song"), - WidgetBool (0, "filepopup_showprogressbar"), - WIDGET_CHILD) -}; + WidgetLabel(N_("Album Art")), + WidgetLabel( + N_("Search for images matching these words (comma-separated):")), + WidgetEntry(0, WidgetString(0, "cover_name_include")), + WidgetLabel(N_("Exclude images matching these words (comma-separated):")), + WidgetEntry(0, WidgetString(0, "cover_name_exclude")), + WidgetCheck(N_("Search for images matching song file name"), + WidgetBool(0, "use_file_cover")), + WidgetCheck(N_("Search recursively"), WidgetBool(0, "recurse_for_cover")), + WidgetSpin(N_("Search depth:"), WidgetInt(0, "recurse_for_cover_depth"), + {0, 100, 1}, WIDGET_CHILD), + WidgetLabel(N_("Popup Information")), + WidgetCheck(N_("Show popup information"), + WidgetBool(0, "show_filepopup_for_tuple")), + WidgetSpin(N_("Popup delay (tenths of a second):"), + WidgetInt(0, "filepopup_delay"), {0, 100, 1}, WIDGET_CHILD), + WidgetCheck(N_("Show time scale for current song"), + WidgetBool(0, "filepopup_showprogressbar"), WIDGET_CHILD)}; static const PreferencesWidget advanced_page_widgets[] = { - WidgetLabel (N_("Compatibility")), - WidgetCheck (N_("Interpret \\ (backward slash) as a folder delimiter"), - WidgetBool (0, "convert_backslash")), - WidgetTable ({{chardet_elements}}), - WidgetLabel (N_("Playlist")), - WidgetCheck (N_("Add folders recursively"), - WidgetBool (0, "recurse_folders")), - WidgetCheck (N_("Add folders nested within playlist files"), - WidgetBool (0, "folders_in_playlist")), - WidgetLabel (N_("Metadata")), - WidgetCheck (N_("Guess missing metadata from file path"), - WidgetBool (0, "metadata_fallbacks")), - WidgetCheck (N_("Do not load metadata for songs until played"), - WidgetBool (0, "metadata_on_play")), - WidgetCheck (N_("Probe content of files with no recognized file name extension"), - WidgetBool (0, "slow_probe")) -}; + WidgetLabel(N_("Compatibility")), + WidgetCheck(N_("Interpret \\ (backward slash) as a folder delimiter"), + WidgetBool(0, "convert_backslash")), + WidgetTable({{chardet_elements}}), + WidgetLabel(N_("Playlist")), + WidgetCheck(N_("Add folders recursively"), + WidgetBool(0, "recurse_folders")), + WidgetCheck(N_("Add folders nested within playlist files"), + WidgetBool(0, "folders_in_playlist")), + WidgetLabel(N_("Metadata")), + WidgetCheck(N_("Guess missing metadata from file path"), + WidgetBool(0, "metadata_fallbacks")), + WidgetCheck(N_("Do not load metadata for songs until played"), + WidgetBool(0, "metadata_on_play")), + WidgetCheck( + N_("Probe content of files with no recognized file name extension"), + WidgetBool(0, "slow_probe")), + WidgetLabel(N_("Miscellaneous")), + WidgetSpin(N_("Step forward/backward by:"), WidgetInt(0, "step_size"), + {1, 60, 1, N_("seconds")}), + WidgetSpin(N_("Adjust volume by:"), WidgetInt(0, "volume_delta"), + {1, 25, 1, N_("percent")})}; #define TITLESTRING_NPRESETS 8 @@ -391,10 +374,11 @@ static const char * const titlestring_presets[TITLESTRING_NPRESETS] = { "${title}${?artist: - ${artist}}${?album: - ${album}}", "${?artist:${artist} - }${title}", "${?artist:${artist} - }${?album:${album} - }${title}", - "${?artist:${artist} - }${?album:${album} - }${?track-number:${track-number}. }${title}", - "${?artist:${artist} }${?album:[ ${album} ] }${?artist:- }${?track-number:${track-number}. }${title}", - "${?album:${album} - }${title}" -}; + "${?artist:${artist} - }${?album:${album} - " + "}${?track-number:${track-number}. }${title}", + "${?artist:${artist} }${?album:[ ${album} ] }${?artist:- " + "}${?track-number:${track-number}. }${title}", + "${?album:${album} - }${title}"}; static const char * const titlestring_preset_names[TITLESTRING_NPRESETS] = { N_("TITLE"), @@ -404,379 +388,380 @@ static const char * const titlestring_preset_names[TITLESTRING_NPRESETS] = { N_("ARTIST - ALBUM - TITLE"), N_("ARTIST - ALBUM - TRACK. TITLE"), N_("ARTIST [ ALBUM ] - TRACK. TITLE"), - N_("ALBUM - TITLE") -}; + N_("ALBUM - TITLE")}; -static void * create_titlestring_table () +static void * create_titlestring_table() { QWidget * w = new QWidget; - QGridLayout * l = new QGridLayout (w); - l->setContentsMargins (0, 0, 0, 0); - l->setSpacing (sizes.TwoPt); + QGridLayout * l = new QGridLayout(w); + l->setContentsMargins(0, 0, 0, 0); + l->setSpacing(sizes.TwoPt); - QLabel * lbl = new QLabel (_("Title format:"), w); - l->addWidget (lbl, 0, 0); + QLabel * lbl = new QLabel(_("Title format:"), w); + l->addWidget(lbl, 0, 0); - QComboBox * cbox = new QComboBox (w); - l->addWidget (cbox, 0, 1); + QComboBox * cbox = new QComboBox(w); + l->addWidget(cbox, 0, 1); - for (int i = 0; i < TITLESTRING_NPRESETS; i ++) - cbox->addItem (translate_str (titlestring_preset_names [i]), i); - cbox->addItem (_("Custom"), TITLESTRING_NPRESETS); - cbox->setCurrentIndex (TITLESTRING_NPRESETS); + for (int i = 0; i < TITLESTRING_NPRESETS; i++) + cbox->addItem(translate_str(titlestring_preset_names[i]), i); + cbox->addItem(_("Custom"), TITLESTRING_NPRESETS); + cbox->setCurrentIndex(TITLESTRING_NPRESETS); - lbl = new QLabel (_("Custom string:"), w); - l->addWidget (lbl, 1, 0); + lbl = new QLabel(_("Custom string:"), w); + l->addWidget(lbl, 1, 0); - QLineEdit * le = new QLineEdit (w); - l->addWidget (le, 1, 1); + QLineEdit * le = new QLineEdit(w); + l->addWidget(le, 1, 1); - String format = aud_get_str (nullptr, "generic_title_format"); - le->setText ((const char *) format); - for (int i = 0; i < TITLESTRING_NPRESETS; i ++) + String format = aud_get_str("generic_title_format"); + le->setText((const char *)format); + for (int i = 0; i < TITLESTRING_NPRESETS; i++) { - if (! strcmp (titlestring_presets [i], format)) - cbox->setCurrentIndex (i); + if (!strcmp(titlestring_presets[i], format)) + cbox->setCurrentIndex(i); } - QObject::connect (le, & QLineEdit::textChanged, [] (const QString & text) { - aud_set_str (nullptr, "generic_title_format", text.toUtf8 ().data ()); + QObject::connect(le, &QLineEdit::textChanged, [](const QString & text) { + aud_set_str("generic_title_format", text.toUtf8().data()); }); - void (QComboBox::* signal) (int) = & QComboBox::currentIndexChanged; - QObject::connect (cbox, signal, [le] (int idx) { + void (QComboBox::*signal)(int) = &QComboBox::currentIndexChanged; + QObject::connect(cbox, signal, [le](int idx) { if (idx < TITLESTRING_NPRESETS) - le->setText (titlestring_presets [idx]); + le->setText(titlestring_presets[idx]); }); /* build menu */ - QPushButton * btn_mnu = new QPushButton (w); - btn_mnu->setFixedWidth (btn_mnu->sizeHint ().height ()); - btn_mnu->setIcon (audqt::get_icon ("list-add")); - l->addWidget (btn_mnu, 1, 2); + QPushButton * btn_mnu = new QPushButton(w); + btn_mnu->setFixedWidth(btn_mnu->sizeHint().height()); + btn_mnu->setIcon(audqt::get_icon("list-add")); + l->addWidget(btn_mnu, 1, 2); - QMenu * mnu_fields = new QMenu (w); + QMenu * mnu_fields = new QMenu(w); for (auto & t : title_field_tags) { - QAction * a = mnu_fields->addAction (_(t.name)); - QObject::connect (a, & QAction::triggered, [=] () { - le->insert (t.tag); - }); + QAction * a = mnu_fields->addAction(_(t.name)); + QObject::connect(a, &QAction::triggered, [=]() { le->insert(t.tag); }); } - QObject::connect (btn_mnu, & QAbstractButton::clicked, [=] () { - mnu_fields->popup (btn_mnu->mapToGlobal (QPoint (0, 0))); + QObject::connect(btn_mnu, &QAbstractButton::clicked, [=]() { + mnu_fields->popup(btn_mnu->mapToGlobal(QPoint(0, 0))); }); return w; } -static Index fill_plugin_combo (PluginType type) +static Index fill_plugin_combo(PluginType type) { Index elems; int i = 0; - for (PluginHandle * plugin : aud_plugin_list (type)) - elems.append (aud_plugin_get_name (plugin), i ++); + for (PluginHandle * plugin : aud_plugin_list(type)) + elems.append(aud_plugin_get_name(plugin), i++); return elems; } -static void send_title_change () +static void send_title_change() { - if (aud_drct_get_ready ()) - hook_call ("title change", nullptr); + if (aud_drct_get_ready()) + hook_call("title change", nullptr); } -static void iface_fill_prefs_box () +static void iface_fill_prefs_box() { - Plugin * header = (Plugin *) aud_plugin_get_header (aud_plugin_get_current (PluginType::Iface)); + Plugin * header = (Plugin *)aud_plugin_get_header( + aud_plugin_get_current(PluginType::Iface)); if (header && header->info.prefs) { - auto vbox = make_vbox (iface_prefs_box, sizes.TwoPt); - prefs_populate (vbox, header->info.prefs->widgets, header->info.domain); + auto vbox = make_vbox(iface_prefs_box, sizes.TwoPt); + prefs_populate(vbox, header->info.prefs->widgets, header->info.domain); } } -static void iface_combo_changed () +static void iface_combo_changed() { /* prevent audqt from being shut down during the switch */ - init (); + init(); - if (QLayout * layout = iface_prefs_box->layout ()) + if (QLayout * layout = iface_prefs_box->layout()) { - clear_layout (layout); + clear_layout(layout); delete layout; } - aud_plugin_enable (aud_plugin_list (PluginType::Iface)[iface_combo_selected], true); + aud_plugin_enable(aud_plugin_list(PluginType::Iface)[iface_combo_selected], + true); - iface_fill_prefs_box (); - cleanup (); + iface_fill_prefs_box(); + cleanup(); } -static ArrayRef iface_combo_fill () +static ArrayRef iface_combo_fill() { - if (! iface_combo_elements.len ()) + if (!iface_combo_elements.len()) { - iface_combo_elements = fill_plugin_combo (PluginType::Iface); - iface_combo_selected = aud_plugin_list (PluginType::Iface). - find (aud_plugin_get_current (PluginType::Iface)); + iface_combo_elements = fill_plugin_combo(PluginType::Iface); + iface_combo_selected = + aud_plugin_list(PluginType::Iface) + .find(aud_plugin_get_current(PluginType::Iface)); } - return {iface_combo_elements.begin (), iface_combo_elements.len ()}; + return {iface_combo_elements.begin(), iface_combo_elements.len()}; } -static void * iface_create_prefs_box () +static void * iface_create_prefs_box() { iface_prefs_box = new QWidget; - iface_fill_prefs_box (); + iface_fill_prefs_box(); return iface_prefs_box; } -static void output_bit_depth_changed () +static void output_bit_depth_changed() { - aud_output_reset (OutputReset::ReopenStream); + aud_output_reset(OutputReset::ReopenStream); } -static void create_category (QStackedWidget * notebook, ArrayRef widgets) +static void create_category(QStackedWidget * notebook, + ArrayRef widgets) { QWidget * w = new QWidget; - auto vbox = make_vbox (w, sizes.TwoPt); - prefs_populate (vbox, widgets, nullptr); - vbox->addStretch (1); + auto vbox = make_vbox(w, sizes.TwoPt); + prefs_populate(vbox, widgets, nullptr); + vbox->addStretch(1); - notebook->addWidget (w); + notebook->addWidget(w); } static QTreeView * s_plugin_view; static PluginListModel * s_plugin_model; -static void create_plugin_category (QStackedWidget * parent) +static void create_plugin_category(QStackedWidget * parent) { - s_plugin_view = new QTreeView (parent); - s_plugin_model = new PluginListModel (s_plugin_view); - - s_plugin_view->setModel (s_plugin_model); - s_plugin_view->setSelectionMode (QTreeView::NoSelection); - s_plugin_view->setAlternatingRowColors (true); - - auto header = s_plugin_view->header (); - - header->hide (); - header->setSectionResizeMode (header->ResizeToContents); - header->setStretchLastSection (true); - - parent->addWidget (s_plugin_view); - - QObject::connect (s_plugin_view, & QAbstractItemView::clicked, [] (const QModelIndex & index) - { - auto p = s_plugin_model->pluginForIndex (index); - if (! p || ! aud_plugin_get_enabled (p)) - return; - - switch (index.column ()) - { - case PluginListModel::AboutColumn: - plugin_about (p); - break; - case PluginListModel::SettingsColumn: - plugin_prefs (p); - break; - } - }); + s_plugin_view = new QTreeView(parent); + s_plugin_model = new PluginListModel(s_plugin_view); + + s_plugin_view->setModel(s_plugin_model); + s_plugin_view->setSelectionMode(QTreeView::NoSelection); + s_plugin_view->setAlternatingRowColors(true); + + auto header = s_plugin_view->header(); + + header->hide(); + header->setSectionResizeMode(header->ResizeToContents); + header->setStretchLastSection(true); + + parent->addWidget(s_plugin_view); + + QObject::connect(s_plugin_view, &QAbstractItemView::clicked, + [](const QModelIndex & index) { + auto p = s_plugin_model->pluginForIndex(index); + if (!p || !aud_plugin_get_enabled(p)) + return; + + switch (index.column()) + { + case PluginListModel::AboutColumn: + plugin_about(p); + break; + case PluginListModel::SettingsColumn: + plugin_prefs(p); + break; + } + }); } static QStackedWidget * s_category_notebook = nullptr; -PrefsWindow::PrefsWindow () : - output_combo_elements (fill_plugin_combo (PluginType::Output)), - output_config_button (new QPushButton (translate_str (N_("_Settings")))), - output_about_button (new QPushButton (translate_str (N_("_About")))), - record_checkbox (new QCheckBox), - record_config_button (new QPushButton (translate_str (N_("_Settings")))), - record_about_button (new QPushButton (translate_str (N_("_About")))) +PrefsWindow::PrefsWindow() + : output_combo_elements(fill_plugin_combo(PluginType::Output)), + output_config_button(new QPushButton(translate_str(N_("_Settings")))), + output_about_button(new QPushButton(translate_str(N_("_About")))), + record_checkbox(new QCheckBox), + record_config_button(new QPushButton(translate_str(N_("_Settings")))), + record_about_button(new QPushButton(translate_str(N_("_About")))) { /* initialize static data */ instance = this; - output_combo_selected = aud_plugin_list (PluginType::Output) - .find (aud_plugin_get_current (PluginType::Output)); + output_combo_selected = + aud_plugin_list(PluginType::Output) + .find(aud_plugin_get_current(PluginType::Output)); - setAttribute (Qt::WA_DeleteOnClose); - setWindowTitle (_("Audacious Settings")); - setContentsMargins (0, 0, 0, 0); + setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(_("Audacious Settings")); + setContentsMargins(0, 0, 0, 0); + + output_config_button->setAutoDefault(false); + output_about_button->setAutoDefault(false); + record_config_button->setAutoDefault(false); + record_about_button->setAutoDefault(false); QToolBar * toolbar = new QToolBar; - toolbar->setToolButtonStyle (Qt::ToolButtonTextUnderIcon); + toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); QWidget * child = new QWidget; - child->setContentsMargins (margins.FourPt); + child->setContentsMargins(margins.FourPt); - auto vbox_parent = make_vbox (this); - vbox_parent->addWidget (toolbar); - vbox_parent->addWidget (child); + auto vbox_parent = make_vbox(this); + vbox_parent->addWidget(toolbar); + vbox_parent->addWidget(child); - auto child_vbox = make_vbox (child); + auto child_vbox = make_vbox(child); s_category_notebook = new QStackedWidget; - child_vbox->addWidget (s_category_notebook); - - create_category (s_category_notebook, appearance_page_widgets); - create_category (s_category_notebook, audio_page_widgets); - create_category (s_category_notebook, connectivity_page_widgets); - create_category (s_category_notebook, playlist_page_widgets); - create_category (s_category_notebook, song_info_page_widgets); - create_plugin_category (s_category_notebook); - create_category (s_category_notebook, advanced_page_widgets); - - QDialogButtonBox * bbox = new QDialogButtonBox (QDialogButtonBox::Close); - bbox->button (QDialogButtonBox::Close)->setText (translate_str (N_("_Close"))); - child_vbox->addWidget (bbox); + child_vbox->addWidget(s_category_notebook); - QObject::connect (bbox, & QDialogButtonBox::rejected, this, & QObject::deleteLater); + create_category(s_category_notebook, appearance_page_widgets); + create_category(s_category_notebook, audio_page_widgets); + create_category(s_category_notebook, connectivity_page_widgets); + create_category(s_category_notebook, playlist_page_widgets); + create_category(s_category_notebook, song_info_page_widgets); + create_plugin_category(s_category_notebook); + create_category(s_category_notebook, advanced_page_widgets); - QSignalMapper * mapper = new QSignalMapper (this); + QDialogButtonBox * bbox = new QDialogButtonBox(QDialogButtonBox::Close); + bbox->button(QDialogButtonBox::Close)->setText(translate_str(N_("_Close"))); + child_vbox->addWidget(bbox); - QObject::connect (mapper, static_cast (&QSignalMapper::mapped), - s_category_notebook, static_cast (&QStackedWidget::setCurrentIndex)); + QObject::connect(bbox, &QDialogButtonBox::rejected, this, + &QObject::deleteLater); - for (int i = 0; i < CATEGORY_COUNT; i ++) + for (int i = 0; i < CATEGORY_COUNT; i++) { - auto a = new QAction (get_icon (categories[i].icon), - translate_str (categories[i].name), toolbar); + auto a = new QAction(get_icon(categories[i].icon), + translate_str(categories[i].name), toolbar); - toolbar->addAction (a); - mapper->setMapping (a, i); + toolbar->addAction(a); - void (QSignalMapper::* slot) () = & QSignalMapper::map; - QObject::connect (a, & QAction::triggered, mapper, slot); + connect(a, &QAction::triggered, + [i]() { s_category_notebook->setCurrentIndex(i); }); } - output_setup (); - record_setup (); - record_update (); + output_setup(); + record_setup(); + record_update(); } -void PrefsWindow::output_setup () +void PrefsWindow::output_setup() { - auto p = aud_plugin_get_current (PluginType::Output); + auto p = aud_plugin_get_current(PluginType::Output); - output_config_button->setEnabled (aud_plugin_has_configure (p)); - output_about_button->setEnabled (aud_plugin_has_about (p)); + output_config_button->setEnabled(aud_plugin_has_configure(p)); + output_about_button->setEnabled(aud_plugin_has_about(p)); - QObject::connect (output_config_button, & QPushButton::clicked, [] (bool) { - plugin_prefs (aud_plugin_get_current (PluginType::Output)); + QObject::connect(output_config_button, &QPushButton::clicked, [](bool) { + plugin_prefs(aud_plugin_get_current(PluginType::Output)); }); - QObject::connect (output_about_button, & QPushButton::clicked, [] (bool) { - plugin_about (aud_plugin_get_current (PluginType::Output)); + QObject::connect(output_about_button, &QPushButton::clicked, [](bool) { + plugin_about(aud_plugin_get_current(PluginType::Output)); }); } -void PrefsWindow::output_change () +void PrefsWindow::output_change() { - auto & list = aud_plugin_list (PluginType::Output); + auto & list = aud_plugin_list(PluginType::Output); auto p = list[output_combo_selected]; - if (aud_plugin_enable (p, true)) + if (aud_plugin_enable(p, true)) { - output_config_button->setEnabled (aud_plugin_has_configure (p)); - output_about_button->setEnabled (aud_plugin_has_about (p)); + output_config_button->setEnabled(aud_plugin_has_configure(p)); + output_about_button->setEnabled(aud_plugin_has_about(p)); } else { /* set combo box back to current output */ - output_combo_selected = list.find (aud_plugin_get_current (PluginType::Output)); - hook_call ("audqt update output combo", nullptr); + output_combo_selected = + list.find(aud_plugin_get_current(PluginType::Output)); + hook_call("audqt update output combo", nullptr); } } -void PrefsWindow::record_setup () +void PrefsWindow::record_setup() { - QObject::connect (record_checkbox, & QCheckBox::clicked, [] (bool checked) { - aud_drct_enable_record (checked); - }); + QObject::connect(record_checkbox, &QCheckBox::clicked, + [](bool checked) { aud_drct_enable_record(checked); }); - QObject::connect (record_config_button, & QPushButton::clicked, [] (bool) { - if (aud_drct_get_record_enabled ()) - plugin_prefs (aud_drct_get_record_plugin ()); + QObject::connect(record_config_button, &QPushButton::clicked, [](bool) { + if (aud_drct_get_record_enabled()) + plugin_prefs(aud_drct_get_record_plugin()); }); - QObject::connect (record_about_button, & QPushButton::clicked, [] (bool) { - if (aud_drct_get_record_enabled ()) - plugin_about (aud_drct_get_record_plugin ()); + QObject::connect(record_about_button, &QPushButton::clicked, [](bool) { + if (aud_drct_get_record_enabled()) + plugin_about(aud_drct_get_record_plugin()); }); } -void PrefsWindow::record_update () +void PrefsWindow::record_update() { - auto p = aud_drct_get_record_plugin (); + auto p = aud_drct_get_record_plugin(); if (p) { - bool enabled = aud_drct_get_record_enabled (); - auto text = str_printf (_("Enable audio stream recording with %s"), aud_plugin_get_name (p)); - - record_checkbox->setEnabled (true); - record_checkbox->setText ((const char *) text); - record_checkbox->setChecked (enabled); - record_config_button->setEnabled (enabled && aud_plugin_has_configure (p)); - record_about_button->setEnabled (enabled && aud_plugin_has_about (p)); + bool enabled = aud_drct_get_record_enabled(); + auto text = str_printf(_("Enable audio stream recording with %s"), + aud_plugin_get_name(p)); + + record_checkbox->setEnabled(true); + record_checkbox->setText((const char *)text); + record_checkbox->setChecked(enabled); + record_config_button->setEnabled(enabled && + aud_plugin_has_configure(p)); + record_about_button->setEnabled(enabled && aud_plugin_has_about(p)); } else { - record_checkbox->setEnabled (false); - record_checkbox->setText (_("No audio recording plugin available")); - record_checkbox->setChecked (false); - record_config_button->setEnabled (false); - record_about_button->setEnabled (false); + record_checkbox->setEnabled(false); + record_checkbox->setText(_("No audio recording plugin available")); + record_checkbox->setChecked(false); + record_config_button->setEnabled(false); + record_about_button->setEnabled(false); } } -EXPORT void prefswin_show () +EXPORT void prefswin_show() { - window_bring_to_front (PrefsWindow::get_instance ()); + window_bring_to_front(PrefsWindow::get_instance()); } -EXPORT void prefswin_hide () -{ - PrefsWindow::destroy_instance (); -} +EXPORT void prefswin_hide() { PrefsWindow::destroy_instance(); } -EXPORT void prefswin_show_page (int id, bool show) +EXPORT void prefswin_show_page(int id, bool show) { if (id < 0 || id > CATEGORY_COUNT) return; - auto win = PrefsWindow::get_instance (); - s_category_notebook->setCurrentIndex (id); + auto win = PrefsWindow::get_instance(); + s_category_notebook->setCurrentIndex(id); if (show) - window_bring_to_front (win); + window_bring_to_front(win); } -EXPORT void prefswin_show_plugin_page (PluginType type) +EXPORT void prefswin_show_plugin_page(PluginType type) { if (type == PluginType::Iface) - prefswin_show_page (CATEGORY_APPEARANCE); + prefswin_show_page(CATEGORY_APPEARANCE); else if (type == PluginType::Output) - prefswin_show_page (CATEGORY_AUDIO); + prefswin_show_page(CATEGORY_AUDIO); else { - prefswin_show_page (CATEGORY_PLUGINS, false); + prefswin_show_page(CATEGORY_PLUGINS, false); - s_plugin_view->collapseAll (); + s_plugin_view->collapseAll(); - auto index = s_plugin_model->indexForType (type); - if (index.isValid ()) + auto index = s_plugin_model->indexForType(type); + if (index.isValid()) { - s_plugin_view->expand (index); - s_plugin_view->scrollTo (index, QTreeView::PositionAtTop); - s_plugin_view->setCurrentIndex (index); + s_plugin_view->expand(index); + s_plugin_view->scrollTo(index, QTreeView::PositionAtTop); + s_plugin_view->setCurrentIndex(index); } - window_bring_to_front (PrefsWindow::get_instance ()); + window_bring_to_front(PrefsWindow::get_instance()); } } diff --git a/src/libaudqt/queue-manager-qt.cc b/src/libaudqt/queue-manager-qt.cc index 11301b3..da6e646 100644 --- a/src/libaudqt/queue-manager-qt.cc +++ b/src/libaudqt/queue-manager-qt.cc @@ -1,6 +1,6 @@ /* * queue-manager.cc - * Copyright 2014 William Pitcock, John Lindgren + * Copyright 2014 Ariadne Conill, John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -22,119 +22,121 @@ #include #include #include -#include #include #include +#include #include #include #include -#include #include #include +#include /* * TODO: * - shifting of selection entries */ -namespace audqt { +namespace audqt +{ class QueueManagerModel : public QAbstractListModel { public: - void update (QItemSelectionModel * sel); - void selectionChanged (const QItemSelection & selected, const QItemSelection & deselected); + void update(QItemSelectionModel * sel); + void selectionChanged(const QItemSelection & selected, + const QItemSelection & deselected); protected: - int rowCount (const QModelIndex & parent) const { return m_rows; } - int columnCount (const QModelIndex & parent) const { return 2; } - QVariant data (const QModelIndex & index, int role) const; + int rowCount(const QModelIndex & parent) const { return m_rows; } + int columnCount(const QModelIndex & parent) const { return 2; } + QVariant data(const QModelIndex & index, int role) const; private: int m_rows = 0; bool m_in_update = false; }; -QVariant QueueManagerModel::data (const QModelIndex & index, int role) const +QVariant QueueManagerModel::data(const QModelIndex & index, int role) const { if (role == Qt::DisplayRole) { - auto list = Playlist::active_playlist (); - int entry = list.queue_get_entry (index.row ()); + auto list = Playlist::active_playlist(); + int entry = list.queue_get_entry(index.row()); - if (index.column () == 0) + if (index.column() == 0) return entry + 1; else { - Tuple tuple = list.entry_tuple (entry, Playlist::NoWait); - return QString ((const char *) tuple.get_str (Tuple::FormattedTitle)); + Tuple tuple = list.entry_tuple(entry, Playlist::NoWait); + return QString((const char *)tuple.get_str(Tuple::FormattedTitle)); } } - else if (role == Qt::TextAlignmentRole && index.column () == 0) + else if (role == Qt::TextAlignmentRole && index.column() == 0) return Qt::AlignRight; - return QVariant (); + return QVariant(); } -void QueueManagerModel::update (QItemSelectionModel * sel) +void QueueManagerModel::update(QItemSelectionModel * sel) { - auto list = Playlist::active_playlist (); - int rows = list.n_queued (); - int keep = aud::min (rows, m_rows); + auto list = Playlist::active_playlist(); + int rows = list.n_queued(); + int keep = aud::min(rows, m_rows); m_in_update = true; if (rows < m_rows) { - beginRemoveRows (QModelIndex (), rows, m_rows - 1); + beginRemoveRows(QModelIndex(), rows, m_rows - 1); m_rows = rows; - endRemoveRows (); + endRemoveRows(); } else if (rows > m_rows) { - beginInsertRows (QModelIndex (), m_rows, rows - 1); + beginInsertRows(QModelIndex(), m_rows, rows - 1); m_rows = rows; - endInsertRows (); + endInsertRows(); } if (keep > 0) { - auto topLeft = createIndex (0, 0); - auto bottomRight = createIndex (keep - 1, 0); - emit dataChanged (topLeft, bottomRight); + auto topLeft = createIndex(0, 0); + auto bottomRight = createIndex(keep - 1, 0); + emit dataChanged(topLeft, bottomRight); } - for (int i = 0; i < rows; i ++) + for (int i = 0; i < rows; i++) { - if (list.entry_selected (list.queue_get_entry (i))) - sel->select (createIndex (i, 0), sel->Select | sel->Rows); + if (list.entry_selected(list.queue_get_entry(i))) + sel->select(createIndex(i, 0), sel->Select | sel->Rows); else - sel->select (createIndex (i, 0), sel->Deselect | sel->Rows); + sel->select(createIndex(i, 0), sel->Deselect | sel->Rows); } m_in_update = false; } -void QueueManagerModel::selectionChanged (const QItemSelection & selected, - const QItemSelection & deselected) +void QueueManagerModel::selectionChanged(const QItemSelection & selected, + const QItemSelection & deselected) { if (m_in_update) return; - auto list = Playlist::active_playlist (); + auto list = Playlist::active_playlist(); - for (auto & index : selected.indexes ()) - list.select_entry (list.queue_get_entry (index.row ()), true); + for (auto & index : selected.indexes()) + list.select_entry(list.queue_get_entry(index.row()), true); - for (auto & index : deselected.indexes ()) - list.select_entry (list.queue_get_entry (index.row ()), false); + for (auto & index : deselected.indexes()) + list.select_entry(list.queue_get_entry(index.row()), false); } class QueueManagerDialog : public QDialog { public: - QueueManagerDialog (QWidget * parent = nullptr); + QueueManagerDialog(QWidget * parent = nullptr); private: QTreeView m_treeview; @@ -143,87 +145,82 @@ private: QPushButton m_btn_close; QueueManagerModel m_model; - void removeSelected (); - void update () { m_model.update (m_treeview.selectionModel ()); } + void removeSelected(); + void update() { m_model.update(m_treeview.selectionModel()); } - const HookReceiver - update_hook {"playlist update", this, & QueueManagerDialog::update}, - activate_hook {"playlist activate", this, & QueueManagerDialog::update}; + const HookReceiver update_hook{ + "playlist update", this, &QueueManagerDialog::update}, + activate_hook{"playlist activate", this, &QueueManagerDialog::update}; }; -QueueManagerDialog::QueueManagerDialog (QWidget * parent) : - QDialog (parent) +QueueManagerDialog::QueueManagerDialog(QWidget * parent) : QDialog(parent) { - setWindowTitle (_("Queue Manager")); - setContentsMargins (margins.TwoPt); + setWindowTitle(_("Queue Manager")); + setContentsMargins(margins.TwoPt); - m_btn_unqueue.setText (translate_str (N_("_Unqueue"))); - m_btn_close.setText (translate_str (N_("_Close"))); + m_btn_unqueue.setText(translate_str(N_("_Unqueue"))); + m_btn_close.setText(translate_str(N_("_Close"))); - connect (& m_btn_close, & QAbstractButton::clicked, this, & QWidget::hide); - connect (& m_btn_unqueue, & QAbstractButton::clicked, this, & QueueManagerDialog::removeSelected); + connect(&m_btn_close, &QAbstractButton::clicked, this, &QWidget::hide); + connect(&m_btn_unqueue, &QAbstractButton::clicked, this, + &QueueManagerDialog::removeSelected); - m_buttonbox.addButton (& m_btn_close, QDialogButtonBox::AcceptRole); - m_buttonbox.addButton (& m_btn_unqueue, QDialogButtonBox::AcceptRole); + m_buttonbox.addButton(&m_btn_close, QDialogButtonBox::AcceptRole); + m_buttonbox.addButton(&m_btn_unqueue, QDialogButtonBox::AcceptRole); - auto layout = make_vbox (this); - layout->addWidget (& m_treeview); - layout->addWidget (& m_buttonbox); + auto layout = make_vbox(this); + layout->addWidget(&m_treeview); + layout->addWidget(&m_buttonbox); - m_treeview.setIndentation (0); - m_treeview.setModel (& m_model); - m_treeview.setSelectionMode (QAbstractItemView::ExtendedSelection); - m_treeview.setHeaderHidden (true); + m_treeview.setIndentation(0); + m_treeview.setModel(&m_model); + m_treeview.setSelectionMode(QAbstractItemView::ExtendedSelection); + m_treeview.setHeaderHidden(true); - update (); + update(); - connect (m_treeview.selectionModel (), - & QItemSelectionModel::selectionChanged, & m_model, - & QueueManagerModel::selectionChanged); + connect(m_treeview.selectionModel(), &QItemSelectionModel::selectionChanged, + &m_model, &QueueManagerModel::selectionChanged); - resize (4 * sizes.OneInch, 3 * sizes.OneInch); + resize(4 * sizes.OneInch, 3 * sizes.OneInch); } -void QueueManagerDialog::removeSelected () +void QueueManagerDialog::removeSelected() { - auto list = Playlist::active_playlist (); - int count = list.n_queued (); + auto list = Playlist::active_playlist(); + int count = list.n_queued(); - for (int i = 0; i < count; ) + for (int i = 0; i < count;) { - int entry = list.queue_get_entry (i); + int entry = list.queue_get_entry(i); - if (list.entry_selected (entry)) + if (list.entry_selected(entry)) { - list.queue_remove (i); - list.select_entry (entry, false); - count --; + list.queue_remove(i); + list.select_entry(entry, false); + count--; } else - i ++; + i++; } } static QueueManagerDialog * s_queuemgr = nullptr; -EXPORT void queue_manager_show () +EXPORT void queue_manager_show() { - if (! s_queuemgr) + if (!s_queuemgr) { s_queuemgr = new QueueManagerDialog; - s_queuemgr->setAttribute (Qt::WA_DeleteOnClose); + s_queuemgr->setAttribute(Qt::WA_DeleteOnClose); - QObject::connect (s_queuemgr, & QObject::destroyed, [] () { - s_queuemgr = nullptr; - }); + QObject::connect(s_queuemgr, &QObject::destroyed, + []() { s_queuemgr = nullptr; }); } - window_bring_to_front (s_queuemgr); + window_bring_to_front(s_queuemgr); } -EXPORT void queue_manager_hide () -{ - delete s_queuemgr; -} +EXPORT void queue_manager_hide() { delete s_queuemgr; } } // namespace audqt diff --git a/src/libaudqt/treeview.cc b/src/libaudqt/treeview.cc new file mode 100644 index 0000000..4e8bfaf --- /dev/null +++ b/src/libaudqt/treeview.cc @@ -0,0 +1,77 @@ +/* + * treeview.cc + * Copyright 2018 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 "treeview.h" + +#include +#include +#include + +namespace audqt +{ + +EXPORT TreeView::TreeView(QWidget * parent) : QTreeView(parent) +{ + // activate() is perhaps a bit redundant with activated() + connect(this, &QTreeView::activated, this, &TreeView::activate); +} + +EXPORT TreeView::~TreeView() {} + +EXPORT void TreeView::keyPressEvent(QKeyEvent * event) +{ + auto CtrlShiftAlt = + Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier; + if (event->key() == Qt::Key_Delete && !(event->modifiers() & CtrlShiftAlt)) + { + removeSelectedRows(); + return; + } + + QTreeView::keyPressEvent(event); +} + +EXPORT void TreeView::removeSelectedRows() +{ + // get all selected rows + Index rows; + for (auto & idx : selectionModel()->selectedRows()) + rows.append(idx.row()); + + // sort in reverse order + rows.sort([](const int & a, const int & b) { return b - a; }); + + // remove rows in reverse order + auto m = model(); + for (int row : rows) + m->removeRow(row); +} + +// TODO: unnecessary, remove at next API break +EXPORT void TreeView::mouseDoubleClickEvent(QMouseEvent * event) +{ + QTreeView::mouseDoubleClickEvent(event); +} + +EXPORT void TreeView::activate(const QModelIndex & index) +{ + (void)index; // base implementation does nothing +} + +} // namespace audqt diff --git a/src/libaudqt/treeview.h b/src/libaudqt/treeview.h new file mode 100644 index 0000000..565af04 --- /dev/null +++ b/src/libaudqt/treeview.h @@ -0,0 +1,49 @@ +/* + * treeview.h + * Copyright 2018 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 LIBAUDQT_TREEVIEW_H +#define LIBAUDQT_TREEVIEW_H + +#include +#include + +namespace audqt +{ + +// This class extends QTreeView and adds a couple of features: +// - An "activate" event (double click or Enter key) +// - A method to remove all selected rows (Delete key) +class LIBAUDQT_PUBLIC TreeView : public QTreeView +{ +public: + TreeView(QWidget * parent = nullptr); + ~TreeView() override; + + void removeSelectedRows(); + +protected: + void keyPressEvent(QKeyEvent * event) override; + void mouseDoubleClickEvent(QMouseEvent * event) override; + + virtual void activate(const QModelIndex & index); +}; + +} // namespace audqt + +#endif // LIBAUDQT_TREEVIEW_H diff --git a/src/libaudqt/url-opener-qt.cc b/src/libaudqt/url-opener-qt.cc index b5bcebf..2ea837a 100644 --- a/src/libaudqt/url-opener-qt.cc +++ b/src/libaudqt/url-opener-qt.cc @@ -31,16 +31,15 @@ #include "libaudqt.h" -namespace audqt { +namespace audqt +{ -static QDialog * buildUrlDialog (bool open) +static QDialog * buildUrlDialog(bool open) { static const PreferencesWidget widgets[] = { - WidgetCheck (N_("_Save to history"), - WidgetBool (0, "save_url_history")) - }; + WidgetCheck(N_("_Save to history"), WidgetBool(0, "save_url_history"))}; - const char * title, * verb, * icon; + const char *title, *verb, *icon; if (open) { @@ -56,89 +55,91 @@ static QDialog * buildUrlDialog (bool open) } auto dialog = new QDialog; - dialog->setWindowTitle (title); - dialog->setContentsMargins (margins.EightPt); + dialog->setWindowTitle(title); + dialog->setContentsMargins(margins.EightPt); - auto label = new QLabel (_("Enter URL:"), dialog); + auto label = new QLabel(_("Enter URL:"), dialog); - auto combobox = new QComboBox (dialog); - combobox->setEditable (true); - combobox->setMinimumContentsLength (50); + auto combobox = new QComboBox(dialog); + combobox->setEditable(true); + combobox->setMinimumContentsLength(50); - auto clear_button = new QPushButton (translate_str (N_("C_lear history")), dialog); - clear_button->setIcon (audqt::get_icon ("edit-clear")); + auto clear_button = + new QPushButton(translate_str(N_("C_lear history")), dialog); + clear_button->setIcon(audqt::get_icon("edit-clear")); - auto hbox = make_hbox (nullptr); - prefs_populate (hbox, widgets, PACKAGE); - hbox->addStretch (1); - hbox->addWidget (clear_button); + auto hbox = make_hbox(nullptr); + prefs_populate(hbox, widgets, PACKAGE); + hbox->addStretch(1); + hbox->addWidget(clear_button); - auto button1 = new QPushButton (translate_str (verb), dialog); - button1->setIcon (audqt::get_icon (icon)); + auto button1 = new QPushButton(translate_str(verb), dialog); + button1->setIcon(audqt::get_icon(icon)); - auto button2 = new QPushButton (translate_str (N_("_Cancel")), dialog); - button2->setIcon (audqt::get_icon ("process-stop")); + auto button2 = new QPushButton(translate_str(N_("_Cancel")), dialog); + button2->setIcon(audqt::get_icon("process-stop")); - auto buttonbox = new QDialogButtonBox (dialog); - buttonbox->addButton (button1, QDialogButtonBox::AcceptRole); - buttonbox->addButton (button2, QDialogButtonBox::RejectRole); + auto buttonbox = new QDialogButtonBox(dialog); + buttonbox->addButton(button1, QDialogButtonBox::AcceptRole); + buttonbox->addButton(button2, QDialogButtonBox::RejectRole); - auto layout = make_vbox (dialog); - layout->addWidget (label); - layout->addWidget (combobox); - layout->addLayout (hbox); - layout->addStretch (1); - layout->addWidget (buttonbox); + auto layout = make_vbox(dialog); + layout->addWidget(label); + layout->addWidget(combobox); + layout->addLayout(hbox); + layout->addStretch(1); + layout->addWidget(buttonbox); - for (int i = 0;; i ++) + for (int i = 0;; i++) { - String item = aud_history_get (i); - if (! item) + String item = aud_history_get(i); + if (!item) break; - combobox->addItem (QString (item)); + combobox->addItem(QString(item)); } - combobox->setCurrentIndex (-1); + combobox->setCurrentIndex(-1); - QObject::connect (clear_button, & QPushButton::pressed, [combobox] () { - combobox->clear (); - aud_history_clear (); + QObject::connect(clear_button, &QPushButton::pressed, [combobox]() { + combobox->clear(); + aud_history_clear(); }); - QObject::connect (buttonbox, & QDialogButtonBox::rejected, dialog, & QDialog::close); + QObject::connect(buttonbox, &QDialogButtonBox::rejected, dialog, + &QDialog::close); - QObject::connect (buttonbox, & QDialogButtonBox::accepted, [dialog, combobox, open] () { - QByteArray url = combobox->currentText ().toUtf8 (); + QObject::connect(buttonbox, &QDialogButtonBox::accepted, + [dialog, combobox, open]() { + QByteArray url = combobox->currentText().toUtf8(); - if (open) - aud_drct_pl_open (url); - else - aud_drct_pl_add (url, -1); + if (open) + aud_drct_pl_open(url); + else + aud_drct_pl_add(url, -1); - if (aud_get_bool (nullptr, "save_url_history")) - aud_history_add (url); + if (aud_get_bool("save_url_history")) + aud_history_add(url); - dialog->close (); - }); + dialog->close(); + }); return dialog; } static QDialog * s_dialog = nullptr; -EXPORT void urlopener_show (bool open) +EXPORT void urlopener_show(bool open) { - if (! s_dialog) + if (!s_dialog) { - s_dialog = buildUrlDialog (open); - s_dialog->setAttribute (Qt::WA_DeleteOnClose); + s_dialog = buildUrlDialog(open); + s_dialog->setAttribute(Qt::WA_DeleteOnClose); - QObject::connect (s_dialog, & QObject::destroyed, [] () { - s_dialog = nullptr; - }); + QObject::connect(s_dialog, &QObject::destroyed, + []() { s_dialog = nullptr; }); } - window_bring_to_front (s_dialog); + window_bring_to_front(s_dialog); } } // namespace audqt diff --git a/src/libaudqt/util-qt.cc b/src/libaudqt/util-qt.cc index 866f3a4..9cc427a 100644 --- a/src/libaudqt/util-qt.cc +++ b/src/libaudqt/util-qt.cc @@ -17,8 +17,8 @@ * the use of this software. */ -#include "libaudqt.h" #include "libaudqt-internal.h" +#include "libaudqt.h" #include #include @@ -26,24 +26,24 @@ #include #include #include -#include #include +#include #include -namespace audqt { +namespace audqt +{ -PopupWidget::PopupWidget (QWidget * parent) : - QWidget (parent) +PopupWidget::PopupWidget(QWidget * parent) : QWidget(parent) { - qApp->installEventFilter (this); + qApp->installEventFilter(this); } // This event filter mimics QToolTip by hiding the popup widget when // certain events are received by any widget. -bool PopupWidget::eventFilter (QObject *, QEvent * e) +bool PopupWidget::eventFilter(QObject *, QEvent * e) { - switch (e->type ()) + switch (e->type()) { case QEvent::Leave: case QEvent::WindowActivate: @@ -55,7 +55,7 @@ bool PopupWidget::eventFilter (QObject *, QEvent * e) case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::Wheel: - deleteLater (); + deleteLater(); break; default: @@ -65,18 +65,18 @@ bool PopupWidget::eventFilter (QObject *, QEvent * e) return false; } -void PopupWidget::showEvent (QShowEvent *) +void PopupWidget::showEvent(QShowEvent *) { - auto pos = QCursor::pos (); - auto geom = QApplication::primaryScreen ()->geometry (); + auto pos = QCursor::pos(); + auto geom = QApplication::primaryScreen()->geometry(); /* find the screen the cursor is on */ - if (! geom.contains (pos)) + if (!geom.contains(pos)) { - for (auto screen : QApplication::screens ()) + for (auto screen : QApplication::screens()) { - auto geom2 = screen->geometry (); - if (geom2.contains (pos)) + auto geom2 = screen->geometry(); + if (geom2.contains(pos)) { geom = geom2; break; @@ -84,46 +84,42 @@ void PopupWidget::showEvent (QShowEvent *) } } - int x = pos.x (); - int y = pos.y (); - int w = width (); - int h = height (); + int x = pos.x(); + int y = pos.y(); + int w = width(); + int h = height(); /* If we show the popup right under the cursor, the underlying window gets * a leaveEvent and immediately hides the popup again. So, we offset the * popup slightly. */ - if (x + w > geom.x () + geom.width ()) + if (x + w > geom.x() + geom.width()) x -= w + 3; else x += 3; - if (y + h > geom.y () + geom.height ()) + if (y + h > geom.y() + geom.height()) y -= h + 3; else y += 3; - move (x, y); + move(x, y); } -void show_copy_context_menu (QWidget * parent, const QPoint & global_pos, - const QString & text_to_copy) +void show_copy_context_menu(QWidget * parent, const QPoint & global_pos, + const QString & text_to_copy) { - auto menu = new QMenu (parent); - auto action = new QAction (audqt::get_icon ("edit-copy"), N_("Copy"), menu); + auto menu = new QMenu(parent); + auto action = new QAction(audqt::get_icon("edit-copy"), N_("Copy"), menu); - QObject::connect (action, & QAction::triggered, action, [text_to_copy] () { + QObject::connect(action, &QAction::triggered, action, [text_to_copy]() { auto data = new QMimeData; - data->setText (text_to_copy); - QApplication::clipboard ()->setMimeData (data); - }); - - /* delete the menu as soon as it's closed */ - QObject::connect (menu, & QMenu::aboutToHide, [menu] () { - menu->deleteLater (); + data->setText(text_to_copy); + QApplication::clipboard()->setMimeData(data); }); - menu->addAction (action); - menu->popup (global_pos); + menu->addAction(action); + menu->setAttribute(Qt::WA_DeleteOnClose); + menu->popup(global_pos); } } // namespace audqt diff --git a/src/libaudqt/volumebutton.cc b/src/libaudqt/volumebutton.cc index 9455c55..8e6c5d9 100644 --- a/src/libaudqt/volumebutton.cc +++ b/src/libaudqt/volumebutton.cc @@ -1,6 +1,6 @@ /* * volumebutton.cc - * Copyright 2014 William Pitcock + * Copyright 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,142 +28,161 @@ #include #include +#include -namespace audqt { +namespace audqt +{ class VolumeButton : public QToolButton { public: - VolumeButton (QWidget * parent = nullptr); + VolumeButton(QWidget * parent = nullptr); private: - void updateIcon (int val); - void updateVolume (); - void showSlider (); - void setVolume (int val); - QToolButton * newSliderButton (int delta); + void updateDelta(); + void updateIcon(int val); + void updateVolume(); + void showSlider(); + void setVolume(int val); + QToolButton * newSliderButton(int dir); - void wheelEvent (QWheelEvent * e); + void wheelEvent(QWheelEvent * e); QSlider * m_slider; QFrame * m_container; + int m_scroll_delta = 0; + + HookReceiver update_hook{"set volume_delta", this, + &VolumeButton::updateDelta}; }; -VolumeButton::VolumeButton (QWidget * parent) : - QToolButton (parent) +VolumeButton::VolumeButton(QWidget * parent) : QToolButton(parent) { - setFocusPolicy (Qt::NoFocus); + setFocusPolicy(Qt::NoFocus); + + m_container = new QFrame(this, Qt::Popup); + m_container->setFrameShape(QFrame::StyledPanel); - m_container = new QFrame (this, Qt::Popup); - m_container->setFrameShape (QFrame::StyledPanel); + m_slider = new QSlider(Qt::Vertical, this); + m_slider->setMinimumHeight(audqt::sizes.OneInch); + m_slider->setRange(0, 100); - m_slider = new QSlider (Qt::Vertical, this); - m_slider->setMinimumHeight (audqt::sizes.OneInch); - m_slider->setRange (0, 100); - m_slider->setSingleStep (2); - m_slider->setPageStep (20); + updateDelta(); - auto layout = make_vbox (m_container, sizes.TwoPt); - layout->setContentsMargins (margins.TwoPt); + auto layout = make_vbox(m_container, sizes.TwoPt); + layout->setContentsMargins(margins.TwoPt); - layout->addWidget (newSliderButton (5)); - layout->addWidget (m_slider); - layout->addWidget (newSliderButton (-5)); + layout->addWidget(newSliderButton(1)); + layout->addWidget(m_slider); + layout->addWidget(newSliderButton(-1)); - int val = aud_drct_get_volume_main (); - m_slider->setValue (val); - updateIcon (val); + int val = aud_drct_get_volume_main(); + m_slider->setValue(val); + updateIcon(val); - connect (this, & QAbstractButton::clicked, this, & VolumeButton::showSlider); - connect (m_slider, & QAbstractSlider::valueChanged, this, & VolumeButton::setVolume); + connect(this, &QAbstractButton::clicked, this, &VolumeButton::showSlider); + connect(m_slider, &QAbstractSlider::valueChanged, this, + &VolumeButton::setVolume); - auto timer = new Timer (TimerRate::Hz4, this, & VolumeButton::updateVolume); - connect (this, & QObject::destroyed, [timer] () { delete timer; }); + auto timer = new Timer(TimerRate::Hz4, this, + &VolumeButton::updateVolume); + connect(this, &QObject::destroyed, [timer]() { delete timer; }); - timer->start (); + timer->start(); } -void VolumeButton::updateIcon (int val) +void VolumeButton::updateDelta() +{ + int delta = aud_get_int("volume_delta"); + m_slider->setSingleStep(delta); + m_slider->setPageStep(delta); +} + +void VolumeButton::updateIcon(int val) { if (val == 0) - setIcon (audqt::get_icon ("audio-volume-muted")); + setIcon(audqt::get_icon("audio-volume-muted")); else if (val < 34) - setIcon (audqt::get_icon ("audio-volume-low")); + setIcon(audqt::get_icon("audio-volume-low")); else if (val < 67) - setIcon (audqt::get_icon ("audio-volume-medium")); + setIcon(audqt::get_icon("audio-volume-medium")); else - setIcon (audqt::get_icon ("audio-volume-high")); + setIcon(audqt::get_icon("audio-volume-high")); - setToolTip (QString ("%1 %").arg (val)); + setToolTip(QString("%1 %").arg(val)); } -void VolumeButton::updateVolume () +void VolumeButton::updateVolume() { - if (m_slider->isSliderDown ()) + if (m_slider->isSliderDown()) return; - int val = aud_drct_get_volume_main (); - if (val != m_slider->value ()) + int val = aud_drct_get_volume_main(); + if (val != m_slider->value()) { - disconnect (m_slider, nullptr, this, nullptr); - m_slider->setValue (val); - updateIcon (val); - connect (m_slider, & QAbstractSlider::valueChanged, this, & VolumeButton::setVolume); + disconnect(m_slider, nullptr, this, nullptr); + m_slider->setValue(val); + updateIcon(val); + connect(m_slider, &QAbstractSlider::valueChanged, this, + &VolumeButton::setVolume); } } -void VolumeButton::showSlider () +void VolumeButton::showSlider() { - QSize button_size = sizeHint (); - QSize container_size = m_container->sizeHint (); + QSize button_size = sizeHint(); + QSize container_size = m_container->sizeHint(); - int dx = container_size.width () / 2 - button_size.width () / 2; - int dy = container_size.height () / 2 - button_size.height () / 2; + int dx = container_size.width() / 2 - button_size.width() / 2; + int dy = container_size.height() / 2 - button_size.height() / 2; - QPoint pos = mapToGlobal (QPoint (0, 0)); - pos -= QPoint (dx, dy); + QPoint pos = mapToGlobal(QPoint(0, 0)); + pos -= QPoint(dx, dy); pos.setX(qMax(pos.x(), 0)); pos.setY(qMax(pos.y(), 0)); - m_container->move (pos); - window_bring_to_front (m_container); + m_container->move(pos); + window_bring_to_front(m_container); } -void VolumeButton::setVolume (int val) +void VolumeButton::setVolume(int val) { - aud_drct_set_volume_main (val); - updateIcon (val); + aud_drct_set_volume_main(val); + updateIcon(val); } -QToolButton * VolumeButton::newSliderButton (int delta) +QToolButton * VolumeButton::newSliderButton(int dir) { - auto button = new QToolButton (this); - button->setText (delta < 0 ? "-" : "+"); - button->setAutoRaise (true); - button->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Preferred); - - connect (button, & QAbstractButton::clicked, [this, delta] () { - int val = aud_drct_get_volume_main (); - m_slider->setValue (val + delta); + auto button = new QToolButton(this); + button->setText(dir < 0 ? "-" : "+"); + button->setAutoRaise(true); + button->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + + connect(button, &QAbstractButton::clicked, [this, dir]() { + m_slider->setValue(m_slider->value() + + dir * aud_get_int("volume_delta")); }); return button; } -void VolumeButton::wheelEvent (QWheelEvent * e) +void VolumeButton::wheelEvent(QWheelEvent * e) { - int val = m_slider->value (); - int y = e->angleDelta ().y (); + m_scroll_delta += e->angleDelta().y(); - if (y < 0) - m_slider->setValue (-- val); - else - m_slider->setValue (++ val); + /* we want discrete steps here */ + int steps = m_scroll_delta / 120; + if (steps != 0) + { + m_scroll_delta -= 120 * steps; + m_slider->setValue(m_slider->value() + + steps * aud_get_int("volume_delta")); + } } -EXPORT QToolButton * volume_button_new (QWidget * parent) +EXPORT QToolButton * volume_button_new(QWidget * parent) { - return new VolumeButton (parent); + return new VolumeButton(parent); } } // namespace audqt diff --git a/src/libaudtag/Makefile b/src/libaudtag/Makefile index 961b768..e11d814 100644 --- a/src/libaudtag/Makefile +++ b/src/libaudtag/Makefile @@ -24,6 +24,8 @@ CPPFLAGS := -I.. -I../.. \ CFLAGS += ${LIB_CFLAGS} -LIBS := -L../libaudcore -laudcore \ +LIB_LDFLAGS := -L../libaudcore $(LIB_LDFLAGS) + +LIBS := -laudcore \ ${LIBS} \ ${GLIB_LIBS} diff --git a/src/libaudtag/ape/ape.cc b/src/libaudtag/ape/ape.cc index 5188aa8..fa93f27 100644 --- a/src/libaudtag/ape/ape.cc +++ b/src/libaudtag/ape/ape.cc @@ -246,19 +246,19 @@ bool APETagModule::read_tag (VFSFile & handle, Tuple & tuple, Index * imag for (const ValuePair & pair : list) { - if (! strcmp (pair.key, "Artist")) + if (! strcmp_nocase (pair.key, "Artist")) tuple.set_str (Tuple::Artist, pair.value); - else if (! strcmp (pair.key, "Title")) + else if (! strcmp_nocase (pair.key, "Title")) tuple.set_str (Tuple::Title, pair.value); - else if (! strcmp (pair.key, "Album")) + else if (! strcmp_nocase (pair.key, "Album")) tuple.set_str (Tuple::Album, pair.value); - else if (! strcmp (pair.key, "Comment")) + else if (! strcmp_nocase (pair.key, "Comment")) tuple.set_str (Tuple::Comment, pair.value); - else if (! strcmp (pair.key, "Genre")) + else if (! strcmp_nocase (pair.key, "Genre")) tuple.set_str (Tuple::Genre, pair.value); - else if (! strcmp (pair.key, "Track")) + else if (! strcmp_nocase (pair.key, "Track")) tuple.set_int (Tuple::Track, atoi (pair.value)); - else if (! strcmp (pair.key, "Year")) + else if (! strcmp_nocase (pair.key, "Year")) tuple.set_int (Tuple::Year, atoi (pair.value)); else if (! strcmp_nocase (pair.key, "REPLAYGAIN_TRACK_GAIN")) tuple.set_gain (Tuple::TrackGain, Tuple::GainDivisor, pair.value); @@ -387,10 +387,10 @@ bool APETagModule::write_tag (VFSFile & handle, const Tuple & tuple) for (const ValuePair & pair : list) { - if (! strcmp (pair.key, "Artist") || ! strcmp (pair.key, "Title") || - ! strcmp (pair.key, "Album") || ! strcmp (pair.key, "Comment") || - ! strcmp (pair.key, "Genre") || ! strcmp (pair.key, "Track") || - ! strcmp (pair.key, "Year")) + if (! strcmp_nocase (pair.key, "Artist") || ! strcmp_nocase (pair.key, "Title") || + ! strcmp_nocase (pair.key, "Album") || ! strcmp_nocase (pair.key, "Comment") || + ! strcmp_nocase (pair.key, "Genre") || ! strcmp_nocase (pair.key, "Track") || + ! strcmp_nocase (pair.key, "Year")) continue; if (! ape_write_item (handle, pair.key, pair.value, & length)) diff --git a/src/libaudtag/builtin.h b/src/libaudtag/builtin.h index 1426def..bd5edd9 100644 --- a/src/libaudtag/builtin.h +++ b/src/libaudtag/builtin.h @@ -1,6 +1,6 @@ /* * builtin.h - * Copyright (c) 2014 William Pitcock + * Copyright (c) 2014 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/libaudtag/id3/id3v22.cc b/src/libaudtag/id3/id3v22.cc index b435faa..f850cfa 100644 --- a/src/libaudtag/id3/id3v22.cc +++ b/src/libaudtag/id3/id3v22.cc @@ -1,7 +1,7 @@ /* * id3v22.c * Copyright 2009-2014 Paula Stanciu, Tony Vroon, John Lindgren, - * and William Pitcock + * and Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/libaudtag/id3/id3v24.cc b/src/libaudtag/id3/id3v24.cc index f8ab6e9..2dda167 100644 --- a/src/libaudtag/id3/id3v24.cc +++ b/src/libaudtag/id3/id3v24.cc @@ -642,6 +642,8 @@ bool ID3v24TagModule::write_tag (VFSFile & f, const Tuple & tuple) if (read_header (f, & version, & syncsafe, & offset, & header_size, & data_size, & footer_size)) read_all_frames (read_tag_data (f, data_size, syncsafe), version, dict); + else + offset = header_size = data_size = footer_size = 0; //make the new frames from tuple and replace in the dictionary the old frames with the new ones add_frameFromTupleStr (tuple, Tuple::Title, ID3_TITLE, dict); diff --git a/src/libaudtag/meson.build b/src/libaudtag/meson.build new file mode 100644 index 0000000..c766bdb --- /dev/null +++ b/src/libaudtag/meson.build @@ -0,0 +1,27 @@ +libaudtag_sources = [ + 'audtag.cc', + 'util.cc', + 'tag_module.cc', + 'id3/id3-common.cc', + 'id3/id3v1.cc', + 'id3/id3v22.cc', + 'id3/id3v24.cc', + 'ape/ape.cc' +] + + +libaudtag_inc = include_directories('.') + + +install_headers('audtag.h', subdir: 'audacious') + + +libaudtag_lib = library('audtag', + libaudtag_sources, + include_directories: src_inc, + dependencies: [glib_dep], + link_with: libaudcore_lib, + version: '3.0.0', + soversion: 3, + install: true +) diff --git a/src/libguess/meson.build b/src/libguess/meson.build new file mode 100644 index 0000000..629341f --- /dev/null +++ b/src/libguess/meson.build @@ -0,0 +1,15 @@ +libguess_sources = [ + 'dfa.c', + 'guess.c', + 'guess_impl.c' +] + + +libguess_lib = static_library('guess', + libguess_sources, + c_args: ['-DLIBGUESS_CORE'], + pic: true +) + + +libguess_inc = include_directories('.') diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..d6f738d --- /dev/null +++ b/src/meson.build @@ -0,0 +1,36 @@ +src_inc = include_directories('.') + + +config_h = configure_file(input: 'config.h.meson', + output: 'config.h', + configuration: conf) + + +config_h_full_path = join_paths(meson.current_build_dir(), 'config.h') + + +if cc.get_id() == 'gcc' or cc.get_id() == 'clang' + add_project_arguments('-include', config_h_full_path, language: 'c') + add_project_arguments('-include', config_h_full_path, language: 'cpp') +else + error('Please implement -include handling for your chosen compiler.') +endif + + +subdir('libguess') +subdir('libaudcore') +subdir('libaudtag') + + +if get_option('qt') + subdir('libaudqt') +endif + + +if get_option('dbus') + subdir('dbus') + subdir('audtool') +endif + + +subdir('audacious') diff --git a/win32/merge.sh b/win32/merge.sh index fb82214..797d5e9 100644 --- a/win32/merge.sh +++ b/win32/merge.sh @@ -10,6 +10,8 @@ for i in `find -type f` ; do cp /C/audacious/win32/override/$i $i elif test -f /C/msys32/mingw32/$i ; then cp /C/msys32/mingw32/$i $i + elif test -f /C/Qt/5.12.5/mingw73_32/$i ; then + cp /C/Qt/5.12.5/mingw73_32/$i $i elif test -f /C/GTK/$i ; then cp /C/GTK/$i $i elif test -f /C/libs/$i ; then diff --git a/win32/notes.html b/win32/notes.html old mode 100644 new mode 100755 index ef5ef61..ed25426 --- a/win32/notes.html +++ b/win32/notes.html @@ -24,7 +24,7 @@ April 13, 2017

Edit C:\msys32\home\<user>\.bashrc and add the following lines:

export PATH="$PATH:/C/cmake/bin:/C/GTK/bin:/C/libs/bin:/C/aud/bin"
-export PKG_CONFIG_PATH=/C/GTK/lib/pkgconfig:/C/libs/lib/pkgconfig:/C/aud/lib/pkgconfig
+export PKG_CONFIG_PATH=/C/Qt/5.12.5/mingw73_32/lib/pkgconfig:/C/GTK/lib/pkgconfig:/C/libs/lib/pkgconfig:/C/aud/lib/pkgconfig
export C_INCLUDE_PATH=/C/GTK/include:/C/libs/include
export CPLUS_INCLUDE_PATH=/C/GTK/include:/C/libs/include
export LIBRARY_PATH=/C/GTK/lib:/C/libs/lib

@@ -42,6 +42,17 @@ pacman -S autoconf automake bison gperf libtool mingw-w64-i686-gcc mingw-w64-i68

Install to C:\cmake.

+

Install Qt (for Qt builds)

+ +

Download and run (choose another mirror if desired):
+ +http://qt.mirror.constant.com/archive/online_installers/3.1/qt-unified-windows-x86-3.1.1-online.exe

+ +

Choose the following install options:
+

  • Skip the Qt account login page
  • +
  • Use the default installation path (C:\Qt)
  • +
  • Install Qt 5.12.5 for MinGW 7.3.0 32-bit

+

Install libpng

Download and unzip to C:\libpng:
@@ -174,7 +185,7 @@ make install

In the MinGW shell:

cd /C/gdk-pixbuf
-./configure --prefix=/C/GTK --enable-relocations --without-gdiplus --without-libtiff --with-included-loaders=jpeg,png
+./configure --prefix=/C/GTK --enable-relocations --without-gdiplus --without-libtiff --with-included-loaders=bmp,jpeg,png
make
make install

@@ -224,7 +235,8 @@ make install

Apply the patch gdkwindow-win32.c.diff to C:\gtksrc\gdk\win32\gdkwindow-win32.c.
Apply the patch gtkicontheme.c.diff to C:\gtksrc\gtk\gtkicontheme.c.
-Apply the patch gtkmain.c.diff to C:\gtksrc\gtk\gtkmain.c.

+Apply the patch gtkmain.c.diff to C:\gtksrc\gtk\gtkmain.c.
+Apply the recursive patch gtk-parentheses.diff.

In the MinGW shell:

cd /C/gtksrc
@@ -273,8 +285,8 @@ for GNOME Icon Theme to install successfully.

Install libxml

Download and unzip to C:\libxml:
- -ftp://xmlsoft.org/libxml2/libxml2-2.9.4.tar.gz

+ +ftp://xmlsoft.org/libxml2/libxml2-2.9.9.tar.gz

In the MinGW shell:

cd /C/libxml
@@ -285,8 +297,8 @@ make install

Install mpg123

Download and unzip to C:\mpg123:
- -http://mpg123.de/download/mpg123-1.25.0.tar.bz2

+ +http://mpg123.de/download/mpg123-1.25.13.tar.bz2

In the MinGW shell:

cd /C/mpg123
@@ -297,16 +309,13 @@ make install

Install libfaad

Download and unzip to C:\libfaad:
- -http://sourceforge.net/projects/faac/files/faad2-src/faad2-2.7/faad2-2.7.tar.bz2/download

+ +https://sourceforge.net/projects/faac/files/faad2-src/faad2-2.8.0/faad2-2.8.8.tar.gz/download

-

Apply the patch libfaad-makefile.am.diff to C:\libfaad\libfaad\Makefile.am.
-Apply the patch libfaad-main.c.diff to C:\libfaad\frontend\main.c.

+

Apply the patch libfaad-decoder.c.diff to C:\libfaad\decoder.c.

In the MinGW shell:

cd /C/libfaad
-cp /C/msys32/usr/share/libtool/build-aux/ltmain.sh .
-autoreconf
./configure --prefix=/C/libs
make
make install

@@ -329,12 +338,8 @@ make install

http://sourceforge.net/projects/bs2b/files/libbs2b/3.1.0/libbs2b-3.1.0.tar.bz2/download

-

Apply the patch libbs2b-makefile.am.diff to C:\libs2b\src\Makefile.am.

-

In the MinGW shell:

cd /C/libbs2b
-cp /C/msys32/usr/share/libtool/build-aux/ltmain.sh build-aux
-autoreconf
./configure --prefix=/C/libs
make
make install

@@ -342,14 +347,20 @@ make install

Install libcdio

Download and unzip to C:\libcdio:
- -http://ftp.gnu.org/gnu/libcdio/libcdio-0.83.tar.gz

+ +http://ftp.gnu.org/gnu/libcdio/libcdio-2.1.0.tar.bz2

-

Apply the recursive patch libcdio-0.83.diff.

+

Download and unzip to C:\libcdio-paranoia:
+ +http://ftp.gnu.org/gnu/libcdio/libcdio-paranoia-10.2+2.0.0.tar.bz2

In the MinGW shell:

cd /C/libcdio
-./configure --prefix=/C/libs --disable-rock
+./configure --prefix=/C/libs
+make
+make install
+cd /C/libcdio-paranoia
+./configure --prefix=/C/libs
make
make install

@@ -370,38 +381,34 @@ make install

Install libcue

Download and unzip to C:\libcue:
- -https://github.com/lipnitsk/libcue/archive/v2.1.0.tar.gz

- -

Apply the recursive patch libcue-install-dll.diff.

+ +https://github.com/lipnitsk/libcue/archive/v2.2.1.tar.gz

In the MinGW shell:

cd /C/libcue
-cmake -DCMAKE_INSTALL_PREFIX=/C/libs -G"MSYS Makefiles"
+cmake -DCMAKE_INSTALL_PREFIX=/C/libs -DBUILD_SHARED_LIBS=1 -G"MSYS Makefiles"
make
make install

Install LAME

Download and unzip to C:\lame:
- -http://sourceforge.net/projects/lame/files/lame/3.99/lame-3.99.5.tar.gz/download

+ +https://sourceforge.net/projects/lame/files/lame/3.100/lame-3.100.tar.gz/download

-

Apply the recursive patch lame-3.99.diff.

+

Apply the patch libmp3lame.sym.diff to C:\lame\include\libmp3lame.sym.

In the MinGW shell:

cd /C/lame
-cp /C/msys32/usr/share/libtool/build-aux/ltmain.sh .
-autoreconf
-./configure --prefix=/C/libs
+./configure --prefix=/C/libs --disable-frontend
make
make install

Install libflac

Download and unzip to C:\libflac:
- -http://downloads.xiph.org/releases/flac/flac-1.3.2.tar.xzz

+ +https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.3.tar.xz

In the MinGW shell:

cd /C/libflac
@@ -412,8 +419,8 @@ make install

Install libogg

Download and unzip to C:\libogg:
- -http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz

+ +https://ftp.osuosl.org/pub/xiph/releases/ogg/libogg-1.3.4.tar.xz

In the MinGW shell:

cd /C/libogg
@@ -424,8 +431,8 @@ make install

Install libvorbis

Download and unzip to C:\libvorbis:
- -http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz

+ +https://ftp.osuosl.org/pub/xiph/releases/vorbis/libvorbis-1.3.6.tar.xz

In the MinGW shell:

cd /C/libvorbis
@@ -443,7 +450,7 @@ make install

In the MinGW shell:

cd /C/libneon
-./autogen.sh +./autogen.sh
./configure --prefix=/C/libs --enable-shared
make
make install

@@ -479,8 +486,8 @@ make install

Install FFmpeg

Download and unzip to C:\ffmpeg:
- -http://ffmpeg.org/releases/ffmpeg-3.3.tar.xz

+ +http://ffmpeg.org/releases/ffmpeg-4.2.1.tar.xz

In the MinGW shell:

cd /C/ffmpeg
@@ -507,8 +514,8 @@ make install

Install libbinio

Download and unzip to C:\libbinio:
- -https://sourceforge.net/projects/libbinio/files/libbinio/1.4/libbinio-1.4.tar.bz2/download

+ +https://github.com/adplug/libbinio/releases/download/libbinio-1.5/libbinio-1.5.tar.bz2

In the MinGW shell:

cd /C/libbinio
@@ -519,8 +526,8 @@ make install

Install adplug

Download and unzip to C:\adplug:
- -https://github.com/adplug/adplug/releases/download/adplug-2.3/adplug-2.3.tar.bz2

+ +https://github.com/adplug/adplug/releases/download/adplug-2.3.1/adplug-2.3.1.tar.bz2

In the MinGW shell:

cd /C/adplug
@@ -543,8 +550,8 @@ make install

Install libsidplayfp

Download and unzip to C:\libsidplayfp:
- -https://sourceforge.net/projects/sidplay-residfp/files/libsidplayfp/1.8/libsidplayfp-1.8.7.tar.gz/download

+ +https://sourceforge.net/projects/sidplay-residfp/files/libsidplayfp/2.0/libsidplayfp-2.0.1.tar.gz/download

In the MinGW shell:

cd /C/libsidplayfp
diff --git a/win32/patches/gtk-parentheses.diff b/win32/patches/gtk-parentheses.diff new file mode 100644 index 0000000..c473d7c --- /dev/null +++ b/win32/patches/gtk-parentheses.diff @@ -0,0 +1,67 @@ +From 889a63dffc72c048502d0f7d2b26bfc8532462eb Mon Sep 17 00:00:00 2001 +From: John Lindgren +Date: Tue, 15 May 2018 21:47:12 -0400 +Subject: [PATCH] Fix compiler warnings with GCC 8.1. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +GCC 8.1 added some new warnings, including warning about parentheses +with no effect in variable declarations. GTK2 headers have a few of +these, which produce a lot of warnings in projects using GTK2. + +The warnings look like: +/usr/include/gtk-2.0/gtk/gtkfilechooserbutton.h:59:8: warning: +unnecessary parentheses in declaration of ‘__gtk_reserved1’ [-Wparentheses] + void (*__gtk_reserved1); + ^ + +Removing the parentheses is harmless and fixes the warnings. +--- + gtk/gtkfilechooserbutton.h | 14 +++++++------- + gtk/gtkstatusicon.h | 4 ++-- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/gtk/gtkfilechooserbutton.h b/gtk/gtkfilechooserbutton.h +index b3d9112cf9..fdacc4b6ec 100644 +--- a/gtk/gtkfilechooserbutton.h ++++ b/gtk/gtkfilechooserbutton.h +@@ -56,13 +56,13 @@ struct _GtkFileChooserButtonClass + + void (* file_set) (GtkFileChooserButton *fc); + +- void (*__gtk_reserved1); +- void (*__gtk_reserved2); +- void (*__gtk_reserved3); +- void (*__gtk_reserved4); +- void (*__gtk_reserved5); +- void (*__gtk_reserved6); +- void (*__gtk_reserved7); ++ void *__gtk_reserved1; ++ void *__gtk_reserved2; ++ void *__gtk_reserved3; ++ void *__gtk_reserved4; ++ void *__gtk_reserved5; ++ void *__gtk_reserved6; ++ void *__gtk_reserved7; + }; + + +diff --git a/gtk/gtkstatusicon.h b/gtk/gtkstatusicon.h +index 19dbd1cdeb..c45caca5ae 100644 +--- a/gtk/gtkstatusicon.h ++++ b/gtk/gtkstatusicon.h +@@ -73,8 +73,8 @@ struct _GtkStatusIconClass + gboolean keyboard_mode, + GtkTooltip *tooltip); + +- void (*__gtk_reserved1); +- void (*__gtk_reserved2); ++ void *__gtk_reserved1; ++ void *__gtk_reserved2; + }; + + GType gtk_status_icon_get_type (void) G_GNUC_CONST; +-- +2.22.0 + diff --git a/win32/patches/lame-3.99.diff b/win32/patches/lame-3.99.diff deleted file mode 100644 index fdb974c..0000000 --- a/win32/patches/lame-3.99.diff +++ /dev/null @@ -1,61 +0,0 @@ -diff --git a/configure.in b/configure.in -index 2f8fa66..813d33d 100644 ---- a/configure.in -+++ b/configure.in -@@ -96,7 +96,6 @@ AC_CHECK_HEADERS( \ - sys/soundcard.h \ - sys/time.h \ - unistd.h \ -- xmmintrin.h \ - linux/soundcard.h) - - dnl Checks for typedefs, structures, and compiler characteristics. -@@ -393,8 +392,6 @@ CONFIG_MATH_LIB="${USE_LIBM}" - - dnl configure use of features - --AM_PATH_GTK(1.2.0, HAVE_GTK="yes", HAVE_GTK="no") -- - dnl ElectricFence malloc debugging - AC_MSG_CHECKING(use of ElectricFence malloc debugging) - AC_ARG_ENABLE(efence, -@@ -527,7 +524,7 @@ else - AC_MSG_RESULT(no) - fi - --if test "${HAVE_GTK}" = "no"; then -+if false ; then - if test "x${WITH_MP3X}" = "xmp3x"; then - AC_MSG_WARN(can't build mp3x, no GTK installed) - WITH_MP3X= -@@ -635,7 +632,7 @@ WITH_VECTOR=no - case $host_cpu in - x86_64|amd64) - CPUTYPE="no" -- if test $ac_cv_header_xmmintrin_h = yes ; then -+ if false ; then - WITH_XMM=yes - WITH_VECTOR=yes - fi -@@ -646,7 +643,7 @@ h precission) - ;; - *86) - CPUTYPE="i386" -- if test $ac_cv_header_xmmintrin_h = yes ; then -+ if false ; then - WITH_XMM=yes - WITH_VECTOR=yes - fi -diff --git a/frontend/Makefile.am b/frontend/Makefile.am -index a35cb17..3cf2d8f 100644 ---- a/frontend/Makefile.am -+++ b/frontend/Makefile.am -@@ -35,7 +35,7 @@ lame_SOURCES = lame_main.c $(common_sources) - mp3rtp_SOURCES = mp3rtp.c rtp.c $(common_sources) - mp3x_SOURCES = mp3x.c gtkanal.c gpkplotting.c $(common_sources) - --CFLAGS = @CFLAGS@ @GTK_CFLAGS@ @FRONTEND_CFLAGS@ @SNDFILE_CFLAGS@ -+CFLAGS = @CFLAGS@ @FRONTEND_CFLAGS@ @SNDFILE_CFLAGS@ - LDFLAGS = @LDFLAGS@ @FRONTEND_LDFLAGS@ @SNDFILE_LIBS@ - - INCLUDES = -I$(top_srcdir)/libmp3lame -I$(top_srcdir)/include -I$(top_builddir) diff --git a/win32/patches/libbs2b-makefile.am.diff b/win32/patches/libbs2b-makefile.am.diff deleted file mode 100644 index 8292c29..0000000 --- a/win32/patches/libbs2b-makefile.am.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- Makefile.am.0 2009-03-20 10:13:53 -0400 -+++ Makefile.am 2013-09-13 21:12:22 -0400 -@@ -18,7 +18,7 @@ - $(bs2b_HEADERS) - - libbs2b_la_LDFLAGS = \ -- -lm -version-info 0:0:0 -+ -lm -version-info 0:0:0 -no-undefined - - libbs2b_la_SOURCES = \ - bs2b.c \ diff --git a/win32/patches/libcdio-0.83.diff b/win32/patches/libcdio-0.83.diff deleted file mode 100644 index 66516a6..0000000 --- a/win32/patches/libcdio-0.83.diff +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/lib/driver/MSWindows/win32_ioctl.c b/lib/driver/MSWindows/win32_ioctl.c -index 02d1576..ca62915 100644 ---- a/lib/driver/MSWindows/win32_ioctl.c -+++ b/lib/driver/MSWindows/win32_ioctl.c -@@ -30,9 +30,9 @@ - # include "NtScsi.h" - # include "undocumented.h" - #else --# include --# include --# include -+# include -+# include -+# include - #endif - - #ifdef WIN32 -diff --git a/src/util.c b/src/util.c -index 21c83cc..efe9cdb 100644 ---- a/src/util.c -+++ b/src/util.c -@@ -510,6 +510,7 @@ print_fs_attrs(iso9660_stat_t *p_statbuf, bool b_rock, bool b_xa, - (unsigned int) p_statbuf->size ); - } - -+#ifdef HAVE_ROCK - if (yep == p_statbuf->rr.b3_rock && b_rock) { - struct tm tm; - -@@ -531,7 +532,9 @@ print_fs_attrs(iso9660_stat_t *p_statbuf, bool b_rock, bool b_xa, - report(stdout, " -> %s", p_statbuf->rr.psz_symlink); - } - -- } else { -+ } else -+#endif -+ { - strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M:%S ", &p_statbuf->tm); - report (stdout," %s %s", date_str, psz_name_translated); - } diff --git a/win32/patches/libcue-install-dll.diff b/win32/patches/libcue-install-dll.diff deleted file mode 100644 index acf3079..0000000 --- a/win32/patches/libcue-install-dll.diff +++ /dev/null @@ -1,11 +0,0 @@ -diff -ur libcue-2.1.0-orig/CMakeLists.txt libcue-2.1.0-mod/CMakeLists.txt ---- libcue-2.1.0-orig/CMakeLists.txt 2016-04-15 01:31:27 -0400 -+++ libcue-2.1.0-mod/CMakeLists.txt 2016-07-31 15:28:48 -0400 -@@ -44,6 +44,7 @@ - C_VISIBILITY_PRESET hidden) - - INSTALL(TARGETS cue -+ RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) - INSTALL(FILES ${CMAKE_SOURCE_DIR}/libcue.h DESTINATION include) diff --git a/win32/patches/libfaad-decoder.c.diff b/win32/patches/libfaad-decoder.c.diff new file mode 100644 index 0000000..5080a19 --- /dev/null +++ b/win32/patches/libfaad-decoder.c.diff @@ -0,0 +1,13 @@ +--- libfaad/decoder.c.0 2017-12-17 11:17:36.000000000 -0500 ++++ libfaad/decoder.c 2019-10-28 15:29:26.058465600 -0400 +@@ -53,10 +53,6 @@ + uint16_t dbg_count; + #endif + +-#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 +-#include "win32_ver.h" +-#endif +- + /* static function declarations */ + static void* aac_frame_decode(NeAACDecStruct *hDecoder, + NeAACDecFrameInfo *hInfo, diff --git a/win32/patches/libfaad-main.c.diff b/win32/patches/libfaad-main.c.diff deleted file mode 100644 index 1241e34..0000000 --- a/win32/patches/libfaad-main.c.diff +++ /dev/null @@ -1,10 +0,0 @@ ---- main.c.0 2008-09-22 13:55:09 -0400 -+++ main.c 2011-04-01 19:00:33 -0500 -@@ -31,7 +31,6 @@ - #ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #include --#define off_t __int64 - #else - #include - #endif diff --git a/win32/patches/libfaad-makefile.am.diff b/win32/patches/libfaad-makefile.am.diff deleted file mode 100644 index 8512846..0000000 --- a/win32/patches/libfaad-makefile.am.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- Makefile.am.0 2013-09-13 21:02:30 -0400 -+++ Makefile.am 2013-09-13 21:02:44 -0400 -@@ -4,7 +4,7 @@ - include_HEADERS = $(top_srcdir)/include/faad.h \ - $(top_srcdir)/include/neaacdec.h - --libfaad_la_LDFLAGS = -version-info 2:0:0 -+libfaad_la_LDFLAGS = -version-info 2:0:0 -no-undefined - libfaad_la_LIBADD = -lm - - libfaad_la_SOURCES = bits.c cfft.c decoder.c drc.c \ diff --git a/win32/patches/libmp3lame.sym.diff b/win32/patches/libmp3lame.sym.diff new file mode 100644 index 0000000..5c31040 --- /dev/null +++ b/win32/patches/libmp3lame.sym.diff @@ -0,0 +1,8 @@ +--- include/libmp3lame.sym.0 2017-09-06 15:33:35.000000000 -0400 ++++ include/libmp3lame.sym 2019-10-28 16:18:05.949994000 -0400 +@@ -1,5 +1,4 @@ + lame_init +-lame_init_old + lame_set_num_samples + lame_get_num_samples + lame_set_in_samplerate -- cgit v1.2.3