Codebase list audacious-plugins / e8d429b
New upstream version 4.0 Andrej Shadura 4 years ago
263 changed file(s) with 12233 addition(s) and 6446 deletion(s). Raw diff Collapse all Expand all
0 BasedOnStyle: LLVM
1 IndentWidth: 4
2 AccessModifierOffset: -4
3 BreakBeforeBraces: Allman
4 PointerAlignment: Middle
5 SpaceAfterTemplateKeyword: false
6 AlwaysBreakTemplateDeclarations: Yes
0 Ariadne Conill <ariadne@dereferenced.org> <nenolod@dereferenced.org>
1313 - sudo apt-get install libneon27-gnutls-dev libnotify-dev libpulse-dev
1414 - sudo apt-get install libsamplerate0-dev libsdl1.2-dev libsidplayfp-dev
1515 - sudo apt-get install libsndfile1-dev libsoxr-dev libvorbis-dev libwavpack-dev
16 - sudo apt-get install libxml2-dev libadplug-dev
16 - sudo apt-get install libxml2-dev libadplug-dev libqt5opengl5-dev
1717 install:
1818 - git clone git://github.com/audacious-media-player/audacious.git audacious
1919 - cd audacious
2020 - ./autogen.sh
21 - ./configure --prefix=/opt/aud --enable-qt
21 - ./configure --prefix=/opt/aud --enable-gtk
2222 - make
2323 - sudo make install
2424 - cd ..
2525 script:
2626 - export PKG_CONFIG_PATH=/opt/aud/lib/pkgconfig
2727 - ./autogen.sh
28 - ./configure --prefix=/opt/aud --enable-qt
28 - ./configure --prefix=/opt/aud --enable-gtk
2929 - make
0 dnl Backward compatibility with older pkg-config <= 0.28
1 dnl Retrieves the value of the pkg-config variable
2 dnl for the given module.
3 dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
4 dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
5 dnl ====================================================
6 m4_ifndef([PKG_CHECK_VAR], [
7 AC_DEFUN([PKG_CHECK_VAR],
8 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
9 AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
10
11 _PKG_CONFIG([$1], [variable="][$3]["], [$2])
12 AS_VAR_COPY([$1], [pkg_cv_][$1])
13
14 AS_VAR_IF([$1], [""], [$5], [$4])dnl
15 ])
16 ])
17
18
019 dnl Add $1 to CFLAGS and CXXFLAGS if supported
120 dnl ==========================================
221
88107 CXXFLAGS="$CXXFLAGS -std=gnu++11 -ffast-math -Wall -pipe"
89108 fi
90109 AUD_CHECK_CFLAGS(-Wtype-limits)
110 AUD_CHECK_CFLAGS(-Wno-stringop-truncation)
91111 AUD_CHECK_CXXFLAGS(-Woverloaded-virtual)
92112 fi
93113
156176 PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32)
157177 PKG_CHECK_MODULES(GMODULE, gmodule-2.0 >= 2.32)
158178
179 AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_32], [target GLib 2.32])
180
159181 dnl GTK+ support
160182 dnl =============
161183
162184 AC_ARG_ENABLE(gtk,
163 AS_HELP_STRING(--disable-gtk, [Disable GTK+ support (default=enabled)]),
164 USE_GTK=$enableval, USE_GTK=yes)
185 AS_HELP_STRING(--enable-gtk, [Enable GTK+ support (default=disabled)]),
186 USE_GTK=$enableval, USE_GTK=no)
165187
166188 if test $USE_GTK = yes ; then
167189 PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.24)
168 AC_DEFINE(USE_GTK, 1, [Define if GTK+ support enabled])
190 AC_DEFINE([USE_GTK], [1], [Define if GTK+ support enabled])
169191 fi
170192
171193 AC_SUBST(USE_GTK)
189211 dnl ==========
190212
191213 AC_ARG_ENABLE(qt,
192 AS_HELP_STRING(--enable-qt, [Enable Qt support (default=disabled)]),
193 USE_QT=$enableval, USE_QT=no)
214 AS_HELP_STRING(--disable-qt, [Disable Qt support (default=enabled)]),
215 USE_QT=$enableval, USE_QT=yes)
194216
195217 if test $USE_QT = yes ; then
196218 PKG_CHECK_MODULES([QTCORE], [Qt5Core >= 5.2])
219 PKG_CHECK_VAR([QTBINPATH], [Qt5Core >= 5.2], [host_bins])
197220 PKG_CHECK_MODULES([QT], [Qt5Core Qt5Gui Qt5Widgets >= 5.2])
198 AC_DEFINE(USE_QT, 1, [Define if Qt support enabled])
221 AC_DEFINE([USE_QT], [1], [Define if Qt support enabled])
199222
200223 # needed if Qt was built with -reduce-relocations
201224 QTCORE_CFLAGS="$QTCORE_CFLAGS -fPIC"
205228 AC_SUBST(USE_QT)
206229 AC_SUBST(QT_CFLAGS)
207230 AC_SUBST(QT_LIBS)
208
209 ])
231 AC_SUBST(QTBINPATH)
232
233 ])
1818 /* Define if Vorbis output part should be built */
1919 #undef FILEWRITER_VORBIS
2020
21 /* target GLib 2.32 */
22 #undef GLIB_VERSION_MIN_REQUIRED
23
24 /* Define to 1 if you have the <adplug/kemuopl.h> header file. */
25 #undef HAVE_ADPLUG_KEMUOPL_H
26
27 /* Define to 1 if you have the <adplug/nemuopl.h> header file. */
28 #undef HAVE_ADPLUG_NEMUOPL_H
29
30 /* Define to 1 if you have the <adplug/wemuopl.h> header file. */
31 #undef HAVE_ADPLUG_WEMUOPL_H
32
2133 /* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the
2234 CoreFoundation framework. */
2335 #undef HAVE_CFLOCALECOPYCURRENT
36
37 /* Define to 1 if you have the Mac OS X function
38 CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */
39 #undef HAVE_CFLOCALECOPYPREFERREDLANGUAGES
2440
2541 /* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in
2642 the CoreFoundation framework. */
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.69 for audacious-plugins 3.10.1.
2 # Generated by GNU Autoconf 2.69 for audacious-plugins 4.0.
33 #
44 #
55 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
88 # This configure script is free software; the Free Software Foundation
99 # gives unlimited permission to copy, distribute and modify it.
1010 #
11 # Copyright (C) 2001-2018 Audacious developers and others
11 # Copyright (C) 2001-2020 Audacious developers and others
1212 ## -------------------- ##
1313 ## M4sh Initialization. ##
1414 ## -------------------- ##
578578 # Identity of this package.
579579 PACKAGE_NAME='audacious-plugins'
580580 PACKAGE_TARNAME='audacious-plugins'
581 PACKAGE_VERSION='3.10.1'
582 PACKAGE_STRING='audacious-plugins 3.10.1'
581 PACKAGE_VERSION='4.0'
582 PACKAGE_STRING='audacious-plugins 4.0'
583583 PACKAGE_BUGREPORT=''
584584 PACKAGE_URL=''
585585
658658 FFMPEG_CFLAGS
659659 QTOPENGL_LIBS
660660 QTOPENGL_CFLAGS
661 QTNETWORK_LIBS
662 QTNETWORK_CFLAGS
661663 QTMULTIMEDIA_LIBS
662664 QTMULTIMEDIA_CFLAGS
663665 AMPACHE_LIBS
693695 BS2B_CFLAGS
694696 SIDPLAYFP_LIBS
695697 SIDPLAYFP_CFLAGS
698 OPENMPT_LIBS
699 OPENMPT_CFLAGS
696700 MODPLUG_LIBS
697701 MODPLUG_CFLAGS
698702 SNDFILE_LIBS
723727 LIBICONV
724728 INTL_MACOSX_LIBS
725729 XGETTEXT_EXTRA_OPTIONS
730 MSGMERGE_FOR_MSGFMT_OPTION
726731 MSGMERGE
727732 XGETTEXT_015
728733 XGETTEXT
729734 GMSGFMT_015
730 MSGFMT_015
731735 GMSGFMT
732736 MSGFMT
733737 GETTEXT_MACRO_VERSION
753757 USE_QT
754758 QT_LIBS
755759 QT_CFLAGS
760 QTBINPATH
756761 QTCORE_LIBS
757762 QTCORE_CFLAGS
758763 GIO_LIBS
871876 enable_wavpack
872877 enable_sndfile
873878 enable_modplug
879 enable_openmpt
874880 enable_sid
875881 enable_console
876882 enable_bs2b
895901 enable_aosd
896902 enable_ampache
897903 enable_qtaudio
904 enable_streamtuner
898905 enable_qtglspectrum
899906 enable_coreaudio
900907 with_ffmpeg
935942 GIO_LIBS
936943 QTCORE_CFLAGS
937944 QTCORE_LIBS
945 QTBINPATH
938946 QT_CFLAGS
939947 QT_LIBS
940948 AUDACIOUS_CFLAGS
959967 SNDFILE_LIBS
960968 MODPLUG_CFLAGS
961969 MODPLUG_LIBS
970 OPENMPT_CFLAGS
971 OPENMPT_LIBS
962972 SIDPLAYFP_CFLAGS
963973 SIDPLAYFP_LIBS
964974 BS2B_CFLAGS
9911001 AMPACHE_LIBS
9921002 QTMULTIMEDIA_CFLAGS
9931003 QTMULTIMEDIA_LIBS
1004 QTNETWORK_CFLAGS
1005 QTNETWORK_LIBS
9941006 QTOPENGL_CFLAGS
9951007 QTOPENGL_LIBS
9961008 FFMPEG_CFLAGS
15371549 # Omit some internal or obsolete options to make the list less imposing.
15381550 # This message is too long to be a string in the A/UX 3.1 sh.
15391551 cat <<_ACEOF
1540 \`configure' configures audacious-plugins 3.10.1 to adapt to many kinds of systems.
1552 \`configure' configures audacious-plugins 4.0 to adapt to many kinds of systems.
15411553
15421554 Usage: $0 [OPTION]... [VAR=VALUE]...
15431555
16041616
16051617 if test -n "$ac_init_help"; then
16061618 case $ac_init_help in
1607 short | recursive ) echo "Configuration of audacious-plugins 3.10.1:";;
1619 short | recursive ) echo "Configuration of audacious-plugins 4.0:";;
16081620 esac
16091621 cat <<\_ACEOF
16101622
16131625 --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
16141626 --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
16151627 --disable-largefile omit support for large files
1616 --disable-gtk Disable GTK+ support (default=enabled)
1617 --enable-qt Enable Qt support (default=disabled)
1628 --enable-gtk Enable GTK+ support (default=disabled)
1629 --disable-qt Disable Qt support (default=enabled)
16181630 --disable-nls do not use Native Language Support
16191631 --disable-rpath do not hardcode runtime library paths
16201632 --enable-adplug enable AdLib support (default=auto)
16271639 --enable-wavpack enable WavPack support (default=yes)
16281640 --enable-sndfile enable libsndfile decoder (default=auto)
16291641 --enable-modplug enable ModPlug (default=auto)
1642 --enable-openmpt enable libopenmpt (default=auto)
16301643 --enable-sid enable Commodore 64 audio (default=auto)
16311644 --enable-console enable Game Music Emu (default=auto)
16321645 --enable-bs2b enable BS2B effect (default=auto)
16511664 --enable-aosd enable X11 OSD (default=auto)
16521665 --enable-ampache enable Ampache browser (default=auto)
16531666 --enable-qtaudio enable QtMultimedia output (default=auto)
1667 --enable-streamtuner enable Stream tuner (default=auto)
16541668 --enable-qtglspectrum enable Qt OpenGL spectrum analyzer (default=auto)
16551669 --disable-coreaudio disable CoreAudio output plugin (default=enabled)
16561670 --enable-sdlout enable SDL Output (default=auto)
17091723 QTCORE_CFLAGS
17101724 C compiler flags for QTCORE, overriding pkg-config
17111725 QTCORE_LIBS linker flags for QTCORE, overriding pkg-config
1726 QTBINPATH value of host_bins for Qt5Core >= 5.2, overriding pkg-config
17121727 QT_CFLAGS C compiler flags for QT, overriding pkg-config
17131728 QT_LIBS linker flags for QT, overriding pkg-config
17141729 AUDACIOUS_CFLAGS
17481763 C compiler flags for MODPLUG, overriding pkg-config
17491764 MODPLUG_LIBS
17501765 linker flags for MODPLUG, overriding pkg-config
1766 OPENMPT_CFLAGS
1767 C compiler flags for OPENMPT, overriding pkg-config
1768 OPENMPT_LIBS
1769 linker flags for OPENMPT, overriding pkg-config
17511770 SIDPLAYFP_CFLAGS
17521771 C compiler flags for SIDPLAYFP, overriding pkg-config
17531772 SIDPLAYFP_LIBS
17921811 C compiler flags for QTMULTIMEDIA, overriding pkg-config
17931812 QTMULTIMEDIA_LIBS
17941813 linker flags for QTMULTIMEDIA, overriding pkg-config
1814 QTNETWORK_CFLAGS
1815 C compiler flags for QTNETWORK, overriding pkg-config
1816 QTNETWORK_LIBS
1817 linker flags for QTNETWORK, overriding pkg-config
17951818 QTOPENGL_CFLAGS
17961819 C compiler flags for QTOPENGL, overriding pkg-config
17971820 QTOPENGL_LIBS
18681891 test -n "$ac_init_help" && exit $ac_status
18691892 if $ac_init_version; then
18701893 cat <<\_ACEOF
1871 audacious-plugins configure 3.10.1
1894 audacious-plugins configure 4.0
18721895 generated by GNU Autoconf 2.69
18731896
18741897 Copyright (C) 2012 Free Software Foundation, Inc.
18751898 This configure script is free software; the Free Software Foundation
18761899 gives unlimited permission to copy, distribute and modify it.
18771900
1878 Copyright (C) 2001-2018 Audacious developers and others
1901 Copyright (C) 2001-2020 Audacious developers and others
18791902 _ACEOF
18801903 exit
18811904 fi
22662289
22672290 } # ac_fn_c_try_link
22682291
2292 # ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES
2293 # ---------------------------------------------------------
2294 # Tests whether HEADER exists and can be compiled using the include files in
2295 # INCLUDES, setting the cache variable VAR accordingly.
2296 ac_fn_cxx_check_header_compile ()
2297 {
2298 as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
2299 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
2300 $as_echo_n "checking for $2... " >&6; }
2301 if eval \${$3+:} false; then :
2302 $as_echo_n "(cached) " >&6
2303 else
2304 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
2305 /* end confdefs.h. */
2306 $4
2307 #include <$2>
2308 _ACEOF
2309 if ac_fn_cxx_try_compile "$LINENO"; then :
2310 eval "$3=yes"
2311 else
2312 eval "$3=no"
2313 fi
2314 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
2315 fi
2316 eval ac_res=\$$3
2317 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
2318 $as_echo "$ac_res" >&6; }
2319 eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
2320
2321 } # ac_fn_cxx_check_header_compile
2322
22692323 # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
22702324 # -------------------------------------------------------
22712325 # Tests whether HEADER exists, giving a warning if it cannot be compiled using
23562410 This file contains any messages produced by compilers while
23572411 running configure, to aid debugging if configure makes a mistake.
23582412
2359 It was created by audacious-plugins $as_me 3.10.1, which was
2413 It was created by audacious-plugins $as_me 4.0, which was
23602414 generated by GNU Autoconf 2.69. Invocation command line was
23612415
23622416 $ $0 $@
49354989 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
49364990
49374991
4992 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C/C++ compiler supports -Wno-stringop-truncation" >&5
4993 $as_echo_n "checking whether the C/C++ compiler supports -Wno-stringop-truncation... " >&6; }
4994 OLDCFLAGS="$CFLAGS"
4995 CFLAGS="$CFLAGS -Wno-stringop-truncation -Werror"
4996 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
4997 /* end confdefs.h. */
4998
4999 int
5000 main ()
5001 {
5002 return 0;
5003 ;
5004 return 0;
5005 }
5006 _ACEOF
5007 if ac_fn_c_try_compile "$LINENO"; then :
5008
5009 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
5010 $as_echo "yes" >&6; }
5011 CFLAGS="$OLDCFLAGS -Wno-stringop-truncation"
5012 CXXFLAGS="$CXXFLAGS -Wno-stringop-truncation"
5013
5014 else
5015
5016 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
5017 $as_echo "no" >&6; }
5018 CFLAGS="$OLDCFLAGS"
5019
5020 fi
5021 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
5022
5023
49385024 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler supports -Woverloaded-virtual" >&5
49395025 $as_echo_n "checking whether the C++ compiler supports -Woverloaded-virtual... " >&6; }
49405026 ac_ext=cpp
66696755 fi
66706756
66716757
6758 $as_echo "#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32" >>confdefs.h
6759
6760
6761
66726762 # Check whether --enable-gtk was given.
66736763 if test "${enable_gtk+set}" = set; then :
66746764 enableval=$enable_gtk; USE_GTK=$enableval
66756765 else
6676 USE_GTK=yes
6766 USE_GTK=no
66776767 fi
66786768
66796769
69767066 if test "${enable_qt+set}" = set; then :
69777067 enableval=$enable_qt; USE_QT=$enableval
69787068 else
6979 USE_QT=no
7069 USE_QT=yes
69807070 fi
69817071
69827072
70737163
70747164 fi
70757165
7166 if test -n "$QTBINPATH"; then
7167 pkg_cv_QTBINPATH="$QTBINPATH"
7168 elif test -n "$PKG_CONFIG"; then
7169 if test -n "$PKG_CONFIG" && \
7170 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.2\""; } >&5
7171 ($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.2") 2>&5
7172 ac_status=$?
7173 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
7174 test $ac_status = 0; }; then
7175 pkg_cv_QTBINPATH=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.2" 2>/dev/null`
7176 test "x$?" != "x0" && pkg_failed=yes
7177 else
7178 pkg_failed=yes
7179 fi
7180 else
7181 pkg_failed=untried
7182 fi
7183 QTBINPATH=$pkg_cv_QTBINPATH
7184
7185 if test "x$QTBINPATH" = x""; then :
7186
7187 fi
7188
70767189 pkg_failed=no
70777190 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for QT" >&5
70787191 $as_echo_n "checking for QT... " >&6; }
71717284 QTCORE_CFLAGS="$QTCORE_CFLAGS -fPIC"
71727285 QT_CFLAGS="$QT_CFLAGS -fPIC"
71737286 fi
7287
71747288
71757289
71767290
75497663
75507664
75517665
7552 GETTEXT_MACRO_VERSION=0.19
7666 GETTEXT_MACRO_VERSION=0.20
75537667
75547668
75557669
76647778
76657779
76667780
7667 case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
7668 '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;;
7669 *) MSGFMT_015=$MSGFMT ;;
7670 esac
7671
7672 case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
7781 case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
76737782 '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;;
76747783 *) GMSGFMT_015=$GMSGFMT ;;
76757784 esac
78217930 fi
78227931
78237932
7824 test -n "$localedir" || localedir='${datadir}/locale'
7933 if LC_ALL=C $MSGMERGE --help | grep ' --for-msgfmt ' >/dev/null; then
7934 MSGMERGE_FOR_MSGFMT_OPTION='--for-msgfmt'
7935 else
7936 if LC_ALL=C $MSGMERGE --help | grep ' --no-fuzzy-matching ' >/dev/null; then
7937 MSGMERGE_FOR_MSGFMT_OPTION='--no-fuzzy-matching --no-location --quiet'
7938 else
7939 MSGMERGE_FOR_MSGFMT_OPTION='--no-location --quiet'
7940 fi
7941 fi
78257942
78267943
78277944 test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS=
78687985 }
78697986 fi
78707987
7871 ac_prog=ld
7872 if test "$GCC" = yes; then
7873 # Check if gcc -print-prog-name=ld gives a path.
7988 if test -n "$LD"; then
7989 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld" >&5
7990 $as_echo_n "checking for ld... " >&6; }
7991 elif test "$GCC" = yes; then
78747992 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
78757993 $as_echo_n "checking for ld used by $CC... " >&6; }
7876 case $host in
7877 *-*-mingw*)
7878 # gcc leaves a trailing carriage return which upsets mingw
7879 ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
7880 *)
7881 ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
7882 esac
7883 case $ac_prog in
7884 # Accept absolute paths.
7885 [\\/]* | ?:[\\/]*)
7886 re_direlt='/[^/][^/]*/\.\./'
7887 # Canonicalize the pathname of ld
7888 ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'`
7889 while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do
7890 ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
7891 done
7892 test -z "$LD" && LD="$ac_prog"
7893 ;;
7894 "")
7895 # If it fails, then pretend we aren't using GCC.
7896 ac_prog=ld
7897 ;;
7898 *)
7899 # If it is relative, then search for the first ld in PATH.
7900 with_gnu_ld=unknown
7901 ;;
7902 esac
79037994 elif test "$with_gnu_ld" = yes; then
79047995 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
79057996 $as_echo_n "checking for GNU ld... " >&6; }
79077998 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
79087999 $as_echo_n "checking for non-GNU ld... " >&6; }
79098000 fi
7910 if ${acl_cv_path_LD+:} false; then :
8001 if test -n "$LD"; then
8002 # Let the user override the test with a path.
8003 :
8004 else
8005 if ${acl_cv_path_LD+:} false; then :
79118006 $as_echo_n "(cached) " >&6
79128007 else
7913 if test -z "$LD"; then
7914 acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
7915 for ac_dir in $PATH; do
7916 IFS="$acl_save_ifs"
7917 test -z "$ac_dir" && ac_dir=.
7918 if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
7919 acl_cv_path_LD="$ac_dir/$ac_prog"
7920 # Check to see if the program is GNU ld. I'd rather use --version,
7921 # but apparently some variants of GNU ld only accept -v.
7922 # Break only if it was the GNU/non-GNU ld that we prefer.
7923 case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
7924 *GNU* | *'with BFD'*)
7925 test "$with_gnu_ld" != no && break
7926 ;;
7927 *)
7928 test "$with_gnu_ld" != yes && break
7929 ;;
8008
8009 acl_cv_path_LD= # Final result of this test
8010 ac_prog=ld # Program to search in $PATH
8011 if test "$GCC" = yes; then
8012 # Check if gcc -print-prog-name=ld gives a path.
8013 case $host in
8014 *-*-mingw*)
8015 # gcc leaves a trailing carriage return which upsets mingw
8016 acl_output=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
8017 *)
8018 acl_output=`($CC -print-prog-name=ld) 2>&5` ;;
8019 esac
8020 case $acl_output in
8021 # Accept absolute paths.
8022 [\\/]* | ?:[\\/]*)
8023 re_direlt='/[^/][^/]*/\.\./'
8024 # Canonicalize the pathname of ld
8025 acl_output=`echo "$acl_output" | sed 's%\\\\%/%g'`
8026 while echo "$acl_output" | grep "$re_direlt" > /dev/null 2>&1; do
8027 acl_output=`echo $acl_output | sed "s%$re_direlt%/%"`
8028 done
8029 # Got the pathname. No search in PATH is needed.
8030 acl_cv_path_LD="$acl_output"
8031 ac_prog=
8032 ;;
8033 "")
8034 # If it fails, then pretend we aren't using GCC.
8035 ;;
8036 *)
8037 # If it is relative, then search for the first ld in PATH.
8038 with_gnu_ld=unknown
8039 ;;
79308040 esac
79318041 fi
7932 done
7933 IFS="$acl_save_ifs"
7934 else
7935 acl_cv_path_LD="$LD" # Let the user override the test with a path.
7936 fi
7937 fi
7938
7939 LD="$acl_cv_path_LD"
8042 if test -n "$ac_prog"; then
8043 # Search for $ac_prog in $PATH.
8044 acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
8045 for ac_dir in $PATH; do
8046 IFS="$acl_save_ifs"
8047 test -z "$ac_dir" && ac_dir=.
8048 if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
8049 acl_cv_path_LD="$ac_dir/$ac_prog"
8050 # Check to see if the program is GNU ld. I'd rather use --version,
8051 # but apparently some variants of GNU ld only accept -v.
8052 # Break only if it was the GNU/non-GNU ld that we prefer.
8053 case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
8054 *GNU* | *'with BFD'*)
8055 test "$with_gnu_ld" != no && break
8056 ;;
8057 *)
8058 test "$with_gnu_ld" != yes && break
8059 ;;
8060 esac
8061 fi
8062 done
8063 IFS="$acl_save_ifs"
8064 fi
8065 case $host in
8066 *-*-aix*)
8067 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8068 /* end confdefs.h. */
8069 #if defined __powerpc64__ || defined _ARCH_PPC64
8070 int ok;
8071 #else
8072 error fail
8073 #endif
8074
8075 _ACEOF
8076 if ac_fn_c_try_compile "$LINENO"; then :
8077 # The compiler produces 64-bit code. Add option '-b64' so that the
8078 # linker groks 64-bit object files.
8079 case "$acl_cv_path_LD " in
8080 *" -b64 "*) ;;
8081 *) acl_cv_path_LD="$acl_cv_path_LD -b64" ;;
8082 esac
8083
8084 fi
8085 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8086 ;;
8087 sparc64-*-netbsd*)
8088 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8089 /* end confdefs.h. */
8090 #if defined __sparcv9 || defined __arch64__
8091 int ok;
8092 #else
8093 error fail
8094 #endif
8095
8096 _ACEOF
8097 if ac_fn_c_try_compile "$LINENO"; then :
8098
8099 else
8100 # The compiler produces 32-bit code. Add option '-m elf32_sparc'
8101 # so that the linker groks 32-bit object files.
8102 case "$acl_cv_path_LD " in
8103 *" -m elf32_sparc "*) ;;
8104 *) acl_cv_path_LD="$acl_cv_path_LD -m elf32_sparc" ;;
8105 esac
8106
8107 fi
8108 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8109 ;;
8110 esac
8111
8112 fi
8113
8114 LD="$acl_cv_path_LD"
8115 fi
79408116 if test -n "$LD"; then
79418117 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
79428118 $as_echo "$LD" >&6; }
79438119 else
79448120 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
79458121 $as_echo "no" >&6; }
7946 fi
7947 test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
8122 as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
8123 fi
79488124 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
79498125 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
79508126 if ${acl_cv_prog_gnu_ld+:} false; then :
80018177
80028178
80038179
8004 acl_libdirstem=lib
8005 acl_libdirstem2=
8180 { $as_echo "$as_me:${as_lineno-$LINENO}: checking 32-bit host C ABI" >&5
8181 $as_echo_n "checking 32-bit host C ABI... " >&6; }
8182 if ${gl_cv_host_cpu_c_abi_32bit+:} false; then :
8183 $as_echo_n "(cached) " >&6
8184 else
8185 if test -n "$gl_cv_host_cpu_c_abi"; then
8186 case "$gl_cv_host_cpu_c_abi" in
8187 i386 | x86_64-x32 | arm | armhf | arm64-ilp32 | hppa | ia64-ilp32 | mips | mipsn32 | powerpc | riscv*-ilp32* | s390 | sparc)
8188 gl_cv_host_cpu_c_abi_32bit=yes ;;
8189 *)
8190 gl_cv_host_cpu_c_abi_32bit=no ;;
8191 esac
8192 else
8193 case "$host_cpu" in
8194
8195 i[4567]86 )
8196 gl_cv_host_cpu_c_abi_32bit=yes
8197 ;;
8198
8199 x86_64 )
8200 # On x86_64 systems, the C compiler may be generating code in one of
8201 # these ABIs:
8202 # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64.
8203 # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64
8204 # with native Windows (mingw, MSVC).
8205 # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32.
8206 # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386.
8207 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8208 /* end confdefs.h. */
8209 #if (defined __x86_64__ || defined __amd64__ \
8210 || defined _M_X64 || defined _M_AMD64) \
8211 && !(defined __ILP32__ || defined _ILP32)
8212 int ok;
8213 #else
8214 error fail
8215 #endif
8216
8217 _ACEOF
8218 if ac_fn_c_try_compile "$LINENO"; then :
8219 gl_cv_host_cpu_c_abi_32bit=no
8220 else
8221 gl_cv_host_cpu_c_abi_32bit=yes
8222 fi
8223 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8224 ;;
8225
8226 arm* | aarch64 )
8227 # Assume arm with EABI.
8228 # On arm64 systems, the C compiler may be generating code in one of
8229 # these ABIs:
8230 # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64.
8231 # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32.
8232 # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf.
8233 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8234 /* end confdefs.h. */
8235 #if defined __aarch64__ && !(defined __ILP32__ || defined _ILP32)
8236 int ok;
8237 #else
8238 error fail
8239 #endif
8240
8241 _ACEOF
8242 if ac_fn_c_try_compile "$LINENO"; then :
8243 gl_cv_host_cpu_c_abi_32bit=no
8244 else
8245 gl_cv_host_cpu_c_abi_32bit=yes
8246 fi
8247 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8248 ;;
8249
8250 hppa1.0 | hppa1.1 | hppa2.0* | hppa64 )
8251 # On hppa, the C compiler may be generating 32-bit code or 64-bit
8252 # code. In the latter case, it defines _LP64 and __LP64__.
8253 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8254 /* end confdefs.h. */
8255 #ifdef __LP64__
8256 int ok;
8257 #else
8258 error fail
8259 #endif
8260
8261 _ACEOF
8262 if ac_fn_c_try_compile "$LINENO"; then :
8263 gl_cv_host_cpu_c_abi_32bit=no
8264 else
8265 gl_cv_host_cpu_c_abi_32bit=yes
8266 fi
8267 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8268 ;;
8269
8270 ia64* )
8271 # On ia64 on HP-UX, the C compiler may be generating 64-bit code or
8272 # 32-bit code. In the latter case, it defines _ILP32.
8273 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8274 /* end confdefs.h. */
8275 #ifdef _ILP32
8276 int ok;
8277 #else
8278 error fail
8279 #endif
8280
8281 _ACEOF
8282 if ac_fn_c_try_compile "$LINENO"; then :
8283 gl_cv_host_cpu_c_abi_32bit=yes
8284 else
8285 gl_cv_host_cpu_c_abi_32bit=no
8286 fi
8287 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8288 ;;
8289
8290 mips* )
8291 # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this
8292 # at 32.
8293 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8294 /* end confdefs.h. */
8295 #if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64)
8296 int ok;
8297 #else
8298 error fail
8299 #endif
8300
8301 _ACEOF
8302 if ac_fn_c_try_compile "$LINENO"; then :
8303 gl_cv_host_cpu_c_abi_32bit=no
8304 else
8305 gl_cv_host_cpu_c_abi_32bit=yes
8306 fi
8307 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8308 ;;
8309
8310 powerpc* )
8311 # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD.
8312 # No need to distinguish them here; the caller may distinguish
8313 # them based on the OS.
8314 # On powerpc64 systems, the C compiler may still be generating
8315 # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may
8316 # be generating 64-bit code.
8317 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8318 /* end confdefs.h. */
8319 #if defined __powerpc64__ || defined _ARCH_PPC64
8320 int ok;
8321 #else
8322 error fail
8323 #endif
8324
8325 _ACEOF
8326 if ac_fn_c_try_compile "$LINENO"; then :
8327 gl_cv_host_cpu_c_abi_32bit=no
8328 else
8329 gl_cv_host_cpu_c_abi_32bit=yes
8330 fi
8331 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8332 ;;
8333
8334 rs6000 )
8335 gl_cv_host_cpu_c_abi_32bit=yes
8336 ;;
8337
8338 riscv32 | riscv64 )
8339 # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d.
8340 # Size of 'long' and 'void *':
8341 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8342 /* end confdefs.h. */
8343 #if defined __LP64__
8344 int ok;
8345 #else
8346 error fail
8347 #endif
8348
8349 _ACEOF
8350 if ac_fn_c_try_compile "$LINENO"; then :
8351 gl_cv_host_cpu_c_abi_32bit=no
8352 else
8353 gl_cv_host_cpu_c_abi_32bit=yes
8354 fi
8355 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8356 ;;
8357
8358 s390* )
8359 # On s390x, the C compiler may be generating 64-bit (= s390x) code
8360 # or 31-bit (= s390) code.
8361 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8362 /* end confdefs.h. */
8363 #if defined __LP64__ || defined __s390x__
8364 int ok;
8365 #else
8366 error fail
8367 #endif
8368
8369 _ACEOF
8370 if ac_fn_c_try_compile "$LINENO"; then :
8371 gl_cv_host_cpu_c_abi_32bit=no
8372 else
8373 gl_cv_host_cpu_c_abi_32bit=yes
8374 fi
8375 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8376 ;;
8377
8378 sparc | sparc64 )
8379 # UltraSPARCs running Linux have `uname -m` = "sparc64", but the
8380 # C compiler still generates 32-bit code.
8381 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
8382 /* end confdefs.h. */
8383 #if defined __sparcv9 || defined __arch64__
8384 int ok;
8385 #else
8386 error fail
8387 #endif
8388
8389 _ACEOF
8390 if ac_fn_c_try_compile "$LINENO"; then :
8391 gl_cv_host_cpu_c_abi_32bit=no
8392 else
8393 gl_cv_host_cpu_c_abi_32bit=yes
8394 fi
8395 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
8396 ;;
8397
8398 *)
8399 gl_cv_host_cpu_c_abi_32bit=no
8400 ;;
8401 esac
8402 fi
8403
8404 fi
8405 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_host_cpu_c_abi_32bit" >&5
8406 $as_echo "$gl_cv_host_cpu_c_abi_32bit" >&6; }
8407
8408 HOST_CPU_C_ABI_32BIT="$gl_cv_host_cpu_c_abi_32bit"
8409
8410
8411
8412
8413
80068414 case "$host_os" in
80078415 solaris*)
8008 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5
8416 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5
80098417 $as_echo_n "checking for 64-bit host... " >&6; }
80108418 if ${gl_cv_solaris_64bit+:} false; then :
80118419 $as_echo_n "(cached) " >&6
80128420 else
80138421 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
80148422 /* end confdefs.h. */
8015
80168423 #ifdef _LP64
8017 sixtyfour bits
8018 #endif
8424 int ok;
8425 #else
8426 error fail
8427 #endif
80198428
80208429 _ACEOF
8021 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
8022 $EGREP "sixtyfour bits" >/dev/null 2>&1; then :
8430 if ac_fn_c_try_compile "$LINENO"; then :
80238431 gl_cv_solaris_64bit=yes
80248432 else
80258433 gl_cv_solaris_64bit=no
80268434 fi
8027 rm -f conftest*
8028
8435 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
80298436
80308437 fi
80318438 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_solaris_64bit" >&5
8032 $as_echo "$gl_cv_solaris_64bit" >&6; }
8033 if test $gl_cv_solaris_64bit = yes; then
8034 acl_libdirstem=lib/64
8035 case "$host_cpu" in
8036 sparc*) acl_libdirstem2=lib/sparcv9 ;;
8037 i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
8038 esac
8039 fi
8040 ;;
8041 *)
8042 searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
8043 if test -n "$searchpath"; then
8044 acl_save_IFS="${IFS= }"; IFS=":"
8045 for searchdir in $searchpath; do
8046 if test -d "$searchdir"; then
8047 case "$searchdir" in
8048 */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
8049 */../ | */.. )
8050 # Better ignore directories of this form. They are misleading.
8051 ;;
8052 *) searchdir=`cd "$searchdir" && pwd`
8439 $as_echo "$gl_cv_solaris_64bit" >&6; };;
8440 esac
8441
8442 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the common suffixes of directories in the library search path" >&5
8443 $as_echo_n "checking for the common suffixes of directories in the library search path... " >&6; }
8444 if ${acl_cv_libdirstems+:} false; then :
8445 $as_echo_n "(cached) " >&6
8446 else
8447 acl_libdirstem=lib
8448 acl_libdirstem2=
8449 case "$host_os" in
8450 solaris*)
8451 if test $gl_cv_solaris_64bit = yes; then
8452 acl_libdirstem=lib/64
8453 case "$host_cpu" in
8454 sparc*) acl_libdirstem2=lib/sparcv9 ;;
8455 i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
8456 esac
8457 fi
8458 ;;
8459 *)
8460 if test "$HOST_CPU_C_ABI_32BIT" != yes; then
8461 searchpath=`(if test -f /usr/bin/gcc \
8462 && LC_ALL=C /usr/bin/gcc -print-search-dirs >/dev/null 2>/dev/null; then \
8463 LC_ALL=C /usr/bin/gcc -print-search-dirs; \
8464 else \
8465 LC_ALL=C $CC -print-search-dirs; \
8466 fi) 2>/dev/null \
8467 | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
8468 if test -n "$searchpath"; then
8469 acl_save_IFS="${IFS= }"; IFS=":"
8470 for searchdir in $searchpath; do
8471 if test -d "$searchdir"; then
80538472 case "$searchdir" in
8054 */lib64 ) acl_libdirstem=lib64 ;;
8055 esac ;;
8056 esac
8057 fi
8058 done
8059 IFS="$acl_save_IFS"
8060 fi
8061 ;;
8062 esac
8063 test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
8064
8473 */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
8474 */../ | */.. )
8475 # Better ignore directories of this form. They are misleading.
8476 ;;
8477 *) searchdir=`cd "$searchdir" && pwd`
8478 case "$searchdir" in
8479 */lib64 ) acl_libdirstem=lib64 ;;
8480 esac ;;
8481 esac
8482 fi
8483 done
8484 IFS="$acl_save_IFS"
8485 fi
8486 fi
8487 ;;
8488 esac
8489 test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
8490 acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2"
8491
8492 fi
8493 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libdirstems" >&5
8494 $as_echo "$acl_cv_libdirstems" >&6; }
8495 # Decompose acl_cv_libdirstems into acl_libdirstem and acl_libdirstem2.
8496 acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'`
8497 acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e '/,/s/.*,//'`
80658498
80668499
80678500
81108543 additional_includedir="$withval/include"
81118544 additional_libdir="$withval/$acl_libdirstem"
81128545 if test "$acl_libdirstem2" != "$acl_libdirstem" \
8113 && ! test -d "$withval/$acl_libdirstem"; then
8546 && test ! -d "$withval/$acl_libdirstem"; then
81148547 additional_libdir="$withval/$acl_libdirstem2"
81158548 fi
81168549 fi
85508983
85518984
85528985
8553
8554
85558986 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5
85568987 $as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; }
85578988 if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then :
86209051 $as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h
86219052
86229053 fi
9054 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyPreferredLanguages" >&5
9055 $as_echo_n "checking for CFLocaleCopyPreferredLanguages... " >&6; }
9056 if ${gt_cv_func_CFLocaleCopyPreferredLanguages+:} false; then :
9057 $as_echo_n "(cached) " >&6
9058 else
9059 gt_save_LIBS="$LIBS"
9060 LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
9061 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
9062 /* end confdefs.h. */
9063 #include <CoreFoundation/CFLocale.h>
9064 int
9065 main ()
9066 {
9067 CFLocaleCopyPreferredLanguages();
9068 ;
9069 return 0;
9070 }
9071 _ACEOF
9072 if ac_fn_c_try_link "$LINENO"; then :
9073 gt_cv_func_CFLocaleCopyPreferredLanguages=yes
9074 else
9075 gt_cv_func_CFLocaleCopyPreferredLanguages=no
9076 fi
9077 rm -f core conftest.err conftest.$ac_objext \
9078 conftest$ac_exeext conftest.$ac_ext
9079 LIBS="$gt_save_LIBS"
9080 fi
9081 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyPreferredLanguages" >&5
9082 $as_echo "$gt_cv_func_CFLocaleCopyPreferredLanguages" >&6; }
9083 if test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then
9084
9085 $as_echo "#define HAVE_CFLOCALECOPYPREFERREDLANGUAGES 1" >>confdefs.h
9086
9087 fi
86239088 INTL_MACOSX_LIBS=
8624 if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then
9089 if test $gt_cv_func_CFPreferencesCopyAppValue = yes \
9090 || test $gt_cv_func_CFLocaleCopyCurrent = yes \
9091 || test $gt_cv_func_CFLocaleCopyPreferredLanguages = yes; then
86259092 INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation"
86269093 fi
86279094
89099376 #endif
89109377 /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
89119378 provided. */
8912 if (/* Try standardized names. */
8913 iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
8914 /* Try IRIX, OSF/1 names. */
8915 && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
8916 /* Try AIX names. */
8917 && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
8918 /* Try HP-UX names. */
8919 && iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
8920 result |= 16;
9379 {
9380 /* Try standardized names. */
9381 iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP");
9382 /* Try IRIX, OSF/1 names. */
9383 iconv_t cd2 = iconv_open ("UTF-8", "eucJP");
9384 /* Try AIX names. */
9385 iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP");
9386 /* Try HP-UX names. */
9387 iconv_t cd4 = iconv_open ("utf8", "eucJP");
9388 if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1)
9389 && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1))
9390 result |= 16;
9391 if (cd1 != (iconv_t)(-1))
9392 iconv_close (cd1);
9393 if (cd2 != (iconv_t)(-1))
9394 iconv_close (cd2);
9395 if (cd3 != (iconv_t)(-1))
9396 iconv_close (cd3);
9397 if (cd4 != (iconv_t)(-1))
9398 iconv_close (cd4);
9399 }
89219400 return result;
89229401
89239402 ;
89709449
89719450
89729451
8973
89749452 use_additional=yes
89759453
89769454 acl_save_prefix="$prefix"
90089486 additional_includedir="$withval/include"
90099487 additional_libdir="$withval/$acl_libdirstem"
90109488 if test "$acl_libdirstem2" != "$acl_libdirstem" \
9011 && ! test -d "$withval/$acl_libdirstem"; then
9489 && test ! -d "$withval/$acl_libdirstem"; then
90129490 additional_libdir="$withval/$acl_libdirstem2"
90139491 fi
90149492 fi
94249902
94259903
94269904
9427
94289905 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5
94299906 $as_echo_n "checking for GNU gettext in libintl... " >&6; }
94309907 if eval \${$gt_func_gnugettext_libintl+:} false; then :
963610113 pkg_cv_AUDACIOUS_CFLAGS="$AUDACIOUS_CFLAGS"
963710114 elif test -n "$PKG_CONFIG"; then
963810115 if test -n "$PKG_CONFIG" && \
9639 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"audacious >= 3.10\""; } >&5
9640 ($PKG_CONFIG --exists --print-errors "audacious >= 3.10") 2>&5
10116 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"audacious >= 4.0\""; } >&5
10117 ($PKG_CONFIG --exists --print-errors "audacious >= 4.0") 2>&5
964110118 ac_status=$?
964210119 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
964310120 test $ac_status = 0; }; then
9644 pkg_cv_AUDACIOUS_CFLAGS=`$PKG_CONFIG --cflags "audacious >= 3.10" 2>/dev/null`
10121 pkg_cv_AUDACIOUS_CFLAGS=`$PKG_CONFIG --cflags "audacious >= 4.0" 2>/dev/null`
964510122 test "x$?" != "x0" && pkg_failed=yes
964610123 else
964710124 pkg_failed=yes
965310130 pkg_cv_AUDACIOUS_LIBS="$AUDACIOUS_LIBS"
965410131 elif test -n "$PKG_CONFIG"; then
965510132 if test -n "$PKG_CONFIG" && \
9656 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"audacious >= 3.10\""; } >&5
9657 ($PKG_CONFIG --exists --print-errors "audacious >= 3.10") 2>&5
10133 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"audacious >= 4.0\""; } >&5
10134 ($PKG_CONFIG --exists --print-errors "audacious >= 4.0") 2>&5
965810135 ac_status=$?
965910136 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
966010137 test $ac_status = 0; }; then
9661 pkg_cv_AUDACIOUS_LIBS=`$PKG_CONFIG --libs "audacious >= 3.10" 2>/dev/null`
10138 pkg_cv_AUDACIOUS_LIBS=`$PKG_CONFIG --libs "audacious >= 4.0" 2>/dev/null`
966210139 test "x$?" != "x0" && pkg_failed=yes
966310140 else
966410141 pkg_failed=yes
967910156 _pkg_short_errors_supported=no
968010157 fi
968110158 if test $_pkg_short_errors_supported = yes; then
9682 AUDACIOUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "audacious >= 3.10" 2>&1`
10159 AUDACIOUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "audacious >= 4.0" 2>&1`
968310160 else
9684 AUDACIOUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "audacious >= 3.10" 2>&1`
10161 AUDACIOUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "audacious >= 4.0" 2>&1`
968510162 fi
968610163 # Put the nasty error message in config.log where it belongs
968710164 echo "$AUDACIOUS_PKG_ERRORS" >&5
968810165
9689 as_fn_error $? "Cannot find Audacious 3.10; have you installed Audacious yet?" "$LINENO" 5
10166 as_fn_error $? "Cannot find Audacious 4.0; have you installed Audacious yet?" "$LINENO" 5
969010167
969110168 elif test $pkg_failed = untried; then
969210169 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
969310170 $as_echo "no" >&6; }
9694 as_fn_error $? "Cannot find Audacious 3.10; have you installed Audacious yet?" "$LINENO" 5
10171 as_fn_error $? "Cannot find Audacious 4.0; have you installed Audacious yet?" "$LINENO" 5
969510172
969610173 else
969710174 AUDACIOUS_CFLAGS=$pkg_cv_AUDACIOUS_CFLAGS
971610193
971710194
971810195 if test $with_system_libxml2 = yes ; then
9719 XML_LIBS="-lxml2"
9720 XML_CFLAGS="-I/usr/include/libxml2"
10196 XML_LIBS=$(xml2-config --libs)
10197 XML_CFLAGS=$(xml2-config --cflags)
972110198
972210199
972310200 else
992610403 if test "x$USE_QT" = "xyes" ; then
992710404 GENERAL_PLUGINS="$GENERAL_PLUGINS albumart-qt lyricwiki-qt playlist-manager-qt search-tool-qt song-info-qt statusicon-qt"
992810405 GENERAL_PLUGINS="$GENERAL_PLUGINS qtui skins-qt"
10406 VISUALIZATION_PLUGINS="$VISUALIZATION_PLUGINS blur_scope-qt qt-spectrum vumeter-qt"
992910407 fi
993010408
993110409 USE_GTK_OR_QT=no
1007410552 fi
1007510553
1007610554
10555 if test $have_adplug = yes ; then
10556 ac_ext=cpp
10557 ac_cpp='$CXXCPP $CPPFLAGS'
10558 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
10559 ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
10560 ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
10561
10562 CPPFLAGS_adplug_backup="${CPPFLAGS}"
10563 CPPFLAGS="${CPPFLAGS} ${ADLIB_CFLAGS}"
10564 for ac_header in adplug/nemuopl.h adplug/wemuopl.h adplug/kemuopl.h
10565 do :
10566 as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
10567 ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include <adplug/adplug.h>
10568 "
10569 if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
10570 cat >>confdefs.h <<_ACEOF
10571 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
10572 _ACEOF
10573
10574 fi
10575
10576 done
10577
10578 CPPFLAGS="${CPPFLAGS_adplug_backup}"
10579 ac_ext=c
10580 ac_cpp='$CPP $CPPFLAGS'
10581 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
10582 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
10583 ac_compiler_gnu=$ac_cv_c_compiler_gnu
10584
10585 fi
10586
1007710587
1007810588 # Check whether --enable-cdaudio was given.
1007910589 if test "${enable_cdaudio+set}" = set; then :
1098011490
1098111491
1098211492
11493 # Check whether --enable-openmpt was given.
11494 if test "${enable_openmpt+set}" = set; then :
11495 enableval=$enable_openmpt; enable_openmpt=$enableval
11496 else
11497 enable_openmpt=auto
11498 fi
11499
11500
11501 have_openmpt=no
11502 check_allowed openmpt $enable_openmpt
11503 if test $enable_openmpt != no -a $plugin_allowed = yes ; then
11504
11505 pkg_failed=no
11506 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENMPT" >&5
11507 $as_echo_n "checking for OPENMPT... " >&6; }
11508
11509 if test -n "$OPENMPT_CFLAGS"; then
11510 pkg_cv_OPENMPT_CFLAGS="$OPENMPT_CFLAGS"
11511 elif test -n "$PKG_CONFIG"; then
11512 if test -n "$PKG_CONFIG" && \
11513 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libopenmpt >= 0.2\""; } >&5
11514 ($PKG_CONFIG --exists --print-errors "libopenmpt >= 0.2") 2>&5
11515 ac_status=$?
11516 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
11517 test $ac_status = 0; }; then
11518 pkg_cv_OPENMPT_CFLAGS=`$PKG_CONFIG --cflags "libopenmpt >= 0.2" 2>/dev/null`
11519 test "x$?" != "x0" && pkg_failed=yes
11520 else
11521 pkg_failed=yes
11522 fi
11523 else
11524 pkg_failed=untried
11525 fi
11526 if test -n "$OPENMPT_LIBS"; then
11527 pkg_cv_OPENMPT_LIBS="$OPENMPT_LIBS"
11528 elif test -n "$PKG_CONFIG"; then
11529 if test -n "$PKG_CONFIG" && \
11530 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libopenmpt >= 0.2\""; } >&5
11531 ($PKG_CONFIG --exists --print-errors "libopenmpt >= 0.2") 2>&5
11532 ac_status=$?
11533 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
11534 test $ac_status = 0; }; then
11535 pkg_cv_OPENMPT_LIBS=`$PKG_CONFIG --libs "libopenmpt >= 0.2" 2>/dev/null`
11536 test "x$?" != "x0" && pkg_failed=yes
11537 else
11538 pkg_failed=yes
11539 fi
11540 else
11541 pkg_failed=untried
11542 fi
11543
11544
11545
11546 if test $pkg_failed = yes; then
11547 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
11548 $as_echo "no" >&6; }
11549
11550 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
11551 _pkg_short_errors_supported=yes
11552 else
11553 _pkg_short_errors_supported=no
11554 fi
11555 if test $_pkg_short_errors_supported = yes; then
11556 OPENMPT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libopenmpt >= 0.2" 2>&1`
11557 else
11558 OPENMPT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libopenmpt >= 0.2" 2>&1`
11559 fi
11560 # Put the nasty error message in config.log where it belongs
11561 echo "$OPENMPT_PKG_ERRORS" >&5
11562
11563
11564 if test $enable_openmpt = yes ; then
11565 as_fn_error $? "Missing dependency for libopenmpt: libopenmpt >= 0.2" "$LINENO" 5
11566 else
11567 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libopenmpt disabled due to missing dependency: libopenmpt >= 0.2" >&5
11568 $as_echo "$as_me: WARNING: libopenmpt disabled due to missing dependency: libopenmpt >= 0.2" >&2;}
11569 fi
11570
11571 elif test $pkg_failed = untried; then
11572 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
11573 $as_echo "no" >&6; }
11574
11575 if test $enable_openmpt = yes ; then
11576 as_fn_error $? "Missing dependency for libopenmpt: libopenmpt >= 0.2" "$LINENO" 5
11577 else
11578 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libopenmpt disabled due to missing dependency: libopenmpt >= 0.2" >&5
11579 $as_echo "$as_me: WARNING: libopenmpt disabled due to missing dependency: libopenmpt >= 0.2" >&2;}
11580 fi
11581
11582 else
11583 OPENMPT_CFLAGS=$pkg_cv_OPENMPT_CFLAGS
11584 OPENMPT_LIBS=$pkg_cv_OPENMPT_LIBS
11585 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
11586 $as_echo "yes" >&6; }
11587
11588 have_openmpt=yes
11589 INPUT_PLUGINS="$INPUT_PLUGINS openmpt"
11590
11591 fi
11592 fi
11593
11594
11595
1098311596 # Check whether --enable-sid was given.
1098411597 if test "${enable_sid+set}" = set; then :
1098511598 enableval=$enable_sid; enable_sid=$enableval
1277013383
1277113384
1277213385 test_songchange () {
12773 for ac_header in sys/wait.h
13386 if test $HAVE_MSWINDOWS = yes ; then
13387 have_songchange=yes
13388 else
13389 for ac_header in sys/wait.h
1277413390 do :
1277513391 ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default"
1277613392 if test "x$ac_cv_header_sys_wait_h" = xyes; then :
1278413400
1278513401 done
1278613402
13403 fi
1278713404 }
1278813405
1278913406
1340014017
1340114018 have_qtaudio=yes
1340214019 OUTPUT_PLUGINS="$OUTPUT_PLUGINS qtaudio"
14020
14021 fi
14022 fi
14023
14024
14025
14026 # Check whether --enable-streamtuner was given.
14027 if test "${enable_streamtuner+set}" = set; then :
14028 enableval=$enable_streamtuner; enable_streamtuner=$enableval
14029 else
14030 enable_streamtuner=auto
14031 fi
14032
14033
14034 have_streamtuner=no
14035 check_allowed streamtuner $enable_streamtuner
14036 if test $enable_streamtuner != no -a $plugin_allowed = yes ; then
14037
14038 pkg_failed=no
14039 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for QTNETWORK" >&5
14040 $as_echo_n "checking for QTNETWORK... " >&6; }
14041
14042 if test -n "$QTNETWORK_CFLAGS"; then
14043 pkg_cv_QTNETWORK_CFLAGS="$QTNETWORK_CFLAGS"
14044 elif test -n "$PKG_CONFIG"; then
14045 if test -n "$PKG_CONFIG" && \
14046 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Network\""; } >&5
14047 ($PKG_CONFIG --exists --print-errors "Qt5Network") 2>&5
14048 ac_status=$?
14049 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
14050 test $ac_status = 0; }; then
14051 pkg_cv_QTNETWORK_CFLAGS=`$PKG_CONFIG --cflags "Qt5Network" 2>/dev/null`
14052 test "x$?" != "x0" && pkg_failed=yes
14053 else
14054 pkg_failed=yes
14055 fi
14056 else
14057 pkg_failed=untried
14058 fi
14059 if test -n "$QTNETWORK_LIBS"; then
14060 pkg_cv_QTNETWORK_LIBS="$QTNETWORK_LIBS"
14061 elif test -n "$PKG_CONFIG"; then
14062 if test -n "$PKG_CONFIG" && \
14063 { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Network\""; } >&5
14064 ($PKG_CONFIG --exists --print-errors "Qt5Network") 2>&5
14065 ac_status=$?
14066 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
14067 test $ac_status = 0; }; then
14068 pkg_cv_QTNETWORK_LIBS=`$PKG_CONFIG --libs "Qt5Network" 2>/dev/null`
14069 test "x$?" != "x0" && pkg_failed=yes
14070 else
14071 pkg_failed=yes
14072 fi
14073 else
14074 pkg_failed=untried
14075 fi
14076
14077
14078
14079 if test $pkg_failed = yes; then
14080 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
14081 $as_echo "no" >&6; }
14082
14083 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
14084 _pkg_short_errors_supported=yes
14085 else
14086 _pkg_short_errors_supported=no
14087 fi
14088 if test $_pkg_short_errors_supported = yes; then
14089 QTNETWORK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "Qt5Network" 2>&1`
14090 else
14091 QTNETWORK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "Qt5Network" 2>&1`
14092 fi
14093 # Put the nasty error message in config.log where it belongs
14094 echo "$QTNETWORK_PKG_ERRORS" >&5
14095
14096
14097 if test $enable_streamtuner = yes ; then
14098 as_fn_error $? "Missing dependency for Stream tuner: Qt5Network" "$LINENO" 5
14099 else
14100 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Stream tuner disabled due to missing dependency: Qt5Network" >&5
14101 $as_echo "$as_me: WARNING: Stream tuner disabled due to missing dependency: Qt5Network" >&2;}
14102 fi
14103
14104 elif test $pkg_failed = untried; then
14105 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
14106 $as_echo "no" >&6; }
14107
14108 if test $enable_streamtuner = yes ; then
14109 as_fn_error $? "Missing dependency for Stream tuner: Qt5Network" "$LINENO" 5
14110 else
14111 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Stream tuner disabled due to missing dependency: Qt5Network" >&5
14112 $as_echo "$as_me: WARNING: Stream tuner disabled due to missing dependency: Qt5Network" >&2;}
14113 fi
14114
14115 else
14116 QTNETWORK_CFLAGS=$pkg_cv_QTNETWORK_CFLAGS
14117 QTNETWORK_LIBS=$pkg_cv_QTNETWORK_LIBS
14118 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
14119 $as_echo "yes" >&6; }
14120
14121 have_streamtuner=yes
14122 GENERAL_PLUGINS="$GENERAL_PLUGINS streamtuner"
1340314123
1340414124 fi
1340514125 fi
1493315653 # report actual input values of CONFIG_FILES etc. instead of their
1493415654 # values after options handling.
1493515655 ac_log="
14936 This file was extended by audacious-plugins $as_me 3.10.1, which was
15656 This file was extended by audacious-plugins $as_me 4.0, which was
1493715657 generated by GNU Autoconf 2.69. Invocation command line was
1493815658
1493915659 CONFIG_FILES = $CONFIG_FILES
1499915719 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
1500015720 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
1500115721 ac_cs_version="\\
15002 audacious-plugins config.status 3.10.1
15722 audacious-plugins config.status 4.0
1500315723 configured by $0, generated by GNU Autoconf 2.69,
1500415724 with options \\"\$ac_cs_config\\"
1500515725
1511815838 # INIT-COMMANDS
1511915839 #
1512015840 # Capture the value of obsolete ALL_LINGUAS because we need it to compute
15121 # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it
15122 # from automake < 1.5.
15123 eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
15841 # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS.
15842 OBSOLETE_ALL_LINGUAS="$ALL_LINGUAS"
1512415843 # Capture the value of LINGUAS because we need it to compute CATALOGS.
1512515844 LINGUAS="${LINGUAS-%UNSET%}"
1512615845
1573516454 if test -n "$OBSOLETE_ALL_LINGUAS"; then
1573616455 test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
1573716456 fi
15738 ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
15739 # Hide the ALL_LINGUAS assignment from automake < 1.5.
15740 eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
16457 ALL_LINGUAS=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
1574116458 POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
1574216459 else
1574316460 # The set of available languages was given in configure.in.
15744 # Hide the ALL_LINGUAS assignment from automake < 1.5.
15745 eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
16461 ALL_LINGUAS=$OBSOLETE_ALL_LINGUAS
1574616462 fi
1574716463 # Compute POFILES
1574816464 # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
1588216598 echo " Commodore 64 audio (sid): $have_sid"
1588316599 echo " Game Music Emu (spc, nsf, gbs, etc.): $have_console"
1588416600 echo " ModPlug: $have_modplug"
16601 echo " OpenMPT: $have_openmpt"
1588516602 echo " Nintendo DS audio (xsf): yes"
1588616603 echo " PlayStation audio (psf/psf2): yes"
1588716604 echo " Vortex Tracker (vtx): yes"
1597216689 echo " Qt Interface: yes"
1597316690 echo " Winamp Classic Interface: yes"
1597416691 echo " Album Art: yes"
16692 echo " Blur Scope: yes"
1597516693 echo " LyricWiki viewer: yes"
1597616694 echo " OpenGL Spectrum Analyzer: $have_qtglspectrum"
1597716695 echo " Playlist Manager: yes"
1597816696 echo " Search Tool: yes"
1597916697 echo " Song Info: yes"
16698 echo " Spectrum Analyzer (2D): yes"
1598016699 echo " Status Icon: yes"
16700 echo " Stream Tuner: $have_streamtuner"
16701 echo " VU Meter: yes"
1598116702 echo
1598216703 fi
1598316704
44 dnl Initialize
55 dnl ==========
66 AC_PREREQ([2.59])
7 AC_INIT([audacious-plugins], [3.10.1])
8 AC_COPYRIGHT([Copyright (C) 2001-2018 Audacious developers and others])
7 AC_INIT([audacious-plugins], [4.0])
8 AC_COPYRIGHT([Copyright (C) 2001-2020 Audacious developers and others])
99
1010 AC_DEFINE_UNQUOTED([PACKAGE], "$PACKAGE_NAME", [Name of package])
1111 AC_DEFINE_UNQUOTED([VERSION], "$PACKAGE_VERSION", [Version number of package])
3131 dnl Check for Audacious
3232 dnl ===================
3333
34 PKG_CHECK_MODULES(AUDACIOUS, [audacious >= 3.10],
34 PKG_CHECK_MODULES(AUDACIOUS, [audacious >= 4.0],
3535 [],
36 [AC_MSG_ERROR([Cannot find Audacious 3.10; have you installed Audacious yet?])]
36 [AC_MSG_ERROR([Cannot find Audacious 4.0; have you installed Audacious yet?])]
3737 )
3838
3939 CPPFLAGS="$CPPFLAGS $AUDACIOUS_CFLAGS"
4949 [with_system_libxml2=yes])
5050
5151 if test $with_system_libxml2 = yes ; then
52 XML_LIBS="-lxml2"
53 XML_CFLAGS="-I/usr/include/libxml2"
52 XML_LIBS=$(xml2-config --libs)
53 XML_CFLAGS=$(xml2-config --cflags)
5454 AC_SUBST(XML_LIBS)
5555 AC_SUBST(XML_CFLAGS)
5656 else
8181 if test "x$USE_QT" = "xyes" ; then
8282 GENERAL_PLUGINS="$GENERAL_PLUGINS albumart-qt lyricwiki-qt playlist-manager-qt search-tool-qt song-info-qt statusicon-qt"
8383 GENERAL_PLUGINS="$GENERAL_PLUGINS qtui skins-qt"
84 VISUALIZATION_PLUGINS="$VISUALIZATION_PLUGINS blur_scope-qt qt-spectrum vumeter-qt"
8485 fi
8586
8687 USE_GTK_OR_QT=no
187188 ADLIB,
188189 adplug)
189190
191 if test $have_adplug = yes ; then
192 AC_LANG_PUSH([C++])
193 CPPFLAGS_adplug_backup="${CPPFLAGS}"
194 CPPFLAGS="${CPPFLAGS} ${ADLIB_CFLAGS}"
195 AC_CHECK_HEADERS([adplug/nemuopl.h adplug/wemuopl.h adplug/kemuopl.h], [],
196 [], [#include <adplug/adplug.h>])
197 CPPFLAGS="${CPPFLAGS_adplug_backup}"
198 AC_LANG_POP([C++])
199 fi
200
190201 ENABLE_PLUGIN_WITH_DEP(cdaudio,
191202 audio CD support,
192203 auto,
256267 INPUT,
257268 MODPLUG,
258269 libmodplug)
270
271 ENABLE_PLUGIN_WITH_DEP(openmpt,
272 libopenmpt,
273 auto,
274 INPUT,
275 OPENMPT,
276 libopenmpt >= 0.2)
259277
260278 ENABLE_PLUGIN_WITH_DEP(sid,
261279 Commodore 64 audio,
413431 GENERAL)
414432
415433 test_songchange () {
416 AC_CHECK_HEADERS(sys/wait.h, have_songchange=yes, have_songchange=no)
434 if test $HAVE_MSWINDOWS = yes ; then
435 have_songchange=yes
436 else
437 AC_CHECK_HEADERS(sys/wait.h, have_songchange=yes, have_songchange=no)
438 fi
417439 }
418440
419441 ENABLE_PLUGIN_WITH_TEST(songchange,
479501 OUTPUT,
480502 QTMULTIMEDIA,
481503 Qt5Multimedia)
504
505 ENABLE_PLUGIN_WITH_DEP(streamtuner,
506 Stream tuner,
507 auto,
508 GENERAL,
509 QTNETWORK,
510 Qt5Network)
482511
483512 test_qtglspectrum () {
484513 PKG_CHECK_MODULES(QTOPENGL, Qt5OpenGL, [
713742 echo " Commodore 64 audio (sid): $have_sid"
714743 echo " Game Music Emu (spc, nsf, gbs, etc.): $have_console"
715744 echo " ModPlug: $have_modplug"
745 echo " OpenMPT: $have_openmpt"
716746 echo " Nintendo DS audio (xsf): yes"
717747 echo " PlayStation audio (psf/psf2): yes"
718748 echo " Vortex Tracker (vtx): yes"
803833 echo " Qt Interface: yes"
804834 echo " Winamp Classic Interface: yes"
805835 echo " Album Art: yes"
836 echo " Blur Scope: yes"
806837 echo " LyricWiki viewer: yes"
807838 echo " OpenGL Spectrum Analyzer: $have_qtglspectrum"
808839 echo " Playlist Manager: yes"
809840 echo " Search Tool: yes"
810841 echo " Song Info: yes"
842 echo " Spectrum Analyzer (2D): yes"
811843 echo " Status Icon: yes"
844 echo " Stream Tuner: $have_streamtuner"
845 echo " VU Meter: yes"
812846 echo
813847 fi
814848
6363 NEON_LIBS ?= @NEON_LIBS@
6464 NOTIFY_CFLAGS ?= @NOTIFY_CFLAGS@
6565 NOTIFY_LIBS ?= @NOTIFY_LIBS@
66 OPENMPT_CFLAGS ?= @OPENMPT_CFLAGS@
67 OPENMPT_LIBS ?= @OPENMPT_LIBS@
6668 OSS_CFLAGS ?= @OSS_CFLAGS@
6769 SAMPLERATE_CFLAGS ?= @SAMPLERATE_CFLAGS@
6870 SAMPLERATE_LIBS ?= @SAMPLERATE_LIBS@
7880 QTMULTIMEDIA_LIBS ?= @QTMULTIMEDIA_LIBS@
7981 QTOPENGL_CFLAGS ?= @QTOPENGL_CFLAGS@
8082 QTOPENGL_LIBS ?= @QTOPENGL_LIBS@
83 QTNETWORK_CFLAGS ?= @QTNETWORK_CFLAGS@
84 QTNETWORK_LIBS ?= @QTNETWORK_LIBS@
8185 VORBIS_CFLAGS ?= @VORBIS_CFLAGS@
8286 VORBIS_LIBS ?= @VORBIS_LIBS@
8387 WAVPACK_CFLAGS ?= @WAVPACK_CFLAGS@
0 project('audacious-plugins', 'c', 'cpp',
1 version: '4.0-devel',
2 meson_version: '>= 0.50')
3
4
5 copyright = 'Copyright (C) 2001-2018 Audacious developers and others'
6
7
8 qt5 = import('qt5')
9 gnome = import('gnome')
10
11
12 glib_req = '>= 2.32'
13 glib_dep = dependency('glib-2.0', version: glib_req, required: true)
14 gmodule_dep = dependency('gmodule-2.0', version: glib_req, required: true)
15
16
17 zlib_dep = dependency('zlib', required: true)
18
19
20 audacious_req = '>= 3.11'
21 audacious_dep = dependency('audacious', version: audacious_req, required: true)
22
23
24 # XXX - make this it's own .pc file
25 audtag_dep = declare_dependency(link_args: [
26 '-L@0@'.format(audacious_dep.get_pkgconfig_variable('lib_dir')),
27 '-laudtag'
28 ])
29
30
31 # XXX - make this it's own .pc file
32 audqt_dep = declare_dependency(link_args: [
33 '-L@0@'.format(audacious_dep.get_pkgconfig_variable('lib_dir')),
34 '-laudqt'
35 ])
36
37
38 xml_dep = dependency('libxml-2.0')
39
40
41 if get_option('qt')
42 qt_req = '>= 5.2'
43 qt_dep = dependency('qt5', version: qt_req, required: true, modules: ['Core', 'Widgets', 'Gui'])
44 endif
45
46
47 cdaudio_enabled = false
48 if get_option('cdaudio')
49 libcdio_dep = dependency('libcdio', version: '>= 0.70', required: false)
50 libcdio_cdda_dep = dependency('libcdio_cdda', version: '>= 0.70', required: false)
51 libcddb_dep = dependency('libcddb', version: '>= 1.2.1', required: false)
52
53 if libcdio_dep.found() and libcdio_cdda_dep.found() and libcddb_dep.found()
54 cdaudio_enabled = true
55 endif
56 endif
57
58
59 samplerate_dep = dependency('samplerate', required: false)
60
61
62 cc = meson.get_compiler('c')
63 cxx = meson.get_compiler('cpp')
64
65
66 if cc.get_id() == 'gcc' or cc.get_id() == 'clang'
67 common_flags = [
68 '-pipe',
69 '-ffast-math',
70 '-Wall',
71 '-Wtype-limits',
72 '-Wno-stringop-truncation'
73 ]
74
75 cxx_flags = [
76 '-Wno-non-virtual-dtor',
77 '-Woverloaded-virtual'
78 ]
79
80 check_cflags = ['-std=gnu99'] + common_flags
81 check_cxxflags = ['-std=gnu++11'] + common_flags + cxx_flags
82
83 foreach arg : check_cflags
84 if cc.has_argument(arg)
85 add_project_arguments(arg, language: 'c')
86 endif
87 endforeach
88
89 foreach arg : check_cxxflags
90 if cxx.has_argument(arg)
91 add_project_arguments(arg, language: 'cpp')
92 endif
93 endforeach
94 endif
95
96
97 conf = configuration_data()
98 conf.set_quoted('BUILDSTAMP', '???')
99 conf.set_quoted('COPYRIGHT', copyright)
100 conf.set_quoted('PACKAGE', meson.project_name())
101 conf.set_quoted('VERSION', meson.project_version())
102 conf.set('PACKAGE_VERSION', meson.project_version())
103 if host_machine.endian() == 'big'
104 conf.set10('WORDS_BIGENDIAN', true)
105 endif
106
107
108 # XXX - investigate to see if we can do better
109 conf.set_quoted('PLUGIN_SUFFIX', '.so')
110 if host_machine.system() == 'windows'
111 conf.set_quoted('PLUGIN_SUFFIX', '.dll')
112 elif host_machine.system() == 'darwin'
113 conf.set_quoted('PLUGIN_SUFFIX', '.dylib')
114 endif
115
116
117 if host_machine.system() == 'windows'
118 conf.set('EXPORT', '__declspec(dllexport)')
119 conf.set_quoted('PLUGIN_SUFFIX', '.dll')
120 elif cc.get_id() == 'gcc' or cc.get_id() == 'clang'
121 add_project_arguments('-fvisibility=hidden', language: 'c')
122 add_project_arguments('-fvisibility=hidden', language: 'cpp')
123 conf.set('EXPORT', '__attribute__((visibility("default")))')
124 endif
125
126
127 install_plugindir = audacious_dep.get_pkgconfig_variable('plugin_dir')
128
129
130 conf.set_quoted('INSTALL_PLUGINDIR', install_plugindir)
131 conf.set('plugindir', install_plugindir)
132
133
134 container_plugin_dir = join_paths(install_plugindir, 'Container')
135 effect_plugin_dir = join_paths(install_plugindir, 'Effect')
136 general_plugin_dir = join_paths(install_plugindir, 'General')
137 input_plugin_dir = join_paths(install_plugindir, 'Input')
138 output_plugin_dir = join_paths(install_plugindir, 'Output')
139 transport_plugin_dir = join_paths(install_plugindir, 'Transport')
140 visualization_plugin_dir = join_paths(install_plugindir, 'Visualization')
141
142
143 if get_option('dbus')
144 conf.set10('USE_DBUS', true)
145 endif
146
147
148 if get_option('qt')
149 conf.set10('USE_QT', true)
150 endif
151
152
153 subdir('src')
154 subdir('po')
0 option('dbus', type: 'boolean', value: true,
1 description: 'Whether DBus support is enabled')
2 option('qt', type: 'boolean', value: true,
3 description: 'Whether Qt support is enabled')
4 option('mpris2', type: 'boolean', value: true,
5 description: 'Whether MPRIS 2.0 support is enabled')
6
7
8 # container plugins
9 option('cue', type: 'boolean', value: true,
10 description: 'Whether libcue support is enabled')
11
12
13 # transport plugins
14 option('neon', type: 'boolean', value: true,
15 description: 'Whether the neon HTTP client is enabled')
16 option('mms', type: 'boolean', value: true,
17 description: 'Whether the libmms MMS client is enabled')
18
19
20 # input plugins
21 option('ffaudio', type: 'string', value: 'ffmpeg',
22 description: 'Choose between ffmpeg, libav or neither')
23 option('mpg123', type: 'boolean', value: true,
24 description: 'Whether MPG123 support is enabled')
25 option('adplug', type: 'boolean', value: true,
26 description: 'Whether AdPlug support is enabled')
27 option('flac', type: 'boolean', value: true,
28 description: 'Whether FLAC support is enabled')
29 option('vorbis', type: 'boolean', value: true,
30 description: 'Whether Ogg Vorbis support is enabled')
31 option('faad', type: 'boolean', value: true,
32 description: 'Whether the FAAD-based raw AAC plugin is enabled')
33 option('modplug', type: 'boolean', value: true,
34 description: 'Whether ModPlug support is enabled')
35 option('openmpt', type: 'boolean', value: true,
36 description: 'Whether OpenMPT support is enabled')
37 option('wavpack', type: 'boolean', value: true,
38 description: 'Whether WavPack support is enabled')
39 option('sndfile', type: 'boolean', value: true,
40 description: 'Whether libsndfile support is enabled')
41 option('cdaudio', type: 'boolean', value: true,
42 description: 'Whether CD audio support is enabled')
43 option('amidiplug', type: 'boolean', value: true,
44 description: 'Whether AMidiPlug plugin is enabled')
45 option('sid', type: 'boolean', value: true,
46 description: 'Whether SID emulation support is enabled')
47
48
49 # output plugins
50 option('alsa', type: 'boolean', value: true,
51 description: 'Whether ALSA support is enabled')
52 option('pulse', type: 'boolean', value: true,
53 description: 'Whether PulseAudio support is enabled')
54 option('filewriter', type: 'boolean', value: true,
55 description: 'Whether FileWriter (transcoding) support is enabled')
56 option('filewriter-mp3', type: 'boolean', value: true,
57 description: 'Whether FileWriter (transcoding) MP3 support is enabled')
58 option('filewriter-ogg', type: 'boolean', value: true,
59 description: 'Whether FileWriter (transcoding) OGG support is enabled')
60 option('filewriter-flac', type: 'boolean', value: true,
61 description: 'Whether FileWriter (transcoding) FLAC support is enabled')
62
63 # general plugins
64 option('songchange', type: 'boolean', value: true,
65 description: 'Whether the Song Change plugin is enabled')
66 option('scrobbler2', type: 'boolean', value: true,
67 description: 'Whether the Scrobbler plugin is enabled')
68 option('notify', type: 'boolean', value: true,
69 description: 'Whether the libnotify OSD plugin is enabled')
70
71
72 # effect plugins
73 option('resample', type: 'boolean', value: true,
74 description: 'Whether the resample effect plugin is enabled')
75 option('speedpitch', type: 'boolean', value: true,
76 description: 'Whether the speed / pitch effect plugin is enabled')
77
78
79 # visualization plugins
80 option('vumeter', type: 'boolean', value: true,
81 description: 'Whether the VUMeter visualization plugin is enabled')
0 ar
1 be
2 bg
3 ca
4 cmn
5 cs
6 da
7 de
8 el
9 en_GB
10 es_AR
11 es_MX
12 es
13 et
14 eu
15 fa_IR
16 fi
17 fr
18 gl
19 hu
20 id_ID
21 it
22 ja
23 ko
24 ky
25 lt
26 lv
27 ml_IN
28 ms
29 nl
30 pl
31 pt_BR
32 pt_PT
33 ru
34 si
35 sk
36 sr
37 sr_RS
38 sv
39 ta
40 tr
41 uk
42 zh_CN
43 zh_TW
33 #
44 # Translators:
55 # Ivailo Monev <xakepa10@gmail.com>, 2014
6 # Kiril Kirilov <cybercop_montana@abv.bg>, 2014-2015,2017-2018
6 # Kiril Kirilov <cybercop_montana@abv.bg>, 2014-2015,2017
77 # Myselus, 2016-2017
88 # Pandi3a <pandi3a@gmail.com>, 2012
99 # Pandi3a <pandi3a@gmail.com>, 2012
1414 msgstr ""
1515 "Project-Id-Version: Audacious Plugins\n"
1616 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
17 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
18 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
19 "Last-Translator: Kiril Kirilov <cybercop_montana@abv.bg>\n"
17 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
18 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
19 "Last-Translator: Thomas Lange\n"
2020 "Language-Team: Bulgarian (http://www.transifex.com/audacious/audacious/"
2121 "language/bg/)\n"
2222 "Language: bg\n"
4444
4545 #: src/adplug/adplug-xmms.cc:298
4646 msgid "16-bit output (if unchecked, output is 8-bit)"
47 msgstr "16 битов изход (ако не е отметнато, изходът е 8 битов)"
47 msgstr ""
4848
4949 #: src/adplug/adplug-xmms.cc:300
5050 msgid "Duplicate mono output to two channels"
51 msgstr "Дублиране на моно изход в два канала"
51 msgstr ""
5252
5353 #: src/adplug/adplug-xmms.cc:302
5454 msgid "Sample rate"
7474
7575 #: src/adplug/adplug-xmms.cc:305
7676 msgid "Repeat song in endless loop"
77 msgstr "Повторете песента в безкраен цикъл"
77 msgstr ""
7878
7979 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
8080 msgid "Alarm"
970970
971971 #: src/cdaudio/cdaudio-ng.cc:611
972972 msgid "Failed to create the CDDB connection."
973 msgstr "Неуспешно създаване на CDDB връзка."
973 msgstr ""
974974
975975 #: src/cdaudio/cdaudio-ng.cc:677
976976 msgid "Failed to query the CDDB server"
984984 #: src/cdaudio/cdaudio-ng.cc:703
985985 #, c-format
986986 msgid "Failed to read the CDDB info: %s"
987 msgstr "Неуспешно четене на CDDB информацията: %s"
987 msgstr ""
988988
989989 #: src/cd-menu-items/cd-menu-items.cc:33
990990 msgid "Audio CD Menu Items"
992992
993993 #: src/cd-menu-items/cd-menu-items.cc:45
994994 msgid "Pla_y CD"
995 msgstr "_Пусни CD"
995 msgstr ""
996996
997997 #: src/cd-menu-items/cd-menu-items.cc:45
998998 msgid "_Add CD"
999 msgstr "_Добави CD"
999 msgstr ""
10001000
10011001 #: src/compressor/compressor.cc:45
10021002 msgid "<b>Compression</b>"
11651165
11661166 #: src/delete-files/delete-files.cc:120
11671167 msgid "No files are selected."
1168 msgstr "Няма избрани файлове."
1168 msgstr ""
11691169
11701170 #: src/delete-files/delete-files.cc:125
11711171 #, c-format
11721172 msgid "Do you want to move %s to the trash?"
1173 msgstr "Наистина ли искате да преместите %s в кошчето?"
1173 msgstr ""
11741174
11751175 #: src/delete-files/delete-files.cc:126
11761176 #, c-format
11771177 msgid "Do you want to permanently delete %s?"
1178 msgstr "Наистина ли искате да изтриете завинаги %s?"
1178 msgstr ""
11791179
11801180 #: src/delete-files/delete-files.cc:133
11811181 #, c-format
11821182 msgid "Do you want to move %d files to the trash?"
1183 msgstr "Наистина ли искате да преместите %d файла в кошчето? "
1183 msgstr ""
11841184
11851185 #: src/delete-files/delete-files.cc:134
11861186 #, c-format
11871187 msgid "Do you want to permanently delete %d files?"
1188 msgstr "Наистина ли искате да изтриете завинаги %d файла?"
1188 msgstr ""
11891189
11901190 #: src/delete-files/delete-files.cc:146
11911191 msgid "Move to trash"
1192 msgstr "Преместване в кошчето"
1192 msgstr ""
11931193
11941194 #: src/delete-files/delete-files.cc:146
11951195 msgid "Delete"
31923192
31933193 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
31943194 msgid "Number of results to show:"
3195 msgstr "Брой на показваните резултати:"
3195 msgstr ""
31963196
31973197 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
31983198 msgid "Rescan library at startup"
3199 msgstr "Сканиране на библиотеката при стартиране"
3199 msgstr ""
32003200
32013201 #: src/search-tool-qt/search-tool-qt.cc:305
32023202 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
42024202
42034203 #: src/soxr/sox-resampler.cc:168
42044204 msgid "Ultra High"
4205 msgstr "Изключително високо"
4205 msgstr ""
42064206
42074207 #: src/soxr/sox-resampler.cc:172
42084208 msgid "Minimum"
4209 msgstr "Минимално"
4209 msgstr ""
42104210
42114211 #: src/soxr/sox-resampler.cc:173
42124212 msgid "Intermediate"
4213 msgstr "Средно"
4213 msgstr ""
42144214
42154215 #: src/soxr/sox-resampler.cc:174
42164216 msgid "Linear"
4217 msgstr "Линейно"
4217 msgstr ""
42184218
42194219 #: src/soxr/sox-resampler.cc:178
42204220 msgid "Quality:"
42224222
42234223 #: src/soxr/sox-resampler.cc:181
42244224 msgid "Phase:"
4225 msgstr "Период:"
4225 msgstr ""
42264226
42274227 #: src/soxr/sox-resampler.cc:185
42284228 msgid "Allow aliasing"
4229 msgstr "Позволи псевдоними"
4229 msgstr ""
42304230
42314231 #: src/soxr/sox-resampler.cc:187
42324232 msgid "Use steep filter"
4233 msgstr "Използвай подсилен филтър"
4233 msgstr ""
42344234
42354235 #: src/speedpitch/speed-pitch.cc:54
42364236 msgid "Speed and Pitch"
1414 # Petr Šimáček <petr.simacek@gmail.com>, 2012
1515 # Petr Šimáček <petr.simacek@gmail.com>, 2012
1616 # Petr Šimáček <petr.simacek@gmail.com>, 2013-2014,2017
17 # Roman Horník <roman.hornik@debian-linux.cz>, 2016,2018
17 # Roman Horník <roman.hornik@debian-linux.cz>, 2016
1818 msgid ""
1919 msgstr ""
2020 "Project-Id-Version: Audacious Plugins\n"
2121 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
22 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
23 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
24 "Last-Translator: Roman Horník <roman.hornik@debian-linux.cz>\n"
22 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
23 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
24 "Last-Translator: Thomas Lange\n"
2525 "Language-Team: Czech (http://www.transifex.com/audacious/audacious/language/"
2626 "cs/)\n"
2727 "Language: cs\n"
5050
5151 #: src/adplug/adplug-xmms.cc:298
5252 msgid "16-bit output (if unchecked, output is 8-bit)"
53 msgstr "16bitový výstup (není-li zaškrtnuto, výstup je 8bitový)"
53 msgstr ""
5454
5555 #: src/adplug/adplug-xmms.cc:300
5656 msgid "Duplicate mono output to two channels"
57 msgstr "Duplikovat monofonní výstup do dvou kanálů"
57 msgstr ""
5858
5959 #: src/adplug/adplug-xmms.cc:302
6060 msgid "Sample rate"
61 msgstr "Vzorkovací kmitočet"
61 msgstr ""
6262
6363 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
6464 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
8080
8181 #: src/adplug/adplug-xmms.cc:305
8282 msgid "Repeat song in endless loop"
83 msgstr "Opakovat nahrávku v nekonečné smyčce"
83 msgstr ""
8484
8585 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
8686 msgid "Alarm"
816816
817817 #: src/blur_scope/blur_scope.cc:55
818818 msgid "Blur Scope"
819 msgstr "Rozostřený osciloskop"
819 msgstr "Rozsah rozostření"
820820
821821 #: src/bs2b/plugin.cc:38
822822 msgid "Bauer Stereophonic-to-Binaural (BS2B)"
844844
845845 #: src/cdaudio/cdaudio-ng.cc:71
846846 msgid "Audio CD Plugin"
847 msgstr "Audio CD plugin"
847 msgstr "Audio CD Plugin"
848848
849849 #: src/cdaudio/cdaudio-ng.cc:118
850850 msgid ""
965965
966966 #: src/cdaudio/cdaudio-ng.cc:611
967967 msgid "Failed to create the CDDB connection."
968 msgstr "Selhalo vytvoření CDDB spojení."
968 msgstr ""
969969
970970 #: src/cdaudio/cdaudio-ng.cc:677
971971 msgid "Failed to query the CDDB server"
979979 #: src/cdaudio/cdaudio-ng.cc:703
980980 #, c-format
981981 msgid "Failed to read the CDDB info: %s"
982 msgstr "Selhalo čtení CDDB informace: %s"
982 msgstr ""
983983
984984 #: src/cd-menu-items/cd-menu-items.cc:33
985985 msgid "Audio CD Menu Items"
987987
988988 #: src/cd-menu-items/cd-menu-items.cc:45
989989 msgid "Pla_y CD"
990 msgstr "Pře_hrát CD"
990 msgstr ""
991991
992992 #: src/cd-menu-items/cd-menu-items.cc:45
993993 msgid "_Add CD"
994 msgstr "Při_dat CD"
994 msgstr ""
995995
996996 #: src/compressor/compressor.cc:45
997997 msgid "<b>Compression</b>"
10151015
10161016 #: src/compressor/compressor.cc:64
10171017 msgid "Dynamic Range Compressor"
1018 msgstr "Kompresor dynamického rozsahu"
1018 msgstr "Dynamický rozsah kompresoru"
10191019
10201020 #: src/console/plugin.cc:15
10211021 msgid ""
10881088 "Based on SDL Output Plugin for Audacious\n"
10891089 "Copyright 2010 John Lindgren"
10901090 msgstr ""
1091 "Výstupní plugin CoreAudio pro Audacious\n"
1092 "Copyright 2014 William Pitcock\n"
1093 "Copyright 2017-18 René J.V. Bertin\n"
1094 " (původní kód a kód převzatý z\n"
1095 "Apple examples, (c) Apple 2013)\n"
1096 "\n"
1097 "Založeno na výstupním pluginu SDL pro Audacious\n"
1098 "Copyright 2010 John Lindgren"
10991091
11001092 #: src/coreaudio/coreaudio.cc:172
11011093 msgid "Use exclusive mode"
11031095
11041096 #: src/coreaudio/coreaudio.cc:174
11051097 msgid "Use bit perfect audio (adapt device sampling rate)"
1106 msgstr "Použit bitově dokonalý zvuk (přizpůsobit vzorkovací kmitočet zařízení)"
1098 msgstr ""
11071099
11081100 #: src/crossfade/crossfade.cc:43
11091101 msgid ""
11681160
11691161 #: src/delete-files/delete-files.cc:120
11701162 msgid "No files are selected."
1171 msgstr "Nebyly zvoleny žádné soubory."
1163 msgstr ""
11721164
11731165 #: src/delete-files/delete-files.cc:125
11741166 #, c-format
11751167 msgid "Do you want to move %s to the trash?"
1176 msgstr "Chcete přesunout %s do koše?"
1168 msgstr ""
11771169
11781170 #: src/delete-files/delete-files.cc:126
11791171 #, c-format
11801172 msgid "Do you want to permanently delete %s?"
1181 msgstr "Chcete trvale odstranit %s?"
1173 msgstr ""
11821174
11831175 #: src/delete-files/delete-files.cc:133
11841176 #, c-format
11851177 msgid "Do you want to move %d files to the trash?"
1186 msgstr "Chcete přesunout %d souborů do koše?"
1178 msgstr ""
11871179
11881180 #: src/delete-files/delete-files.cc:134
11891181 #, c-format
11901182 msgid "Do you want to permanently delete %d files?"
1191 msgstr "Chcete trvale odstranit %d souborů?"
1183 msgstr ""
11921184
11931185 #: src/delete-files/delete-files.cc:146
11941186 msgid "Move to trash"
1195 msgstr "Přesunout do koše"
1187 msgstr ""
11961188
11971189 #: src/delete-files/delete-files.cc:146
11981190 msgid "Delete"
12551247
12561248 #: src/ffaudio/ffaudio-core.cc:49
12571249 msgid "FFmpeg Plugin"
1258 msgstr "FFmpeg plugin"
1250 msgstr "FFmpeg Plugin"
12591251
12601252 #: src/ffaudio/ffaudio-core.cc:627
12611253 msgid ""
15711563
15721564 #: src/flac/flacng.h:35
15731565 msgid "FLAC Decoder"
1574 msgstr "FLAC dekodér"
1566 msgstr "FLAC Dekodér"
15751567
15761568 #: src/flac/metadata.cc:270 src/wavpack/wavpack.cc:209
15771569 msgid "lossless"
15991591
16001592 #: src/gio/gio.cc:42
16011593 msgid "GIO Plugin"
1602 msgstr "GIO plugin"
1594 msgstr "GIO Plugin"
16031595
16041596 #: src/gio/gio.cc:152
16051597 msgid "Read-and-append mode not supported"
17471739
17481740 #: src/gtkui/menus.cc:84 src/qtui/menus.cc:75
17491741 msgid "Search _Library"
1750 msgstr "Prohledat knihovnu"
1742 msgstr "Prohledej knihovnu"
17511743
17521744 #: src/gtkui/menus.cc:86 src/qtui/menus.cc:77
17531745 msgid "A_bout ..."
19411933
19421934 #: src/gtkui/menus.cc:164 src/gtkui/menus.cc:223 src/qtui/menus.cc:154
19431935 msgid "Remo_ve"
1944 msgstr "Odstranit"
1936 msgstr "Odstraň"
19451937
19461938 #: src/gtkui/menus.cc:166 src/qtui/menus.cc:156
19471939 msgid "_Import ..."
21332125 #: src/gtkui/ui_gtk.cc:796 src/qtui/main_window.cc:101 src/skins/menus.cc:86
21342126 #: src/skins-qt/menus.cc:77
21352127 msgid "Search Library"
2136 msgstr "Prohledat knihovnu"
2128 msgstr "Prohledej knihovnu"
21372129
21382130 #: src/gtkui/ui_gtk.cc:804 src/qtui/main_window.cc:102
21392131 msgid "Open Files"
22822274 "\n"
22832275 "Do you want to continue?"
22842276 msgstr ""
2285 "Nedoporučuje se jako klávesové zkratky používat primární tlačítka myši bez "
2286 "modifikátorů.\n"
2287 "\n"
2288 "Chcete pokračovat?"
22892277
22902278 #: src/hotkey/gui.cc:236
22912279 msgid "Binding mouse buttons"
24382426
24392427 #: src/lirc/lirc.cc:55
24402428 msgid "LIRC Plugin"
2441 msgstr "LIRC plugin"
2429 msgstr "LIRC Plugin"
24422430
24432431 #: src/lirc/lirc.cc:379
24442432 msgid ""
24832471
24842472 #: src/lyricwiki/lyricwiki.cc:42 src/lyricwiki-qt/lyricwiki.cc:70
24852473 msgid "LyricWiki Plugin"
2486 msgstr "LyricWiki plugin"
2474 msgstr "LyricWiki Plugin"
24872475
24882476 #: src/lyricwiki/lyricwiki.cc:132 src/lyricwiki-qt/lyricwiki.cc:151
24892477 #: src/lyricwiki-qt/lyricwiki.cc:337
25292517
25302518 #: src/m3u/m3u.cc:32
25312519 msgid "M3U Playlists"
2532 msgstr "M3U seznamy skladeb"
2520 msgstr "M3U Playlisty"
25332521
25342522 #: src/metronom/metronom.cc:44
25352523 msgid "Tact Generator"
25812569
25822570 #: src/mms/mms.cc:35
25832571 msgid "MMS Plugin"
2584 msgstr "MMS plugin"
2572 msgstr "MMS Plugin"
25852573
25862574 #: src/mms/mms.cc:82
25872575 msgid "Error connecting to MMS server"
26982686
26992687 #: src/mpg123/mpg123.cc:54
27002688 msgid "MPG123 Plugin"
2701 msgstr "MPG123 plugin"
2689 msgstr "MPG123 Plugin"
27022690
27032691 #: src/mpg123/mpg123.cc:80
27042692 msgid "<b>Advanced</b>"
27142702
27152703 #: src/mpris2/plugin.cc:38
27162704 msgid "MPRIS 2 Server"
2717 msgstr "MPRIS 2 server"
2705 msgstr "MPRIS 2 Server"
27182706
27192707 #: src/neon/neon.cc:97
27202708 msgid "Neon HTTP/HTTPS Plugin"
2721 msgstr "Neon HTTP/HTTPS plugin"
2709 msgstr "Neon HTTP/HTTPS Plugin"
27222710
27232711 #: src/neon/neon.cc:526
27242712 msgid "Error parsing redirect"
28722860
28732861 #: src/psf/plugin.cc:45
28742862 msgid "OpenPSF PSF1/PSF2 Decoder"
2875 msgstr "OpenPSF PSF1/PSF2 dekodér"
2863 msgstr "OpenPSF PSF1/PSF2 Dekodér"
28762864
28772865 #: src/pulse/pulse_audio.cc:40
28782866 msgid "PulseAudio Output"
2879 msgstr "PulseAudio výstup"
2867 msgstr "PulseAudio Výstup"
28802868
28812869 #: src/pulse/pulse_audio.cc:532
28822870 msgid ""
30123000
30133001 #: src/qtui/search_bar.cc:47
30143002 msgid "Search playlist"
3015 msgstr "Prohledat seznam skladeb"
3003 msgstr "Prohledat playlist"
30163004
30173005 #: src/resample/resample.cc:43
30183006 msgid "Sample Rate Converter"
31863174
31873175 #: src/sdlout/sdlout.cc:43
31883176 msgid "SDL Output"
3189 msgstr "SDL výstup"
3177 msgstr "SDL Výstup"
31903178
31913179 #: src/sdlout/sdlout.cc:72
31923180 msgid ""
31983186
31993187 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32003188 msgid "Number of results to show:"
3201 msgstr "Počet výsledků k zobrazení:"
3189 msgstr ""
32023190
32033191 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32043192 msgid "Rescan library at startup"
3205 msgstr "Při spuštění přeskenovat knihovnu"
3193 msgstr ""
32063194
32073195 #: src/search-tool-qt/search-tool-qt.cc:305
32083196 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
32793267
32803268 #: src/sid/xmms-sid.cc:43
32813269 msgid "SID Player"
3282 msgstr "SID přehrávač"
3270 msgstr "SID Přehrávač"
32833271
32843272 #: src/sid/xs_config.cc:62
32853273 msgid "Channels:"
40794067
40804068 #: src/sndio/sndio.cc:43
40814069 msgid "Sndio Output"
4082 msgstr "Sndio výstup"
4070 msgstr "Sndio Výstup"
40834071
40844072 #: src/sndio/sndio.cc:98
40854073 msgid "Device (blank for default):"
42124200
42134201 #: src/soxr/sox-resampler.cc:168
42144202 msgid "Ultra High"
4215 msgstr "Ultra vysoká"
4203 msgstr ""
42164204
42174205 #: src/soxr/sox-resampler.cc:172
42184206 msgid "Minimum"
4219 msgstr "Minimální"
4207 msgstr ""
42204208
42214209 #: src/soxr/sox-resampler.cc:173
42224210 msgid "Intermediate"
4223 msgstr "Střední"
4211 msgstr ""
42244212
42254213 #: src/soxr/sox-resampler.cc:174
42264214 msgid "Linear"
4227 msgstr "Lineární"
4215 msgstr ""
42284216
42294217 #: src/soxr/sox-resampler.cc:178
42304218 msgid "Quality:"
42324220
42334221 #: src/soxr/sox-resampler.cc:181
42344222 msgid "Phase:"
4235 msgstr "Fáze:"
4223 msgstr ""
42364224
42374225 #: src/soxr/sox-resampler.cc:185
42384226 msgid "Allow aliasing"
4239 msgstr "Povolit aliasing"
4227 msgstr ""
42404228
42414229 #: src/soxr/sox-resampler.cc:187
42424230 msgid "Use steep filter"
4243 msgstr "Použít strmý filtr"
4231 msgstr ""
42444232
42454233 #: src/speedpitch/speed-pitch.cc:54
42464234 msgid "Speed and Pitch"
4247 msgstr "Rychlost a výška"
4235 msgstr "Rychlost a výška:"
42484236
42494237 #: src/speedpitch/speed-pitch.cc:247
42504238 msgid "<b>Speed</b>"
42524240
42534241 #: src/speedpitch/speed-pitch.cc:248
42544242 msgid "Decouple from pitch"
4255 msgstr "Oddělit od výšek tónu"
4243 msgstr "Oddělit od výšek"
42564244
42574245 #: src/speedpitch/speed-pitch.cc:250 src/speedpitch/speed-pitch.cc:258
42584246 msgid "Multiplier:"
42604248
42614249 #: src/speedpitch/speed-pitch.cc:254
42624250 msgid "<b>Pitch</b>"
4263 msgstr "<b>Výška tónu</b>"
4251 msgstr "<b>Výška</b>"
42644252
42654253 #: src/statusicon-qt/statusicon.cc:45 src/statusicon/statusicon.cc:47
42664254 msgid "Status Icon"
43384326
43394327 #: src/stereo_plugin/stereo.cc:19
43404328 msgid "Extra Stereo"
4341 msgstr "Extra stereo"
4329 msgstr "Extra Stereo"
43424330
43434331 #: src/stereo_plugin/stereo.cc:36
43444332 msgid ""
43464334 "\n"
43474335 "By Johan Levin, 1999"
43484336 msgstr ""
4349 "Extra stereo modul\n"
4337 "Extra Stereo modul\n"
43504338 "\n"
43514339 "Od Johana Levina, 1999"
43524340
43534341 #: src/stereo_plugin/stereo.cc:44
43544342 msgid "<b>Extra Stereo</b>"
4355 msgstr "<b>Extra stereo</b>"
4343 msgstr "<b>Extra Stereo</b>"
43564344
43574345 #: src/tonegen/tonegen.cc:45
43584346 msgid "Tone Generator"
44334421
44344422 #: src/vorbis/vorbis.h:18
44354423 msgid "Ogg Vorbis Decoder"
4436 msgstr "Ogg Vorbis dekodér"
4424 msgstr "Ogg Vorbis Dekodér"
44374425
44384426 #: src/vtx/info.cc:24
44394427 #, c-format
44684456
44694457 #: src/vtx/vtx.cc:38
44704458 msgid "VTX Decoder"
4471 msgstr "VTX dekodér"
4459 msgstr "VTX Dekodér"
44724460
44734461 #: src/vtx/vtx.cc:176
44744462 msgid ""
44944482
44954483 #: src/wavpack/wavpack.cc:24
44964484 msgid "WavPack Decoder"
4497 msgstr "WavPack dekodér"
4485 msgstr "WavPack Dekodér"
44984486
44994487 #: src/wavpack/wavpack.cc:211
45004488 msgid "lossy (hybrid)"
45164504
45174505 #: src/xsf/plugin.cc:50
45184506 msgid "2SF Decoder"
4519 msgstr "2SF dekodér"
4507 msgstr "2SF Dekodér"
45204508
45214509 #: src/xsf/plugin.cc:231
45224510 msgid "<b>XSF Configuration</b>"
88 msgstr ""
99 "Project-Id-Version: Audacious Plugins\n"
1010 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
11 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
12 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
13 "Last-Translator: scootergrisen\n"
11 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
12 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
13 "Last-Translator: Thomas Lange\n"
1414 "Language-Team: Danish (http://www.transifex.com/audacious/audacious/language/"
1515 "da/)\n"
1616 "Language: da\n"
482482
483483 #: src/amidiplug/i_configure-fluidsynth.cc:57
484484 msgid "_Cancel"
485 msgstr "_Annuller"
485 msgstr "_Afbryd"
486486
487487 #: src/amidiplug/i_configure-fluidsynth.cc:58
488488 msgid "_Open"
957957
958958 #: src/cdaudio/cdaudio-ng.cc:611
959959 msgid "Failed to create the CDDB connection."
960 msgstr "Kunne ikke oprette CDDB-forbindelsen."
960 msgstr ""
961961
962962 #: src/cdaudio/cdaudio-ng.cc:677
963963 msgid "Failed to query the CDDB server"
971971 #: src/cdaudio/cdaudio-ng.cc:703
972972 #, c-format
973973 msgid "Failed to read the CDDB info: %s"
974 msgstr "Kunne ikke læse CDDB-informationen: %s"
974 msgstr ""
975975
976976 #: src/cd-menu-items/cd-menu-items.cc:33
977977 msgid "Audio CD Menu Items"
11941194 #: src/delete-files/delete-files.cc:213 src/delete-files/delete-files.cc:234
11951195 #: src/skins/search-select.cc:76
11961196 msgid "Cancel"
1197 msgstr "Annuller"
1197 msgstr "Afbryd"
11981198
11991199 #: src/delete-files/delete-files.cc:268
12001200 msgid "Delete Selected Files"
14641464
14651465 #: src/filewriter/filewriter.cc:476
14661466 msgid "Bitrate:"
1467 msgstr "Bithastighed:"
1467 msgstr "Bitfrekvens:"
14681468
14691469 #: src/filewriter/filewriter.cc:483
14701470 msgid "Compression ratio:"
14921492
14931493 #: src/filewriter/filewriter.cc:506
14941494 msgid "Minimum bitrate:"
1495 msgstr "Minimum bithastighed:"
1495 msgstr "Minimum bitfrekvens:"
14961496
14971497 #: src/filewriter/filewriter.cc:510
14981498 msgid "Maximum bitrate:"
1499 msgstr "Maksimum bithastighed:"
1499 msgstr "Maksimum bitfrekvens:"
15001500
15011501 #: src/filewriter/filewriter.cc:514
15021502 msgid "Average bitrate:"
1503 msgstr "Gennemsnitlig bithastighed:"
1503 msgstr "Gennemsnitlig bitfrekvens:"
15041504
15051505 #: src/filewriter/filewriter.cc:518
15061506 msgid "VBR quality level:"
15081508
15091509 #: src/filewriter/filewriter.cc:522
15101510 msgid "Strictly enforce minimum bitrate"
1511 msgstr "Fremtving strengt minimum for bithastighed"
1511 msgstr "Fremtving strengt minimum for bitfrekvens"
15121512
15131513 #: src/filewriter/filewriter.cc:525
15141514 msgid "Omit Xing VBR header"
16791679
16801680 #: src/gtkui/columns.cc:48 src/qtui/playlist_model.cc:49
16811681 msgid "Bitrate"
1682 msgstr "Bithastighed"
1682 msgstr "Bitfrekvens"
16831683
16841684 #: src/gtkui/columns.cc:49 src/qtui/playlist_model.cc:50
16851685 msgid "Comment"
37133713 #: src/skins/menus.cc:197 src/skins/menus.cc:212 src/skins-qt/menus.cc:191
37143714 #: src/skins-qt/menus.cc:206
37153715 msgid "By Album Artist"
3716 msgstr "Efter kunstner"
3716 msgstr "Efter kunster"
37173717
37183718 #: src/skins/menus.cc:198 src/skins/menus.cc:214 src/skins-qt/menus.cc:192
37193719 #: src/skins-qt/menus.cc:208
41414141 "%t: Playlist position\n"
41424142 "%T: Title (unformatted)"
41434143 msgstr ""
4144 "%a: Kunstner\n"
4144 "%a: Kunster\n"
41454145 "%b: Album\n"
41464146 "%c: Antal kanaler\n"
41474147 "%f: Filnavn (fuld sti)\n"
1313 msgstr ""
1414 "Project-Id-Version: Audacious Plugins\n"
1515 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
16 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
17 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
18 "Last-Translator: Ioannis LM\n"
16 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
17 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
18 "Last-Translator: Thomas Lange\n"
1919 "Language-Team: Greek (http://www.transifex.com/audacious/audacious/language/"
2020 "el/)\n"
2121 "Language: el\n"
4747
4848 #: src/adplug/adplug-xmms.cc:300
4949 msgid "Duplicate mono output to two channels"
50 msgstr "Αντιγραφή μονοφωνικής εξόδου σε 2 κανάλια"
50 msgstr ""
5151
5252 #: src/adplug/adplug-xmms.cc:302
5353 msgid "Sample rate"
54 msgstr "Ρυθμός δειγματοληψίας"
54 msgstr ""
5555
5656 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
5757 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
7373
7474 #: src/adplug/adplug-xmms.cc:305
7575 msgid "Repeat song in endless loop"
76 msgstr "Επαναλαμβανόμενη επανάληψη τραγουδιού"
76 msgstr ""
7777
7878 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
7979 msgid "Alarm"
9292 "Ένα πρόσθετο που μπορεί να χρησιμοποιηθεί για να ξεκινήσετε την αναπαραγωγή "
9393 "σε ένα ορισμένο χρονικό διάστημα.\n"
9494 "\n"
95 "Αρχικά γραμμένο από τους Adam Deakin και Daniel Stodden."
95 "Γραμμένο αρχικά από τον Adam Deakin και τον Daniel Stodden."
9696
9797 #: src/alarm/interface.cc:28
9898 msgid ""
148148 " Ειδοποίηση:\n"
149149 " Η ώρα ενεργοποίησης της ειδοποίησης.\n"
150150 "\n"
151 " Χρόνος σίγησης:\n"
152 " Σίγηση ειδοποίησης ύστερα από τόσο χρόνο.\n"
151 " Χρόνος σίγασης:\n"
152 " Σίγαση ειδοποίησης ύστερα από τόσο χρόνο.\n"
153153 " (αν δεν κλείσει το παράθυρο αφύπνισης)\n"
154154 "\n"
155155 "\n"
156156 "Ημέρες\n"
157 " Ημέρα:\n"
157 " Μέρα:\n"
158158 " Επιλέξτε τις ημέρες που θα ενεργοποιείται η ειδοποίηση.\n"
159159 "\n"
160 " Χρόνος:\n"
160 " Ώρα:\n"
161161 " Επιλέξτε την ώρα ειδοποίησης για κάθε ημέρα,\n"
162 " ή επιλέξτε το κουμπί για την προεπιλεγμένη ώρα.\n"
162 " ή επιλέξτε το κουμπί για την προκαθορισμένη ώρα.\n"
163163 "\n"
164164 "\n"
165165 "Ένταση\n"
176176 "\n"
177177 "\n"
178178 "Επιλογές:\n"
179 " Επιπρόσθετη εντολή:\n"
179 " Επιπλέον εντολή:\n"
180180 " Εκτέλεση αυτής της εντολής την ώρα της ειδοποίησης.\n"
181181 "\n"
182182 " Λίστα αναπαραγωγής:\n"
186186 "\n"
187187 " Υπενθύμιση:\n"
188188 " Εμφάνιση μίας υπενθύμισης κατά την ειδοποίηση.\n"
189 " Πληκτρολογήστε την υπενθύμιση στο πεδίο κειμένου και επιλέξτε\n"
190 " ενεργοποίηση αν θέλετε να εμφανίζεται."
189 " Πληκτρολογήστε την υπενθύμιση στο πεδίο κειμένου και τικάρετε\n"
190 " το κουτάκι αν θέλετε να εμφανίζεται."
191191
192192 #: src/alarm/interface.cc:78
193193 msgid "This is your wakeup call."
236236
237237 #: src/alarm/interface.cc:167
238238 msgid "Alarm at (default):"
239 msgstr "Έναρξη στις (προεπιλογή):"
239 msgstr "Κτύπα στις (προεπιλογή):"
240240
241241 #: src/alarm/interface.cc:189
242242 msgid "h"
244244
245245 #: src/alarm/interface.cc:192
246246 msgid "Quiet after:"
247 msgstr "Σίγηση μετά από:"
247 msgstr "Σίγαση μετά από"
248248
249249 #: src/alarm/interface.cc:204
250250 msgid "hours"
256256
257257 #: src/alarm/interface.cc:224
258258 msgid "Choose the days for the alarm to come on"
259 msgstr "Επιλογή ημερών που θα χτυπήσει το ξυπνητήρι"
259 msgstr "Διαλέξτε τις ημέρες που θα χτυπήσει το ξυπνητήρι"
260260
261261 #: src/alarm/interface.cc:231
262262 msgid "Day"
272272
273273 #: src/alarm/interface.cc:286
274274 msgid "Fading"
275 msgstr "Εξασθένηση"
275 msgstr "Ξεθωριάζει"
276276
277277 #: src/alarm/interface.cc:294 src/console/plugin.cc:41
278278 #: src/crossfade/crossfade.cc:52 src/crossfade/crossfade.cc:58
287287
288288 #: src/alarm/interface.cc:306
289289 msgid "Start at"
290 msgstr "Έναρξη στο"
290 msgstr "Ξεκινάει στις"
291291
292292 #: src/alarm/interface.cc:322
293293 msgid "Final"
294 msgstr "Τελική"
294 msgstr "Τελικό"
295295
296296 #: src/alarm/interface.cc:335
297297 msgid "Current"
298 msgstr "Τωρινή"
298 msgstr "Τωρινό"
299299
300300 #: src/alarm/interface.cc:348
301301 msgid "Additional Command"
345345 "Πνευματικά δικαιώματα 2009-2012 John Lindgren\n"
346346 "\n"
347347 "Τις ευχαριστίες μου στον William Pitcock, δημιουργό του πρόσθετου Έξοδος "
348 "ALSA NG, του οποίου ο κώδικας υπηρέτησε ως σημείο αναφοράς όταν το "
348 "ALSA NG, της οποίας ο κώδικας υπηρέτησε ως σημείο αναφοράς όταν το "
349349 "εγχειρίδιο ALSA δεν ήταν αρκετό."
350350
351351 #: src/alsa/config.cc:61
533533
534534 #: src/amidiplug/i_fileinfo.cc:226
535535 msgid "Time Div:"
536 msgstr "Χρόνος Div:"
536 msgstr "Χρόνος:"
537537
538538 #: src/amidiplug/i_fileinfo.cc:237
539539 msgid "<span size=\"smaller\"> MIDI Comments and Lyrics </span>"
907907
908908 #: src/cdaudio/cdaudio-ng.cc:220
909909 msgid "Failed to initialize cdio subsystem."
910 msgstr "Αποτυχία αρχικοποίησης του υποσυστήματος cdio."
910 msgstr "Απέτυχε η αρχικοποίηση του υποσυστήματος cdio."
911911
912912 #: src/cdaudio/cdaudio-ng.cc:250
913913 #, c-format
964964
965965 #: src/cdaudio/cdaudio-ng.cc:611
966966 msgid "Failed to create the CDDB connection."
967 msgstr "Αποτυχία σύνδεσης με την CDDB"
967 msgstr ""
968968
969969 #: src/cdaudio/cdaudio-ng.cc:677
970970 msgid "Failed to query the CDDB server"
971 msgstr "Αποτυχία για την αναζήτηση στο διακομιστή CDDB"
971 msgstr "Αποτυχία στην αναζήτηση του διακομιστή CDDB"
972972
973973 #: src/cdaudio/cdaudio-ng.cc:679
974974 #, c-format
975975 msgid "Failed to query the CDDB server: %s"
976 msgstr "Αποτυχία για την αναζήτηση στο διακομιστή CDDB: %s"
976 msgstr "Αποτυχία για την αναζήτηση του διακομιστή CDDB: %s"
977977
978978 #: src/cdaudio/cdaudio-ng.cc:703
979979 #, c-format
980980 msgid "Failed to read the CDDB info: %s"
981 msgstr "Αποτυχία ανάκτησης πληροφοριών από CDDB: %s"
981 msgstr ""
982982
983983 #: src/cd-menu-items/cd-menu-items.cc:33
984984 msgid "Audio CD Menu Items"
986986
987987 #: src/cd-menu-items/cd-menu-items.cc:45
988988 msgid "Pla_y CD"
989 msgstr "_Αναπαραγωγή CD"
989 msgstr ""
990990
991991 #: src/cd-menu-items/cd-menu-items.cc:45
992992 msgid "_Add CD"
993 msgstr "_Προσθήκη CD"
993 msgstr ""
994994
995995 #: src/compressor/compressor.cc:45
996996 msgid "<b>Compression</b>"
10891089 "Based on SDL Output Plugin for Audacious\n"
10901090 "Copyright 2010 John Lindgren"
10911091 msgstr ""
1092 "Πρόσθετο Έξοδος CoreAudio για το Audacious\n"
1093 "Πνευματικά δικαιώματα 2014 William Pitcock\n"
1094 "Πνευματικά δικαιώματα 2017,18 René J.V. Bertin\n"
1095 "(αρχικός κώδικας και προσαρμογή από\n"
1096 " Apple examples, (C) Apple 2013)\n"
1097 "\n"
1098 "Βασισμένο στο πρόσθετο SDL Output για το Audacious\n"
1099 "Πνευματικά δικαιώματα 2010 John Lindgren"
11001092
11011093 #: src/coreaudio/coreaudio.cc:172
11021094 msgid "Use exclusive mode"
11691161
11701162 #: src/delete-files/delete-files.cc:120
11711163 msgid "No files are selected."
1172 msgstr "Δεν έχουν επιλεγεί αρχεία."
1164 msgstr ""
11731165
11741166 #: src/delete-files/delete-files.cc:125
11751167 #, c-format
11761168 msgid "Do you want to move %s to the trash?"
1177 msgstr "Θέλετε να μετακινήσετε %s στα απορρίμματα;"
1169 msgstr ""
11781170
11791171 #: src/delete-files/delete-files.cc:126
11801172 #, c-format
11811173 msgid "Do you want to permanently delete %s?"
1182 msgstr "Θέλετε να διαγράψετε οριστικά το %s;"
1174 msgstr ""
11831175
11841176 #: src/delete-files/delete-files.cc:133
11851177 #, c-format
11861178 msgid "Do you want to move %d files to the trash?"
1187 msgstr "Θέλετε να μετακινήσετε %d αρχεία στα απορρίμματα;"
1179 msgstr ""
11881180
11891181 #: src/delete-files/delete-files.cc:134
11901182 #, c-format
11911183 msgid "Do you want to permanently delete %d files?"
1192 msgstr "Θέλετε να διαγράψετε οριστικά τα %d αρχεία;"
1184 msgstr ""
11931185
11941186 #: src/delete-files/delete-files.cc:146
11951187 msgid "Move to trash"
1196 msgstr "Μετακίνηση στα απορρίμματα"
1188 msgstr ""
11971189
11981190 #: src/delete-files/delete-files.cc:146
11991191 msgid "Delete"
19571949
19581950 #: src/gtkui/menus.cc:169 src/qtui/menus.cc:159
19591951 msgid "Playlist _Manager ..."
1960 msgstr "Διαχειριστής λίστας αναπαρα_γωγής ..."
1952 msgstr "Διαχειριστής λιστών αναπαρα_γωγής ..."
19611953
19621954 #: src/gtkui/menus.cc:170 src/qtui/menus.cc:160
19631955 msgid "_Queue Manager ..."
22842276 "\n"
22852277 "Do you want to continue?"
22862278 msgstr ""
2287 "Δεν συνιστάται να δεσμεύονται τα κυρίως πλήκτρα του ποντικιού χωρίς "
2288 "τροποποιήσεις.\n"
2289 "\n"
2290 "Θέλετε να συνεχίσετε;"
22912279
22922280 #: src/hotkey/gui.cc:236
22932281 msgid "Binding mouse buttons"
22982286 "Press a key combination inside a text field.\n"
22992287 "You can also bind mouse buttons."
23002288 msgstr ""
2301 "Πατήστε ένα συνδυασμό πλήκτρων μέσα σε ένα πεδίο κειμένου.\n"
2289 "Πατήστε έναν συνδυασμό πλήκτρων μέσα σε ένα πεδίο κειμένου.\n"
23022290 "Μπορείτε επίσης να δεσμεύσετε τα κουμπιά ποντικιού."
23032291
23042292 #: src/hotkey/gui.cc:396
23762364
23772365 #: src/jack/jack-ng.cc:205
23782366 msgid "Failed to connect to the JACK server; is it running?"
2379 msgstr "Αποτυχία σύνδεσης με το διακομιστή JACK; είναι σε λειτουργία;"
2367 msgstr "Απέτυχε η σύνδεση με το διακομιστή JACK; είναι σε λειτουργία;"
23802368
23812369 #: src/jack/jack-ng.cc:281
23822370 #, c-format
32073195
32083196 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32093197 msgid "Number of results to show:"
3210 msgstr "Αριθμός αποτελεσμάτων για εμφάνιση:"
3198 msgstr ""
32113199
32123200 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32133201 msgid "Rescan library at startup"
3214 msgstr "Επανάληψη σάρωσης στη βιβλιοθήκη κατά στην εκκίνηση "
3202 msgstr ""
32153203
32163204 #: src/search-tool-qt/search-tool-qt.cc:305
32173205 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
32693257 "To import your music library into Audacious, choose a folder and then click "
32703258 "the \"refresh\" icon."
32713259 msgstr ""
3272 "Για να εισάγεται τη συλλογή μουσικής σας στο Audacious, διαλέξτε ένα φάκελο "
3260 "Για να εισάγεται τη συλλογή μουσικής σας στο Audacious, διαλέξτε έναν φάκελο "
32733261 "και κάνετε κλικ στο εικονίδιο «ανανέωση»."
32743262
32753263 #: src/search-tool-qt/search-tool-qt.cc:889 src/search-tool/search-tool.cc:793
33143302
33153303 #: src/sid/xs_config.cc:80
33163304 msgid "<b>Playback time</b>"
3317 msgstr "<b>Διάρκεια αναπαραγωγής</b>"
3305 msgstr "<b>Χρόνος αναπαραγωγής</b>"
33183306
33193307 #: src/sid/xs_config.cc:81
33203308 msgid "Set maximum playback time:"
35033491
35043492 #: src/skins/menus.cc:85 src/skins-qt/menus.cc:76
35053493 msgid "Open URL ..."
3506 msgstr "Άνοιγμα διεύθυνσης URL ..."
3494 msgstr "Άνοιγμα διεύθυνσης URL..."
35073495
35083496 #: src/skins/menus.cc:88 src/skins-qt/menus.cc:79
35093497 msgid "Playback"
36023590
36033591 #: src/skins/menus.cc:135 src/skins-qt/menus.cc:128
36043592 msgid "Playlist Manager ..."
3605 msgstr "Διαχειριστής λίστας αναπαραγωγής ..."
3593 msgstr "Διαχειριστής λιστών αναπαραγωγής ..."
36063594
36073595 #: src/skins/menus.cc:136 src/skins-qt/menus.cc:129
36083596 msgid "Queue Manager ..."
42164204
42174205 #: src/soxr/sox-resampler.cc:168
42184206 msgid "Ultra High"
4219 msgstr "Υπέρ υψηλά "
4207 msgstr ""
42204208
42214209 #: src/soxr/sox-resampler.cc:172
42224210 msgid "Minimum"
4223 msgstr "Ελάχιστη"
4211 msgstr ""
42244212
42254213 #: src/soxr/sox-resampler.cc:173
42264214 msgid "Intermediate"
4227 msgstr "Ενδιάμεση"
4215 msgstr ""
42284216
42294217 #: src/soxr/sox-resampler.cc:174
42304218 msgid "Linear"
4231 msgstr "Γραμμική"
4219 msgstr ""
42324220
42334221 #: src/soxr/sox-resampler.cc:178
42344222 msgid "Quality:"
42364224
42374225 #: src/soxr/sox-resampler.cc:181
42384226 msgid "Phase:"
4239 msgstr "Φάση:"
4227 msgstr ""
42404228
42414229 #: src/soxr/sox-resampler.cc:185
42424230 msgid "Allow aliasing"
43854373 "Τροποποιήθηκε από τον Daniel J. Peng <danielpeng@bigfoot.com>\n"
43864374 "\n"
43874375 "Για να την χρησιμοποιήσετε, προσθέστε ένα URL: τόνος://συχνότητα 1; "
4388 "συχνότητα2συχνότητα 3;...\n"
4389 "π.χ. τόνος://2000;2005 για να παίξει ένα τόνο 2000 Hz και ένα τόνο 2005 Hz"
4376 "συχνότητα2; συχνότητα 3;...\n"
4377 "π.χ. τόνος://2000;2005 για να παίξει έναν τόνο 2000 Hz και έναν τόνο 2005 Hz"
43904378
43914379 #: src/ui-common/dialogs-qt.cc:31
43924380 msgid "Working ..."
22 # This file is distributed under the same license as the Audacious Plugins package.
33 #
44 # Translators:
5 # Andi Chandler <andi@gowling.com>, 2013,2016-2018
5 # Andi Chandler <andi@gowling.com>, 2013,2016-2017
66 msgid ""
77 msgstr ""
88 "Project-Id-Version: Audacious Plugins\n"
99 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
10 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
11 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
12 "Last-Translator: Andi Chandler <andi@gowling.com>\n"
10 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
11 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
12 "Last-Translator: Thomas Lange\n"
1313 "Language-Team: English (United Kingdom) (http://www.transifex.com/audacious/"
1414 "audacious/language/en_GB/)\n"
1515 "Language: en_GB\n"
3333
3434 #: src/adplug/adplug-xmms.cc:297 src/sid/xs_config.cc:61
3535 msgid "<b>Output</b>"
36 msgstr "<b>Output</b>"
36 msgstr ""
3737
3838 #: src/adplug/adplug-xmms.cc:298
3939 msgid "16-bit output (if unchecked, output is 8-bit)"
40 msgstr "16-bit output (if unchecked, output is 8-bit)"
40 msgstr ""
4141
4242 #: src/adplug/adplug-xmms.cc:300
4343 msgid "Duplicate mono output to two channels"
44 msgstr "Duplicate mono output to two channels"
44 msgstr ""
4545
4646 #: src/adplug/adplug-xmms.cc:302
4747 msgid "Sample rate"
48 msgstr "Sample rate"
48 msgstr ""
4949
5050 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
5151 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
6363 #: src/modplug/plugin_main.cc:109 src/qtui/settings.cc:66
6464 #: src/skins-qt/skins_cfg.cc:298 src/skins/skins_cfg.cc:280
6565 msgid "<b>Miscellaneous</b>"
66 msgstr "<b>Miscellaneous</b>"
66 msgstr ""
6767
6868 #: src/adplug/adplug-xmms.cc:305
6969 msgid "Repeat song in endless loop"
70 msgstr "Repeat song in endless loop"
70 msgstr ""
7171
7272 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
7373 msgid "Alarm"
931931
932932 #: src/cdaudio/cdaudio-ng.cc:611
933933 msgid "Failed to create the CDDB connection."
934 msgstr "Failed to create the CDDB connection."
934 msgstr ""
935935
936936 #: src/cdaudio/cdaudio-ng.cc:677
937937 msgid "Failed to query the CDDB server"
945945 #: src/cdaudio/cdaudio-ng.cc:703
946946 #, c-format
947947 msgid "Failed to read the CDDB info: %s"
948 msgstr "Failed to read the CDDB info: %s"
948 msgstr ""
949949
950950 #: src/cd-menu-items/cd-menu-items.cc:33
951951 msgid "Audio CD Menu Items"
953953
954954 #: src/cd-menu-items/cd-menu-items.cc:45
955955 msgid "Pla_y CD"
956 msgstr "Pla_y CD"
956 msgstr ""
957957
958958 #: src/cd-menu-items/cd-menu-items.cc:45
959959 msgid "_Add CD"
960 msgstr "_Add CD"
960 msgstr ""
961961
962962 #: src/compressor/compressor.cc:45
963963 msgid "<b>Compression</b>"
10091009
10101010 #: src/console/plugin.cc:36
10111011 msgid "Echo:"
1012 msgstr "Echo:"
1012 msgstr ""
10131013
10141014 #: src/console/plugin.cc:39
10151015 msgid "Default song length:"
10171017
10181018 #: src/console/plugin.cc:42 src/modplug/plugin_main.cc:62
10191019 msgid "<b>Resampling</b>"
1020 msgstr "<b>Resampling</b>"
1020 msgstr ""
10211021
10221022 #: src/console/plugin.cc:43
10231023 msgid "Enable audio resampling"
35743574
35753575 #: src/skins/menus.cc:235 src/skins-qt/menus.cc:229
35763576 msgid "Copy"
3577 msgstr "Copy"
3577 msgstr ""
35783578
35793579 #: src/skins/menus.cc:236 src/skins-qt/menus.cc:230
35803580 msgid "Paste"
22 # This file is distributed under the same license as the Audacious Plugins package.
33 #
44 # Translators:
5 # AO <ao@localizationlab.org>, 2012-2013
6 # AO <ao@localizationlab.org>, 2017-2018
7 # AO <ao@localizationlab.org>, 2016
5 # French language coordinator <french.coordinator@rbox.me>, 2012-2013
6 # French language coordinator <french.coordinator@rbox.me>, 2017-2018
7 # French language coordinator <french.coordinator@rbox.me>, 2016
88 # Oxayotl <jagw40k@free.fr>, 2013-2014
99 # Oxayotl <jagw40k@free.fr>, 2011-2012
1010 # Jean-Alexandre Anglès d'Auriac <jagw40k@free.fr>, 2011
11 # AO <ao@localizationlab.org>, 2015
12 # AO <ao@localizationlab.org>, 2013-2015
11 # French language coordinator <french.coordinator@rbox.me>, 2015
12 # French language coordinator <french.coordinator@rbox.me>, 2013-2015
1313 msgid ""
1414 msgstr ""
1515 "Project-Id-Version: Audacious Plugins\n"
1616 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
17 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
18 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
19 "Last-Translator: AO <ao@localizationlab.org>\n"
17 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
18 "PO-Revision-Date: 2018-07-30 13:42+0000\n"
19 "Last-Translator: French language coordinator <french.coordinator@rbox.me>\n"
2020 "Language-Team: French (http://www.transifex.com/audacious/audacious/language/"
2121 "fr/)\n"
2222 "Language: fr\n"
342342 "code served as a reference when the ALSA manual was not enough."
343343 msgstr ""
344344 "Greffon de sortie ALSA pour Audacious\n"
345 "Tous droits réservés © 2009 à 2012 John Lindgren\n"
345 "Tous droits réservés © 2009-2012 John Lindgren\n"
346346 "\n"
347347 "Mes remerciements à Wiliam Pitcock, auteur du greffon de sortie ALSA NG, "
348348 "dont le code a servi de référence quand la documentation d’ALSA n’était pas "
858858 "\n"
859859 "This was a Google Summer of Code 2007 project."
860860 msgstr ""
861 "Tous droits réservés © 2007 à 2012 Calin Crisan <ccrisan@gmail.com> et "
861 "Tous droits réservés © 2007-2012 Calin Crisan <ccrisan@gmail.com> et "
862862 "autres.\n"
863863 "\n"
864864 "Un grand merci aux développeurs de libcdio <http://www.gnu.org/software/"
10161016 "Copyright 2010-2014 John Lindgren"
10171017 msgstr ""
10181018 "Greffon de compression d’étendue dynamique pour Audacious\n"
1019 "Tous droits réservés © 2010 à 2014 John Lindgren"
1019 "Tous droits réservés © 2010-2014 John Lindgren"
10201020
10211021 #: src/compressor/compressor.cc:64
10221022 msgid "Dynamic Range Compressor"
11191119 "Copyright 2010-2014 John Lindgren"
11201120 msgstr ""
11211121 "Greffon de fondu enchaîné pour Audacious\n"
1122 "Tous droits réservés © 2010 à 2014 John Lindgren"
1122 "Tous droits réservés © 2010-2014 John Lindgren"
11231123
11241124 #: src/crossfade/crossfade.cc:47
11251125 msgid "<b>Crossfade</b>"
16041604 "Copyright 2009-2012 John Lindgren"
16051605 msgstr ""
16061606 "Greffon GIO pour Audacious\n"
1607 "Tous droits réservés © 2009 à 2012 John Lindgren"
1607 "Tous droits réservés © 2009-2012 John Lindgren"
16081608
16091609 #: src/gio/gio.cc:42
16101610 msgid "GIO Plugin"
23452345 "Contrôler le lecteur avec des combinaisons globales de touches ou des "
23462346 "touches multimédia\n"
23472347 "\n"
2348 "Tous droits réservés © 2007 à 2008 Sascha Hlusiak <contact@saschahlusiak."
2349 "de>\n"
2348 "Tous droits réservés © 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>\n"
23502349 "\n"
23512350 "Parmi les contributeurs :\n"
2352 "Tous droits réservés © 2006 à 2007 Vladimir Paskov <vlado.paskov@gmail.com>\n"
2353 "Tous droits réservés © 2000 à 2002 Ville Syrjälä <syrjala@sci.fi>,\n"
2351 "Tous droits réservés © 2006-2007 Vladimir Paskov <vlado.paskov@gmail.com>\n"
2352 "Tous droits réservés © 2000-2002 Ville Syrjälä <syrjala@sci.fi>,\n"
23542353 " Bryn Davies <curious@ihug.com.au>,\n"
23552354 " Jonathan A. Davis <davis@jdhouse.org>,\n"
23562355 " Jeremy Tan <nsx@nsx.homeip.net>"
25802579 "Copyright 2011-2012 John Lindgren and Michał Lipski"
25812580 msgstr ""
25822581 "Greffon de mélange des canaux pour Audacious\n"
2583 "Tous droits réservés © 2011 à 2012 John Lindgren et Michał Lipski"
2582 "Tous droits réservés © 2011-2012 John Lindgren et Michał Lipski"
25842583
25852584 #: src/mixer/mixer.cc:231
25862585 msgid "<b>Channel Mixer</b>"
27802779 msgstr ""
27812780 "Greffon de notifications de bureau pour Audacious\n"
27822781 "Tous droits réservés © 2010 Maximilian Bogner\n"
2783 "Tous droits réservés © 2011 à 2013 John Lindgren et Jean-Alexandre Anglès "
2782 "Tous droits réservés © 2011-2013 John Lindgren et Jean-Alexandre Anglès "
27842783 "d’Auriac\n"
27852784 "\n"
27862785 "Ce greffon est un logiciel libre; vous pouvez le redistribuer ou le modifier "
28532852 "Lindgren and of course the authors of the previous OSS plugin."
28542853 msgstr ""
28552854 "Greffon de sortie OSS4 pour Audacious\n"
2856 "Tous droits réservés © 2010 à 2012 Michał Lipski\n"
2855 "Tous droits réservés © 2010-2012 Michał Lipski\n"
28572856 "\n"
28582857 "Je souhaiterais remercier les gens présent sur #audacious, particulièrement "
28592858 "Tony Vroon and John Lindgren, et bien entendu les auteurs du précédent "
29602959 "Tous droits réservés © 2014 William Pitcock\n"
29612960 "\n"
29622961 "Fondé sur le greffon XMMS :\n"
2963 "Tous droits réservés © 1998 à 2000 Peter Alm, Mikael Alm, Olle Hallnas, "
2964 "Thomas Nilsson, et 4Front Technologies\n"
2962 "Tous droits réservés © 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas "
2963 "Nilsson, et 4Front Technologies\n"
29652964 "\n"
29662965 "Licence : GPLv2+"
29672966
30393038 "Copyright 2010-2012 John Lindgren"
30403039 msgstr ""
30413040 "Greffon de convertisseur de fréquence d’échantillonnage pour Audacious\n"
3042 "Tous droits réservés © 2010 à 2012 John Lindgren"
3041 "Tous droits réservés © 2010-2012 John Lindgren"
30433042
30443043 #: src/resample/resample.cc:187
30453044 msgid "Skip/repeat samples"
31893188 msgstr ""
31903189 "Greffon Scrobbler 2.0 pour Audacious par Pitxyoki,\n"
31913190 "\n"
3192 "Tous droits réservés © 2012 à 2013 Luís M. Picciochi Oliveira "
3193 "<Pitxyoki@Gmail.com>\n"
3191 "Tous droits réservés © 2012-2013 Luís M. Picciochi Oliveira <Pitxyoki@Gmail."
3192 "com>\n"
31943193 "\n"
31953194 "Remerciements à John Lindgren pour m’avoir donné un coup de main au début de "
31963195 "ce projet.\n"
42124211 "Tous droits réservés © 2013 Michał Lipski\n"
42134212 "\n"
42144213 "Fondé sur le greffon de conversion de la fréquence d’échantillonnage :\n"
4215 "Tous droits réservés © 2010 à 2012 John Lindgren"
4214 "Tous droits réservés © 2010-2012 John Lindgren"
42164215
42174216 #: src/soxr/sox-resampler.cc:163
42184217 msgid "Quick"
42994298 msgstr ""
43004299 "Greffon d’icône d’état (port partiel pour l’interface Qt)\n"
43014300 "\n"
4302 "Tous droits réservés © 2005 à 2007 Giacomo Lozito <james@develia.org>\n"
4301 "Tous droits réservés © 2005-2007 Giacomo Lozito <james@develia.org>\n"
43034302 "Tous droits réservés © 2010 Michał Lipski <tallica@o2.pl>\n"
43044303 "Tous droits réservés © 2015 Eugene Paskevich <eugene@raptor.kiev.ua>\n"
43054304 "\n"
43504349 msgstr ""
43514350 "Greffon d’icône d’état\n"
43524351 "\n"
4353 "Tous droits réservés © 2005 à 2007 Giacomo Lozito <james@develia.org>\n"
4352 "Tous droits réservés © 2005-2007 Giacomo Lozito <james@develia.org>\n"
43544353 "Tous droits réservés © 2010 Michał Lipski <tallica@o2.pl>\n"
43554354 "\n"
43564355 "Ce greffon ajoute une icône d’état dans la zone\n"
45644563 #~ "Greffon de prise en charge des raccourcis de GNOME\n"
45654564 #~ "Vous permet de contrôler le lecteur avec les raccourcis de GNOME\n"
45664565 #~ "\n"
4567 #~ "Tous droits réservés © 2007 à 2008 Sascha Hlusiak <contact@saschahlusiak."
4568 #~ "de>"
4566 #~ "Tous droits réservés © 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>"
1515 msgstr ""
1616 "Project-Id-Version: Audacious Plugins\n"
1717 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
18 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
19 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
20 "Last-Translator: Balázs Meskó <meskobalazs@gmail.com>\n"
18 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
19 "PO-Revision-Date: 2018-08-01 16:11+0000\n"
20 "Last-Translator: blackc0de <complic@vipmail.hu>\n"
2121 "Language-Team: Hungarian (http://www.transifex.com/audacious/audacious/"
2222 "language/hu/)\n"
2323 "Language: hu\n"
3232
3333 #: src/adplug/adplug-xmms.cc:50
3434 msgid "AdPlug (AdLib Player)"
35 msgstr "AdPlug (AdLib lejátszó)"
35 msgstr "AdPlug (AdLib Lejátszó)"
3636
3737 #: src/adplug/adplug-xmms.cc:148 src/modplug/modplugbmp.cc:337
3838 #: src/psf/plugin.cc:136 src/vtx/vtx.cc:89 src/xsf/plugin.cc:106
4545
4646 #: src/adplug/adplug-xmms.cc:298
4747 msgid "16-bit output (if unchecked, output is 8-bit)"
48 msgstr "16 bites kimenet (ha nincs bejelölve, akkor 8 bites)"
48 msgstr ""
4949
5050 #: src/adplug/adplug-xmms.cc:300
5151 msgid "Duplicate mono output to two channels"
5353
5454 #: src/adplug/adplug-xmms.cc:302
5555 msgid "Sample rate"
56 msgstr "Mintavételi frekvencia"
56 msgstr ""
5757
5858 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
5959 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
7575
7676 #: src/adplug/adplug-xmms.cc:305
7777 msgid "Repeat song in endless loop"
78 msgstr "A szám ismétlése végtelen ciklusban"
78 msgstr ""
7979
8080 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
8181 msgid "Alarm"
289289
290290 #: src/alarm/interface.cc:306
291291 msgid "Start at"
292 msgstr "Kezdés itt:"
292 msgstr "Kezdjük a"
293293
294294 #: src/alarm/interface.cc:322
295295 msgid "Final"
305305
306306 #: src/alarm/interface.cc:354 src/alarm/interface.cc:377
307307 msgid "enable"
308 msgstr "engedélyezés"
308 msgstr "engedélyez"
309309
310310 #: src/alarm/interface.cc:361
311311 msgid "Playlist (optional)"
317317
318318 #: src/alarm/interface.cc:385
319319 msgid "Options"
320 msgstr "Beállítások"
320 msgstr "Opciók"
321321
322322 #: src/alarm/interface.cc:390
323323 msgid "What do these options mean?"
964964
965965 #: src/cdaudio/cdaudio-ng.cc:611
966966 msgid "Failed to create the CDDB connection."
967 msgstr "A CDDB kapcsolat létrehozása meghiúsult."
967 msgstr ""
968968
969969 #: src/cdaudio/cdaudio-ng.cc:677
970970 msgid "Failed to query the CDDB server"
978978 #: src/cdaudio/cdaudio-ng.cc:703
979979 #, c-format
980980 msgid "Failed to read the CDDB info: %s"
981 msgstr "A CDDB információ kiolvasása meghiúsult: %s"
981 msgstr ""
982982
983983 #: src/cd-menu-items/cd-menu-items.cc:33
984984 msgid "Audio CD Menu Items"
986986
987987 #: src/cd-menu-items/cd-menu-items.cc:45
988988 msgid "Pla_y CD"
989 msgstr "CD _lejátszása"
989 msgstr ""
990990
991991 #: src/cd-menu-items/cd-menu-items.cc:45
992992 msgid "_Add CD"
993 msgstr "CD _hozzáadása"
993 msgstr ""
994994
995995 #: src/compressor/compressor.cc:45
996996 msgid "<b>Compression</b>"
10881088 "Based on SDL Output Plugin for Audacious\n"
10891089 "Copyright 2010 John Lindgren"
10901090 msgstr ""
1091 "CoreAudio kimeneti bővítmény az Audacious-hoz\n"
1092 "Copyright 2014 William Pitcock\n"
1093 "Copyright 2017,18 René J.V. Bertin\n"
1094 " (eredeti kód, és az Apple mintákból\n"
1095 " átvett példák, (C) Apple 2013)\n"
1096 "\n"
1097 "Az SDL kimeneti bővítmény alapján\n"
1098 "Copyright 2010 John Lindgren"
10991091
11001092 #: src/coreaudio/coreaudio.cc:172
11011093 msgid "Use exclusive mode"
11031095
11041096 #: src/coreaudio/coreaudio.cc:174
11051097 msgid "Use bit perfect audio (adapt device sampling rate)"
1106 msgstr "Bitpontos hang használata (eszköz mintavételi arányának igazítása)"
1098 msgstr ""
11071099
11081100 #: src/crossfade/crossfade.cc:43
11091101 msgid ""
11681160
11691161 #: src/delete-files/delete-files.cc:120
11701162 msgid "No files are selected."
1171 msgstr "Nincs fájl kiválasztva."
1163 msgstr ""
11721164
11731165 #: src/delete-files/delete-files.cc:125
11741166 #, c-format
11751167 msgid "Do you want to move %s to the trash?"
1176 msgstr "Kukába helyezi: %s?"
1168 msgstr ""
11771169
11781170 #: src/delete-files/delete-files.cc:126
11791171 #, c-format
11801172 msgid "Do you want to permanently delete %s?"
1181 msgstr "Véglegesen törli: %s?"
1173 msgstr ""
11821174
11831175 #: src/delete-files/delete-files.cc:133
11841176 #, c-format
11851177 msgid "Do you want to move %d files to the trash?"
1186 msgstr "Kukába helyez %d fájlt?"
1178 msgstr ""
11871179
11881180 #: src/delete-files/delete-files.cc:134
11891181 #, c-format
11901182 msgid "Do you want to permanently delete %d files?"
1191 msgstr "Véglegesen töröl %d fájlt?"
1183 msgstr ""
11921184
11931185 #: src/delete-files/delete-files.cc:146
11941186 msgid "Move to trash"
1195 msgstr "Kukába helyezés"
1187 msgstr ""
11961188
11971189 #: src/delete-files/delete-files.cc:146
11981190 msgid "Delete"
22852277 "\n"
22862278 "Do you want to continue?"
22872279 msgstr ""
2288 "Nem ajánlott az elsődleges egérgombokat módosítók nélkül társítani.\n"
2289 "\n"
2290 "Biztos, hogy folytatja?"
22912280
22922281 #: src/hotkey/gui.cc:236
22932282 msgid "Binding mouse buttons"
32173206
32183207 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32193208 msgid "Number of results to show:"
3220 msgstr "Megjelenítendő találatok:"
3209 msgstr ""
32213210
32223211 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32233212 msgid "Rescan library at startup"
3224 msgstr "Gyűjtemény átvizsgálása indításkor"
3213 msgstr ""
32253214
32263215 #: src/search-tool-qt/search-tool-qt.cc:305
32273216 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
42324221
42334222 #: src/soxr/sox-resampler.cc:168
42344223 msgid "Ultra High"
4235 msgstr "Nagyon magas"
4224 msgstr ""
42364225
42374226 #: src/soxr/sox-resampler.cc:172
42384227 msgid "Minimum"
4239 msgstr "Legalacsonyabb"
4228 msgstr ""
42404229
42414230 #: src/soxr/sox-resampler.cc:173
42424231 msgid "Intermediate"
4243 msgstr "Közepes"
4232 msgstr ""
42444233
42454234 #: src/soxr/sox-resampler.cc:174
42464235 msgid "Linear"
42524241
42534242 #: src/soxr/sox-resampler.cc:181
42544243 msgid "Phase:"
4255 msgstr "Fázis:"
4244 msgstr ""
42564245
42574246 #: src/soxr/sox-resampler.cc:185
42584247 msgid "Allow aliasing"
4259 msgstr "Alul-mintavételezés engedélyezése"
4248 msgstr ""
42604249
42614250 #: src/soxr/sox-resampler.cc:187
42624251 msgid "Use steep filter"
4263 msgstr "Meredek szűrő"
4252 msgstr ""
42644253
42654254 #: src/speedpitch/speed-pitch.cc:54
42664255 msgid "Speed and Pitch"
1010 # Bervianto Leo Pratama <bervianto.leo@gmail.com>, 2016
1111 # <bu0ncu3@yahoo.com>, 2012
1212 # Catur Susetyo <satyafree@gmail.com>, 2013
13 # IMAM MUJAHIDIN <amangimam@hotmail.com>, 2018
1413 # <kokabiel9@gmail.com>, 2012
1514 # Liffindra Angga Zaaldian <findrakecil@gmail.com>, 2015
1615 # martadinata666 <martadinata666@gmail.com>, 2012
2524 msgstr ""
2625 "Project-Id-Version: Audacious Plugins\n"
2726 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
28 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
29 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
30 "Last-Translator: IMAM MUJAHIDIN <amangimam@hotmail.com>\n"
27 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
28 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
29 "Last-Translator: Thomas Lange\n"
3130 "Language-Team: Indonesian (Indonesia) (http://www.transifex.com/audacious/"
3231 "audacious/language/id_ID/)\n"
3332 "Language: id_ID\n"
10851084
10861085 #: src/delete-files/delete-files.cc:120
10871086 msgid "No files are selected."
1088 msgstr "Tidak ada berkas yang dipilih"
1087 msgstr ""
10891088
10901089 #: src/delete-files/delete-files.cc:125
10911090 #, c-format
10921091 msgid "Do you want to move %s to the trash?"
1093 msgstr "Anda ingin memindahkan %sberkas ke keranjang sampah?"
1092 msgstr ""
10941093
10951094 #: src/delete-files/delete-files.cc:126
10961095 #, c-format
10971096 msgid "Do you want to permanently delete %s?"
1098 msgstr "Anda ingin menghapus %sberkas secara permanen?"
1097 msgstr ""
10991098
11001099 #: src/delete-files/delete-files.cc:133
11011100 #, c-format
11021101 msgid "Do you want to move %d files to the trash?"
1103 msgstr "Anda ingin memindahkan %dberkas ke tempat sampah?"
1102 msgstr ""
11041103
11051104 #: src/delete-files/delete-files.cc:134
11061105 #, c-format
11071106 msgid "Do you want to permanently delete %d files?"
1108 msgstr "Anda ingin menghapus %dberkas secara permanen?"
1107 msgstr ""
11091108
11101109 #: src/delete-files/delete-files.cc:146
11111110 msgid "Move to trash"
1112 msgstr "Pindahkan ke keranjang sampah"
1111 msgstr ""
11131112
11141113 #: src/delete-files/delete-files.cc:146
11151114 msgid "Delete"
22 # This file is distributed under the same license as the Audacious Plugins package.
33 #
44 # Translators:
5 # ABE Tsunehiko, 2015-2018
5 # ABE Tsunehiko, 2015-2017
66 # natird zoto <dritan86@gmail.com>, 2012
77 # ABE Tsunehiko, 2013
88 # ABE Tsunehiko, 2012
1616 msgstr ""
1717 "Project-Id-Version: Audacious Plugins\n"
1818 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
19 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
20 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
21 "Last-Translator: ABE Tsunehiko\n"
19 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
20 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
21 "Last-Translator: Thomas Lange\n"
2222 "Language-Team: Japanese (http://www.transifex.com/audacious/audacious/"
2323 "language/ja/)\n"
2424 "Language: ja\n"
4646
4747 #: src/adplug/adplug-xmms.cc:298
4848 msgid "16-bit output (if unchecked, output is 8-bit)"
49 msgstr "16-bit 出力 (チェックされていない場合は 8-bit で出力します)"
49 msgstr ""
5050
5151 #: src/adplug/adplug-xmms.cc:300
5252 msgid "Duplicate mono output to two channels"
53 msgstr "モノラル出力を2チャンネルに複製する"
53 msgstr ""
5454
5555 #: src/adplug/adplug-xmms.cc:302
5656 msgid "Sample rate"
57 msgstr "サンプリングレート"
57 msgstr ""
5858
5959 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
6060 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
7676
7777 #: src/adplug/adplug-xmms.cc:305
7878 msgid "Repeat song in endless loop"
79 msgstr "曲を無限に繰り返す"
79 msgstr ""
8080
8181 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
8282 msgid "Alarm"
965965
966966 #: src/cdaudio/cdaudio-ng.cc:611
967967 msgid "Failed to create the CDDB connection."
968 msgstr "CDDB コネクションの作成に失敗しました。"
968 msgstr ""
969969
970970 #: src/cdaudio/cdaudio-ng.cc:677
971971 msgid "Failed to query the CDDB server"
979979 #: src/cdaudio/cdaudio-ng.cc:703
980980 #, c-format
981981 msgid "Failed to read the CDDB info: %s"
982 msgstr "CDDB 情報の読み取りに失敗しました: %s"
982 msgstr ""
983983
984984 #: src/cd-menu-items/cd-menu-items.cc:33
985985 msgid "Audio CD Menu Items"
987987
988988 #: src/cd-menu-items/cd-menu-items.cc:45
989989 msgid "Pla_y CD"
990 msgstr "CD を再生 (_Y)"
990 msgstr ""
991991
992992 #: src/cd-menu-items/cd-menu-items.cc:45
993993 msgid "_Add CD"
994 msgstr "CD を追加 (_A)"
994 msgstr ""
995995
996996 #: src/compressor/compressor.cc:45
997997 msgid "<b>Compression</b>"
10881088 "Based on SDL Output Plugin for Audacious\n"
10891089 "Copyright 2010 John Lindgren"
10901090 msgstr ""
1091 "CoreAudio 出力プラグイン for Audacious\n"
1092 "Copyright 2014 William Pitcock\n"
1093 "Copyright 2017,18 René J.V. Bertin\n"
1094 " (original code and code adapted from\n"
1095 " Apple examples, (C) Apple 2013)\n"
1096 "\n"
1097 "Based on SDL Output Plugin for Audacious\n"
1098 "Copyright 2010 John Lindgren"
10991091
11001092 #: src/coreaudio/coreaudio.cc:172
11011093 msgid "Use exclusive mode"
11041096 #: src/coreaudio/coreaudio.cc:174
11051097 msgid "Use bit perfect audio (adapt device sampling rate)"
11061098 msgstr ""
1107 "ビットパーフェクトオーディオを使用する (デバイスのサンプリングレートを適合さ"
1108 "せる)"
11091099
11101100 #: src/crossfade/crossfade.cc:43
11111101 msgid ""
11701160
11711161 #: src/delete-files/delete-files.cc:120
11721162 msgid "No files are selected."
1173 msgstr "ファイルが選択されていません。"
1163 msgstr ""
11741164
11751165 #: src/delete-files/delete-files.cc:125
11761166 #, c-format
11771167 msgid "Do you want to move %s to the trash?"
1178 msgstr "%s をゴミ箱に移動しますか?"
1168 msgstr ""
11791169
11801170 #: src/delete-files/delete-files.cc:126
11811171 #, c-format
11821172 msgid "Do you want to permanently delete %s?"
1183 msgstr "%s を完全に削除しますか?"
1173 msgstr ""
11841174
11851175 #: src/delete-files/delete-files.cc:133
11861176 #, c-format
11871177 msgid "Do you want to move %d files to the trash?"
1188 msgstr "%d 個のファイルをゴミ箱に移動しますか?"
1178 msgstr ""
11891179
11901180 #: src/delete-files/delete-files.cc:134
11911181 #, c-format
11921182 msgid "Do you want to permanently delete %d files?"
1193 msgstr "%d 個のファイルを完全に削除しますか?"
1183 msgstr ""
11941184
11951185 #: src/delete-files/delete-files.cc:146
11961186 msgid "Move to trash"
1197 msgstr "ゴミ箱に移動する"
1187 msgstr ""
11981188
11991189 #: src/delete-files/delete-files.cc:146
12001190 msgid "Delete"
22822272 "\n"
22832273 "Do you want to continue?"
22842274 msgstr ""
2285 "修飾キーなしでプライマリーマウスのボタンに割り当てるのはお勧めしません。\n"
2286 "\n"
2287 "本当によろしいですか?"
22882275
22892276 #: src/hotkey/gui.cc:236
22902277 msgid "Binding mouse buttons"
32033190
32043191 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32053192 msgid "Number of results to show:"
3206 msgstr "検索結果の表示件数:"
3193 msgstr ""
32073194
32083195 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32093196 msgid "Rescan library at startup"
3210 msgstr "起動時にライブラリーを再スキャンする"
3197 msgstr ""
32113198
32123199 #: src/search-tool-qt/search-tool-qt.cc:305
32133200 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
42084195
42094196 #: src/soxr/sox-resampler.cc:168
42104197 msgid "Ultra High"
4211 msgstr "究極品質"
4198 msgstr ""
42124199
42134200 #: src/soxr/sox-resampler.cc:172
42144201 msgid "Minimum"
4215 msgstr "最小限"
4202 msgstr ""
42164203
42174204 #: src/soxr/sox-resampler.cc:173
42184205 msgid "Intermediate"
4219 msgstr "中間"
4206 msgstr ""
42204207
42214208 #: src/soxr/sox-resampler.cc:174
42224209 msgid "Linear"
4223 msgstr "線形"
4210 msgstr ""
42244211
42254212 #: src/soxr/sox-resampler.cc:178
42264213 msgid "Quality:"
42284215
42294216 #: src/soxr/sox-resampler.cc:181
42304217 msgid "Phase:"
4231 msgstr "位相応答:"
4218 msgstr ""
42324219
42334220 #: src/soxr/sox-resampler.cc:185
42344221 msgid "Allow aliasing"
4235 msgstr "エイリアシングを許可"
4222 msgstr ""
42364223
42374224 #: src/soxr/sox-resampler.cc:187
42384225 msgid "Use steep filter"
4239 msgstr "急峻なフィルターを使う"
4226 msgstr ""
42404227
42414228 #: src/speedpitch/speed-pitch.cc:54
42424229 msgid "Speed and Pitch"
0 i18n = import('i18n')
1
2
3 i18n.gettext('audacious-plugins',
4 args: [
5 '--default-domain=audacious-plugins',
6 '--language=C',
7 '--keyword=_',
8 '--keyword=N_',
9 '--from-code=UTF-8',
10 '--msgid-bugs-address="https://redmine.audacious-media-player.org/"',
11 '--directory=%0%'.format(meson.source_root()),
12 '--files-from=POTFILES.in'
13 ]
14 )
2626 msgstr ""
2727 "Project-Id-Version: Audacious Plugins\n"
2828 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
29 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
30 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
29 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
30 "PO-Revision-Date: 2018-07-30 03:51+0000\n"
3131 "Last-Translator: No Ne\n"
3232 "Language-Team: Polish (http://www.transifex.com/audacious/audacious/language/"
3333 "pl/)\n"
483483
484484 #: src/amidiplug/i_configure.cc:141
485485 msgid "<b>SoundFont</b>"
486 msgstr "<b>SoundFont</b>"
486 msgstr "<b>Czcionka</b>"
487487
488488 #: src/amidiplug/i_configure.cc:145
489489 msgid "<b>Synthesizer</b>"
496496
497497 #: src/amidiplug/i_configure-fluidsynth.cc:54
498498 msgid "AMIDI-Plug - select SoundFont file"
499 msgstr "AMIDI-Plug - wybierz plik SoundFont"
499 msgstr "AMIDI-Plug - wybierz plik czcionki"
500500
501501 #: src/amidiplug/i_configure-fluidsynth.cc:57
502502 msgid "_Cancel"
532532
533533 #: src/amidiplug/i_fileinfo.cc:207
534534 msgid "No. of Tracks:"
535 msgstr "Liczba ścieżek:"
535 msgstr "Liczba utworów:"
536536
537537 #: src/amidiplug/i_fileinfo.cc:213
538538 msgid "variable"
756756 msgstr ""
757757 "Nie wykryto menedżera okien obsługującego kompozycje.\n"
758758 "Aby menu ekranowe było wyświetlanie prawidłowo, należy uruchomić menedżer "
759 "okien obsługujący kompozycje"
759 "okien obsługujący kompozycje (np. Compiz)."
760760
761761 #: src/aosd/aosd_ui.cc:668
762762 msgid "Composite manager not required for fake transparency"
10631063
10641064 #: src/console/plugin.cc:39
10651065 msgid "Default song length:"
1066 msgstr "Domyślna długość piosenki:"
1066 msgstr "Domyślny czas trwania ścieżki:"
10671067
10681068 #: src/console/plugin.cc:42 src/modplug/plugin_main.cc:62
10691069 msgid "<b>Resampling</b>"
15001500
15011501 #: src/filewriter/filewriter.cc:490
15021502 msgid "Audio mode:"
1503 msgstr "Tryb audio:"
1503 msgstr "tryb audio:"
15041504
15051505 #: src/filewriter/filewriter.cc:493
15061506 msgid "Enforce strict ISO compliance"
16791679
16801680 #: src/gtkui/columns.cc:40
16811681 msgid "Album artist"
1682 msgstr "Wykonawca albumu"
1682 msgstr "Artysta albumu"
16831683
16841684 #: src/gtkui/columns.cc:41 src/qtui/playlist_model.cc:42
16851685 msgid "Track"
1686 msgstr "Ścieżka"
1686 msgstr "Numer ścieżki"
16871687
16881688 #: src/gtkui/columns.cc:42 src/qtui/playlist_model.cc:43
16891689 msgid "Genre"
18281828
18291829 #: src/gtkui/menus.cc:102 src/qtui/menus.cc:96
18301830 msgid "Stop A_fter This Song"
1831 msgstr "Z_atrzymaj odtwarzanie po tej piosence"
1831 msgstr "Z_atrzymaj odtwarzanie po tym utworze"
18321832
18331833 #: src/gtkui/menus.cc:104 src/gtkui/menus.cc:205 src/qtui/menus.cc:98
18341834 #: src/qtui/menus.cc:200
18351835 msgid "Song _Info ..."
1836 msgstr "_Informacje o piosence..."
1836 msgstr "_Informacje o ścieżce..."
18371837
18381838 #: src/gtkui/menus.cc:105
18391839 msgid "Jump to _Time ..."
18411841
18421842 #: src/gtkui/menus.cc:106
18431843 msgid "_Jump to Song ..."
1844 msgstr "Przejdź do piosen_ki..."
1844 msgstr "Przejdź do ścież_ki..."
18451845
18461846 #: src/gtkui/menus.cc:108
18471847 msgid "Set Repeat Point _A"
1848 msgstr "Ustaw punkt powtarzania _A"
1848 msgstr "Ustaw punkt początkowy pętli"
18491849
18501850 #: src/gtkui/menus.cc:109
18511851 msgid "Set Repeat Point _B"
1852 msgstr "Ustaw punkt powtarzania _B"
1852 msgstr "Ustaw punkt końcowy pętli"
18531853
18541854 #: src/gtkui/menus.cc:110
18551855 msgid "_Clear Repeat Points"
19301930
19311931 #: src/gtkui/menus.cc:154 src/qtui/menus.cc:142
19321932 msgid "_Play/Resume"
1933 msgstr "_Odtwórz lub wznów"
1933 msgstr "_Odtwórz/Ponów"
19341934
19351935 #: src/gtkui/menus.cc:155 src/qtui/menus.cc:143
19361936 msgid "_Refresh"
1937 msgstr "O_dśwież"
1937 msgstr "_Wczytaj ponownie"
19381938
19391939 #: src/gtkui/menus.cc:157 src/qtui/menus.cc:147
19401940 msgid "_Sort"
20572057
20582058 #: src/gtkui/menus.cc:206 src/qtui/menus.cc:201
20592059 msgid "_Queue/Unqueue"
2060 msgstr "_Przełącz kolejkę"
2060 msgstr "_Dodaj/Usuń kolejkę"
20612061
20622062 #: src/gtkui/menus.cc:208 src/qtui/menus.cc:203
20632063 msgid "_Open Containing Folder"
20652065
20662066 #: src/gtkui/menus.cc:209 src/qtui/menus.cc:204
20672067 msgid "_Refresh Selected"
2068 msgstr "O_dśwież zaznaczone"
2068 msgstr "Odśwież zaznaczone"
20692069
20702070 #: src/gtkui/menus.cc:211 src/qtui/menus.cc:206
20712071 msgid "Cu_t"
20812081
20822082 #: src/gtkui/menus.cc:214 src/qtui/menus.cc:209
20832083 msgid "Paste at _End"
2084 msgstr "_Wklej na końcu"
2084 msgstr "Wklej na końcu"
20852085
20862086 #: src/gtkui/menus.cc:215 src/qtui/menus.cc:210
20872087 msgid "Select _All"
22322232
22332233 #: src/gtkui/ui_statusbar.cc:117 src/skins/main.cc:474 src/skins-qt/main.cc:460
22342234 msgid "Stopping after song."
2235 msgstr "Zatrzymaj po tej piosence."
2235 msgstr "Zatrzymaj po tym utworze."
22362236
22372237 #: src/hotkey/gui.cc:71
22382238 msgid "Previous track"
2239 msgstr "Poprzedna ścieżka"
2239 msgstr "Poprzedni utwór"
22402240
22412241 #: src/hotkey/gui.cc:73
22422242 msgid "Pause/Resume"
22442244
22452245 #: src/hotkey/gui.cc:75
22462246 msgid "Next track"
2247 msgstr "Następna ścieżka"
2247 msgstr "Następny utwór"
22482248
22492249 #: src/hotkey/gui.cc:76
22502250 msgid "Forward 5 seconds"
25392539
25402540 #: src/lyricwiki/lyricwiki.cc:299 src/lyricwiki-qt/lyricwiki.cc:351
25412541 msgid "Missing song metadata"
2542 msgstr "Brakujące metadane piosenki"
2542 msgstr "Brakujące metadane utworu"
25432543
25442544 #: src/lyricwiki/lyricwiki.cc:310 src/lyricwiki-qt/lyricwiki.cc:362
25452545 msgid "Connecting to lyrics.wikia.com ..."
25802580 "Instrukcja: wprowadź adres URL: tact://uderzenia*liczba jednostek "
25812581 "metrycznych/jednostka metryczna\n"
25822582 "na przykład tact://77 aby wygenerować 77 uderzeń na minutę\n"
2583 "lub tact://60*3/4 aby wygenerować 60 uderzeń na minutę w metrum 3/4"
2583 "lub tact://60*3/4 aby wygenerować 60 uderzeń na minutę w metrum 3/4."
25842584
25852585 #: src/mixer/mixer.cc:38
25862586 msgid "Channel Mixer"
29812981
29822982 #: src/qtui/main_window.cc:110 src/skins/menus.cc:107 src/skins-qt/menus.cc:98
29832983 msgid "Stop After This Song"
2984 msgstr "Zatrzymaj odtwarzanie po tej piosence"
2984 msgstr "Zatrzymaj odtwarzanie po tym utworze"
29852985
29862986 #: src/qtui/menus.cc:69
29872987 msgid "_Open Folder ..."
30173017
30183018 #: src/qtui/playlist_model.cc:41
30193019 msgid "Album Artist"
3020 msgstr "Wykonawca albumu"
3020 msgstr "Artysta albumu"
30213021
30223022 #: src/qtui/playlist_model.cc:44
30233023 msgid "Queue Position"
31753175 #: src/scrobbler2/config_window.cc:91
31763176 msgid "You need to allow Audacious to scrobble tracks to your Last.fm account."
31773177 msgstr ""
3178 "Musisz pozwolić Audacious wysyłać nazwy ścieżek do swojego konta Last.fm."
3178 "Musisz pozwolić Audacious wysyłać nazwy utworów do swojego konta Last.fm."
31793179
31803180 #: src/scrobbler2/scrobbler.cc:29
31813181 msgid "Scrobbler 2.0"
38773877
38783878 #: src/skins-qt/skins_cfg.cc:215 src/skins/skins_cfg.cc:197
38793879 msgid "Scroll song title in both directions"
3880 msgstr "Przewijanie tytułu piosenki w obydwu kierunkach"
3880 msgstr "Przewijanie tytułu utworu w obydwu kierunkach"
38813881
38823882 #: src/skins-qt/skins_cfg.cc:220 src/skins/skins_cfg.cc:202
38833883 msgid "Analyzer"
41394139
41404140 #: src/songchange/song_change.cc:33
41414141 msgid "Song Change"
4142 msgstr "Zmiana piosenki"
4142 msgstr "Polecenie przy zmianie ścieżki"
41434143
41444144 #: src/songchange/song_change.cc:268
41454145 msgid "<b>Commands</b>"
42084208
42094209 #: src/song-info-qt/song-info.cc:33
42104210 msgid "Song Info"
4211 msgstr "Informacje o piosence"
4211 msgstr "Informacje o nagraniu"
42124212
42134213 #: src/soxr/sox-resampler.cc:44
42144214 msgid "SoX Resampler"
43304330
43314331 #: src/statusicon-qt/statusicon.cc:92 src/statusicon/statusicon.cc:385
43324332 msgid "Change playing song"
4333 msgstr "Zmiana bieżącej piosenki"
4333 msgstr "Zmiana bieżącej ścieżki"
43344334
43354335 #: src/statusicon-qt/statusicon.cc:95 src/statusicon/statusicon.cc:388
43364336 msgid "<b>Other Settings</b>"
44124412 "Instrukcja użytkowania: wprowadź URL tone://częstotliwość1;częstotliwość2;"
44134413 "częstotliwość3;...\n"
44144414 "przykładowo wprowadzenie: tone://2000;2005 wytworzy dźwięk o częstotliwości "
4415 "2000 Hz oraz 2005 Hz"
4415 "2000 Hz oraz 2005 Hz."
44164416
44174417 #: src/ui-common/dialogs-qt.cc:31
44184418 msgid "Working ..."
44904490 "Tytuł: %t\n"
44914491 "Autor: %a\n"
44924492 "Z: %f\n"
4493 "Tracker: %T\n"
4493 "Tropiciel: %T\n"
44944494 "Komentarz: %C\n"
44954495 "Rodzaj układu: %c\n"
44964496 "Stereo: %s\n"
44 # Translators:
55 # Alexandro Casanova <shorterfire@gmail.com>, 2013
66 # Conservador Ressurge, 2014
7 # Eduardo Marinho <e@calmaamigo.com>, 2018
87 # Eudes Soares <eudes.sp2007@gmail.com>, 2014
98 # F Marcelo O Amarante <marcelo.amarante@hotmail.com>, 2015
109 # Fuad Saud <fuadksd@gmail.com>, 2012
2524 msgstr ""
2625 "Project-Id-Version: Audacious Plugins\n"
2726 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
28 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
29 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
30 "Last-Translator: Eduardo Marinho <e@calmaamigo.com>\n"
27 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
28 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
29 "Last-Translator: Thomas Lange\n"
3130 "Language-Team: Portuguese (Brazil) (http://www.transifex.com/audacious/"
3231 "audacious/language/pt_BR/)\n"
3332 "Language: pt_BR\n"
34253424
34263425 #: src/skins/equalizer.cc:271 src/skins-qt/equalizer.cc:267
34273426 msgid "Audacious Equalizer"
3428 msgstr "Equalizador do Audacious"
3427 msgstr "Esqualizador do Audacious"
34293428
34303429 #: src/skins/main.cc:447 src/skins-qt/main.cc:433
34313430 msgid "Recording on"
44 # Translators:
55 # Alexander Orlov <alxorlov@pochta.ru>, 2007
66 # Денис <alpi_bel@mail.ru>, 2014
7 # Andrei Stepanov <adem4ik@gmail.com>, 2014-2015
7 # Andrei Stepanov, 2014-2015
88 # Danila E <KnightDanila@gmail.com>, 2018
99 # dartraiden, 2018
1010 # dartraiden, 2018
4040 # Someonefree <drag-sasha@mail.ru>, 2013
4141 # Oleg <kvantarium@gmail.com>, 2012
4242 # Victor Ponomarev <victor.a.ponomarev@gmail.com>, 2013
43 # Volk Daemon <volk-daemon@rambler.ru>, 2016,2018
43 # Volk Daemon <volk-daemon@rambler.ru>, 2016
4444 # Алексей <kvadrocu7@gmail.com>, 2013
4545 # Денис <alpi_bel@mail.ru>, 2014-2015
4646 # Денис Локтев <den32ds@gmail.com>, 2017
47 # Петро Проценко <petruk3@gmail.com>, 2018
4847 msgid ""
4948 msgstr ""
5049 "Project-Id-Version: Audacious Plugins\n"
5150 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
52 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
53 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
54 "Last-Translator: Volk Daemon <volk-daemon@rambler.ru>\n"
51 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
52 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
53 "Last-Translator: Thomas Lange\n"
5554 "Language-Team: Russian (http://www.transifex.com/audacious/audacious/"
5655 "language/ru/)\n"
5756 "Language: ru\n"
8180
8281 #: src/adplug/adplug-xmms.cc:298
8382 msgid "16-bit output (if unchecked, output is 8-bit)"
84 msgstr "16-битный вывод (если не выбрано, 8-битный вывод)"
83 msgstr ""
8584
8685 #: src/adplug/adplug-xmms.cc:300
8786 msgid "Duplicate mono output to two channels"
88 msgstr "Дублировать вывод на оба канала"
87 msgstr ""
8988
9089 #: src/adplug/adplug-xmms.cc:302
9190 msgid "Sample rate"
111110
112111 #: src/adplug/adplug-xmms.cc:305
113112 msgid "Repeat song in endless loop"
114 msgstr "Повторить песню в бесконечном цикле"
113 msgstr ""
115114
116115 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
117116 msgid "Alarm"
10031002
10041003 #: src/cdaudio/cdaudio-ng.cc:611
10051004 msgid "Failed to create the CDDB connection."
1006 msgstr "Не удалось создать соединение CDDB."
1005 msgstr ""
10071006
10081007 #: src/cdaudio/cdaudio-ng.cc:677
10091008 msgid "Failed to query the CDDB server"
10171016 #: src/cdaudio/cdaudio-ng.cc:703
10181017 #, c-format
10191018 msgid "Failed to read the CDDB info: %s"
1020 msgstr "Не удалось прочитать информацию CDDB: %s"
1019 msgstr ""
10211020
10221021 #: src/cd-menu-items/cd-menu-items.cc:33
10231022 msgid "Audio CD Menu Items"
10251024
10261025 #: src/cd-menu-items/cd-menu-items.cc:45
10271026 msgid "Pla_y CD"
1028 msgstr "Воспроизведение компакт-дисков"
1027 msgstr ""
10291028
10301029 #: src/cd-menu-items/cd-menu-items.cc:45
10311030 msgid "_Add CD"
11991198
12001199 #: src/delete-files/delete-files.cc:120
12011200 msgid "No files are selected."
1202 msgstr "Файлы не выбраны"
1201 msgstr ""
12031202
12041203 #: src/delete-files/delete-files.cc:125
12051204 #, c-format
12061205 msgid "Do you want to move %s to the trash?"
1207 msgstr "Вы хотите переместить %s в корзину?"
1206 msgstr ""
12081207
12091208 #: src/delete-files/delete-files.cc:126
12101209 #, c-format
12111210 msgid "Do you want to permanently delete %s?"
1212 msgstr "Вы хотите удалить навсегда %s?"
1211 msgstr ""
12131212
12141213 #: src/delete-files/delete-files.cc:133
12151214 #, c-format
12161215 msgid "Do you want to move %d files to the trash?"
1217 msgstr "Вы хотите переместить %d файлы в корзину?"
1216 msgstr ""
12181217
12191218 #: src/delete-files/delete-files.cc:134
12201219 #, c-format
12211220 msgid "Do you want to permanently delete %d files?"
1222 msgstr "Вы хотите удалить файлы %d навсегда?"
1221 msgstr ""
12231222
12241223 #: src/delete-files/delete-files.cc:146
12251224 msgid "Move to trash"
23132312 "\n"
23142313 "Do you want to continue?"
23152314 msgstr ""
2316 "Не рекомендуется связывать основные кнопки мыши без модификаторов.\n"
2317 "\n"
2318 "Вы хотите продолжить?"
23192315
23202316 #: src/hotkey/gui.cc:236
23212317 msgid "Binding mouse buttons"
30293025
30303026 #: src/qtui/playlist_model.cc:48
30313027 msgid "Custom Title"
3032 msgstr "Пользовательский заголовок"
3028 msgstr ""
30333029
30343030 #: src/qtui/qtui.cc:39
30353031 msgid "Qt Interface"
32253221
32263222 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32273223 msgid "Number of results to show:"
3228 msgstr "Количество результатов, чтобы показать:"
3224 msgstr ""
32293225
32303226 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32313227 msgid "Rescan library at startup"
3232 msgstr "Пересканировать библиотеку при запуске"
3228 msgstr ""
32333229
32343230 #: src/search-tool-qt/search-tool-qt.cc:305
32353231 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
42424238
42434239 #: src/soxr/sox-resampler.cc:168
42444240 msgid "Ultra High"
4245 msgstr "Сверхвысокий"
4241 msgstr ""
42464242
42474243 #: src/soxr/sox-resampler.cc:172
42484244 msgid "Minimum"
4249 msgstr "Минимальный"
4245 msgstr ""
42504246
42514247 #: src/soxr/sox-resampler.cc:173
42524248 msgid "Intermediate"
4253 msgstr "Промежуточный"
4249 msgstr ""
42544250
42554251 #: src/soxr/sox-resampler.cc:174
42564252 msgid "Linear"
4257 msgstr "Линейный"
4253 msgstr ""
42584254
42594255 #: src/soxr/sox-resampler.cc:178
42604256 msgid "Quality:"
42624258
42634259 #: src/soxr/sox-resampler.cc:181
42644260 msgid "Phase:"
4265 msgstr "Фаза"
4261 msgstr ""
42664262
42674263 #: src/soxr/sox-resampler.cc:185
42684264 msgid "Allow aliasing"
4269 msgstr "Разрешить псевдонимы"
4265 msgstr ""
42704266
42714267 #: src/soxr/sox-resampler.cc:187
42724268 msgid "Use steep filter"
88 # Henrik Mattsson-Mårn <h@reglage.net>, 2015
99 # Jonatan Nyberg, 2018
1010 # Jonatan Nyberg, 2017-2018
11 # Kristoffer Grundström <hamnisdude@gmail.com>, 2016
11 # Kristoffer Grundström <kristoffer.grundstrom1983@gmail.com>, 2016
1212 # Luna Jernberg <bittin@cafe8bitar.se>, 2014
1313 msgid ""
1414 msgstr ""
1515 "Project-Id-Version: Audacious Plugins\n"
1616 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
17 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
18 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
17 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
18 "PO-Revision-Date: 2018-07-31 15:09+0000\n"
1919 "Last-Translator: Jonatan Nyberg\n"
2020 "Language-Team: Swedish (http://www.transifex.com/audacious/audacious/"
2121 "language/sv/)\n"
659659
660660 #: src/aosd/aosd_ui.cc:209
661661 msgid "Max OSD width:"
662 msgstr "Största OSD-bredd:"
662 msgstr "Max OSD-bredd:"
663663
664664 #: src/aosd/aosd_ui.cc:220
665665 msgid "Multi-Monitor options"
14871487
14881488 #: src/filewriter/filewriter.cc:510
14891489 msgid "Maximum bitrate:"
1490 msgstr "Högsta överföringskapacitet:"
1490 msgstr "Maximal överföringskapacitet:"
14911491
14921492 #: src/filewriter/filewriter.cc:514
14931493 msgid "Average bitrate:"
17321732
17331733 #: src/gtkui/menus.cc:84 src/qtui/menus.cc:75
17341734 msgid "Search _Library"
1735 msgstr "Sök i _biblioteket"
1735 msgstr "Sök i _bibliotek"
17361736
17371737 #: src/gtkui/menus.cc:86 src/qtui/menus.cc:77
17381738 msgid "A_bout ..."
21182118 #: src/gtkui/ui_gtk.cc:796 src/qtui/main_window.cc:101 src/skins/menus.cc:86
21192119 #: src/skins-qt/menus.cc:77
21202120 msgid "Search Library"
2121 msgstr "Sök i biblioteket"
2121 msgstr "Sök i bibliotek"
21222122
21232123 #: src/gtkui/ui_gtk.cc:804 src/qtui/main_window.cc:102
21242124 msgid "Open Files"
23502350 "JACK supports only floating-point audio. You must change the output bit "
23512351 "depth to floating-point in Audacious settings."
23522352 msgstr ""
2353 "JACK stöder endast flyttal-ljud. Du måste ändra utmatningsbitdjupet till "
2354 "flyttal i Audacious-inställningar."
23552353
23562354 #: src/jack/jack-ng.cc:205
23572355 msgid "Failed to connect to the JACK server; is it running?"
27482746 "You should have received a copy of the GNU General Public License along with "
27492747 "this program. If not, see <http://www.gnu.org/licenses/>."
27502748 msgstr ""
2751 "Desktop Notifications Plugin för Audacious\n"
2752 "Copyright (C) 2010 Maximilian Bogner\n"
2753 "Copyright (C) 2011-2013 John Lindgren och Jean-Alexandre Anglès d'Auriac\n"
2754 "\n"
2755 "This plugin is free software: you can redistribute it and/or modify it under "
2756 "the terms of the GNU General Public License as published by the Free "
2757 "Software Foundation, either version 3 of the License, or (at your option) "
2758 "any later version.\n"
2759 "\n"
2760 "This plugin is distributed in the hope that it will be useful, but WITHOUT "
2761 "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or "
2762 "FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for "
2763 "more details.\n"
2764 "\n"
2765 "You should have received a copy of the GNU General Public License along with "
2766 "this program. If not, see <http://www.gnu.org/licenses/>."
27672749
27682750 #: src/notify/notify.cc:102
27692751 msgid "Show playback controls"
31703152
31713153 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
31723154 msgid "Rescan library at startup"
3173 msgstr "Sök igenom biblioteket vid uppstart"
3155 msgstr "Sök igenom bibliotek vid uppstart"
31743156
31753157 #: src/search-tool-qt/search-tool-qt.cc:305
31763158 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
33853367
33863368 #: src/skins/equalizer.cc:271 src/skins-qt/equalizer.cc:267
33873369 msgid "Audacious Equalizer"
3388 msgstr "Audacious-equalizer"
3370 msgstr "Audacious Equalizer"
33893371
33903372 #: src/skins/main.cc:447 src/skins-qt/main.cc:433
33913373 msgid "Recording on"
40204002 "this program; if not, write to the Free Software Foundation, Inc., 51 "
40214003 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
40224004 msgstr ""
4023 "Baserat på xmms_sndfile-insticksmodulen:\n"
4024 "Copyright (C) 2000, 2002 Erik de Castro Lopo\n"
4025 "\n"
4026 "Anpassad för Audacious av Tony Vroon <chainsaw@gentoo.org>\n"
4027 "\n"
4028 "This program is free software; you can redistribute it and/or modify it "
4029 "under the terms of the GNU General Public License as published by the Free "
4030 "Software Foundation; either version 2 of the License, or (at your option) "
4031 "any later version.\n"
4032 "\n"
4033 "This program is distributed in the hope that it will be useful, but WITHOUT "
4034 "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or "
4035 "FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for "
4036 "more details.\n"
4037 "\n"
4038 "You should have received a copy of the GNU General Public License along with "
4039 "this program; if not, write to the Free Software Foundation, Inc., 51 "
4040 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
40414005
40424006 #: src/sndio/sndio.cc:43
40434007 msgid "Sndio Output"
42664230
42674231 #: src/statusicon-qt/statusicon.cc:96 src/statusicon/statusicon.cc:389
42684232 msgid "Disable the popup window"
4269 msgstr "Inaktivera poppupp-fönstret"
4233 msgstr "Inaktivera popup-fönstret"
42704234
42714235 #: src/statusicon-qt/statusicon.cc:98 src/statusicon/statusicon.cc:391
42724236 msgid "Close to the system tray"
+377
-685
po/tr.po less more
44 # Translators:
55 # aamet <aaydin159@gmail.com>, 2012
66 # aamet <aaydin159@gmail.com>, 2012
7 # Dragon Blogger <dodokur@gmail.com>, 2016
7 # Dragon xarax <dodokur@gmail.com>, 2016
88 # elmasevmem <drmxmyt@gmail.com>, 2013
99 # elmasevmem <drmxmyt@gmail.com>, 2013
1010 # Emre FIRAT <emrefirat93@gmail.com>, 2013
2323 # tarkan255 <t.oguzman@hotmail.com>, 2012
2424 # Tolga <tolsen92@outlook.com>, 2014
2525 # Volkan Gezer <volkangezer@gmail.com>, 2013,2015
26 # yaşar çiv <yasarciv67@gmail.com>, 2018
2726 msgid ""
2827 msgstr ""
2928 "Project-Id-Version: Audacious Plugins\n"
3029 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
31 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
32 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
33 "Last-Translator: yaşar çiv <yasarciv67@gmail.com>\n"
30 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
31 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
32 "Last-Translator: Thomas Lange\n"
3433 "Language-Team: Turkish (http://www.transifex.com/audacious/audacious/"
3534 "language/tr/)\n"
3635 "Language: tr\n"
5453
5554 #: src/adplug/adplug-xmms.cc:297 src/sid/xs_config.cc:61
5655 msgid "<b>Output</b>"
57 msgstr "<b>Çıktı</b>"
56 msgstr ""
5857
5958 #: src/adplug/adplug-xmms.cc:298
6059 msgid "16-bit output (if unchecked, output is 8-bit)"
61 msgstr "16-bit çıktı (işaretlenmemişse, çıktı 8-bittir)"
60 msgstr ""
6261
6362 #: src/adplug/adplug-xmms.cc:300
6463 msgid "Duplicate mono output to two channels"
65 msgstr "İki kanala mono kopya çoğalt"
64 msgstr ""
6665
6766 #: src/adplug/adplug-xmms.cc:302
6867 msgid "Sample rate"
69 msgstr "Örnekleme oranı"
68 msgstr ""
7069
7170 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
7271 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
8887
8988 #: src/adplug/adplug-xmms.cc:305
9089 msgid "Repeat song in endless loop"
91 msgstr "Sonsuz döngüde şarkıyı tekrarla"
90 msgstr ""
9291
9392 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
9493 msgid "Alarm"
324323
325324 #: src/alarm/interface.cc:361
326325 msgid "Playlist (optional)"
327 msgstr "Çalma Listesi (isteğe bağlı)"
326 msgstr "Çalma Listesi(isteğe bağlı)"
328327
329328 #: src/alarm/interface.cc:365
330329 msgid "Select a playlist"
348347
349348 #: src/alsa/alsa.h:64
350349 msgid "ALSA Output"
351 msgstr "ALSA Çıkışı"
350 msgstr "ALSA Çıktısı"
352351
353352 #: src/alsa/config.cc:28
354353 msgid ""
444443
445444 #: src/amidiplug/i_configure.cc:110
446445 msgid "Override default reverb:"
447 msgstr "Varsayılan yankıyı geçersiz kıl:"
446 msgstr "Varsayılan reverb'ı geçersiz kıl:"
448447
449448 #: src/amidiplug/i_configure.cc:112 src/amidiplug/i_configure.cc:120
450449 msgid "On"
452451
453452 #: src/amidiplug/i_configure.cc:118
454453 msgid "Override default chorus:"
455 msgstr "Varsayılan koroyu geçersiz kıl:"
454 msgstr "Varsayılan chorus'u geçersiz kıl:"
456455
457456 #: src/amidiplug/i_configure.cc:128 src/console/plugin.cc:29
458457 msgid "<b>Playback</b>"
464463
465464 #: src/amidiplug/i_configure.cc:131 src/speedpitch/speed-pitch.cc:257
466465 msgid "semitones"
467 msgstr "yarım tonlar"
466 msgstr "semitonlar"
468467
469468 #: src/amidiplug/i_configure.cc:132
470469 msgid "Drum shift:"
471 msgstr "Davul tonlaması:"
470 msgstr ""
472471
473472 #: src/amidiplug/i_configure.cc:134
474473 msgid "note numbers"
476475
477476 #: src/amidiplug/i_configure.cc:135
478477 msgid "Skip leading silence"
479 msgstr "Baştaki sessizliği atla"
478 msgstr ""
480479
481480 #: src/amidiplug/i_configure.cc:137
482481 msgid "Skip trailing silence"
483 msgstr "Sondaki sessizliği atla"
482 msgstr ""
484483
485484 #: src/amidiplug/i_configure.cc:141
486485 msgid "<b>SoundFont</b>"
487 msgstr "<b>SoundFont</b>"
486 msgstr ""
488487
489488 #: src/amidiplug/i_configure.cc:145
490489 msgid "<b>Synthesizer</b>"
491 msgstr "<b>Sentezleyici</b>"
490 msgstr ""
492491
493492 #: src/amidiplug/i_configure.cc:150 src/console/plugin.cc:45
494493 #: src/filewriter/filewriter.cc:473 src/sid/xs_config.cc:65
533532
534533 #: src/amidiplug/i_fileinfo.cc:207
535534 msgid "No. of Tracks:"
536 msgstr "Parça Sayısı:"
535 msgstr ""
537536
538537 #: src/amidiplug/i_fileinfo.cc:213
539538 msgid "variable"
573572
574573 #: src/ampache/ampache.cc:33
575574 msgid "Ampache Browser"
576 msgstr "Ampache Tarayıcı"
575 msgstr ""
577576
578577 #: src/ampache/ampache.cc:46
579578 msgid ""
583582 "Copyright (C) Róbert Čerňanský and John Lindgren\n"
584583 "License: GNU GPLv3"
585584 msgstr ""
586 "Audacious için Ampache Tarayıcı\n"
587 "http://ampache-browser.org/\n"
588 "\n"
589 "Róbert Čerňanský ve John Lindgren'in Telif Hakları (C)\n"
590 "Lisans: GNU GPLv3"
591585
592586 #: src/aosd/aosd.cc:31
593587 msgid ""
599593 "Based in part on Evan Martin's Ghosd library:\n"
600594 "http://neugierig.org/software/ghosd/"
601595 msgstr ""
602 "Audacious OSD\n"
603 "http://www.develia.org/projects.php?p=audacious#aosd\n"
604 "\n"
605 "Giacomo Lozito tarafından yazıldı <james@develia.org>\n"
606 "\n"
607 "Evan Martin's Ghosd kütüphanesinde kısmen yer aldı:\n"
608 "http://neugierig.org/software/ghosd/"
609596
610597 #: src/aosd/aosd.h:37
611598 msgid "AOSD (On-Screen Display)"
612 msgstr "AOSD (On-Screen Display)"
599 msgstr ""
613600
614601 #: src/aosd/aosd_style.cc:54
615602 msgid "Rectangle"
633620
634621 #: src/aosd/aosd_trigger.cc:50
635622 msgid "Triggers OSD when a playlist entry is played."
636 msgstr "Çalma listesindeki girdi oynatıldığında OSD'yi başlatır."
623 msgstr "Parça listesindeki girdi oynatıldığında OSD'yi başlatır."
637624
638625 #: src/aosd/aosd_trigger.cc:55
639626 msgid "Title Change"
641628
642629 #: src/aosd/aosd_trigger.cc:56
643630 msgid "Triggers OSD when the song title changes (for internet streams)."
644 msgstr "Şarkı adı değiştiğinde OSD'yi tetikler (internet akışları için)."
631 msgstr ""
645632
646633 #: src/aosd/aosd_trigger.cc:61
647634 msgid "Pause On"
732719 #: src/aosd/aosd_ui.cc:512
733720 #, c-format
734721 msgid "Color %i:"
735 msgstr "Renk %i:"
722 msgstr "Renkler %i:"
736723
737724 #: src/aosd/aosd_ui.cc:599
738725 msgid "Enable trigger"
744731
745732 #: src/aosd/aosd_ui.cc:653
746733 msgid "Composite manager detected"
747 msgstr "Bileşiklik yöneticisi tespit edildi"
734 msgstr "Composite yöneticisi tespit edildi"
748735
749736 #: src/aosd/aosd_ui.cc:660
750737 msgid ""
752739 "unless you know that you have one running, please activate a composite "
753740 "manager otherwise the OSD won't work properly"
754741 msgstr ""
755 "Bileşiklik yöneticisi tespit edilemedi;\n"
756 "Çalışan bir bileşiklik yöneticisinin olduğundan emin değilseniz lütfen "
757 "OSD'nin düzgün çalışması için bir bileşiklik yöneticisi çalıştırınız"
742 "Composite yöneticisi tespit edilemedi;\n"
743 "Çalışan bir Composite yöneticisinin olduğundan emin değilseniz lütfen "
744 "OSD'nin düzgün çalışması için bir Composite yöneticisi çalıştırınız"
758745
759746 #: src/aosd/aosd_ui.cc:668
760747 msgid "Composite manager not required for fake transparency"
761 msgstr "Sahte şeffaflık için bileşiklik yöneticisi gerekli değil"
748 msgstr "Sahte şeffaflık için composite yöneticisi gerekli değil"
762749
763750 #: src/aosd/aosd_ui.cc:705
764751 msgid "Transparency"
770757
771758 #: src/aosd/aosd_ui.cc:713
772759 msgid "Real transparency (requires X Composite Ext.)"
773 msgstr "Gerçek Şeffaflık (X Bileşiklik Eklentisi gerekli)"
760 msgstr "Gerçek Şeffaflık (X Composite Eklentisi gerekli)"
774761
775762 #: src/aosd/aosd_ui.cc:754
776763 msgid "Composite extension not loaded"
777 msgstr "Bileşiklik eklentisi yüklü değil"
764 msgstr "Composite eklentisi yüklü değil"
778765
779766 #: src/aosd/aosd_ui.cc:771
780767 #, c-format
811798
812799 #: src/asx3/asx3.cc:35
813800 msgid "ASXv3 Playlists"
814 msgstr "ASXv3 Çalma listesi"
801 msgstr "ASXv3 Parça listesi"
815802
816803 #: src/asx/asx.cc:33
817804 msgid "ASXv1/ASXv2 Playlists"
818 msgstr "ASXv1/ASXv2 Çalma Listesi"
805 msgstr ""
819806
820807 #: src/audpl/audpl.cc:33
821808 msgid "Audacious Playlists (audpl)"
822 msgstr "Audacious Çalma Listeleri (audpl)"
809 msgstr ""
823810
824811 #: src/blur_scope/blur_scope.cc:39
825812 msgid "<b>Color</b>"
827814
828815 #: src/blur_scope/blur_scope.cc:55
829816 msgid "Blur Scope"
830 msgstr "Bulanıklık Kapsamı"
817 msgstr ""
831818
832819 #: src/bs2b/plugin.cc:38
833820 msgid "Bauer Stereophonic-to-Binaural (BS2B)"
834 msgstr "Bauer Stereophonic-to-Binaural (BS2B)"
821 msgstr ""
835822
836823 #: src/bs2b/plugin.cc:129
837824 msgid "Presets:"
839826
840827 #: src/bs2b/plugin.cc:136
841828 msgid "Feed level:"
842 msgstr "Besleme seviyesi:"
829 msgstr ""
843830
844831 #: src/bs2b/plugin.cc:138
845832 msgid "x1/10 dB"
846 msgstr "x1/10 dB"
833 msgstr ""
847834
848835 #: src/bs2b/plugin.cc:139
849836 msgid "Cut frequency:"
850 msgstr "Kesim frekansı:"
837 msgstr ""
851838
852839 #: src/cairo-spectrum/cairo-spectrum.cc:41
853840 msgid "Spectrum Analyzer"
854 msgstr "İzgesel Çözümleyici"
841 msgstr ""
855842
856843 #: src/cdaudio/cdaudio-ng.cc:71
857844 msgid "Audio CD Plugin"
858 msgstr "Ses CD'si Eklentisi"
845 msgstr "Ses CD'si eklentisi"
859846
860847 #: src/cdaudio/cdaudio-ng.cc:118
861848 msgid ""
868855 "\n"
869856 "This was a Google Summer of Code 2007 project."
870857 msgstr ""
871 "Telif Hakkı (C) 2007-2012 Calin Crisan <ccrisan@gmail.com> ve diğerleri.\n"
872 "\n"
873 "Libcdio geliştiricilerine çok teşekkürler <http://www.gnu.org/software/"
874 "libcdio/>\n"
875 "ve libcddb geliştiricilerine <http://libcddb.sourceforge.net/>.\n"
876 "\n"
877 "Ayrıca bana mentörlük ve rehberlik ettiği için Tony Vroon'a teşekkür "
878 "ederim.\n"
879 "Bu bir Google Summer of Code 2007 projesiydi."
880858
881859 #: src/cdaudio/cdaudio-ng.cc:134
882860 msgid "<b>Device</b>"
883 msgstr "<b>Aygıt</b>"
861 msgstr ""
884862
885863 #: src/cdaudio/cdaudio-ng.cc:135
886864 msgid "Read speed:"
887 msgstr "Okuma hızı:"
865 msgstr ""
888866
889867 #: src/cdaudio/cdaudio-ng.cc:138
890868 msgid "Override device:"
891 msgstr "Aygıtı geçersiz kıl:"
869 msgstr ""
892870
893871 #: src/cdaudio/cdaudio-ng.cc:140
894872 msgid "<b>Metadata</b>"
896874
897875 #: src/cdaudio/cdaudio-ng.cc:141
898876 msgid "Use CD-Text"
899 msgstr "CD-Text kullan"
877 msgstr ""
900878
901879 #: src/cdaudio/cdaudio-ng.cc:143
902880 msgid "Use CDDB"
903 msgstr "CDDB kullan"
881 msgstr ""
904882
905883 #: src/cdaudio/cdaudio-ng.cc:145
906884 msgid "Use HTTP instead of CDDBP"
920898
921899 #: src/cdaudio/cdaudio-ng.cc:220
922900 msgid "Failed to initialize cdio subsystem."
923 msgstr "Cdio alt sistemi başlatılamadı."
901 msgstr ""
924902
925903 #: src/cdaudio/cdaudio-ng.cc:250
926904 #, c-format
927905 msgid "Invalid URI %s."
928 msgstr "Geçersiz URL %s."
906 msgstr ""
929907
930908 #: src/cdaudio/cdaudio-ng.cc:252
931909 #, c-format
932910 msgid "Track %d not found."
933 msgstr "%d parçası bulunamadı."
911 msgstr ""
934912
935913 #: src/cdaudio/cdaudio-ng.cc:254
936914 #, c-format
937915 msgid "Track %d is a data track."
938 msgstr "%d bir veri parçasıdır."
916 msgstr ""
939917
940918 #: src/cdaudio/cdaudio-ng.cc:329
941919 msgid "Error reading audio CD."
942 msgstr "Ses CD'si okunurken hata oluştu."
920 msgstr ""
943921
944922 #: src/cdaudio/cdaudio-ng.cc:398
945923 msgid "Audio CD"
948926 #: src/cdaudio/cdaudio-ng.cc:434 src/cdaudio/cdaudio-ng.cc:443
949927 #, c-format
950928 msgid "Failed to open CD device %s."
951 msgstr "%s CD aygıtı açılamadı."
929 msgstr ""
952930
953931 #: src/cdaudio/cdaudio-ng.cc:446
954932 msgid "No audio capable CD drive found."
955 msgstr "Ses özellikli CD sürücüsü bulunamadı."
933 msgstr ""
956934
957935 #: src/cdaudio/cdaudio-ng.cc:469
958936 msgid "Drive is empty."
964942
965943 #: src/cdaudio/cdaudio-ng.cc:495
966944 msgid "Failed to finish initializing opened CD drive."
967 msgstr "Açılan CD sürücüsü başlatılamadı."
945 msgstr ""
968946
969947 #: src/cdaudio/cdaudio-ng.cc:508
970948 msgid "Failed to retrieve first/last track number."
971 msgstr "İlk/son parça numarası alınamadı."
949 msgstr ""
972950
973951 #: src/cdaudio/cdaudio-ng.cc:529
974952 #, c-format
975953 msgid "Cannot read start/end LSN for track %d."
976 msgstr "%d parçası için başlangıç/bitiş LSN okunamıyor."
954 msgstr ""
977955
978956 #: src/cdaudio/cdaudio-ng.cc:611
979957 msgid "Failed to create the CDDB connection."
980 msgstr "CDDB bağlantısı oluşturulamadı."
958 msgstr ""
981959
982960 #: src/cdaudio/cdaudio-ng.cc:677
983961 msgid "Failed to query the CDDB server"
984 msgstr "CDDB sunucusu sorgulanamadı"
962 msgstr ""
985963
986964 #: src/cdaudio/cdaudio-ng.cc:679
987965 #, c-format
988966 msgid "Failed to query the CDDB server: %s"
989 msgstr "CDDB sunucusu sorgulanamadı: %s"
967 msgstr ""
990968
991969 #: src/cdaudio/cdaudio-ng.cc:703
992970 #, c-format
993971 msgid "Failed to read the CDDB info: %s"
994 msgstr "CDDB bilgisi okunamadı: %s"
972 msgstr ""
995973
996974 #: src/cd-menu-items/cd-menu-items.cc:33
997975 msgid "Audio CD Menu Items"
998 msgstr "Ses CD'si Menü Öğeleri"
976 msgstr ""
999977
1000978 #: src/cd-menu-items/cd-menu-items.cc:45
1001979 msgid "Pla_y CD"
1002 msgstr "CD'yi o_ynat"
980 msgstr ""
1003981
1004982 #: src/cd-menu-items/cd-menu-items.cc:45
1005983 msgid "_Add CD"
1006 msgstr "CD _Ekle"
984 msgstr ""
1007985
1008986 #: src/compressor/compressor.cc:45
1009987 msgid "<b>Compression</b>"
1010 msgstr "<b>Sıkıştırma</b>"
988 msgstr ""
1011989
1012990 #: src/compressor/compressor.cc:46
1013991 msgid "Center volume:"
1014 msgstr "Merkez ses seviyesi:"
992 msgstr ""
1015993
1016994 #: src/compressor/compressor.cc:49
1017995 msgid "Dynamic range:"
1018 msgstr "Dinamik aralık:"
996 msgstr "Dinamik alan:"
1019997
1020998 #: src/compressor/compressor.cc:57
1021999 msgid ""
10221000 "Dynamic Range Compression Plugin for Audacious\n"
10231001 "Copyright 2010-2014 John Lindgren"
10241002 msgstr ""
1025 "Audacious için Dinamik Aralık Sıkıştırma Eklentisi\n"
1026 "Telif Hakkı 2010-2014 John Lindgren"
10271003
10281004 #: src/compressor/compressor.cc:64
10291005 msgid "Dynamic Range Compressor"
1030 msgstr "Dinamik Aralık Sıkıştırıcısı"
1006 msgstr ""
10311007
10321008 #: src/console/plugin.cc:15
10331009 msgid ""
10381014 "William Pitcock <nenolod@dereferenced.org>\n"
10391015 "Shay Green <gblargg@gmail.com>"
10401016 msgstr ""
1041 "Game_Music_Emu 0.5.2 tabanlı konsol müzik kod çözücü motoru\n"
1042 "Desteklenen biçimler: AY, GBS, GYM, HES, KSS, NSF, NSFE, SAP, SPC, VGM, VGZ\n"
1043 "\n"
1044 "Audacious eklentisi:\n"
1045 "William Pitcock <nenolod@dereferenced.org>\n"
1046 "Shay Green <gblargg@gmail.com>"
10471017
10481018 #: src/console/plugin.cc:30
10491019 msgid "Bass:"
10631033
10641034 #: src/console/plugin.cc:42 src/modplug/plugin_main.cc:62
10651035 msgid "<b>Resampling</b>"
1066 msgstr "<b>Yeniden örnekleme</b>"
1036 msgstr ""
10671037
10681038 #: src/console/plugin.cc:43
10691039 msgid "Enable audio resampling"
10711041
10721042 #: src/console/plugin.cc:49
10731043 msgid "<b>SPC</b>"
1074 msgstr "<b>SPC</b>"
1044 msgstr ""
10751045
10761046 #: src/console/plugin.cc:50
10771047 msgid "Ignore length from SPC tags"
10871057
10881058 #: src/coreaudio/coreaudio.cc:53
10891059 msgid "CoreAudio output"
1090 msgstr "Çekirdek Ses çıkışı"
1060 msgstr ""
10911061
10921062 #: src/coreaudio/coreaudio.cc:156
10931063 msgid ""
11001070 "Based on SDL Output Plugin for Audacious\n"
11011071 "Copyright 2010 John Lindgren"
11021072 msgstr ""
1103 "Audacious için Çekirdek Ses çıkışı eklentisi\n"
1104 "Telif Hakkı 2014 William Pitcock\n"
1105 "Telif Hakkı 2017,18 René J.V. Bertin\n"
1106 " (asıl kod ve Apple örneklerinden\n"
1107 " uyarlanan kod , (C) Apple 2013)\n"
1108 "\n"
1109 "Audacious için SDL Çıkış Eklentisine Dayalı\n"
1110 "Telif Hakkı 2010 John Lindgren"
11111073
11121074 #: src/coreaudio/coreaudio.cc:172
11131075 msgid "Use exclusive mode"
1114 msgstr "Özel mod kullan"
1076 msgstr ""
11151077
11161078 #: src/coreaudio/coreaudio.cc:174
11171079 msgid "Use bit perfect audio (adapt device sampling rate)"
1118 msgstr "Bit mükemmel ses kullan (cihaz örnekleme oranını uyarla)"
1080 msgstr ""
11191081
11201082 #: src/crossfade/crossfade.cc:43
11211083 msgid ""
11221084 "Crossfade Plugin for Audacious\n"
11231085 "Copyright 2010-2014 John Lindgren"
11241086 msgstr ""
1125 "Audacious için Çapraz Geçiş Eklentisi\n"
1126 "Telif Hakkı 2010-2014 John Lindgren"
11271087
11281088 #: src/crossfade/crossfade.cc:47
11291089 msgid "<b>Crossfade</b>"
1130 msgstr "<b>Çapraz Geçiş</b>"
1090 msgstr ""
11311091
11321092 #: src/crossfade/crossfade.cc:48
11331093 msgid "On automatic song change"
1134 msgstr "Otomatik şarkı değişikliğinde"
1094 msgstr ""
11351095
11361096 #: src/crossfade/crossfade.cc:50 src/crossfade/crossfade.cc:56
11371097 msgid "Overlap:"
1138 msgstr "Üst üste gelme:"
1098 msgstr ""
11391099
11401100 #: src/crossfade/crossfade.cc:54
11411101 msgid "On seek or manual song change"
1142 msgstr "Aramada veya manuel şarkıda değişiklik"
1102 msgstr ""
11431103
11441104 #: src/crossfade/crossfade.cc:60
11451105 msgid "<b>Tip</b>"
1146 msgstr "<b>Uç</b>"
1106 msgstr ""
11471107
11481108 #: src/crossfade/crossfade.cc:61
11491109 msgid ""
11501110 "For better crossfading, enable\n"
11511111 "the Silence Removal effect."
11521112 msgstr ""
1153 "Daha iyi çapraz geçiş için\n"
1154 "Sessizlik Kaldırma efektini etkinleştirin."
11551113
11561114 #: src/crossfade/crossfade.cc:71
11571115 msgid "Crossfade"
1158 msgstr "Çapraz Geçiş"
1116 msgstr ""
11591117
11601118 #: src/crystalizer/crystalizer.cc:31
11611119 msgid "<b>Crystalizer</b>"
1162 msgstr "<b>Billurlaştırıcı</b>"
1120 msgstr ""
11631121
11641122 #: src/crystalizer/crystalizer.cc:32 src/stereo_plugin/stereo.cc:45
11651123 msgid "Intensity:"
1166 msgstr "Yoğunluk:"
1124 msgstr ""
11671125
11681126 #: src/crystalizer/crystalizer.cc:43
11691127 msgid "Crystalizer"
1170 msgstr "Billurlaştırıcı"
1128 msgstr ""
11711129
11721130 #: src/cue/cue.cc:42
11731131 msgid "Cue Sheet Plugin"
1174 msgstr "İşaret Sayfası Eklentisi"
1132 msgstr ""
11751133
11761134 #: src/delete-files/delete-files.cc:53 src/delete-files/delete-files.cc:215
11771135 #: src/delete-files/delete-files.cc:230
11801138
11811139 #: src/delete-files/delete-files.cc:120
11821140 msgid "No files are selected."
1183 msgstr "Hiçbir dosya seçilmedi."
1141 msgstr ""
11841142
11851143 #: src/delete-files/delete-files.cc:125
11861144 #, c-format
11871145 msgid "Do you want to move %s to the trash?"
1188 msgstr "%s'i çöpe taşımak istiyor musunuz?"
1146 msgstr ""
11891147
11901148 #: src/delete-files/delete-files.cc:126
11911149 #, c-format
11921150 msgid "Do you want to permanently delete %s?"
1193 msgstr "%s'i kalıcı olarak silmek istiyor musunuz?"
1151 msgstr ""
11941152
11951153 #: src/delete-files/delete-files.cc:133
11961154 #, c-format
11971155 msgid "Do you want to move %d files to the trash?"
1198 msgstr "%d dosyalarını çöp kutusuna taşımak istiyor musunuz? "
1156 msgstr ""
11991157
12001158 #: src/delete-files/delete-files.cc:134
12011159 #, c-format
12021160 msgid "Do you want to permanently delete %d files?"
1203 msgstr "%d dosyaları kalıcı olarak silmek istiyor musunuz?"
1161 msgstr ""
12041162
12051163 #: src/delete-files/delete-files.cc:146
12061164 msgid "Move to trash"
1207 msgstr "Çöpe taşı"
1165 msgstr ""
12081166
12091167 #: src/delete-files/delete-files.cc:146
12101168 msgid "Delete"
12211179
12221180 #: src/delete-files/delete-files.cc:288
12231181 msgid "<b>Delete Method</b>"
1224 msgstr "<b>Silme Yöntemi</b>"
1182 msgstr ""
12251183
12261184 #: src/delete-files/delete-files.cc:289
12271185 msgid "Move to trash instead of deleting immediately"
1228 msgstr "Hemen silmek yerine çöp kutusuna taşı"
1186 msgstr ""
12291187
12301188 #: src/echo_plugin/echo.cc:9
12311189 msgid ""
12341192 "Surround echo by Carl van Schaik, 1999\n"
12351193 "Updated for Audacious by William Pitcock and John Lindgren, 2010-2014"
12361194 msgstr ""
1237 "Yankı Eklentisi\n"
1238 "Johan Levin, 1999\n"
1239 "Surround yankısı Carl van Schaik, 1999\n"
1240 "Auducious tarafından William Pitcock ve John Lindgren tarafından "
1241 "güncellendi, 2010-2014"
12421195
12431196 #: src/echo_plugin/echo.cc:21
12441197 msgid "<b>Echo</b>"
1245 msgstr "<b>Yankı</b>"
1198 msgstr ""
12461199
12471200 #: src/echo_plugin/echo.cc:22 src/modplug/plugin_main.cc:76
12481201 #: src/modplug/plugin_main.cc:86
12561209
12571210 #: src/echo_plugin/echo.cc:25
12581211 msgid "Feedback:"
1259 msgstr "Geribesleme:"
1212 msgstr ""
12601213
12611214 #: src/echo_plugin/echo.cc:28 src/modplug/plugin_main.cc:90
12621215 msgid "Volume:"
1263 msgstr "Hacim:"
1216 msgstr ""
12641217
12651218 #: src/echo_plugin/echo.cc:39
12661219 msgid "Echo"
1267 msgstr "Yankı"
1220 msgstr ""
12681221
12691222 #: src/ffaudio/ffaudio-core.cc:49
12701223 msgid "FFmpeg Plugin"
12791232 "William Pitcock <nenolod@nenolod.net>\n"
12801233 "Matti Hämäläinen <ccr@tnsp.org>"
12811234 msgstr ""
1282 "FFmpeg multimedya çerçevesini kullanarak Audacious\n"
1283 " için çok biçimli ses kod çözme eklentisi (http://www.ffmpeg.org/)\n"
1284 "\n"
1285 "Audacious eklentisi:\n"
1286 "William Pitcock <nenolod@nenolod.net>\n"
1287 "Matti Hämäläinen <ccr@tnsp.org>"
12881235
12891236 #: src/filewriter/filewriter.cc:48
12901237 msgid "FileWriter Plugin"
1291 msgstr "Dosya Yazma Eklentisi"
1238 msgstr ""
12921239
12931240 #: src/filewriter/filewriter.cc:350
12941241 msgid ""
13061253 "this program; if not, write to the Free Software Foundation, Inc., 51 "
13071254 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
13081255 msgstr ""
1309 "Bu program ücretsiz bir yazılımdır; Özgür Yazılım Vakfı tarafından "
1310 "yayımlanan GNU Genel Kamu Lisansı şartlarına göre yeniden dağıtabilir ve/"
1311 "veya değiştirebilirsiniz; lisansın 2 numaralı sürümü veya (seçimlerinize "
1312 "göre) herhangi bir sonraki sürümü.\n"
1313 "Bu program yararlı olacağı umuduyla dağıtılır, ancak HERHANGİ BİR GARANTİ "
1314 "OLMAKSIZIN; SATILABİLİRLİK veya BELİRLİ BİR AMACA UYGUNLUĞU'nun zımni "
1315 "garantisi dahi olmadan. Daha fazla bilgi için GNU Genel Kamu Lisansına "
1316 "bakınız.\n"
1317 "\n"
1318 "Bu programla birlikte GNU Genel Kamu Lisansının bir kopyasını almış "
1319 "olmalısınız; eğer değilse, Free Software Foundation, Inc., 51 Franklin "
1320 "Street, Beşinci Kat, Boston, MA 02110-1301, ABD'ye yazın."
13211256
13221257 #: src/filewriter/filewriter.cc:377
13231258 msgid "Output file format:"
13291264
13301265 #: src/filewriter/filewriter.cc:384
13311266 msgid "Save into custom directory:"
1332 msgstr "Özel dizine kaydet"
1267 msgstr ""
13331268
13341269 #: src/filewriter/filewriter.cc:392
13351270 msgid "Generate file name from:"
1336 msgstr "Şuradan dosya adı oluştur:"
1271 msgstr ""
13371272
13381273 #: src/filewriter/filewriter.cc:393
13391274 msgid "Original file name"
1340 msgstr "Özgün dosya adı"
1275 msgstr "Orijinal dosya adı"
13411276
13421277 #: src/filewriter/filewriter.cc:396
13431278 msgid "Original file name (no suffix)"
1344 msgstr "Özgün dosya adı (son ek yok)"
1279 msgstr ""
13451280
13461281 #: src/filewriter/filewriter.cc:399
13471282 msgid "Original file tag"
1348 msgstr "Özgün dosya etiketi"
1283 msgstr ""
13491284
13501285 #: src/filewriter/filewriter.cc:403
13511286 msgid "Prepend track number to file name"
1352 msgstr "Parça numarasını dosya adına ekle"
1287 msgstr ""
13531288
13541289 #: src/filewriter/filewriter.cc:409 src/filewriter/filewriter.cc:441
13551290 msgid "Auto"
14711406
14721407 #: src/filewriter/filewriter.cc:448
14731408 msgid "VBR"
1474 msgstr "VBR"
1409 msgstr "320 kbps"
14751410
14761411 #: src/filewriter/filewriter.cc:449
14771412 msgid "ABR"
14951430
14961431 #: src/filewriter/filewriter.cc:493
14971432 msgid "Enforce strict ISO compliance"
1498 msgstr "ISO standartlarına mutlak uyum gözetmeye zorla"
1433 msgstr ""
14991434
15001435 #: src/filewriter/filewriter.cc:495
15011436 msgid "Error protection"
15111446
15121447 #: src/filewriter/filewriter.cc:506
15131448 msgid "Minimum bitrate:"
1514 msgstr "En düşük bit oranı:"
1449 msgstr ""
15151450
15161451 #: src/filewriter/filewriter.cc:510
15171452 msgid "Maximum bitrate:"
1518 msgstr "En yüksek bit oranı:"
1453 msgstr ""
15191454
15201455 #: src/filewriter/filewriter.cc:514
15211456 msgid "Average bitrate:"
1522 msgstr "Ortalama bit oranı:"
1457 msgstr ""
15231458
15241459 #: src/filewriter/filewriter.cc:518
15251460 msgid "VBR quality level:"
15311466
15321467 #: src/filewriter/filewriter.cc:525
15331468 msgid "Omit Xing VBR header"
1534 msgstr "Xing VBR başlığını atla"
1469 msgstr ""
15351470
15361471 #: src/filewriter/filewriter.cc:531
15371472 msgid "<b>Frame Headers</b>"
1538 msgstr "<b>Çerçeve Başlıkları</b>"
1473 msgstr ""
15391474
15401475 #: src/filewriter/filewriter.cc:532
15411476 msgid "Mark as copyright"
15431478
15441479 #: src/filewriter/filewriter.cc:534
15451480 msgid "Mark as original"
1546 msgstr "Özgün olarak işaretle"
1481 msgstr "Orijinal olarak işaretle"
15471482
15481483 #: src/filewriter/filewriter.cc:536
15491484 msgid "<b>ID3 Tags</b>"
1550 msgstr "<b>ID3 Etiketleri</b>"
1485 msgstr ""
15511486
15521487 #: src/filewriter/filewriter.cc:537
15531488 msgid "Force addition of version 2 tag"
15841519
15851520 #: src/flac/flacng.h:35
15861521 msgid "FLAC Decoder"
1587 msgstr "FLAC Çözücü"
1522 msgstr ""
15881523
15891524 #: src/flac/metadata.cc:270 src/wavpack/wavpack.cc:209
15901525 msgid "lossless"
15971532 "\n"
15981533 "http://www.skytale.net/projects/bmp-flac2/"
15991534 msgstr ""
1600 "Özgün kod\n"
1601 "Ralf Ertzinger <ralf@skytale.net> tarafından\n"
1602 "\n"
1603 "http://www.skytale.net/projects/bmp-flac2/"
16041535
16051536 #: src/gio/gio.cc:34
16061537 msgid ""
16071538 "GIO Plugin for Audacious\n"
16081539 "Copyright 2009-2012 John Lindgren"
16091540 msgstr ""
1610 "Audacious için GIO Eklentisi \n"
1611 "Telif Hakkı 2009-2012 John Lindgren"
16121541
16131542 #: src/gio/gio.cc:42
16141543 msgid "GIO Plugin"
1615 msgstr "GIO Eklentisi"
1544 msgstr ""
16161545
16171546 #: src/gio/gio.cc:152
16181547 msgid "Read-and-append mode not supported"
1619 msgstr "Okuma-ve-ekleme modu desteklenmiyor"
1548 msgstr ""
16201549
16211550 #: src/gio/gio.cc:165
16221551 msgid "Invalid open mode"
1623 msgstr "Geçersiz açma modu"
1552 msgstr ""
16241553
16251554 #: src/glspectrum/gl-spectrum.cc:51
16261555 msgid ""
16331562 "\n"
16341563 "License: GPLv2+"
16351564 msgstr ""
1636 "Auducious için OpenGL İzgesel Çözümleyici\n"
1637 "Telif Hakkı 2013 Christophe Budé, John Lindgren ve Carlo Bramini\n"
1638 "\n"
1639 "XMMS eklentisine dayanarak:\n"
1640 "Telif Hakkı 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson ve "
1641 "4Front Technologies\n"
1642 "\n"
1643 "Lisans: GPLv2+"
16441565
16451566 #: src/glspectrum/gl-spectrum.cc:62 src/qtglspectrum/gl-spectrum.cc:53
16461567 msgid "OpenGL Spectrum Analyzer"
1647 msgstr "Opengl İzgesel Çözümleyici"
1568 msgstr ""
16481569
16491570 #: src/gtkui/columns.cc:35
16501571 msgid "Entry number"
17061627
17071628 #: src/gtkui/columns.cc:315
17081629 msgid "Available columns"
1709 msgstr "Kullanılabilir sütunlar"
1630 msgstr ""
17101631
17111632 #: src/gtkui/columns.cc:341
17121633 msgid "Displayed columns"
1713 msgstr "Görüntülenen sütunlar"
1634 msgstr ""
17141635
17151636 #: src/gtkui/layout.cc:73 src/search-tool-qt/search-tool-qt.cc:62
17161637 #: src/search-tool/search-tool.cc:49
17481669
17491670 #: src/gtkui/menus.cc:80 src/qtui/menus.cc:70
17501671 msgid "Open _URL ..."
1751 msgstr "_URL Aç ..."
1672 msgstr "URL _Aç ..."
17521673
17531674 #: src/gtkui/menus.cc:81 src/qtui/menus.cc:71
17541675 msgid "_Add Files ..."
1755 msgstr "Dosy_aları Ekle ..."
1676 msgstr "_Dosyaları Ekle ..."
17561677
17571678 #: src/gtkui/menus.cc:82 src/qtui/menus.cc:73
17581679 msgid "Add U_RL ..."
17601681
17611682 #: src/gtkui/menus.cc:84 src/qtui/menus.cc:75
17621683 msgid "Search _Library"
1763 msgstr "Kitap_lığı Ara"
1684 msgstr ""
17641685
17651686 #: src/gtkui/menus.cc:86 src/qtui/menus.cc:77
17661687 msgid "A_bout ..."
18111732
18121733 #: src/gtkui/menus.cc:100 src/qtui/menus.cc:94
18131734 msgid "Shuffle by Albu_m"
1814 msgstr "Albü_me göre karıştır"
1735 msgstr ""
18151736
18161737 #: src/gtkui/menus.cc:101 src/qtui/menus.cc:95
18171738 msgid "N_o Playlist Advance"
1818 msgstr "Oynatılabilir Çalma Listesi y_ok"
1739 msgstr ""
18191740
18201741 #: src/gtkui/menus.cc:102 src/qtui/menus.cc:96
18211742 msgid "Stop A_fter This Song"
1822 msgstr "Bu Şarkıdan Son_ra Dur"
1743 msgstr ""
18231744
18241745 #: src/gtkui/menus.cc:104 src/gtkui/menus.cc:205 src/qtui/menus.cc:98
18251746 #: src/qtui/menus.cc:200
18281749
18291750 #: src/gtkui/menus.cc:105
18301751 msgid "Jump to _Time ..."
1831 msgstr "Zamana Gi_t ..."
1752 msgstr "Süre Atla"
18321753
18331754 #: src/gtkui/menus.cc:106
18341755 msgid "_Jump to Song ..."
1835 msgstr "Şarkıya Git ..."
1756 msgstr "Şarkı Atla"
18361757
18371758 #: src/gtkui/menus.cc:108
18381759 msgid "Set Repeat Point _A"
1839 msgstr "Tekrarlama Başlangıcı _A"
1760 msgstr "Tekrarlama Başlancığı _A"
18401761
18411762 #: src/gtkui/menus.cc:109
18421763 msgid "Set Repeat Point _B"
18531774
18541775 #: src/gtkui/menus.cc:115 src/qtui/menus.cc:103
18551776 msgid "By _File Name"
1856 msgstr "_Dosya İsmine Göre"
1777 msgstr ""
18571778
18581779 #: src/gtkui/menus.cc:116 src/qtui/menus.cc:104
18591780 msgid "By File _Path"
18721793 #: src/gtkui/menus.cc:123 src/gtkui/menus.cc:140 src/qtui/menus.cc:111
18731794 #: src/qtui/menus.cc:128
18741795 msgid "By Al_bum"
1875 msgstr "Al_büme Göre"
1796 msgstr ""
18761797
18771798 #: src/gtkui/menus.cc:124 src/gtkui/menus.cc:141 src/qtui/menus.cc:112
18781799 #: src/qtui/menus.cc:129
18791800 msgid "By Albu_m Artist"
1880 msgstr "Albü_m Sanatçısına Göre"
1801 msgstr ""
18811802
18821803 #: src/gtkui/menus.cc:125 src/gtkui/menus.cc:142 src/qtui/menus.cc:113
18831804 #: src/qtui/menus.cc:130
18871808 #: src/gtkui/menus.cc:126 src/gtkui/menus.cc:143 src/qtui/menus.cc:114
18881809 #: src/qtui/menus.cc:131
18891810 msgid "By _Genre"
1890 msgstr "Türüne _Göre"
1811 msgstr ""
18911812
18921813 #: src/gtkui/menus.cc:127 src/gtkui/menus.cc:144 src/qtui/menus.cc:115
18931814 #: src/qtui/menus.cc:132
18941815 msgid "By _Length"
1895 msgstr "Uzun_luğuna Göre"
1816 msgstr ""
18961817
18971818 #: src/gtkui/menus.cc:128 src/gtkui/menus.cc:145 src/qtui/menus.cc:116
18981819 #: src/qtui/menus.cc:133
18991820 msgid "By _File Path"
1900 msgstr "_Dosya Yoluna Göre"
1821 msgstr ""
19011822
19021823 #: src/gtkui/menus.cc:129 src/gtkui/menus.cc:146 src/qtui/menus.cc:117
19031824 #: src/qtui/menus.cc:134
19041825 msgid "By _Custom Title"
1905 msgstr "Özel _Başlığa Göre"
1826 msgstr "Özel Başlık"
19061827
19071828 #: src/gtkui/menus.cc:130 src/gtkui/menus.cc:147 src/qtui/menus.cc:118
19081829 #: src/qtui/menus.cc:135
19091830 msgid "By C_omment"
1910 msgstr "Y_oruma Göre"
1831 msgstr ""
19111832
19121833 #: src/gtkui/menus.cc:132 src/gtkui/menus.cc:149 src/qtui/menus.cc:120
19131834 #: src/qtui/menus.cc:137
19141835 msgid "R_everse Order"
1915 msgstr "T_ersine Sıra"
1836 msgstr ""
19161837
19171838 #: src/gtkui/menus.cc:133 src/gtkui/menus.cc:150 src/qtui/menus.cc:121
19181839 #: src/qtui/menus.cc:138
19211842
19221843 #: src/gtkui/menus.cc:154 src/qtui/menus.cc:142
19231844 msgid "_Play/Resume"
1924 msgstr "_Oynat/Devam et"
1845 msgstr ""
19251846
19261847 #: src/gtkui/menus.cc:155 src/qtui/menus.cc:143
19271848 msgid "_Refresh"
19331854
19341855 #: src/gtkui/menus.cc:158 src/qtui/menus.cc:148
19351856 msgid "Sort Se_lected"
1936 msgstr "Seçi_leni Sırala"
1857 msgstr ""
19371858
19381859 #: src/gtkui/menus.cc:159 src/qtui/menus.cc:149
19391860 msgid "Remove _Duplicates"
1940 msgstr "Kopyaları Kal_dır"
1861 msgstr ""
19411862
19421863 #: src/gtkui/menus.cc:160 src/qtui/menus.cc:150
19431864 msgid "Remove _Unavailable Files"
1944 msgstr "K_ullanılamayan Dosyaları Kaldır"
1865 msgstr ""
19451866
19461867 #: src/gtkui/menus.cc:162 src/playlist-manager/playlist-manager.cc:218
19471868 #: src/playlist-manager-qt/playlist-manager-qt.cc:356 src/qtui/menus.cc:152
19501871
19511872 #: src/gtkui/menus.cc:163 src/qtui/menus.cc:153
19521873 msgid "Ren_ame ..."
1953 msgstr "_Adlandır ..."
1874 msgstr ""
19541875
19551876 #: src/gtkui/menus.cc:164 src/gtkui/menus.cc:223 src/qtui/menus.cc:154
19561877 msgid "Remo_ve"
1957 msgstr "_Kaldır"
1878 msgstr ""
19581879
19591880 #: src/gtkui/menus.cc:166 src/qtui/menus.cc:156
19601881 msgid "_Import ..."
19661887
19671888 #: src/gtkui/menus.cc:169 src/qtui/menus.cc:159
19681889 msgid "Playlist _Manager ..."
1969 msgstr "Çal_ma Listesi Yöneticisi"
1890 msgstr ""
19701891
19711892 #: src/gtkui/menus.cc:170 src/qtui/menus.cc:160
19721893 msgid "_Queue Manager ..."
19821903
19831904 #: src/gtkui/menus.cc:177 src/qtui/menus.cc:167
19841905 msgid "_Equalizer ..."
1985 msgstr "_Ekolayzır ..."
1906 msgstr ""
19861907
19871908 #: src/gtkui/menus.cc:178 src/qtui/menus.cc:168
19881909 msgid "E_ffects ..."
1989 msgstr "E_fektler ..."
1910 msgstr ""
19901911
19911912 #: src/gtkui/menus.cc:180
19921913 msgid "_Record Stream"
1993 msgstr "Akışı _Kaydet"
1914 msgstr ""
19941915
19951916 #: src/gtkui/menus.cc:181
19961917 msgid "Audio _Settings ..."
1997 msgstr "_Ses Ayarları ..."
1918 msgstr ""
19981919
19991920 #: src/gtkui/menus.cc:185 src/qtui/menus.cc:175
20001921 msgid "Show _Menu Bar"
20061927
20071928 #: src/gtkui/menus.cc:187 src/qtui/menus.cc:177
20081929 msgid "Show Info Bar Vis_ualization"
2009 msgstr "Bilgi Ç_ubuğu Görselleştirmesini Göster"
1930 msgstr ""
20101931
20111932 #: src/gtkui/menus.cc:188 src/qtui/menus.cc:178
20121933 msgid "Show _Status Bar"
20141935
20151936 #: src/gtkui/menus.cc:190 src/qtui/menus.cc:180
20161937 msgid "Show _Remaining Time"
2017 msgstr "Kalan Sü_reyi göster"
1938 msgstr ""
20181939
20191940 #: src/gtkui/menus.cc:192 src/qtui/menus.cc:182 src/skins/menus.cc:155
20201941 #: src/skins-qt/menus.cc:150
20211942 msgid "_Visualizations ..."
2022 msgstr "_Görselleştirme ..."
1943 msgstr ""
20231944
20241945 #: src/gtkui/menus.cc:196 src/qtui/menus.cc:186
20251946 msgid "_File"
20481969
20491970 #: src/gtkui/menus.cc:206 src/qtui/menus.cc:201
20501971 msgid "_Queue/Unqueue"
2051 msgstr "_Kuyruğa Ekle/Kaldır"
1972 msgstr ""
20521973
20531974 #: src/gtkui/menus.cc:208 src/qtui/menus.cc:203
20541975 msgid "_Open Containing Folder"
2055 msgstr "İçeren _Dizini Aç"
1976 msgstr ""
20561977
20571978 #: src/gtkui/menus.cc:209 src/qtui/menus.cc:204
20581979 msgid "_Refresh Selected"
2059 msgstr "Seçilenle_ri Yenile"
1980 msgstr ""
20601981
20611982 #: src/gtkui/menus.cc:211 src/qtui/menus.cc:206
20621983 msgid "Cu_t"
20721993
20731994 #: src/gtkui/menus.cc:214 src/qtui/menus.cc:209
20741995 msgid "Paste at _End"
2075 msgstr "_Sonunda Yapıştır"
1996 msgstr ""
20761997
20771998 #: src/gtkui/menus.cc:215 src/qtui/menus.cc:210
20781999 msgid "Select _All"
20802001
20812002 #: src/gtkui/menus.cc:222
20822003 msgid "_Rename ..."
2083 msgstr "Yeniden adlandı_r ..."
2004 msgstr ""
20842005
20852006 #: src/gtkui/settings.cc:35 src/qtui/settings.cc:54
20862007 msgid "<b>Playlist Tabs</b>"
2087 msgstr "<b>Çalma Listesi Sekmeleri</b>"
2008 msgstr ""
20882009
20892010 #: src/gtkui/settings.cc:36 src/qtui/settings.cc:56
20902011 msgid "Always show tabs"
2091 msgstr "Sekmeleri her zaman göster"
2012 msgstr ""
20922013
20932014 #: src/gtkui/settings.cc:38 src/qtui/settings.cc:59
20942015 msgid "Show entry counts"
21082029
21092030 #: src/gtkui/settings.cc:47 src/qtui/settings.cc:67
21102031 msgid "Arrow keys seek by:"
2111 msgstr "Ok tuşları ile arama:"
2032 msgstr ""
21122033
21132034 #: src/gtkui/settings.cc:50 src/qtui/settings.cc:70
21142035 msgid "Scroll on song change"
2115 msgstr "Şarkı değişikliğinde kaydır"
2036 msgstr ""
21162037
21172038 #: src/gtkui/ui_gtk.cc:73
21182039 msgid "GTK Interface"
21462067 #: src/gtkui/ui_gtk.cc:796 src/qtui/main_window.cc:101 src/skins/menus.cc:86
21472068 #: src/skins-qt/menus.cc:77
21482069 msgid "Search Library"
2149 msgstr "Kitaplığı Ara"
2070 msgstr "Arama Kütüphanesi"
21502071
21512072 #: src/gtkui/ui_gtk.cc:804 src/qtui/main_window.cc:102
21522073 msgid "Open Files"
22612182
22622183 #: src/hotkey/gui.cc:82
22632184 msgid "Toggle player window(s)"
2264 msgstr "Oynatıcı pencere(leri)si aç"
2185 msgstr ""
22652186
22662187 #: src/hotkey/gui.cc:83
22672188 msgid "Show On-Screen-Display"
2268 msgstr "On-Screen-Display Göster"
2189 msgstr ""
22692190
22702191 #: src/hotkey/gui.cc:84
22712192 msgid "Toggle repeat"
2272 msgstr "Tekrarlama yap"
2193 msgstr ""
22732194
22742195 #: src/hotkey/gui.cc:85
22752196 msgid "Toggle shuffle"
2276 msgstr "Karıştırmayı aç"
2197 msgstr ""
22772198
22782199 #: src/hotkey/gui.cc:86
22792200 msgid "Toggle stop after current"
2280 msgstr "Şimdiki çalmadan sonra durdurmayı aç"
2201 msgstr ""
22812202
22822203 #: src/hotkey/gui.cc:87
22832204 msgid "Raise player window(s)"
2284 msgstr "Oynatma pencere(ler)sini yükselt"
2205 msgstr ""
22852206
22862207 #: src/hotkey/gui.cc:97
22872208 msgid "(none)"
22932214 "\n"
22942215 "Do you want to continue?"
22952216 msgstr ""
2296 "Birincil fare düğmelerini değiştiriciler olmadan bağlamak tavsiye edilmez.\n"
2297 "\n"
2298 "Devam etmek istiyor musunuz?"
22992217
23002218 #: src/hotkey/gui.cc:236
23012219 msgid "Binding mouse buttons"
2302 msgstr "Fare düğmeleri bağlaması"
2220 msgstr ""
23032221
23042222 #: src/hotkey/gui.cc:391
23052223 msgid ""
23062224 "Press a key combination inside a text field.\n"
23072225 "You can also bind mouse buttons."
23082226 msgstr ""
2309 "Bir metin alanının içindeki tuş kombinasyonuna basın.\n"
2310 "Fare düğmelerini de bağlayabilirsiniz."
23112227
23122228 #: src/hotkey/gui.cc:396
23132229 msgid "Hotkeys:"
23192235
23202236 #: src/hotkey/gui.cc:420
23212237 msgid "<b>Key Binding:</b>"
2322 msgstr "<b>Anahtar Bağlama:</b>"
2238 msgstr ""
23232239
23242240 #: src/hotkey/gui.cc:468
23252241 msgid "_Add"
23272243
23282244 #: src/hotkey/plugin.cc:61
23292245 msgid "Global Hotkeys"
2330 msgstr "Genel Kısayollar"
2246 msgstr ""
23312247
23322248 #: src/hotkey/plugin.cc:80
23332249 msgid ""
23432259 " Jonathan A. Davis <davis@jdhouse.org>,\n"
23442260 " Jeremy Tan <nsx@nsx.homeip.net>"
23452261 msgstr ""
2346 "Genel Kısayol Eklentisi\n"
2347 "Oynatıcıyı genel tuş bileşimleri veya çoklu ortam tuşları ile kontrol edin.\n"
2348 "\n"
2349 "Telif Hakkı (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>\n"
2350 "\n"
2351 "Katkıda bulunanlar:\n"
2352 "Telif Hakkı (C) 2006-2007 Vladimir Paskov <vlado.paskov@gmail.com>\n"
2353 "Telif Hakkı (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>,\n"
2354 " Bryn Davies <curious@ihug.com.au>,\n"
2355 " Jonathan A. Davis <davis@jdhouse.org>,\n"
2356 " Jeremy Tan <nsx@nsx.homeip.net>"
23572262
23582263 #: src/jack/jack-ng.cc:50
23592264 msgid "JACK Output"
23612266
23622267 #: src/jack/jack-ng.cc:115
23632268 msgid "Automatically connect to output ports"
2364 msgstr "Çıkış bağlantı noktalarına otomatik olarak bağlanma"
2269 msgstr ""
23652270
23662271 #: src/jack/jack-ng.cc:156
23672272 #, c-format
23682273 msgid "Only %d JACK output ports were found but %d are required."
2369 msgstr "Sadece %d JACK çıkış portları bulundu, ancak %d gerekiyor."
2274 msgstr ""
23702275
23712276 #: src/jack/jack-ng.cc:172
23722277 #, c-format
23782283 "JACK supports only floating-point audio. You must change the output bit "
23792284 "depth to floating-point in Audacious settings."
23802285 msgstr ""
2381 "JACK yalnızca kayan noktalı sesi destekler. Audacious ayarlarında çıkış biti "
2382 "derinliğini kayan noktaya değiştirmelisiniz."
23832286
23842287 #: src/jack/jack-ng.cc:205
23852288 msgid "Failed to connect to the JACK server; is it running?"
2386 msgstr "JACK sunucusuna bağlanılamadı; çalışıyor mu?"
2289 msgstr ""
23872290
23882291 #: src/jack/jack-ng.cc:281
23892292 #, c-format
23912294 "The JACK server requires a sample rate of %d Hz, but Audacious is playing at "
23922295 "%d Hz. Please use the Sample Rate Converter effect to correct the mismatch."
23932296 msgstr ""
2394 "JACK sunucusu örnek bir %d Hz hızını gerektirir, ancak Audacious %d Hz'de "
2395 "çalar. Uyumsuzluğu düzeltmek için lütfen Örnek Hızı Dönüştürücü efekti "
2396 "kullanın."
23972297
23982298 #: src/ladspa/plugin.cc:415
23992299 #, c-format
24102310 "These paths are searched in addition to LADSPA_PATH.\n"
24112311 "After adding new paths, press Enter to scan for new plugins.</small>"
24122312 msgstr ""
2413 "<small>Bir kolon ile birden çok yolu ayırın.\n"
2414 "Bu yollar LADSPA_PATH'e ek olarak aranır.\n"
2415 "Yeni yollar ekledikten sonra, yeni eklentileri taramak için Enter tuşuna "
2416 "basın.</small>"
24172313
24182314 #: src/ladspa/plugin.cc:502
24192315 msgid "Available plugins:"
24382334 "LADSPA Host for Audacious\n"
24392335 "Copyright 2011 John Lindgren"
24402336 msgstr ""
2441 "Audacious için LADSPA AnaBilgisayar\n"
2442 "Telif Hakkı 2011 John Lindgren"
24432337
24442338 #: src/ladspa/plugin.h:78
24452339 msgid "LADSPA Host"
2446 msgstr "LADSPA AnaBilgisayar"
2340 msgstr ""
24472341
24482342 #: src/lirc/lirc.cc:55
24492343 msgid "LIRC Plugin"
2450 msgstr "LIRC Eklentisi"
2344 msgstr ""
24512345
24522346 #: src/lirc/lirc.cc:379
24532347 msgid ""
24642358 "\n"
24652359 "For more information about LIRC, see http://lirc.org."
24662360 msgstr ""
2467 "LIRC uzaktan kumanda programı kullanarak Audacious'u kontrol etmek için "
2468 "basit bir eklenti\n"
2469 "\n"
2470 "Audacious için uyarlanmış:\n"
2471 "Tony Vroon <chainsaw@gentoo.org>\n"
2472 "Joonas Harjumäki <jharjuma@gmail.com>\n"
2473 "\n"
2474 "XMMS LIRC eklentisine dayanarak:LIRC hakkında daha fazla bilgi için bkz. "
2475 "Http://lirc.org.\n"
2476 "Carl van Schaik <carl@leg.uct.ac.za>\n"
2477 "Christoph Bartelmus <xmms@bartelmus.de>\n"
2478 "Andrew O. Shadoura <bugzilla@tut.by>\n"
2479 "\n"
2480 "LIRC hakkında daha fazla bilgi için bkz. http://lirc.org."
24812361
24822362 #: src/lirc/lirc.cc:390
24832363 msgid "<b>Connection</b>"
2484 msgstr "<b>Bağlantı</b>"
2364 msgstr ""
24852365
24862366 #: src/lirc/lirc.cc:391
24872367 msgid "Reconnect to LIRC server"
2488 msgstr "LIRC sunucusuna yeniden bağlan"
2368 msgstr ""
24892369
24902370 #: src/lirc/lirc.cc:393
24912371 msgid "Wait before reconnecting:"
2492 msgstr "Yeniden bağlanmadan önce bekleyin:"
2372 msgstr ""
24932373
24942374 #: src/lyricwiki/lyricwiki.cc:42 src/lyricwiki-qt/lyricwiki.cc:70
24952375 msgid "LyricWiki Plugin"
2496 msgstr "LyricWiki Eklentisi"
2376 msgstr ""
24972377
24982378 #: src/lyricwiki/lyricwiki.cc:132 src/lyricwiki-qt/lyricwiki.cc:151
24992379 #: src/lyricwiki-qt/lyricwiki.cc:337
25002380 msgid "No lyrics available"
2501 msgstr "Şarkı sözleri yok"
2381 msgstr ""
25022382
25032383 #: src/lyricwiki/lyricwiki.cc:251 src/lyricwiki/lyricwiki.cc:260
25042384 #: src/lyricwiki/lyricwiki.cc:275 src/lyricwiki/lyricwiki.cc:284
25132393 #: src/lyricwiki-qt/lyricwiki.cc:292 src/lyricwiki-qt/lyricwiki.cc:322
25142394 #, c-format
25152395 msgid "Unable to fetch %s"
2516 msgstr "%s getirilemiyor"
2396 msgstr ""
25172397
25182398 #: src/lyricwiki/lyricwiki.cc:261 src/lyricwiki/lyricwiki.cc:285
25192399 #: src/lyricwiki-qt/lyricwiki.cc:307 src/lyricwiki-qt/lyricwiki.cc:331
25202400 #, c-format
25212401 msgid "Unable to parse %s"
2522 msgstr "%s ayrıştırılamıyor"
2402 msgstr ""
25232403
25242404 #: src/lyricwiki/lyricwiki.cc:291 src/lyricwiki-qt/lyricwiki.cc:343
25252405 msgid "Looking for lyrics ..."
2526 msgstr "Şarkı sözü ara ..."
2406 msgstr ""
25272407
25282408 #: src/lyricwiki/lyricwiki.cc:299 src/lyricwiki-qt/lyricwiki.cc:351
25292409 msgid "Missing song metadata"
2530 msgstr "Eksik üst verisi"
2410 msgstr ""
25312411
25322412 #: src/lyricwiki/lyricwiki.cc:310 src/lyricwiki-qt/lyricwiki.cc:362
25332413 msgid "Connecting to lyrics.wikia.com ..."
2534 msgstr "lyrics.wikia.com adresine bağlanıyor ..."
2414 msgstr ""
25352415
25362416 #: src/lyricwiki/lyricwiki.cc:351 src/lyricwiki-qt/lyricwiki.cc:442
25372417 msgid "Edit lyrics ..."
2538 msgstr "Şarkı sözlerini düzenle ..."
2418 msgstr ""
25392419
25402420 #: src/m3u/m3u.cc:32
25412421 msgid "M3U Playlists"
2542 msgstr "M3U Çalma Listeleri"
2422 msgstr ""
25432423
25442424 #: src/metronom/metronom.cc:44
25452425 msgid "Tact Generator"
2546 msgstr "Takt Oluşturucu"
2426 msgstr ""
25472427
25482428 #: src/metronom/metronom.cc:145
25492429 #, c-format
25632443 "e.g. tact://77 to play 77 beats per minute\n"
25642444 "or tact://60*3/4 to play 60 bpm in 3/4 tacts"
25652445 msgstr ""
2566 "Tact Üretici, Martin Strauss <mys@faveve.uni-stuttgart.de>\n"
2567 "\n"
2568 "Kullanmak için URL ekleyin: tact://beats*num/den\n"
2569 "örneğin tact://77 ile dakikada 77 vurgu ya da\n"
2570 "tact://60*3/4 ile 60 bpm yi 3/4 tact ile"
25712446
25722447 #: src/mixer/mixer.cc:38
25732448 msgid "Channel Mixer"
2574 msgstr "Kanal Değiştirici"
2449 msgstr ""
25752450
25762451 #: src/mixer/mixer.cc:227
25772452 msgid ""
25782453 "Channel Mixer Plugin for Audacious\n"
25792454 "Copyright 2011-2012 John Lindgren and Michał Lipski"
25802455 msgstr ""
2581 "Audacious için Kanal Değiştirici Eklentisi \n"
2582 "Telif Hakkı 2011-2012 John Lindgren ve Michał Lipski"
25832456
25842457 #: src/mixer/mixer.cc:231
25852458 msgid "<b>Channel Mixer</b>"
2586 msgstr "<b>Kanal Değiştirici</b>"
2459 msgstr ""
25872460
25882461 #: src/mixer/mixer.cc:232
25892462 msgid "Output channels:"
25912464
25922465 #: src/mms/mms.cc:35
25932466 msgid "MMS Plugin"
2594 msgstr "MMS Eklentisi"
2467 msgstr ""
25952468
25962469 #: src/mms/mms.cc:82
25972470 msgid "Error connecting to MMS server"
2598 msgstr "MMS sunucusuna bağlanırken hata oluştu"
2471 msgstr ""
25992472
26002473 #: src/modplug/modplugbmp.h:57
26012474 msgid "ModPlug (Module Player)"
2602 msgstr "ModPlug (Modül Oynatıcı)"
2475 msgstr ""
26032476
26042477 #: src/modplug/plugin_main.cc:56
26052478 msgid "<b>Resolution</b>"
2606 msgstr "<b>Çözünürlük</b>"
2479 msgstr ""
26072480
26082481 #: src/modplug/plugin_main.cc:57
26092482 msgid "8-bit"
26152488
26162489 #: src/modplug/plugin_main.cc:59
26172490 msgid "<b>Channels</b>"
2618 msgstr "<b>Kanallar</b>"
2491 msgstr ""
26192492
26202493 #: src/modplug/plugin_main.cc:63
26212494 msgid "Nearest (fastest)"
26272500
26282501 #: src/modplug/plugin_main.cc:65
26292502 msgid "Spline (good)"
2630 msgstr "Spline (iyi)"
2503 msgstr ""
26312504
26322505 #: src/modplug/plugin_main.cc:66
26332506 msgid "Polyphase (best)"
2634 msgstr "Polifaze (en iyi)"
2507 msgstr ""
26352508
26362509 #: src/modplug/plugin_main.cc:67
26372510 msgid "<b>Sample rate</b>"
2638 msgstr "<b>Örnekleme oranı</b>"
2511 msgstr ""
26392512
26402513 #: src/modplug/plugin_main.cc:68
26412514 msgid "22 kHz"
26602533
26612534 #: src/modplug/plugin_main.cc:81
26622535 msgid "Cutoff:"
2663 msgstr "Kesme:"
2536 msgstr ""
26642537
26652538 #: src/modplug/plugin_main.cc:94
26662539 msgid "<b>Reverb</b>"
2667 msgstr "<b>Yankı</b>"
2540 msgstr ""
26682541
26692542 #: src/modplug/plugin_main.cc:97
26702543 msgid "<b>Bass Boost</b>"
2671 msgstr "<b>Bas Kuvvetlendirme</b>"
2544 msgstr ""
26722545
26732546 #: src/modplug/plugin_main.cc:100
26742547 msgid "<b>Surround</b>"
2675 msgstr "<b>Kuşatma</b>"
2548 msgstr ""
26762549
26772550 #: src/modplug/plugin_main.cc:103
26782551 msgid "<b>Preamp</b>"
2679 msgstr "<b>Ön güçlendirme</b>"
2552 msgstr ""
26802553
26812554 #: src/modplug/plugin_main.cc:110
26822555 msgid "Oversample"
2683 msgstr "Örnek üzerinde"
2556 msgstr ""
26842557
26852558 #: src/modplug/plugin_main.cc:111
26862559 msgid "Noise reduction"
26882561
26892562 #: src/modplug/plugin_main.cc:112
26902563 msgid "Play Amiga MODs"
2691 msgstr "Amiga MOD'ları oynat"
2564 msgstr ""
26922565
26932566 #: src/modplug/plugin_main.cc:113
26942567 msgid "<b>Repeat</b>"
2695 msgstr "<b>Tekrarla</b>"
2568 msgstr ""
26962569
26972570 #: src/modplug/plugin_main.cc:114
26982571 msgid "Repeat count:"
2699 msgstr "Tekrarlama sayısı:"
2572 msgstr ""
27002573
27012574 #: src/modplug/plugin_main.cc:115
27022575 msgid "To repeat forever, set the repeat count to -1."
2703 msgstr "Sonsuza kadar tekrarlamak için, tekrar sayısını -1 olarak ayarlayın."
2576 msgstr ""
27042577
27052578 #: src/modplug/plugin_main.cc:128 src/sid/xs_config.cc:106
27062579 msgid "These settings will take effect when Audacious is restarted."
2707 msgstr "Audacious yeniden başlatıldığında bu ayarlar yürürlüğe girer."
2580 msgstr ""
27082581
27092582 #: src/mpg123/mpg123.cc:54
27102583 msgid "MPG123 Plugin"
2711 msgstr "MPG123 Eklentisi"
2584 msgstr ""
27122585
27132586 #: src/mpg123/mpg123.cc:80
27142587 msgid "<b>Advanced</b>"
27162589
27172590 #: src/mpg123/mpg123.cc:81
27182591 msgid "Use accurate length calculation (slow)"
2719 msgstr "Doğru uzunluk hesaplaması kullan (yavaş)"
2592 msgstr ""
27202593
27212594 #: src/mpg123/mpg123.cc:245
27222595 msgid "Surround"
27242597
27252598 #: src/mpris2/plugin.cc:38
27262599 msgid "MPRIS 2 Server"
2727 msgstr "MPRIS 2 Sunucusu"
2600 msgstr ""
27282601
27292602 #: src/neon/neon.cc:97
27302603 msgid "Neon HTTP/HTTPS Plugin"
2731 msgstr "Neon HTTP/HTTPS Eklentisi"
2604 msgstr ""
27322605
27332606 #: src/neon/neon.cc:526
27342607 msgid "Error parsing redirect"
2735 msgstr "Yönlendirme ayrıştırılırken hata oluştu"
2608 msgstr ""
27362609
27372610 #: src/neon/neon.cc:540
27382611 msgid "Unknown HTTP error"
2739 msgstr "Bilinmeyen HTTP hatası"
2612 msgstr ""
27402613
27412614 #: src/neon/neon.cc:574
27422615 msgid "Error parsing URL"
2743 msgstr "URL ayrıştırılırken hata oluştu"
2616 msgstr ""
27442617
27452618 #: src/neon/neon.cc:637
27462619 msgid "Too many redirects"
2747 msgstr "Çok fazla yönlendirme var"
2620 msgstr ""
27482621
27492622 #: src/notify/event.cc:97
27502623 msgid "Stopped"
27772650 "You should have received a copy of the GNU General Public License along with "
27782651 "this program. If not, see <http://www.gnu.org/licenses/>."
27792652 msgstr ""
2780 "Audacious için Masaüstü Bildirim Eklentisi\n"
2781 "Telif Hakkı (C) 2010 Maximilian Bogner\n"
2782 "Telif Hakkı (C) 2011-2013 John Lindgren ve Jean-Alexandre Anglès d'Auriac\n"
2783 "\n"
2784 "Bu eklenti ücretsiz bir yazılımdır: Özgür Yazılım Vakfı tarafından "
2785 "yayımlanan GNU Genel Kamu Lisansı, lisansın 3. sürümü ya da (sizin "
2786 "tercihinize göre) daha sonraki bir versiyonda bu hakları yeniden dağıtabilir "
2787 "ve/veya değiştirebilirsiniz.\n"
2788 "\n"
2789 "Bu eklenti, yararlı olacağı umuduyla dağıtılır, ancak HERHANGİ BİR GARANTİ "
2790 "OLMAKSIZIN; SATILABİLİRLİK veya BELİRLİ BİR AMACA UYGUNLUĞU'nun zımni "
2791 "garantisi dahi olmadan. Daha fazla bilgi için GNU Genel Kamu Lisansına "
2792 "bakınız.\n"
2793 "\n"
2794 "Bu programla birlikte GNU Genel Kamu Lisansının bir kopyasını almış "
2795 "olmalısınız. Değilse, bkz. <http://www.gnu.org/licenses/>."
27962653
27972654 #: src/notify/notify.cc:102
27982655 msgid "Show playback controls"
2799 msgstr "Oynatma kontrollerini göster"
2656 msgstr ""
28002657
28012658 #: src/notify/notify.cc:104
28022659 msgid "Always show notification"
28042661
28052662 #: src/notify/notify.cc:106
28062663 msgid "Include album name in notification"
2807 msgstr "Bildirimde albüm adını dahil et"
2664 msgstr ""
28082665
28092666 #: src/notify/osd.cc:59
28102667 msgid "Show"
28122669
28132670 #: src/oss4/oss.h:75
28142671 msgid "OSS4 Output"
2815 msgstr "OSS4 Çıkışı"
2672 msgstr ""
28162673
28172674 #: src/oss4/oss.h:77
28182675 msgid "OSS3 Output"
2819 msgstr "OSS3 Çıkışı"
2676 msgstr ""
28202677
28212678 #: src/oss4/plugin.cc:35
28222679 msgid "Default device"
2823 msgstr "Varsayılan Aygıt"
2680 msgstr ""
28242681
28252682 #: src/oss4/plugin.cc:78
28262683 msgid "Audio device:"
28322689
28332690 #: src/oss4/plugin.cc:85
28342691 msgid "Save volume between sessions."
2835 msgstr "Oturumlar arasında ses düzeyini kaydet"
2692 msgstr ""
28362693
28372694 #: src/oss4/plugin.cc:87
28382695 msgid "Enable format conversions made by the OSS software."
2839 msgstr "OSS yazılımı tarafından yapılan biçim dönüşümlerini etkinleştir."
2696 msgstr ""
28402697
28412698 #: src/oss4/plugin.cc:89
28422699 msgid "Enable exclusive mode to prevent virtual mixing."
2843 msgstr "Sanal değiştirmeyi önlemek için özel modu etkinleştirin."
2700 msgstr ""
28442701
28452702 #: src/oss4/plugin.cc:101
28462703 msgid ""
28502707 "I would like to thank people on #audacious, especially Tony Vroon and John "
28512708 "Lindgren and of course the authors of the previous OSS plugin."
28522709 msgstr ""
2853 "Audacious için OSS4 Çıkış Eklentisi\n"
2854 "Telif Hakkı 2010-2012 Michał Lipski\n"
2855 "\n"
2856 "#audacious için emeği insanlara teşekkür etmek isterim, özellikle Tony Vroon "
2857 "ve John Lindgren ve tabii ki önceki OSS eklentisinin yazarlarına."
28582710
28592711 #: src/playlist-manager/playlist-manager.cc:37
28602712 #: src/playlist-manager-qt/playlist-manager-qt.cc:40
28782730
28792731 #: src/pls/pls.cc:35
28802732 msgid "PLS Playlists"
2881 msgstr "PLS Çalma listeleri"
2733 msgstr ""
28822734
28832735 #: src/psf/plugin.cc:45
28842736 msgid "OpenPSF PSF1/PSF2 Decoder"
2885 msgstr "OpenPSF PSF1/PSF2 Çözücüsü"
2737 msgstr ""
28862738
28872739 #: src/pulse/pulse_audio.cc:40
28882740 msgid "PulseAudio Output"
2889 msgstr "PulseAudio Çıkışı"
2741 msgstr ""
28902742
28912743 #: src/pulse/pulse_audio.cc:532
28922744 msgid ""
29062758 "this program; if not, write to the Free Software Foundation, Inc., 51 "
29072759 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
29082760 msgstr ""
2909 "Audacious PulseAudio Çıkış Eklentisi\n"
2910 "\n"
2911 "Bu program ücretsiz bir yazılımdır; Özgür Yazılım Vakfı tarafından "
2912 "yayımlanan GNU Genel Kamu Lisansı şartlarına göre yeniden dağıtabilir ve/"
2913 "veya değiştirebilirsiniz. Lisansın 2 numaralı sürümü veya (seçimlerinize "
2914 "göre) herhangi bir sonraki sürümü.\n"
2915 "\n"
2916 "Bu program yararlı olacağı umuduyla dağıtılır, ancak HERHANGİ BİR GARANTİ "
2917 "OLMAKSIZIN; SATILABİLİRLİK veya BELİRLİ BİR AMACA UYGUNLUĞU'nun zımni "
2918 "garantisi dahi olmadan. Daha fazla bilgi için GNU Genel Kamu Lisansına "
2919 "bakınız.\n"
2920 "\n"
2921 "Bu programla birlikte GNU Genel Kamu Lisansının bir kopyasını almış "
2922 "olmalısınız; eğer değilse, Free Software Foundation, Inc., 51 Franklin "
2923 "Street, Beşinci Kat, Boston, MA 02110-1301, ABD'ye yazın."
29242761
29252762 #: src/qtaudio/qtaudio.cc:44
29262763 msgid "QtMultimedia Output"
2927 msgstr "QtMultimedia Çıkışı"
2764 msgstr ""
29282765
29292766 #: src/qtaudio/qtaudio.cc:72
29302767 msgid ""
29342771 "Based on SDL Output Plugin for Audacious\n"
29352772 "Copyright 2010 John Lindgren"
29362773 msgstr ""
2937 "Audacious için QtMultimedia Ses Çıkış Eklentisi\n"
2938 "Telif Hakkı 2014 William Pitcock\n"
2939 "\n"
2940 "Audacious için SDL Çıkış Eklentisine Dayalı\n"
2941 "Telif Hakkı 2010 John Lindgren"
29422774
29432775 #: src/qtglspectrum/gl-spectrum.cc:41
29442776 msgid ""
29522784 "\n"
29532785 "License: GPLv2+"
29542786 msgstr ""
2955 "Auducious için OpenGL İzgesel Çözümleyici\n"
2956 "Telif Hakkı 2013 Christophe Budé, John Lindgren ve Carlo Bramini\n"
2957 "Copyright 2014 William Pitcock\n"
2958 "\n"
2959 "XMMS eklentisine dayanarak:\n"
2960 "Telif Hakkı 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson ve "
2961 "4Front Technologies\n"
2962 "\n"
2963 "Lisans: GPLv2+"
29642787
29652788 #: src/qtui/main_window.cc:110 src/skins/menus.cc:107 src/skins-qt/menus.cc:98
29662789 msgid "Stop After This Song"
29762799
29772800 #: src/qtui/menus.cc:80
29782801 msgid "_Log Inspector ..."
2979 msgstr "Günlük Denet_leyici ..."
2802 msgstr ""
29802803
29812804 #: src/qtui/menus.cc:145
29822805 msgid "_Find ..."
2983 msgstr "_Bul ..."
2806 msgstr ""
29842807
29852808 #: src/qtui/menus.cc:171 src/skins/menus.cc:80 src/skins-qt/menus.cc:70
29862809 msgid "Audio Settings ..."
29882811
29892812 #: src/qtui/playlist_header.cc:201
29902813 msgid "Reset to Defaults"
2991 msgstr "Varsayılanlara Dön"
2814 msgstr ""
29922815
29932816 #: src/qtui/playlist_model.cc:35
29942817 msgid "Now Playing"
29962819
29972820 #: src/qtui/playlist_model.cc:36
29982821 msgid "Entry Number"
2999 msgstr "Sayı Girin"
2822 msgstr ""
30002823
30012824 #: src/qtui/playlist_model.cc:41
30022825 msgid "Album Artist"
30042827
30052828 #: src/qtui/playlist_model.cc:44
30062829 msgid "Queue Position"
3007 msgstr "Sıra Konumu"
2830 msgstr ""
30082831
30092832 #: src/qtui/playlist_model.cc:46
30102833 msgid "File Path"
3011 msgstr "Dosya Yolu"
2834 msgstr ""
30122835
30132836 #: src/qtui/playlist_model.cc:47
30142837 msgid "File Name"
3015 msgstr "Dosya Adı"
2838 msgstr ""
30162839
30172840 #: src/qtui/playlist_model.cc:48
30182841 msgid "Custom Title"
3019 msgstr "Özel Başlık"
2842 msgstr ""
30202843
30212844 #: src/qtui/qtui.cc:39
30222845 msgid "Qt Interface"
3023 msgstr "Qt Arayüzü"
2846 msgstr ""
30242847
30252848 #: src/qtui/search_bar.cc:47
30262849 msgid "Search playlist"
3027 msgstr "Çalma listesini ara"
2850 msgstr ""
30282851
30292852 #: src/resample/resample.cc:43
30302853 msgid "Sample Rate Converter"
3031 msgstr "Örnek Oran Dönüştürücü"
2854 msgstr ""
30322855
30332856 #: src/resample/resample.cc:183
30342857 msgid ""
30352858 "Sample Rate Converter Plugin for Audacious\n"
30362859 "Copyright 2010-2012 John Lindgren"
30372860 msgstr ""
3038 "Audacious için Örnek Oran Dönüştürücü Eklentisi\n"
3039 "Telif Hakkı 2010-2012 John Lindgren"
30402861
30412862 #: src/resample/resample.cc:187
30422863 msgid "Skip/repeat samples"
3043 msgstr "Örnekleri atla/tekrarla"
2864 msgstr ""
30442865
30452866 #: src/resample/resample.cc:188
30462867 msgid "Linear interpolation"
30482869
30492870 #: src/resample/resample.cc:189
30502871 msgid "Fast sinc interpolation"
3051 msgstr "Hızlı sinc interpolasyon"
2872 msgstr ""
30522873
30532874 #: src/resample/resample.cc:190
30542875 msgid "Medium sinc interpolation"
3055 msgstr "Orta sinc interpolasyonu"
2876 msgstr ""
30562877
30572878 #: src/resample/resample.cc:191
30582879 msgid "Best sinc interpolation"
3059 msgstr "En iyi sinc interpolasyon"
2880 msgstr ""
30602881
30612882 #: src/resample/resample.cc:195
30622883 msgid "<b>Conversion</b>"
30722893
30732894 #: src/resample/resample.cc:202
30742895 msgid "<b>Rate Mappings</b>"
3075 msgstr "<b>Oran Eşlemeleri</b>"
2896 msgstr ""
30762897
30772898 #: src/resample/resample.cc:203
30782899 msgid "Use rate mappings"
3079 msgstr "Oran eşlemelerini kullan"
2900 msgstr ""
30802901
30812902 #: src/resample/resample.cc:205
30822903 msgid "8 kHz:"
31272948 "Your scrobbles are being saved on your computer temporarily. They will be "
31282949 "submitted as soon as Audacious is allowed access."
31292950 msgstr ""
3130 "Skroplamalar geçici olarak bilgisayarınıza kaydediliyor. Audacious erişim "
3131 "izni verilir verilmez gönderilecektir."
31322951
31332952 #: src/scrobbler2/config_window.cc:33
31342953 #, c-format
31352954 msgid "Permission granted. Scrobbling for user %s."
3136 msgstr "İzin verildi. %s kullanıcısı için skroblanıyor."
2955 msgstr ""
31372956
31382957 #: src/scrobbler2/config_window.cc:37
31392958 msgid ""
31402959 "Permission denied. Open the following URL in a browser, allow Audacious "
31412960 "access to your account, and then click 'Check Permission' again:"
31422961 msgstr ""
3143 "İzin reddedildi. Bir tarayıcıda aşağıdaki URL'yi açın, Hesabınıza Audacious "
3144 "erişim izni verin ve ardından 'İzin Ver'i tekrar tıklayın:"
31452962
31462963 #: src/scrobbler2/config_window.cc:47
31472964 msgid "There was a problem contacting Last.fm."
3148 msgstr "Last.fm ile bağlantı kurulurken bir sorun oluştu."
2965 msgstr ""
31492966
31502967 #: src/scrobbler2/config_window.cc:86
31512968 msgid "Check Permission"
3152 msgstr "İzin Kontrolü"
2969 msgstr ""
31532970
31542971 #: src/scrobbler2/config_window.cc:87
31552972 msgid "Revoke Permission"
3156 msgstr "İzin İptali"
2973 msgstr ""
31572974
31582975 #: src/scrobbler2/config_window.cc:91
31592976 msgid "You need to allow Audacious to scrobble tracks to your Last.fm account."
31602977 msgstr ""
3161 "Audacious'in Last.fm hesabınıza parçaları karıştırmasına izin vermelisiniz."
31622978
31632979 #: src/scrobbler2/scrobbler.cc:29
31642980 msgid "Scrobbler 2.0"
3165 msgstr "Scrobbler 2.0"
2981 msgstr ""
31662982
31672983 #: src/scrobbler2/scrobbler.cc:224
31682984 msgid ""
31692985 "The Scrobbler plugin could not be started.\n"
31702986 "There might be a problem with your installation."
31712987 msgstr ""
3172 "Scrobbler eklentisi başlatılamadı.\n"
3173 "Yüklemenizde bir sorun olabilir."
31742988
31752989 #: src/scrobbler2/scrobbler.cc:289
31762990 msgid ""
31822996 "project.\n"
31832997 "\n"
31842998 msgstr ""
3185 "Audacious Scrobbler Eklentisi 2.0 Pitxyoki tarafından,\n"
3186 "\n"
3187 "Telif Hakkı © 2012-2013 Luís M. Picciochi Oliveira <Pitxyoki@Gmail.com>\n"
3188 "\n"
3189 "Bu projenin başında bana yardım ettiği için John Lindgren'e teşekkürler.\n"
3190 "\n"
31912999
31923000 #: src/scrobbler2/scrobbler_communication.cc:639
31933001 msgid ""
31943002 "Audacious is now using an improved version of the Last.fm Scrobbler.\n"
31953003 "Please check the Preferences for the Scrobbler plugin."
31963004 msgstr ""
3197 "Audacious artık Last.fm Scrobbler'in geliştirilmiş bir sürümünü kullanıyor.\n"
3198 "Lütfen Scrobbler eklentisi için Tercihleri kontrol edin."
31993005
32003006 #: src/sdlout/sdlout.cc:43
32013007 msgid "SDL Output"
3202 msgstr "SDL Çıkışı"
3008 msgstr ""
32033009
32043010 #: src/sdlout/sdlout.cc:72
32053011 msgid ""
32063012 "SDL Output Plugin for Audacious\n"
32073013 "Copyright 2010 John Lindgren"
32083014 msgstr ""
3209 "Audacious için SDL Çıkışı Eklentisi\n"
3210 "Telif Hakkı 2010 John Lindgren"
32113015
32123016 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32133017 msgid "Number of results to show:"
3214 msgstr "Gösterilecek sonuç sayısı:"
3018 msgstr ""
32153019
32163020 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32173021 msgid "Rescan library at startup"
3218 msgstr "Başlangıçta kitaplığı yeniden tara"
3022 msgstr ""
32193023
32203024 #: src/search-tool-qt/search-tool-qt.cc:305
32213025 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
32223026 #: src/search-tool/search-tool.cc:160
32233027 msgid "Library"
3224 msgstr "Kitaplık"
3028 msgstr "Kütüphane"
32253029
32263030 #: src/search-tool-qt/search-tool-qt.cc:586 src/search-tool/search-tool.cc:430
32273031 #, c-format
32283032 msgid "%d of %d result shown"
32293033 msgid_plural "%d of %d results shown"
3230 msgstr[0] "%d sonucun %di gösteriliyor"
3231 msgstr[1] "%d sonuçların %d'si gösteriliyor"
3034 msgstr[0] ""
3035 msgstr[1] ""
32323036
32333037 #: src/search-tool-qt/search-tool-qt.cc:590 src/search-tool/search-tool.cc:434
32343038 #, c-format
32353039 msgid "%d result"
32363040 msgid_plural "%d results"
3237 msgstr[0] "%d sonuç"
3238 msgstr[1] "%d sonuçlar"
3041 msgstr[0] ""
3042 msgstr[1] ""
32393043
32403044 #: src/search-tool-qt/search-tool-qt.cc:799 src/search-tool/search-tool.cc:631
32413045 #, c-format
32423046 msgid "%d song"
32433047 msgid_plural "%d songs"
3244 msgstr[0] "%d şarkı"
3245 msgstr[1] "%d şarkılar"
3048 msgstr[0] ""
3049 msgstr[1] ""
32463050
32473051 #: src/search-tool-qt/search-tool-qt.cc:808 src/search-tool/search-tool.cc:638
32483052 msgid "of this genre"
3249 msgstr "bu türün"
3053 msgstr ""
32503054
32513055 #: src/search-tool-qt/search-tool-qt.cc:814 src/search-tool/search-tool.cc:645
32523056 msgid "on"
3253 msgstr "üzerinde"
3057 msgstr ""
32543058
32553059 #: src/search-tool-qt/search-tool-qt.cc:814 src/search-tool/search-tool.cc:645
32563060 msgid "by"
3257 msgstr "tarafından"
3061 msgstr ""
32583062
32593063 #: src/search-tool-qt/search-tool-qt.cc:832 src/search-tool/search-tool.cc:685
32603064 msgid "_Create Playlist"
3261 msgstr "_Çalma Listesi Oluştur"
3065 msgstr ""
32623066
32633067 #: src/search-tool-qt/search-tool-qt.cc:833 src/search-tool/search-tool.cc:687
32643068 msgid "_Add to Playlist"
3265 msgstr "Ç_alma Listesine Ekle"
3069 msgstr ""
32663070
32673071 #: src/search-tool-qt/search-tool-qt.cc:881 src/search-tool/search-tool.cc:780
32683072 msgid "Search library"
3269 msgstr "Kitaplığı ara"
3073 msgstr ""
32703074
32713075 #: src/search-tool-qt/search-tool-qt.cc:883 src/search-tool/search-tool.cc:784
32723076 msgid ""
32733077 "To import your music library into Audacious, choose a folder and then click "
32743078 "the \"refresh\" icon."
32753079 msgstr ""
3276 "Müzik kitaplığınızı Audacious'a aktarmak için bir dizin seçin ve ardından "
3277 "\"yenileme\" simgesine tıklayın."
32783080
32793081 #: src/search-tool-qt/search-tool-qt.cc:889 src/search-tool/search-tool.cc:793
32803082 msgid "Please wait ..."
3281 msgstr "Lütfen bekleyin ..."
3083 msgstr ""
32823084
32833085 #: src/search-tool/search-tool.cc:821
32843086 msgid "Choose Folder"
32863088
32873089 #: src/sid/xmms-sid.cc:43
32883090 msgid "SID Player"
3289 msgstr "SID Oynatıcı"
3091 msgstr ""
32903092
32913093 #: src/sid/xs_config.cc:62
32923094 msgid "Channels:"
32943096
32953097 #: src/sid/xs_config.cc:68
32963098 msgid "<b>Emulation</b>"
3297 msgstr "<b>Öykünme</b>"
3099 msgstr ""
32983100
32993101 #: src/sid/xs_config.cc:69
33003102 msgid "Emulate MOS 8580 (default: MOS 6581)"
3301 msgstr "MOS 8580 öykün (varsayılan: MOS 6581)"
3103 msgstr ""
33023104
33033105 #: src/sid/xs_config.cc:71
33043106 msgid "Do not automatically select chip model"
3305 msgstr "Çip modelini otomatik seçmeyin"
3107 msgstr ""
33063108
33073109 #: src/sid/xs_config.cc:73
33083110 msgid "Emulate filter"
3309 msgstr "Süzgeci öykün"
3111 msgstr ""
33103112
33113113 #: src/sid/xs_config.cc:75
33123114 msgid "Clock speed:"
3313 msgstr "Saat hızı:"
3115 msgstr ""
33143116
33153117 #: src/sid/xs_config.cc:78
33163118 msgid "Do not automatically select clock speed"
3317 msgstr "Saat hızını otomatik seçmeyin"
3119 msgstr ""
33183120
33193121 #: src/sid/xs_config.cc:80
33203122 msgid "<b>Playback time</b>"
3321 msgstr "<b>Çalma süresi</b>"
3123 msgstr ""
33223124
33233125 #: src/sid/xs_config.cc:81
33243126 msgid "Set maximum playback time:"
3325 msgstr "En fazla oynatma süresini ayarla:"
3127 msgstr ""
33263128
33273129 #: src/sid/xs_config.cc:87
33283130 msgid "Use only when song length is unknown"
3329 msgstr "Sadece şarkı uzunluğu bilinmiyorsa kullanın"
3131 msgstr ""
33303132
33313133 #: src/sid/xs_config.cc:90
33323134 msgid "Set minimum playback time:"
3333 msgstr "En az oynatma süresini ayarla:"
3135 msgstr ""
33343136
33353137 #: src/sid/xs_config.cc:96
33363138 msgid "<b>Subtunes</b>"
3337 msgstr "<b>AltMelodiler</b>"
3139 msgstr ""
33383140
33393141 #: src/sid/xs_config.cc:97
33403142 msgid "Enable subtunes"
3341 msgstr "AltMelodileri etkinleştir"
3143 msgstr ""
33423144
33433145 #: src/sid/xs_config.cc:99
33443146 msgid "Ignore subtunes shorter than:"
3345 msgstr "Alt melodileri, aşağıdakilerden daha kısa olarak yoksay:"
3147 msgstr ""
33463148
33473149 #: src/sid/xs_config.cc:105
33483150 msgid "<b>Note</b>"
3349 msgstr "<b>Not</b>"
3151 msgstr ""
33503152
33513153 #: src/silence-removal/silence-removal.cc:39
33523154 msgid "Silence Removal"
3353 msgstr "Sessizlik Kaldırma"
3155 msgstr ""
33543156
33553157 #: src/silence-removal/silence-removal.cc:58
33563158 msgid ""
33573159 "Silence Removal Plugin for Audacious\n"
33583160 "Copyright 2014 John Lindgren"
33593161 msgstr ""
3360 "Audacious için Sessizlik Kaldırma Eklentisi\n"
3361 "Telif Hakkı 2014 John Lindgren"
33623162
33633163 #: src/silence-removal/silence-removal.cc:67
33643164 msgid "<b>Silence Removal</b>"
3365 msgstr "<b>Sessizlik Kaldırma</b>"
3165 msgstr ""
33663166
33673167 #: src/silence-removal/silence-removal.cc:68
33683168 msgid "Threshold:"
3369 msgstr "Eşik:"
3169 msgstr ""
33703170
33713171 #: src/silence-removal/silence-removal.cc:70
33723172 msgid "dB"
33743174
33753175 #: src/skins/actions.cc:45 src/skins-qt/actions.cc:43
33763176 msgid "Repeat points cleared."
3377 msgstr "Tekrarlanan noktalar temizlendi."
3177 msgstr ""
33783178
33793179 #: src/skins/actions.cc:60 src/skins-qt/actions.cc:58
33803180 msgid "Repeat point A set."
3381 msgstr "Tekrarlama noktası A ayarlı"
3181 msgstr ""
33823182
33833183 #: src/skins/actions.cc:65 src/skins-qt/actions.cc:63
33843184 msgid "Repeat point B set."
3385 msgstr "Tekrarlama noktası B ayarlı"
3185 msgstr ""
33863186
33873187 #: src/skins/equalizer.cc:224 src/skins-qt/equalizer.cc:220
33883188 msgid "Preamp"
3389 msgstr "Ön güçlendirme"
3189 msgstr "Preamp"
33903190
33913191 #: src/skins/equalizer.cc:228 src/skins-qt/equalizer.cc:224
33923192 msgid "31 Hz"
35153315
35163316 #: src/skins/menus.cc:89 src/skins-qt/menus.cc:80
35173317 msgid "Playlist"
3518 msgstr "Çalma Listesi"
3318 msgstr "Parça Listesi"
35193319
35203320 #: src/skins/menus.cc:90 src/skins-qt/menus.cc:81
35213321 msgid "Output"
36383438
36393439 #: src/skins/menus.cc:151 src/skins-qt/menus.cc:146
36403440 msgid "Roll Up Player"
3641 msgstr "Çalıcıyı Topla"
3441 msgstr ""
36423442
36433443 #: src/skins/menus.cc:152 src/skins-qt/menus.cc:147
36443444 msgid "Roll Up Playlist Editor"
3645 msgstr "Oynatma Listesi Düzenleyicisi'ni Topla"
3445 msgstr ""
36463446
36473447 #: src/skins/menus.cc:153 src/skins-qt/menus.cc:148
36483448 msgid "Roll Up Equalizer"
3649 msgstr "Ekolayzır'ı Topla"
3449 msgstr ""
36503450
36513451 #: src/skins/menus.cc:161 src/skins-qt/menus.cc:156
36523452 msgid "Add URL ..."
36603460 #: src/skins-qt/menus.cc:162 src/skins-qt/menus.cc:188
36613461 #: src/skins-qt/menus.cc:203
36623462 msgid "By Title"
3663 msgstr "Başlığa Göre"
3463 msgstr ""
36643464
36653465 #: src/skins/menus.cc:167 src/skins/menus.cc:201 src/skins/menus.cc:216
36663466 #: src/skins-qt/menus.cc:163 src/skins-qt/menus.cc:195
36673467 #: src/skins-qt/menus.cc:210
36683468 msgid "By File Name"
3669 msgstr "Dosya İsmine Göre"
3469 msgstr ""
36703470
36713471 #: src/skins/menus.cc:168 src/skins/menus.cc:202 src/skins/menus.cc:217
36723472 #: src/skins-qt/menus.cc:164 src/skins-qt/menus.cc:196
36733473 #: src/skins-qt/menus.cc:211
36743474 msgid "By File Path"
3675 msgstr "Dosya Yoluna Göre"
3475 msgstr ""
36763476
36773477 #: src/skins/menus.cc:174 src/skins-qt/menus.cc:170
36783478 msgid "Remove All"
36803480
36813481 #: src/skins/menus.cc:175 src/skins-qt/menus.cc:171
36823482 msgid "Clear Queue"
3683 msgstr "Kuyruğu Temizle"
3483 msgstr ""
36843484
36853485 #: src/skins/menus.cc:177 src/skins-qt/menus.cc:173
36863486 msgid "Remove Unavailable Files"
37523552 #: src/skins/menus.cc:203 src/skins/menus.cc:218 src/skins-qt/menus.cc:197
37533553 #: src/skins-qt/menus.cc:212
37543554 msgid "By Custom Title"
3755 msgstr "Özel Başlığa Göre"
3555 msgstr ""
37563556
37573557 #: src/skins/menus.cc:204 src/skins/menus.cc:219 src/skins-qt/menus.cc:198
37583558 #: src/skins-qt/menus.cc:213
37593559 msgid "By Comment"
3760 msgstr "Yoruma Göre"
3560 msgstr ""
37613561
37623562 #: src/skins/menus.cc:223 src/skins-qt/menus.cc:217
37633563 msgid "Randomize List"
37653565
37663566 #: src/skins/menus.cc:224 src/skins-qt/menus.cc:218
37673567 msgid "Reverse List"
3768 msgstr "Ters Liste"
3568 msgstr ""
37693569
37703570 #: src/skins/menus.cc:226 src/skins-qt/menus.cc:220
37713571 msgid "Sort Selected"
3772 msgstr "Seçileni Sırala"
3572 msgstr ""
37733573
37743574 #: src/skins/menus.cc:227 src/skins-qt/menus.cc:221
37753575 msgid "Sort List"
37773577
37783578 #: src/skins/menus.cc:232 src/skins-qt/menus.cc:226
37793579 msgid "Open Containing Folder"
3780 msgstr "İçeren Dizini Aç"
3580 msgstr ""
37813581
37823582 #: src/skins/menus.cc:234 src/skins-qt/menus.cc:228
37833583 msgid "Cut"
37933593
37943594 #: src/skins/menus.cc:237 src/skins-qt/menus.cc:231
37953595 msgid "Paste at End"
3796 msgstr "Sonunda Yapıştır"
3596 msgstr ""
37973597
37983598 #: src/skins/menus.cc:239 src/skins-qt/menus.cc:233
37993599 msgid "Queue/Unqueue"
3800 msgstr "Kuyruğa Ekle/Kaldır"
3600 msgstr ""
38013601
38023602 #: src/skins/playlist-widget.cc:55 src/skins-qt/playlist-widget.cc:53
38033603 #, c-format
38043604 msgid "%s (%d of %d)"
3805 msgstr "%s (%d 'den %d 'si)"
3605 msgstr ""
38063606
38073607 #: src/skins/playlistwin.cc:492 src/skins-qt/playlistwin.cc:477
38083608 msgid "Audacious Playlist Editor"
3809 msgstr "Audacious Çalma Listesi Düzenleyici"
3609 msgstr ""
38103610
38113611 #: src/skins/plugin.cc:49 src/skins-qt/plugin.cc:51
38123612 msgid "Winamp Classic Interface"
3813 msgstr "Winamp Klasik Arayüzü"
3613 msgstr ""
38143614
38153615 #: src/skins-qt/menus.cc:75
38163616 msgid "Open Folder ..."
3817 msgstr "Dizin Aç ..."
3617 msgstr ""
38183618
38193619 #: src/skins-qt/menus.cc:157
38203620 msgid "Add Folder ..."
3821 msgstr "Dizin Ekle ..."
3621 msgstr ""
38223622
38233623 #: src/skins-qt/skins_cfg.cc:196 src/skins/skins_cfg.cc:180
38243624 msgid "Player:"
3825 msgstr "Çalıcı:"
3625 msgstr ""
38263626
38273627 #: src/skins-qt/skins_cfg.cc:198 src/skins/skins_cfg.cc:182
38283628 msgid "Select main player window font:"
38303630
38313631 #: src/skins-qt/skins_cfg.cc:199 src/skins/skins_cfg.cc:183
38323632 msgid "Playlist:"
3833 msgstr "Çalma Listesi:"
3633 msgstr ""
38343634
38353635 #: src/skins-qt/skins_cfg.cc:201 src/skins/skins_cfg.cc:185
38363636 msgid "Select playlist font:"
3837 msgstr "Çalma listesi yazıtipi seç:"
3637 msgstr ""
38383638
38393639 #: src/skins-qt/skins_cfg.cc:205 src/skins/skins_cfg.cc:189
38403640 msgid "<b>Skin</b>"
3841 msgstr "<b>Kabuk</b>"
3641 msgstr ""
38423642
38433643 #: src/skins-qt/skins_cfg.cc:209 src/skins/skins_cfg.cc:191
38443644 msgid "<b>Fonts</b>"
3845 msgstr "<b>Yazıtipleri</b>"
3645 msgstr ""
38463646
38473647 #: src/skins-qt/skins_cfg.cc:211 src/skins/skins_cfg.cc:193
38483648 msgid "Use bitmap fonts (supports ASCII only)"
3849 msgstr "Bitmap yazı tiplerini kullan (yalnızca ASCII'yi destekler)"
3649 msgstr ""
38503650
38513651 #: src/skins-qt/skins_cfg.cc:213 src/skins/skins_cfg.cc:195
38523652 msgid "Scroll song title"
3853 msgstr "Şarkı başlığını kaydır"
3653 msgstr ""
38543654
38553655 #: src/skins-qt/skins_cfg.cc:215 src/skins/skins_cfg.cc:197
38563656 msgid "Scroll song title in both directions"
3857 msgstr "Her iki yönde şarkı başlığını kaydır"
3657 msgstr ""
38583658
38593659 #: src/skins-qt/skins_cfg.cc:220 src/skins/skins_cfg.cc:202
38603660 msgid "Analyzer"
38623662
38633663 #: src/skins-qt/skins_cfg.cc:221 src/skins/skins_cfg.cc:203
38643664 msgid "Scope"
3865 msgstr "Kapsam"
3665 msgstr ""
38663666
38673667 #: src/skins-qt/skins_cfg.cc:222 src/skins/skins_cfg.cc:204
38683668 msgid "Voiceprint / VU meter"
3869 msgstr "Ses izi / VU metre"
3669 msgstr ""
38703670
38713671 #: src/skins-qt/skins_cfg.cc:223 src/skins/skins_cfg.cc:205
38723672 msgid "Off"
38853685
38863686 #: src/skins-qt/skins_cfg.cc:229 src/skins/skins_cfg.cc:211
38873687 msgid "Vertical lines"
3888 msgstr "Dikey çizgiler"
3688 msgstr ""
38893689
38903690 #: src/skins-qt/skins_cfg.cc:233 src/skins/skins_cfg.cc:215
38913691 msgid "Lines"
38973697
38983698 #: src/skins-qt/skins_cfg.cc:238 src/skins/skins_cfg.cc:220
38993699 msgid "Slowest"
3900 msgstr "En yavaş"
3700 msgstr ""
39013701
39023702 #: src/skins-qt/skins_cfg.cc:239 src/skins/skins_cfg.cc:221
39033703 msgid "Slow"
39143714
39153715 #: src/skins-qt/skins_cfg.cc:242 src/skins/skins_cfg.cc:224
39163716 msgid "Fastest"
3917 msgstr "En hızlı"
3717 msgstr ""
39183718
39193719 #: src/skins-qt/skins_cfg.cc:246 src/skins/skins_cfg.cc:228
39203720 msgid "Dots"
3921 msgstr "Noktalar"
3721 msgstr ""
39223722
39233723 #: src/skins-qt/skins_cfg.cc:247 src/skins/skins_cfg.cc:229
39243724 msgid "Line"
39263726
39273727 #: src/skins-qt/skins_cfg.cc:248 src/skins/skins_cfg.cc:230
39283728 msgid "Solid"
3929 msgstr "Katı"
3729 msgstr ""
39303730
39313731 #: src/skins-qt/skins_cfg.cc:254 src/skins/skins_cfg.cc:236
39323732 msgid "Ice"
3933 msgstr "Buz"
3733 msgstr ""
39343734
39353735 #: src/skins-qt/skins_cfg.cc:259 src/skins/skins_cfg.cc:241
39363736 msgid "Smooth"
3937 msgstr "Pürüzsüz"
3737 msgstr ""
39383738
39393739 #: src/skins-qt/skins_cfg.cc:263 src/skins/skins_cfg.cc:245
39403740 msgid "Coloring:"
3941 msgstr "Boyama:"
3741 msgstr ""
39423742
39433743 #: src/skins-qt/skins_cfg.cc:266 src/skins/skins_cfg.cc:248
39443744 msgid "Style:"
3945 msgstr "Tarz:"
3745 msgstr ""
39463746
39473747 #: src/skins-qt/skins_cfg.cc:269 src/skins/skins_cfg.cc:251
39483748 msgid "Falloff:"
3949 msgstr "Düşme:"
3749 msgstr ""
39503750
39513751 #: src/skins-qt/skins_cfg.cc:272 src/skins/skins_cfg.cc:254
39523752 msgid "Peak falloff:"
3953 msgstr "Tepe düşme:"
3753 msgstr ""
39543754
39553755 #: src/skins-qt/skins_cfg.cc:278 src/skins/skins_cfg.cc:260
39563756 msgid "Scope Style:"
3957 msgstr "Kapsam Tarzı:"
3757 msgstr ""
39583758
39593759 #: src/skins-qt/skins_cfg.cc:281 src/skins/skins_cfg.cc:263
39603760 msgid "Voiceprint Coloring:"
3961 msgstr "Ses izi Boyama:"
3761 msgstr ""
39623762
39633763 #: src/skins-qt/skins_cfg.cc:284 src/skins/skins_cfg.cc:266
39643764 msgid "VU Meter Style:"
3965 msgstr "VU Metre Tarzı:"
3765 msgstr ""
39663766
39673767 #: src/skins-qt/skins_cfg.cc:290 src/skins/skins_cfg.cc:272
39683768 msgid "<b>Type</b>"
3969 msgstr "<b>Tür</b>"
3769 msgstr ""
39703770
39713771 #: src/skins-qt/skins_cfg.cc:291 src/skins/skins_cfg.cc:273
39723772 msgid "Visualization type:"
3973 msgstr "Görselleştirme türü:"
3773 msgstr ""
39743774
39753775 #: src/skins-qt/skins_cfg.cc:294 src/skins/skins_cfg.cc:276
39763776 msgid "<b>Analyzer</b>"
3977 msgstr "<b>Çözümleyici</b>"
3777 msgstr ""
39783778
39793779 #: src/skins-qt/skins_cfg.cc:295 src/skins/skins_cfg.cc:277
39803780 msgid "Show peaks"
3981 msgstr "Tepeleri göster"
3781 msgstr ""
39823782
39833783 #: src/skins-qt/skins_cfg.cc:304 src/skins/skins_cfg.cc:286
39843784 msgid "Visualization"
39863786
39873787 #: src/skins-qt/skinselector.cc:98 src/skins/skinselector.cc:111
39883788 msgid "Archived Winamp 2.x skin"
3989 msgstr "Arşivlenmiş Winamp 2.x kabuğu"
3789 msgstr ""
39903790
39913791 #: src/skins-qt/skinselector.cc:102 src/skins/skinselector.cc:115
39923792 msgid "Unarchived Winamp 2.x skin"
3993 msgstr "Arşivlenmemiş Winamp 2.x kabuğu"
3793 msgstr ""
39943794
39953795 #: src/skins/search-select.cc:75
39963796 msgid "Search entries in active playlist"
3997 msgstr "Etkin oynatma listesinde arama girişleri"
3797 msgstr ""
39983798
39993799 #: src/skins/search-select.cc:76
40003800 msgid "Search"
40073807 "expressions work, simply insert a literal portion of what you're searching "
40083808 "for."
40093809 msgstr ""
4010 "Bir veya daha fazla alanı doldurarak oynatma listesindeki girişleri seçin. "
4011 "Alanlarda normal ifadeler sözdizimi, büyük / küçük harf duyarlı değil. "
4012 "Normal ifadelerin nasıl çalıştığını bilmiyorsanız, aradığınız şeylerin basit "
4013 "bir kısmını eklemeniz yeterlidir."
40143810
40153811 #: src/skins/search-select.cc:89
40163812 msgid "Title:"
40343830
40353831 #: src/skins/search-select.cc:118
40363832 msgid "Automatically toggle queue for matching entries"
4037 msgstr "Eşleşen girişler için sıraya otomatik olarak geçiş yap"
3833 msgstr ""
40383834
40393835 #: src/skins/search-select.cc:121
40403836 msgid "Create a new playlist with matching entries"
4041 msgstr "Eşleşen girişlerle yeni bir oynatma listesi oluşturun"
3837 msgstr ""
40423838
40433839 #: src/sndfile/plugin.cc:37
40443840 msgid "Sndfile Plugin"
4045 msgstr "Sndfile Eklentisi"
3841 msgstr ""
40463842
40473843 #: src/sndfile/plugin.cc:361
40483844 msgid ""
40653861 "this program; if not, write to the Free Software Foundation, Inc., 51 "
40663862 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
40673863 msgstr ""
4068 "Xmms_sndfile eklentisine dayanarak:\n"
4069 "Telif Hakkı (C) 2000, 2002 Erik de Castro Lopo\n"
4070 "\n"
4071 "Audacious için Tony Vroon tarafından uyarlanmıştır <chainsaw@gentoo.org>\n"
4072 "\n"
4073 "Bu program ücretsiz bir yazılımdır; Özgür Yazılım Vakfı tarafından "
4074 "yayımlanan GNU Genel Kamu Lisansı şartlarına göre yeniden dağıtabilir ve / "
4075 "veya değiştirebilirsiniz. Lisansın 2 numaralı sürümü veya (seçimlerinize "
4076 "göre) herhangi bir sonraki sürümü.\n"
4077 "\n"
4078 "Bu program yararlı olacağı umuduyla dağıtılır, ancak HERHANGİ BİR GARANTİ "
4079 "OLMAKSIZIN; SATILABİLİRLİK veya BELİRLİ BİR AMACA UYGUNLUĞU'nun zımni "
4080 "garantisi dahi olmadan. Daha fazla bilgi için GNU Genel Kamu Lisansına "
4081 "bakınız.\n"
4082 "\n"
4083 "Bu programla birlikte GNU Genel Kamu Lisansının bir kopyasını almış "
4084 "olmalısınız; eğer değilse, Free Software Foundation, Inc., 51 Franklin "
4085 "Street, Beşinci Kat, Boston, MA 02110-1301, ABD'ye yazın."
40863864
40873865 #: src/sndio/sndio.cc:43
40883866 msgid "Sndio Output"
4089 msgstr "Sndio Çıkışı"
3867 msgstr ""
40903868
40913869 #: src/sndio/sndio.cc:98
40923870 msgid "Device (blank for default):"
4093 msgstr "Aygıt (varsayılan olarak boş):"
3871 msgstr ""
40943872
40953873 #: src/sndio/sndio.cc:100
40963874 msgid "Save and restore volume:"
4097 msgstr "Sesi kaydet ve geri yükle:"
3875 msgstr ""
40983876
40993877 #: src/sndio/sndio.cc:181
41003878 #, c-format
41013879 msgid "Sndio error: Unsupported audio format (%d)"
4102 msgstr "Sndio hatası: Desteklenmeyen ses biçimi (%d)"
3880 msgstr ""
41033881
41043882 #: src/sndio/sndio.cc:192
41053883 msgid "Sndio error: sio_open() failed"
4106 msgstr "Sndio hatası: sio_open () başarısız oldu"
3884 msgstr ""
41073885
41083886 #: src/sndio/sndio.cc:221
41093887 msgid "Sndio error: sio_setpar() failed"
4110 msgstr "Sndio hatası: sio_setpar () başarısız oldu"
3888 msgstr ""
41113889
41123890 #: src/sndio/sndio.cc:233
41133891 msgid "Sndio error: sio_start() failed"
4114 msgstr "Sndio hatası: sio_start () başarısız oldu"
3892 msgstr ""
41153893
41163894 #: src/songchange/song_change.cc:33
41173895 msgid "Song Change"
41233901
41243902 #: src/songchange/song_change.cc:270
41253903 msgid "Command to run when starting a new song:"
4126 msgstr "Yeni bir şarkı başlatırken çalıştırılacak komut:"
3904 msgstr ""
41273905
41283906 #: src/songchange/song_change.cc:273
41293907 msgid "Command to run at the end of a song:"
4130 msgstr "Bir şarkının sonunda çalıştırmak için komut:"
3908 msgstr ""
41313909
41323910 #: src/songchange/song_change.cc:276
41333911 msgid "Command to run at the end of the playlist:"
4134 msgstr "Çalma listesinin sonunda çalıştırılacak komut:"
3912 msgstr ""
41353913
41363914 #: src/songchange/song_change.cc:279
41373915 msgid "Command to run when song title changes (for network streams):"
4138 msgstr "Şarkı adı değiştiğinde çalıştırılacak komut (ağ akışları için):"
3916 msgstr ""
41393917
41403918 #: src/songchange/song_change.cc:282
41413919 msgid ""
41423920 "You can use the following format codes, which will be replaced before "
41433921 "running the command (not all are useful for the end-of-playlist command):"
41443922 msgstr ""
4145 "Komutu çalıştırmadan önce değiştirilecek olan aşağıdaki kodları "
4146 "kullanabilirsiniz (çalma listesi komutu için hepsi kullanışlı değildir):"
41473923
41483924 #: src/songchange/song_change.cc:285
41493925 msgid ""
41593935 "%t: Playlist position\n"
41603936 "%T: Title (unformatted)"
41613937 msgstr ""
4162 "%a: Sanatçı\n"
4163 "%b: Albüm\n"
4164 "%c: Kanalların Sayısı\n"
4165 "%f: Dosya adı (tam yol)\n"
4166 "%F: Frekans (Hertz)\n"
4167 "%l: Uzunluk (milisaniye)\n"
4168 "%n or %s: Biçimlendirilmiş başlık (çalma listesi ayarlarına bakın)\n"
4169 "%p: Şu anda çalan (1 veya 0)\n"
4170 "%r: Oran (Saniye başına bit)\n"
4171 "%t: Çalma listesi konumu\n"
4172 "%T: Başlık (biçimlendirilmemiş)"
41733938
41743939 #: src/songchange/song_change.cc:296
41753940 msgid ""
41763941 "Parameters passed to the shell should be enclosed in quotation marks. "
41773942 "Unquoted parameters may lead to unexpected results."
41783943 msgstr ""
4179 "Kabuğa geçirilen parametreler tırnak içine alınmalıdır. Belirtilmeyen "
4180 "parametreler beklenmedik sonuçlara yol açabilir."
41813944
41823945 #: src/song-info-qt/song-info.cc:33
41833946 msgid "Song Info"
41853948
41863949 #: src/soxr/sox-resampler.cc:44
41873950 msgid "SoX Resampler"
4188 msgstr "SoX Resampler"
3951 msgstr ""
41893952
41903953 #: src/soxr/sox-resampler.cc:157
41913954 msgid ""
41953958 "Based on Sample Rate Converter Plugin:\n"
41963959 "Copyright 2010-2012 John Lindgren"
41973960 msgstr ""
4198 "Audacious için Sox Resampler Eklentisi\n"
4199 "Telif Hakkı 2013 Michał Lipski\n"
4200 "\n"
4201 "Örnekleme Hızı Dönüştürücü Eklentisine dayalı:\n"
4202 "Copyright 2010-2012 John Lindgren"
42033961
42043962 #: src/soxr/sox-resampler.cc:163
42053963 msgid "Quick"
42193977
42203978 #: src/soxr/sox-resampler.cc:168
42213979 msgid "Ultra High"
4222 msgstr "Çok Yüksek"
3980 msgstr ""
42233981
42243982 #: src/soxr/sox-resampler.cc:172
42253983 msgid "Minimum"
4226 msgstr "En az"
3984 msgstr ""
42273985
42283986 #: src/soxr/sox-resampler.cc:173
42293987 msgid "Intermediate"
4230 msgstr "Orta düzey"
3988 msgstr ""
42313989
42323990 #: src/soxr/sox-resampler.cc:174
42333991 msgid "Linear"
4234 msgstr "Doğrusal"
3992 msgstr ""
42353993
42363994 #: src/soxr/sox-resampler.cc:178
42373995 msgid "Quality:"
42393997
42403998 #: src/soxr/sox-resampler.cc:181
42413999 msgid "Phase:"
4242 msgstr "Faz:"
4000 msgstr ""
42434001
42444002 #: src/soxr/sox-resampler.cc:185
42454003 msgid "Allow aliasing"
4246 msgstr "Allow aliasing"
4004 msgstr ""
42474005
42484006 #: src/soxr/sox-resampler.cc:187
42494007 msgid "Use steep filter"
4250 msgstr "Dik filtre kullan"
4008 msgstr ""
42514009
42524010 #: src/speedpitch/speed-pitch.cc:54
42534011 msgid "Speed and Pitch"
4254 msgstr "Hız ve Saha"
4012 msgstr ""
42554013
42564014 #: src/speedpitch/speed-pitch.cc:247
42574015 msgid "<b>Speed</b>"
4258 msgstr "<b>Hız</b>"
4016 msgstr ""
42594017
42604018 #: src/speedpitch/speed-pitch.cc:248
42614019 msgid "Decouple from pitch"
4262 msgstr "Sahadan çözme"
4020 msgstr ""
42634021
42644022 #: src/speedpitch/speed-pitch.cc:250 src/speedpitch/speed-pitch.cc:258
42654023 msgid "Multiplier:"
4266 msgstr "Çarpan:"
4024 msgstr ""
42674025
42684026 #: src/speedpitch/speed-pitch.cc:254
42694027 msgid "<b>Pitch</b>"
4270 msgstr "<b>Saha</b>"
4028 msgstr ""
42714029
42724030 #: src/statusicon-qt/statusicon.cc:45 src/statusicon/statusicon.cc:47
42734031 msgid "Status Icon"
42844042 "This plugin provides a status icon, placed in\n"
42854043 "the system tray area of the window manager."
42864044 msgstr ""
4287 "Durum Simgesi Eklentisi (Qt arabirimi için kısmi bağlantı noktası)\n"
4288 "Telif Hakkı 2005-2007 Giacomo Lozito <james@develia.org>\n"
4289 "Telif Hakkı 2010 Michał Lipski <tallica@o2.pl>\n"
4290 "Telif Hakkı 2015 Eugene Paskevich <eugene@raptor.kiev.ua>\n"
4291 "\n"
4292 "Bu eklenti, pencere yöneticisinin sistem tepsisi\n"
4293 "alanına yerleştirilmiş bir durum simgesi sağlar."
42944045
42954046 #: src/statusicon-qt/statusicon.cc:88 src/statusicon/statusicon.cc:381
42964047 msgid "<b>Mouse Scroll Action</b>"
43184069
43194070 #: src/statusicon-qt/statusicon.cc:100 src/statusicon/statusicon.cc:393
43204071 msgid "Advance in playlist when scrolling upward"
4321 msgstr "Yukarı kaydırma yaparken çalma listesinde ilerleyin"
4072 msgstr ""
43224073
43234074 #: src/statusicon-qt/statusicon.cc:115 src/statusicon/statusicon.cc:284
43244075 msgid "Se_ttings ..."
4325 msgstr "A_yarlar ..."
4076 msgstr ""
43264077
43274078 #: src/statusicon/statusicon.cc:374
43284079 msgid ""
43344085 "This plugin provides a status icon, placed in\n"
43354086 "the system tray area of the window manager."
43364087 msgstr ""
4337 "Durum Simgesi Eklentisi\n"
4338 "\n"
4339 "Telif Hakkı 2005-2007 Giacomo Lozito <james@develia.org>\n"
4340 "Telif Hakkı 2010 Michał Lipski <tallica@o2.pl>\n"
4341 "\n"
4342 "Bu eklenti, pencere yöneticisinin sistem tepsisi\n"
4343 "alanına yerleştirilmiş bir durum simgesi sağlar."
43444088
43454089 #: src/stereo_plugin/stereo.cc:19
43464090 msgid "Extra Stereo"
43524096 "\n"
43534097 "By Johan Levin, 1999"
43544098 msgstr ""
4355 "Stereo Artırma Eklentisi\n"
4356 "\n"
4357 "Johan Levin tarafından, 1999"
43584099
43594100 #: src/stereo_plugin/stereo.cc:44
43604101 msgid "<b>Extra Stereo</b>"
43624103
43634104 #: src/tonegen/tonegen.cc:45
43644105 msgid "Tone Generator"
4365 msgstr "Ton Oluşturucu"
4106 msgstr ""
43664107
43674108 #: src/tonegen/tonegen.cc:92
43684109 #, c-format
43814122 "To use it, add a URL: tone://frequency1;frequency2;frequency3;...\n"
43824123 "e.g. tone://2000;2005 to play a 2000 Hz tone and a 2005 Hz tone"
43834124 msgstr ""
4384 "Håvard Kvålen'in ton üreteci <havardk@xmms.org>\n"
4385 "Daniel J. Peng tarafından değiştirildi <danielpeng@bigfoot.com>\n"
4386 "\n"
4387 "Kullanmak için bir URL ekleyin: tone://frequency1;frequency2;frequency3;...\n"
4388 "örneğin tone://2000;2005 bir 2000 Hz ton ve bir 2005 Hz ton çalmak için"
43894125
43904126 #: src/ui-common/dialogs-qt.cc:31
43914127 msgid "Working ..."
44194155 "Gian-Carlo Pascutto <gcp@sjeng.org>\n"
44204156 "Eugene Zagidullin <e.asphyx@gmail.com>"
44214157 msgstr ""
4422 "Audacious Ogg Vorbis Çözücü\n"
4423 "\n"
4424 "Xiph.org Vakfı’nın Ogg Vorbis Eklentisine dayanarak:\n"
4425 "http://www.xiph.org/\n"
4426 "\n"
4427 "Özgün kod:\n"
4428 "Tony Arcieri tarafından <bascule@inferno.tusculum.edu>\n"
4429 "\n"
4430 "Katkıcılar:\n"
4431 "Chris Montgomery <monty@xiph.org>\n"
4432 "Peter Alm <peter@xmms.org>\n"
4433 "Michael Smith <msmith@labyrinth.edu.au>\n"
4434 "Jack Moffitt <jack@icecast.org>\n"
4435 "Jorn Baayen <jorn@nl.linux.org>\n"
4436 "Håvard Kvålen <havardk@xmms.org>\n"
4437 "Gian-Carlo Pascutto <gcp@sjeng.org>\n"
4438 "Eugene Zagidullin <e.asphyx@gmail.com>"
44394158
44404159 #: src/vorbis/vorbis.h:18
44414160 msgid "Ogg Vorbis Decoder"
44444163 #: src/vtx/info.cc:24
44454164 #, c-format
44464165 msgid "Details about %s"
4447 msgstr "%s hakkında ayrıntılar"
4166 msgstr ""
44484167
44494168 #: src/vtx/info.cc:26
44504169 msgid ""
44604179 "Player Freq: %P\n"
44614180 "Year: %y"
44624181 msgstr ""
4463 "Başlık: %t\n"
4464 "Yazar: %a\n"
4465 "İtibaren: %f\n"
4466 "Takipçi: %T\n"
4467 "Yorum: %C\n"
4468 "Çip türü: %c\n"
4469 "Stereo: %s\n"
4470 "Döngü: %l\n"
4471 "Çip Frekansı: %F\n"
4472 "Çalıcı Frekansı: %P\n"
4473 "Yıl: %y"
44744182
44754183 #: src/vtx/vtx.cc:38
44764184 msgid "VTX Decoder"
44824190 "Based on in_vtx.dll by Roman Sherbakov <v_soft@microfor.ru>\n"
44834191 "Audacious plugin by Pavel Vymetalek <pvymetalek@seznam.cz>"
44844192 msgstr ""
4485 "Sashnov Alexander tarafından Vortex dosya biçimi çalıcı <sashnov@ngs.ru>\n"
4486 "Roman Sherbakov tarafından in_vtx.dll dayanarak <v_soft@microfor.ru>\n"
4487 "Pavel Vymetalek tarafından Audacious eklentisi <pvymetalek@seznam.cz>"
44884193
44894194 #: src/waveout/waveout.cc:43
44904195 msgid "Win32 waveOut"
4491 msgstr "Win32 waveOut"
4196 msgstr ""
44924197
44934198 #: src/waveout/waveout.cc:69
44944199 msgid ""
44954200 "Win32 waveOut Plugin for Audacious\n"
44964201 "Copyright 2016 John Lindgren"
44974202 msgstr ""
4498 "Audacious için Win32 waveOut eklentisi\n"
4499 "Telif Hakkı 2016 John Lindgren"
45004203
45014204 #: src/wavpack/wavpack.cc:24
45024205 msgid "WavPack Decoder"
45044207
45054208 #: src/wavpack/wavpack.cc:211
45064209 msgid "lossy (hybrid)"
4507 msgstr "yozlaşmış (melez)"
4210 msgstr ""
45084211
45094212 #: src/wavpack/wavpack.cc:213
45104213 msgid "lossy"
4511 msgstr "yozlaşmış"
4214 msgstr ""
45124215
45134216 #: src/wavpack/wavpack.cc:251
45144217 msgid ""
45274230
45284231 #: src/xsf/plugin.cc:231
45294232 msgid "<b>XSF Configuration</b>"
4530 msgstr "<b>XSF Yapılandırması</b>"
4233 msgstr ""
45314234
45324235 #: src/xsf/plugin.cc:232
45334236 msgid "Ignore length from file"
4534 msgstr "Dosyadan uzunluğu yoksay"
4237 msgstr ""
45354238
45364239 #: src/xspf/xspf.cc:91
45374240 msgid "XML Shareable Playlists (XSPF)"
4538 msgstr "XML Paylaşılabilir çalma listesi (XSPF)"
4241 msgstr "XML Paylaşılabilir müzik listesi (XSPF)"
45394242
45404243 #~ msgid "GNOME Shortcuts"
45414244 #~ msgstr "GNOME Kısayolları"
4542
4543 #~ msgid ""
4544 #~ "GNOME Shortcut Plugin\n"
4545 #~ "Lets you control the player with GNOME's shortcuts.\n"
4546 #~ "\n"
4547 #~ "Copyright (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>"
4548 #~ msgstr ""
4549 #~ "GNOME Kısayol Eklentisi\n"
4550 #~ "Oynatıcıyı GNOME'un kısayollarıyla kontrol etmenizi sağlar.\n"
4551 #~ "\n"
4552 #~ "Telif Hakkı (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>"
+287
-428
po/uk.po less more
1717 # Rustam Tsurik <rustam.tsurik@gmail.com>, 2013
1818 # Rustam Tsurik <rustam.tsurik@gmail.com>, 2013
1919 # Oleg <kvantarium@gmail.com>, 2012
20 # Taras Holyj, 2017-2018
20 # Taras Shevchenko, 2017
2121 # Yuri Chornoivan <yurchor@ukr.net>, 2012
2222 # Олександр Сенін <aleniksenin@gmail.com>, 2016
2323 # Ярослав Смук <Smuk.Slavko@yandex.ua>, 2018
2525 msgstr ""
2626 "Project-Id-Version: Audacious Plugins\n"
2727 "Report-Msgid-Bugs-To: https://redmine.audacious-media-player.org/\n"
28 "POT-Creation-Date: 2018-08-04 20:51+0200\n"
29 "PO-Revision-Date: 2018-12-26 06:11+0000\n"
30 "Last-Translator: Taras Holyj\n"
28 "POT-Creation-Date: 2018-08-04 20:48+0200\n"
29 "PO-Revision-Date: 2018-07-29 21:54+0000\n"
30 "Last-Translator: Thomas Lange\n"
3131 "Language-Team: Ukrainian (http://www.transifex.com/audacious/audacious/"
3232 "language/uk/)\n"
3333 "Language: uk\n"
4141
4242 #: src/aac/aac.cc:18
4343 msgid "AAC (Raw) Decoder"
44 msgstr "Декодер AAC (Сирий)"
44 msgstr "Декодер AAC (Raw)"
4545
4646 #: src/adplug/adplug-xmms.cc:50
4747 msgid "AdPlug (AdLib Player)"
5454
5555 #: src/adplug/adplug-xmms.cc:297 src/sid/xs_config.cc:61
5656 msgid "<b>Output</b>"
57 msgstr "<b>Виведення</b>"
57 msgstr "<b>Вихід</b>"
5858
5959 #: src/adplug/adplug-xmms.cc:298
6060 msgid "16-bit output (if unchecked, output is 8-bit)"
61 msgstr "16-тибітове виведення (якщо вимкнено, виводиметься у 8 бітів)"
61 msgstr ""
6262
6363 #: src/adplug/adplug-xmms.cc:300
6464 msgid "Duplicate mono output to two channels"
65 msgstr "Дублювати моно у два канали"
65 msgstr ""
6666
6767 #: src/adplug/adplug-xmms.cc:302
6868 msgid "Sample rate"
69 msgstr "Частота дискретизації"
69 msgstr ""
7070
7171 #: src/adplug/adplug-xmms.cc:303 src/amidiplug/i_configure.cc:152
7272 #: src/bs2b/plugin.cc:141 src/console/plugin.cc:47
8888
8989 #: src/adplug/adplug-xmms.cc:305
9090 msgid "Repeat song in endless loop"
91 msgstr "Зациклити пісню у вічному повторенні"
91 msgstr ""
9292
9393 #: src/alarm/alarm.cc:55 src/alarm/interface.cc:79
9494 msgid "Alarm"
9696
9797 #: src/alarm/alarm.cc:782
9898 msgid "Set Alarm ..."
99 msgstr "Встановити будильника..."
99 msgstr "Встановити будильник..."
100100
101101 #: src/alarm/alarm.cc:810
102102 msgid ""
106106 msgstr ""
107107 "Відтворення в заданий час.\n"
108108 "\n"
109 "Автори джерельного втулку: Adam Feakin, Daniel Stodden."
109 "Автори плаґіну-оригіналу: Adam Feakin, Daniel Stodden."
110110
111111 #: src/alarm/interface.cc:28
112112 msgid ""
158158 " Type the reminder in the input field and enable\n"
159159 " the checkbox if you want it to be shown."
160160 msgstr ""
161 "Час\n"
162 " Починати о: \n"
163 " Час початку відтворення.\n"
164 "\n"
165 " Закінчити через: \n"
166 " Тривалість відтворення.\n"
167 " (якщо діалогове вікно пробудження\n"
168 " не закрито примусово)\n"
169 "\n"
170 "\n"
171 "Дні\n"
172 " День:\n"
173 " День тижня, в який працюватиме будильник.\n"
174 "\n"
175 " Час:\n"
176 " Час спрацювання в обраний день.\n"
177 " Якщо вибрано «Як типово», будильник спрацює\n"
178 " в типовий час (вкладка «Час»).\n"
179 "\n"
180 "\n"
181 "Гучність\n"
182 " Наростання: \n"
183 " Період наростання гучності.\n"
184 "\n"
185 " На початку: \n"
186 " Гучність на початку наростання.\n"
187 "\n"
188 " По закінченню: \n"
189 " Гучність наприкінці наростання. Якщо часом\n"
190 " наростання є «0», то все відтворення йтиме\n"
191 " з цією гучністю.\n"
192 "\n"
193 "\n"
194 "Опції:\n"
195 " Виконувати команду:\n"
196 " Команда запускатиметься при спрацьовуванні.\n"
197 "\n"
198 " Список відтворення (необов’язково): \n"
199 " Відтворювати список відтворення (лише\n"
200 " з суфіксом .m3u). Якщо не вказано, то\n"
201 " відтворюватимуться останні відкриті\n"
202 " доріжки.\n"
203 " Можна ввести сюди URL mp3- чи ogg-потоку.\n"
204 " Поки що звантаження списків відтворення\n"
205 " за URL не підтримується.\n"
206 "\n"
207 " Нагадування:\n"
208 " Повідомлення буде показано при спрацьовуванні.\n"
209 " Введіть повідомлення в поле\n"
210 " й увімкніть Використовувати, якщо ви хочети його бачити."
211161
212162 #: src/alarm/interface.cc:78
213163 msgid "This is your wakeup call."
214 msgstr "Ваш текст для пробудження."
164 msgstr "Ваш текст для піднімання."
215165
216166 #: src/alarm/interface.cc:96
217167 msgid "Your reminder for today is..."
361311 "My thanks to William Pitcock, author of the ALSA Output Plugin NG, whose "
362312 "code served as a reference when the ALSA manual was not enough."
363313 msgstr ""
364 " Виводний втулок ALSA,\n"
314 "Плаґін виводу ALSA,\n"
365315 "написаний Джоном Ліндґреном у 2010–2012 роках.\n"
366316 "\n"
367317 "Дякую авторові ALSA Output Plugin NG (William Pitcock), чий код допомагав, "
389339
390340 #: src/alsa/config.cc:302
391341 msgid "Mixer element:"
392 msgstr "Елемент мікшеру:"
342 msgstr "Елемент мікшера:"
393343
394344 #: src/amidiplug/amidi-plug.cc:41
395345 msgid "AMIDI-Plug (MIDI Player)"
454404
455405 #: src/amidiplug/i_configure.cc:118
456406 msgid "Override default chorus:"
457 msgstr "Змінити типовий хорус:"
407 msgstr "Змінити типовий хор:"
458408
459409 #: src/amidiplug/i_configure.cc:128 src/console/plugin.cc:29
460410 msgid "<b>Playback</b>"
482432
483433 #: src/amidiplug/i_configure.cc:137
484434 msgid "Skip trailing silence"
485 msgstr "Пропустити кінцеву тишу"
435 msgstr ""
486436
487437 #: src/amidiplug/i_configure.cc:141
488438 msgid "<b>SoundFont</b>"
527477
528478 #: src/amidiplug/i_fileinfo.cc:201
529479 msgid "Format:"
530 msgstr "Формат:"
480 msgstr "Назва:"
531481
532482 #: src/amidiplug/i_fileinfo.cc:204
533483 msgid "Length (msec):"
535485
536486 #: src/amidiplug/i_fileinfo.cc:207
537487 msgid "No. of Tracks:"
538 msgstr "Кількість стежок:"
488 msgstr "Кількість доріжок:"
539489
540490 #: src/amidiplug/i_fileinfo.cc:213
541491 msgid "variable"
559509
560510 #: src/amidiplug/i_fileinfo.cc:284
561511 msgid "* no comments available in this MIDI file *"
562 msgstr "* цей MIDI-файл не має коментарів *"
512 msgstr "* у цьому MIDI-файлі немає коментарів *"
563513
564514 #: src/amidiplug/i_fileinfo.cc:296
565515 msgid "* no lyrics available in this MIDI file *"
566 msgstr "* цей MIDI-файл не має тексту пісні *"
516 msgstr "* у цьому MIDI-файлі немає слів пісні *"
567517
568518 #: src/amidiplug/i_fileinfo.cc:306 src/ladspa/plugin.cc:417
569519 msgid "_Close"
643593
644594 #: src/aosd/aosd_trigger.cc:56
645595 msgid "Triggers OSD when the song title changes (for internet streams)."
646 msgstr "Триґерити OSD під час зміни назв пісень (для інтернетових стримів)."
596 msgstr "Триґерити OSD при зміні назви пісні (для інтернет плинів)."
647597
648598 #: src/aosd/aosd_trigger.cc:61
649599 msgid "Pause On"
650 msgstr "Павза"
600 msgstr "Пауза"
651601
652602 #: src/aosd/aosd_trigger.cc:62
653603 msgid "Triggers OSD when playback is paused."
655605
656606 #: src/aosd/aosd_trigger.cc:67
657607 msgid "Pause Off"
658 msgstr "Продовжити"
608 msgstr "Продовження"
659609
660610 #: src/aosd/aosd_trigger.cc:68
661611 msgid "Triggers OSD when playback is unpaused."
692642 #: src/aosd/aosd_ui.cc:229
693643 #, c-format
694644 msgid "monitor %i"
695 msgstr "моніторові %i"
645 msgstr "моніторі %i"
696646
697647 #: src/aosd/aosd_ui.cc:281
698648 msgid "Timing (ms)"
813763
814764 #: src/asx3/asx3.cc:35
815765 msgid "ASXv3 Playlists"
816 msgstr "ASXv3-плейлисти"
766 msgstr "ASXv3 Плейлісти"
817767
818768 #: src/asx/asx.cc:33
819769 msgid "ASXv1/ASXv2 Playlists"
820 msgstr "ASXv1/ASXv2-плейлисти"
770 msgstr "ASXv1/ASXv2-списки відтворення"
821771
822772 #: src/audpl/audpl.cc:33
823773 msgid "Audacious Playlists (audpl)"
833783
834784 #: src/bs2b/plugin.cc:38
835785 msgid "Bauer Stereophonic-to-Binaural (BS2B)"
836 msgstr "Перетворення стереозвуку до бінаврального за Бавером (BS2B)"
786 msgstr "Перетворення стереозвуку в бінауральний за Бауером (BS2B)"
837787
838788 #: src/bs2b/plugin.cc:129
839789 msgid "Presets:"
845795
846796 #: src/bs2b/plugin.cc:138
847797 msgid "x1/10 dB"
848 msgstr "x1/10 дБ"
798 msgstr "x1/10 dB"
849799
850800 #: src/bs2b/plugin.cc:139
851801 msgid "Cut frequency:"
857807
858808 #: src/cdaudio/cdaudio-ng.cc:71
859809 msgid "Audio CD Plugin"
860 msgstr "Втулок авдіодисків"
810 msgstr "Плаґін аудіодисків"
861811
862812 #: src/cdaudio/cdaudio-ng.cc:118
863813 msgid ""
926876 #: src/cdaudio/cdaudio-ng.cc:250
927877 #, c-format
928878 msgid "Invalid URI %s."
929 msgstr "Хибна ланка: %s."
879 msgstr "Хибне посилання: %s."
930880
931881 #: src/cdaudio/cdaudio-ng.cc:252
932882 #, c-format
933883 msgid "Track %d not found."
934 msgstr "Стежки %d не знайдено."
884 msgstr "Доріжки %d не знайдено."
935885
936886 #: src/cdaudio/cdaudio-ng.cc:254
937887 #, c-format
938888 msgid "Track %d is a data track."
939 msgstr "Стежка %d — не музичні дані."
889 msgstr "Доріжка %d — не музичні дані."
940890
941891 #: src/cdaudio/cdaudio-ng.cc:329
942892 msgid "Error reading audio CD."
943 msgstr "Стався збій при читанні авдіодиску."
893 msgstr "Стався збій при читанні аудіодиску."
944894
945895 #: src/cdaudio/cdaudio-ng.cc:398
946896 msgid "Audio CD"
947 msgstr "Авдіодиск"
897 msgstr "Аудіодиск"
948898
949899 #: src/cdaudio/cdaudio-ng.cc:434 src/cdaudio/cdaudio-ng.cc:443
950900 #, c-format
953903
954904 #: src/cdaudio/cdaudio-ng.cc:446
955905 msgid "No audio capable CD drive found."
956 msgstr "Не знайдено CD-пристрою з підтримкою авдіо."
906 msgstr "Не знайдено CD-пристрою з підтримкою аудіо."
957907
958908 #: src/cdaudio/cdaudio-ng.cc:469
959909 msgid "Drive is empty."
969919
970920 #: src/cdaudio/cdaudio-ng.cc:508
971921 msgid "Failed to retrieve first/last track number."
972 msgstr "Не вдалося отримати номер першої/останньої стежки."
922 msgstr "Не вдалося отримати номер першої/останньої доріжки."
973923
974924 #: src/cdaudio/cdaudio-ng.cc:529
975925 #, c-format
976926 msgid "Cannot read start/end LSN for track %d."
977 msgstr "Не вдалося прочитати LSN початку/кінця стежки %d."
927 msgstr "Не вдалося прочитати LSN початку/кінця доріжки %d."
978928
979929 #: src/cdaudio/cdaudio-ng.cc:611
980930 msgid "Failed to create the CDDB connection."
981 msgstr "Не вдалося створити з'єднання з CDDB."
931 msgstr ""
982932
983933 #: src/cdaudio/cdaudio-ng.cc:677
984934 msgid "Failed to query the CDDB server"
992942 #: src/cdaudio/cdaudio-ng.cc:703
993943 #, c-format
994944 msgid "Failed to read the CDDB info: %s"
995 msgstr "Не вдалося прочитати дані з CDDB: %s"
945 msgstr ""
996946
997947 #: src/cd-menu-items/cd-menu-items.cc:33
998948 msgid "Audio CD Menu Items"
999 msgstr "Пункти меню для авдіодисків"
949 msgstr "Пункти меню для аудіодисків"
1000950
1001951 #: src/cd-menu-items/cd-menu-items.cc:45
1002952 msgid "Pla_y CD"
1003 msgstr "Програ_ти КД"
953 msgstr ""
1004954
1005955 #: src/cd-menu-items/cd-menu-items.cc:45
1006956 msgid "_Add CD"
1007 msgstr "_Додати КД"
957 msgstr ""
1008958
1009959 #: src/compressor/compressor.cc:45
1010960 msgid "<b>Compression</b>"
1023973 "Dynamic Range Compression Plugin for Audacious\n"
1024974 "Copyright 2010-2014 John Lindgren"
1025975 msgstr ""
1026 "Втулок стиснення динамічного діапазону для Audacious\n"
976 "Dynamic Range Compression плаґін для Audacious\n"
1027977 "Copyright 2010-2014 Джон Ліндґрен"
1028978
1029979 #: src/compressor/compressor.cc:64
1039989 "William Pitcock <nenolod@dereferenced.org>\n"
1040990 "Shay Green <gblargg@gmail.com>"
1041991 msgstr ""
1042 "Рушій відтворення консольної музики в наступних форматах:\n"
992 "Двигун відтворення консольної музики в наступних форматах:\n"
1043993 "AY, GBS, GYM, HES, KSS, NSF, NSFE, SAP, SPC, VGM, VGZ.\n"
1044994 "\n"
1045995 "Заснований на Game_Music_Emu 0.5.2.\n"
10561006
10571007 #: src/console/plugin.cc:36
10581008 msgid "Echo:"
1059 msgstr "Луна:"
1009 msgstr "Ехо:"
10601010
10611011 #: src/console/plugin.cc:39
10621012 msgid "Default song length:"
10761026
10771027 #: src/console/plugin.cc:50
10781028 msgid "Ignore length from SPC tags"
1079 msgstr "Ігнорувати тривалість з міток SPC"
1029 msgstr "Ігнорувати тривалість із теґів SPC"
10801030
10811031 #: src/console/plugin.cc:52
10821032 msgid "Increase reverb"
10881038
10891039 #: src/coreaudio/coreaudio.cc:53
10901040 msgid "CoreAudio output"
1091 msgstr "Вивід CoreAudio"
1041 msgstr "Вихід CoreAudio"
10921042
10931043 #: src/coreaudio/coreaudio.cc:156
10941044 msgid ""
11011051 "Based on SDL Output Plugin for Audacious\n"
11021052 "Copyright 2010 John Lindgren"
11031053 msgstr ""
1104 "Вихідний втулок CoreAudio для Audacious\n"
1105 "Копірайт 2014 William Pitcock\n"
1106 "Копірайт 2017,18 René J.V. Bertin\n"
1107 "(початковий та адаптований коди з\n"
1108 "Apple examples, (C) Apple 2013)\n"
1109 "\n"
1110 "Основано на вихідному втулкові SDL для Audacious\n"
1111 "Копірайт 2010 John Lindgren"
11121054
11131055 #: src/coreaudio/coreaudio.cc:172
11141056 msgid "Use exclusive mode"
11171059 #: src/coreaudio/coreaudio.cc:174
11181060 msgid "Use bit perfect audio (adapt device sampling rate)"
11191061 msgstr ""
1120 "Використовувати бітперфектний звук (адаптувати пристрієву частоту "
1121 "дискредитації)"
11221062
11231063 #: src/crossfade/crossfade.cc:43
11241064 msgid ""
11251065 "Crossfade Plugin for Audacious\n"
11261066 "Copyright 2010-2014 John Lindgren"
11271067 msgstr ""
1128 "Втулок \"перехресного затихання\" для Audacious\n"
1068 "Плаґін Crossfade для Audacious\n"
11291069 "Copyright 2010-2014 Джон Ліндґрен"
11301070
11311071 #: src/crossfade/crossfade.cc:47
11421082
11431083 #: src/crossfade/crossfade.cc:54
11441084 msgid "On seek or manual song change"
1145 msgstr "Перемикання пісень стандартно або навмання"
1085 msgstr ""
11461086
11471087 #: src/crossfade/crossfade.cc:60
11481088 msgid "<b>Tip</b>"
11741114
11751115 #: src/cue/cue.cc:42
11761116 msgid "Cue Sheet Plugin"
1177 msgstr "Втулок списків розмічування"
1117 msgstr "Плаґін cue-листів"
11781118
11791119 #: src/delete-files/delete-files.cc:53 src/delete-files/delete-files.cc:215
11801120 #: src/delete-files/delete-files.cc:230
11831123
11841124 #: src/delete-files/delete-files.cc:120
11851125 msgid "No files are selected."
1186 msgstr "Жодного файлу не вибрано."
1126 msgstr ""
11871127
11881128 #: src/delete-files/delete-files.cc:125
11891129 #, c-format
11901130 msgid "Do you want to move %s to the trash?"
1191 msgstr "Чи ви хочете перемістити %s до смітнику?"
1131 msgstr ""
11921132
11931133 #: src/delete-files/delete-files.cc:126
11941134 #, c-format
11951135 msgid "Do you want to permanently delete %s?"
1196 msgstr "Чи ви хочете назавжди видалити %s?"
1136 msgstr ""
11971137
11981138 #: src/delete-files/delete-files.cc:133
11991139 #, c-format
12001140 msgid "Do you want to move %d files to the trash?"
1201 msgstr "Чи ви хочете перемістити файли %d до смітнику?"
1141 msgstr ""
12021142
12031143 #: src/delete-files/delete-files.cc:134
12041144 #, c-format
12051145 msgid "Do you want to permanently delete %d files?"
1206 msgstr "Чи ви хочете назавжди видалити файли %d?"
1146 msgstr ""
12071147
12081148 #: src/delete-files/delete-files.cc:146
12091149 msgid "Move to trash"
1210 msgstr "Перемістити до смітнику"
1150 msgstr ""
12111151
12121152 #: src/delete-files/delete-files.cc:146
12131153 msgid "Delete"
12201160
12211161 #: src/delete-files/delete-files.cc:268
12221162 msgid "Delete Selected Files"
1223 msgstr "Видалити обрані файли"
1163 msgstr "Видалити вибрані файли"
12241164
12251165 #: src/delete-files/delete-files.cc:288
12261166 msgid "<b>Delete Method</b>"
1227 msgstr "<b>Метод видалення</b>"
1167 msgstr "<b>Метод Видалення</b>"
12281168
12291169 #: src/delete-files/delete-files.cc:289
12301170 msgid "Move to trash instead of deleting immediately"
1231 msgstr "Перемістити до смітнику замість негайного видалення"
1171 msgstr "Перемістити до смітника замість видалення відразу"
12321172
12331173 #: src/echo_plugin/echo.cc:9
12341174 msgid ""
12371177 "Surround echo by Carl van Schaik, 1999\n"
12381178 "Updated for Audacious by William Pitcock and John Lindgren, 2010-2014"
12391179 msgstr ""
1240 "Втулок Echo \n"
1180 "Плаґін Echo \n"
12411181 "Створено Джоан Левін, 1999\n"
12421182 "Surround echo створено Карлом ван Шайком, 1999\n"
12431183 "Оновлено для Audacious Вільямом Піткоком та Джоном Ліндґреном, 2010-2014"
12701210
12711211 #: src/ffaudio/ffaudio-core.cc:49
12721212 msgid "FFmpeg Plugin"
1273 msgstr "Втулок FFmpeg"
1213 msgstr "Плаґін FFmpeg"
12741214
12751215 #: src/ffaudio/ffaudio-core.cc:627
12761216 msgid ""
12811221 "William Pitcock <nenolod@nenolod.net>\n"
12821222 "Matti Hämäläinen <ccr@tnsp.org>"
12831223 msgstr ""
1284 "Відтворення звуку у різних форматах\n"
1224 "Відтворення звуку в різних форматах\n"
12851225 "за допомогою фреймворку FFmpeg\n"
12861226 "\n"
12871227 "http://www.ffmpeg.org/\n"
12881228 "\n"
1289 "Автори втулку:\n"
1229 "Автори плаґіну:\n"
12901230 "William Pitcock <nenolod@nenolod.net>\n"
12911231 "Matti Hämäläinen <ccr@tnsp.org>"
12921232
12931233 #: src/filewriter/filewriter.cc:48
12941234 msgid "FileWriter Plugin"
1295 msgstr "Втулок запису у файл"
1235 msgstr "Плаґін запису у файл"
12961236
12971237 #: src/filewriter/filewriter.cc:350
12981238 msgid ""
13101250 "this program; if not, write to the Free Software Foundation, Inc., 51 "
13111251 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
13121252 msgstr ""
1313 "Ця програма є вільним програмним забезпеченням — ви можете розповсюджувати "
1314 "та/чи модифікувати її відповідно до умов Загальної публічної ліцензії GNU, 2-"
1315 "ої або (на вашу думку) будь-якої новішої версії у тому вигляді, якому її "
1316 "опублікувано\n"
1317 "\n"
1318 "Програма розповсюджується зі сподіванням, що вона виявиться корисною, але "
1319 "БЕЗ ЖОДНОЇ ГАРАНТІЇ; навіть без умовної гарантії КОМЕРЦІЙНОЇ ПРИДАТНОСТІ чи "
1320 "ПРИДАТНОСТІ ДО ПЕВНОГО ЗАСТОСУВАННЯ. Зверніться до Загальної публічної "
1321 "ліцензії GNU за подробицями.\n"
1322 "\n"
1323 "Ви мали отримати копію Загальної публічної ліцензії GNU разом із цією "
1324 "програмою. Якщо ви не отримали копії, зверніться за наступною адресою: Free "
1325 "Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA "
1326 "02110-1301, USA"
13271253
13281254 #: src/filewriter/filewriter.cc:377
13291255 msgid "Output file format:"
13311257
13321258 #: src/filewriter/filewriter.cc:381
13331259 msgid "Save into original directory"
1334 msgstr "Зберігати до первісної теки"
1260 msgstr "Зберігати в теку оригіналу"
13351261
13361262 #: src/filewriter/filewriter.cc:384
13371263 msgid "Save into custom directory:"
13431269
13441270 #: src/filewriter/filewriter.cc:393
13451271 msgid "Original file name"
1346 msgstr "Початкова назва файлу"
1272 msgstr "Ориґінальна назва файлу"
13471273
13481274 #: src/filewriter/filewriter.cc:396
13491275 msgid "Original file name (no suffix)"
1350 msgstr "Початкова назва файлу (без наростку)"
1276 msgstr "Ориґінальна назва файлу (без наростка)"
13511277
13521278 #: src/filewriter/filewriter.cc:399
13531279 msgid "Original file tag"
1354 msgstr "Початкова мітка файлу"
1280 msgstr "Ориґінальний теґ файлу"
13551281
13561282 #: src/filewriter/filewriter.cc:403
13571283 msgid "Prepend track number to file name"
1358 msgstr "Номер стежки на початку назви файлу"
1284 msgstr "Номер доріжки на початку назви файлу"
13591285
13601286 #: src/filewriter/filewriter.cc:409 src/filewriter/filewriter.cc:441
13611287 msgid "Auto"
14851411
14861412 #: src/filewriter/filewriter.cc:470
14871413 msgid "Algorithm quality:"
1488 msgstr "Алґоритм якости:"
1414 msgstr "Алґоритм якості:"
14891415
14901416 #: src/filewriter/filewriter.cc:476
14911417 msgid "Bitrate:"
14931419
14941420 #: src/filewriter/filewriter.cc:483
14951421 msgid "Compression ratio:"
1496 msgstr "Коєфіцієнт стиснення:"
1422 msgstr "Коефіцієнт стиснення:"
14971423
14981424 #: src/filewriter/filewriter.cc:490
14991425 msgid "Audio mode:"
15091435
15101436 #: src/filewriter/filewriter.cc:500
15111437 msgid "Enable VBR/ABR"
1512 msgstr "Ввімкнути змінний чи усереднений бітрейт"
1438 msgstr "Увімкнути змінний чи усереднений бітрейт"
15131439
15141440 #: src/filewriter/filewriter.cc:502
15151441 msgid "Type:"
15531479
15541480 #: src/filewriter/filewriter.cc:536
15551481 msgid "<b>ID3 Tags</b>"
1556 msgstr "<b>ID3 Мітки</b>"
1482 msgstr "<b>ID3 Теґи</b>"
15571483
15581484 #: src/filewriter/filewriter.cc:537
15591485 msgid "Force addition of version 2 tag"
1560 msgstr "Примусово додавати мітку другої версії"
1486 msgstr "Примусово додавати теґ другої версії"
15611487
15621488 #: src/filewriter/filewriter.cc:539
15631489 msgid "Only add v1 tag"
1564 msgstr "Додавати лише v1-мітку"
1490 msgstr "Додавати лише v1-теґ"
15651491
15661492 #: src/filewriter/filewriter.cc:541
15671493 msgid "Only add v2 tag"
1568 msgstr "Додавати лише v2-мітку"
1494 msgstr "Додавати лише v2-теґ"
15691495
15701496 #: src/filewriter/filewriter.cc:546
15711497 msgid "Quality"
15771503
15781504 #: src/filewriter/filewriter.cc:548
15791505 msgid "Tags"
1580 msgstr "Мітки"
1506 msgstr "Теґи"
15811507
15821508 #: src/filewriter/filewriter.cc:558
15831509 msgid "Quality (0-1):"
16131539 "GIO Plugin for Audacious\n"
16141540 "Copyright 2009-2012 John Lindgren"
16151541 msgstr ""
1616 "Втулок GIO,\n"
1542 "Плаґін GIO,\n"
16171543 "написаний Джоном Ліндґреном у 2010–2012 роках."
16181544
16191545 #: src/gio/gio.cc:42
16201546 msgid "GIO Plugin"
1621 msgstr "Втулок GIO"
1547 msgstr "Плаґін GIO"
16221548
16231549 #: src/gio/gio.cc:152
16241550 msgid "Read-and-append mode not supported"
1625 msgstr "Режим читання-додавання не підтримується"
1551 msgstr ""
16261552
16271553 #: src/gio/gio.cc:165
16281554 msgid "Invalid open mode"
1629 msgstr "Недійсний режим відкривання"
1555 msgstr ""
16301556
16311557 #: src/glspectrum/gl-spectrum.cc:51
16321558 msgid ""
16391565 "\n"
16401566 "License: GPLv2+"
16411567 msgstr ""
1642 "OpenGL Спектровий аналізатор для Audacious\n"
1568 "OpenGL Аналізатор Спектру для Audacious\n"
16431569 "Авторське право 2013 Christophe Budé, John Lindgren, та Carlo Bramini\n"
16441570 "\n"
1645 "На основі втулку для XMMS:\n"
1571 "На основі плаґіну для XMMS:\n"
16461572 "Авторське право 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas "
16471573 "Nilsson, та 4Front Technologies\n"
16481574 "\n"
16501576
16511577 #: src/glspectrum/gl-spectrum.cc:62 src/qtglspectrum/gl-spectrum.cc:53
16521578 msgid "OpenGL Spectrum Analyzer"
1653 msgstr "OpenGL спектровий аналізатор"
1579 msgstr "OpenGL аналізатор спектру"
16541580
16551581 #: src/gtkui/columns.cc:35
16561582 msgid "Entry number"
1657 msgstr "Списковий номер"
1583 msgstr "Номер у списку"
16581584
16591585 #: src/gtkui/columns.cc:36 src/playlist-manager/playlist-manager.cc:199
16601586 #: src/playlist-manager-qt/playlist-manager-qt.cc:183
16801606
16811607 #: src/gtkui/columns.cc:41 src/qtui/playlist_model.cc:42
16821608 msgid "Track"
1683 msgstr "Стежка"
1609 msgstr "Доріжка"
16841610
16851611 #: src/gtkui/columns.cc:42 src/qtui/playlist_model.cc:43
16861612 msgid "Genre"
1687 msgstr "Напрямок"
1613 msgstr "Жанр"
16881614
16891615 #: src/gtkui/columns.cc:43
16901616 msgid "Queue position"
17371663
17381664 #: src/gtkui/layout.cc:169
17391665 msgid "Dock at Bottom"
1740 msgstr "Прикріпити долі"
1666 msgstr "Прикріпити внизу"
17411667
17421668 #: src/gtkui/layout.cc:169
17431669 msgid "Undock"
17501676 #: src/gtkui/menus.cc:79 src/qtui/menus.cc:68
17511677 #: src/statusicon-qt/statusicon.cc:114 src/statusicon/statusicon.cc:283
17521678 msgid "_Open Files ..."
1753 msgstr "_Відтворити файли ..."
1679 msgstr "Відтворити _файли..."
17541680
17551681 #: src/gtkui/menus.cc:80 src/qtui/menus.cc:70
17561682 msgid "Open _URL ..."
1757 msgstr "Відтворити файли за _ланкою ..."
1683 msgstr "Відтворити файли за _посиланням..."
17581684
17591685 #: src/gtkui/menus.cc:81 src/qtui/menus.cc:71
17601686 msgid "_Add Files ..."
1761 msgstr "_Додати файли ..."
1687 msgstr "_Додати файли..."
17621688
17631689 #: src/gtkui/menus.cc:82 src/qtui/menus.cc:73
17641690 msgid "Add U_RL ..."
1765 msgstr "Додати файли за ла_нкою ..."
1691 msgstr "Додати файли _за посиланням..."
17661692
17671693 #: src/gtkui/menus.cc:84 src/qtui/menus.cc:75
17681694 msgid "Search _Library"
17701696
17711697 #: src/gtkui/menus.cc:86 src/qtui/menus.cc:77
17721698 msgid "A_bout ..."
1773 msgstr "П_ро Audacious ..."
1699 msgstr "П_ро Audacious..."
17741700
17751701 #: src/gtkui/menus.cc:87 src/qtui/menus.cc:78
17761702 msgid "_Settings ..."
17791705 #: src/gtkui/menus.cc:88 src/qtui/menus.cc:82
17801706 #: src/statusicon-qt/statusicon.cc:116 src/statusicon/statusicon.cc:285
17811707 msgid "_Quit"
1782 msgstr "_Вийти"
1708 msgstr "_Вихід"
17831709
17841710 #: src/gtkui/menus.cc:92 src/gtkui/menus.cc:221 src/qtui/menus.cc:86
17851711 #: src/search-tool-qt/search-tool-qt.cc:831 src/search-tool/search-tool.cc:683
17901716 #: src/gtkui/menus.cc:93 src/qtui/menus.cc:87
17911717 #: src/statusicon-qt/statusicon.cc:109 src/statusicon/statusicon.cc:278
17921718 msgid "Paus_e"
1793 msgstr "Призупини_ти"
1719 msgstr "_Призупинити"
17941720
17951721 #: src/gtkui/menus.cc:94 src/qtui/menus.cc:88
17961722 #: src/statusicon-qt/statusicon.cc:110 src/statusicon/statusicon.cc:279
18001726 #: src/gtkui/menus.cc:95 src/qtui/menus.cc:89
18011727 #: src/statusicon-qt/statusicon.cc:111 src/statusicon/statusicon.cc:280
18021728 msgid "Pre_vious"
1803 msgstr "По_передня"
1729 msgstr "П_опередня"
18041730
18051731 #: src/gtkui/menus.cc:96 src/qtui/menus.cc:90
18061732 #: src/statusicon-qt/statusicon.cc:112 src/statusicon/statusicon.cc:281
18091735
18101736 #: src/gtkui/menus.cc:98 src/qtui/menus.cc:92
18111737 msgid "_Repeat"
1812 msgstr "_Повторювати"
1738 msgstr "Повто_рювати"
18131739
18141740 #: src/gtkui/menus.cc:99 src/qtui/menus.cc:93
18151741 msgid "S_huffle"
18251751
18261752 #: src/gtkui/menus.cc:102 src/qtui/menus.cc:96
18271753 msgid "Stop A_fter This Song"
1828 msgstr "Зупинити пі_сля цієї пісні"
1754 msgstr "Зупинити після _цієї пісні"
18291755
18301756 #: src/gtkui/menus.cc:104 src/gtkui/menus.cc:205 src/qtui/menus.cc:98
18311757 #: src/qtui/menus.cc:200
18321758 msgid "Song _Info ..."
1833 msgstr "_Інформація про стежку ..."
1759 msgstr "_Інформація про доріжку..."
18341760
18351761 #: src/gtkui/menus.cc:105
18361762 msgid "Jump to _Time ..."
1837 msgstr "Перейти до _часу ..."
1763 msgstr "Перейти до _часу..."
18381764
18391765 #: src/gtkui/menus.cc:106
18401766 msgid "_Jump to Song ..."
1841 msgstr "Перейти до _стежки ..."
1767 msgstr "Перейти до _доріжки..."
18421768
18431769 #: src/gtkui/menus.cc:108
18441770 msgid "Set Repeat Point _A"
18591785
18601786 #: src/gtkui/menus.cc:115 src/qtui/menus.cc:103
18611787 msgid "By _File Name"
1862 msgstr "За _назвою файлу"
1788 msgstr "По _назві файлу"
18631789
18641790 #: src/gtkui/menus.cc:116 src/qtui/menus.cc:104
18651791 msgid "By File _Path"
18681794 #: src/gtkui/menus.cc:120 src/gtkui/menus.cc:137 src/qtui/menus.cc:108
18691795 #: src/qtui/menus.cc:125
18701796 msgid "By Track _Number"
1871 msgstr "_За номером стежки"
1797 msgstr "_За номером доріжки"
18721798
18731799 #: src/gtkui/menus.cc:122 src/gtkui/menus.cc:139 src/qtui/menus.cc:110
18741800 #: src/qtui/menus.cc:127
18831809 #: src/gtkui/menus.cc:124 src/gtkui/menus.cc:141 src/qtui/menus.cc:112
18841810 #: src/qtui/menus.cc:129
18851811 msgid "By Albu_m Artist"
1886 msgstr "За альбо_мом виконавця"
1812 msgstr "По альбо_му виконавця"
18871813
18881814 #: src/gtkui/menus.cc:125 src/gtkui/menus.cc:142 src/qtui/menus.cc:113
18891815 #: src/qtui/menus.cc:130
19181844 #: src/gtkui/menus.cc:132 src/gtkui/menus.cc:149 src/qtui/menus.cc:120
19191845 #: src/qtui/menus.cc:137
19201846 msgid "R_everse Order"
1921 msgstr "_У зворотньому порядкові"
1847 msgstr "_У зворотньому порядку"
19221848
19231849 #: src/gtkui/menus.cc:133 src/gtkui/menus.cc:150 src/qtui/menus.cc:121
19241850 #: src/qtui/menus.cc:138
19251851 msgid "_Random Order"
1926 msgstr "У випадковому по_рядкові"
1852 msgstr "У випадковому по_рядку"
19271853
19281854 #: src/gtkui/menus.cc:154 src/qtui/menus.cc:142
19291855 msgid "_Play/Resume"
19561882
19571883 #: src/gtkui/menus.cc:163 src/qtui/menus.cc:153
19581884 msgid "Ren_ame ..."
1959 msgstr "Змінити_назву ..."
1885 msgstr "Пере_йменувати..."
19601886
19611887 #: src/gtkui/menus.cc:164 src/gtkui/menus.cc:223 src/qtui/menus.cc:154
19621888 msgid "Remo_ve"
1963 msgstr "Усуну_ти"
1889 msgstr "Видали_ти"
19641890
19651891 #: src/gtkui/menus.cc:166 src/qtui/menus.cc:156
19661892 msgid "_Import ..."
1967 msgstr "_Імпортувати ..."
1893 msgstr "_Імпортувати..."
19681894
19691895 #: src/gtkui/menus.cc:167 src/qtui/menus.cc:157
19701896 msgid "_Export ..."
1971 msgstr "_Експортувати ..."
1897 msgstr "_Експортувати..."
19721898
19731899 #: src/gtkui/menus.cc:169 src/qtui/menus.cc:159
19741900 msgid "Playlist _Manager ..."
1975 msgstr "Керування списками _відтворення ..."
1901 msgstr "Керування списками _відтворення..."
19761902
19771903 #: src/gtkui/menus.cc:170 src/qtui/menus.cc:160
19781904 msgid "_Queue Manager ..."
1979 msgstr "Керування _чергою ..."
1905 msgstr "Керування _чергою..."
19801906
19811907 #: src/gtkui/menus.cc:174 src/qtui/menus.cc:164
19821908 msgid "Volume _Up"
19921918
19931919 #: src/gtkui/menus.cc:178 src/qtui/menus.cc:168
19941920 msgid "E_ffects ..."
1995 msgstr "Е_фекти ..."
1921 msgstr "Е_фекти..."
19961922
19971923 #: src/gtkui/menus.cc:180
19981924 msgid "_Record Stream"
1999 msgstr "_записування стриму"
1925 msgstr "_записування потоку"
20001926
20011927 #: src/gtkui/menus.cc:181
20021928 msgid "Audio _Settings ..."
20421968 #: src/gtkui/menus.cc:199 src/gtkui/menus.cc:217 src/qtui/menus.cc:189
20431969 #: src/qtui/menus.cc:212
20441970 msgid "_Services"
2045 msgstr "_Служби"
1971 msgstr "С_лужби"
20461972
20471973 #: src/gtkui/menus.cc:200 src/qtui/menus.cc:190
20481974 msgid "_Output"
2049 msgstr "_Вивід"
1975 msgstr "В_ивід"
20501976
20511977 #: src/gtkui/menus.cc:201 src/qtui/menus.cc:191
20521978 msgid "_View"
2053 msgstr "_Вигляд"
1979 msgstr "Ви_гляд"
20541980
20551981 #: src/gtkui/menus.cc:206 src/qtui/menus.cc:201
20561982 msgid "_Queue/Unqueue"
20661992
20671993 #: src/gtkui/menus.cc:211 src/qtui/menus.cc:206
20681994 msgid "Cu_t"
2069 msgstr "Виріза_ти"
1995 msgstr "_Вирізати"
20701996
20711997 #: src/gtkui/menus.cc:212 src/qtui/menus.cc:207
20721998 msgid "_Copy"
20742000
20752001 #: src/gtkui/menus.cc:213 src/qtui/menus.cc:208
20762002 msgid "_Paste"
2077 msgstr "_Вставити"
2003 msgstr "Вст_авити"
20782004
20792005 #: src/gtkui/menus.cc:214 src/qtui/menus.cc:209
20802006 msgid "Paste at _End"
20862012
20872013 #: src/gtkui/menus.cc:222
20882014 msgid "_Rename ..."
2089 msgstr "_Змінити назву ..."
2015 msgstr "Пере_йменувати..."
20902016
20912017 #: src/gtkui/settings.cc:35 src/qtui/settings.cc:54
20922018 msgid "<b>Playlist Tabs</b>"
21312057
21322058 #: src/gtkui/ui_gtk.cc:223 src/qtui/main_window.cc:308
21332059 msgid "Buffering ..."
2134 msgstr "Буферую ..."
2060 msgstr "Буферую..."
21352061
21362062 #: src/gtkui/ui_gtk.cc:226 src/skins/main.cc:224 src/skins-qt/main.cc:224
21372063 msgid "Audacious"
21652091 #: src/gtkui/ui_gtk.cc:810 src/qtui/main_window.cc:107 src/skins/menus.cc:112
21662092 #: src/skins-qt/menus.cc:103
21672093 msgid "Previous"
2168 msgstr "Попередня cтежка"
2094 msgstr "Попередня доріжка"
21692095
21702096 #: src/gtkui/ui_gtk.cc:812 src/hotkey/gui.cc:74 src/qtui/main_window.cc:109
21712097 #: src/skins/menus.cc:111 src/skins-qt/menus.cc:102
21752101 #: src/gtkui/ui_gtk.cc:813 src/notify/osd.cc:74 src/qtui/main_window.cc:112
21762102 #: src/skins/menus.cc:113 src/skins-qt/menus.cc:104
21772103 msgid "Next"
2178 msgstr "Наступна стежка"
2104 msgstr "Наступна доріжка"
21792105
21802106 #: src/gtkui/ui_gtk.cc:815 src/qtui/main_window.cc:113 src/qtui/menus.cc:170
21812107 #: src/skins/menus.cc:79 src/skins-qt/menus.cc:69
22212147
22222148 #: src/gtkui/ui_statusbar.cc:107 src/skins/main.cc:466 src/skins-qt/main.cc:452
22232149 msgid "Single mode."
2224 msgstr "Одностежковий режим."
2150 msgstr "Однодоріжковий режим."
22252151
22262152 #: src/gtkui/ui_statusbar.cc:109 src/skins/main.cc:468 src/skins-qt/main.cc:454
22272153 msgid "Playlist mode."
2228 msgstr "Режим списку відтворення."
2154 msgstr "Режим списка відтворення."
22292155
22302156 #: src/gtkui/ui_statusbar.cc:117 src/skins/main.cc:474 src/skins-qt/main.cc:460
22312157 msgid "Stopping after song."
2232 msgstr "Зупинити після цієї стежки."
2158 msgstr "Зупинити після цієї доріжки."
22332159
22342160 #: src/hotkey/gui.cc:71
22352161 msgid "Previous track"
2236 msgstr "Попередня стежка"
2162 msgstr "Попередня доріжка"
22372163
22382164 #: src/hotkey/gui.cc:73
22392165 msgid "Pause/Resume"
22412167
22422168 #: src/hotkey/gui.cc:75
22432169 msgid "Next track"
2244 msgstr "Наступна стежка"
2170 msgstr "Наступна доріжка"
22452171
22462172 #: src/hotkey/gui.cc:76
22472173 msgid "Forward 5 seconds"
23012227 "\n"
23022228 "Do you want to continue?"
23032229 msgstr ""
2304 "Не раджу пов’язувати головні кнопки миші без модифікаторів.\n"
2305 "\n"
2306 "Продовжувати попри це?"
23072230
23082231 #: src/hotkey/gui.cc:236
23092232 msgid "Binding mouse buttons"
23522275 " Jonathan A. Davis <davis@jdhouse.org>,\n"
23532276 " Jeremy Tan <nsx@nsx.homeip.net>"
23542277 msgstr ""
2355 "Втулок надає можливість керувати відтворенням\n"
2278 "Плаґін надає можливість керувати відтворенням\n"
23562279 "за допомогою глобальних клавіатурних скорочень,\n"
23572280 "що також називаються «гарячими клавішами».\n"
23582281 "\n"
2359 "Автор у 2007–2008 роках — Саша Глюсяк <contact@saschahlusiak.de>.\n"
2282 "Автор у 2007–2008 роках — Sascha Hlusiak <contact@saschahlusiak.de>.\n"
23602283 "\n"
23612284 "Vladimir Paskov <vlado.paskov@gmail.com> (у 2006–2007),\n"
23622285 "Ville Syrjälä <syrjala@sci.fi> (у 2000–2002),\n"
23712294
23722295 #: src/jack/jack-ng.cc:115
23732296 msgid "Automatically connect to output ports"
2374 msgstr "Автоматично під'єдунувати до вивідних портів"
2297 msgstr ""
23752298
23762299 #: src/jack/jack-ng.cc:156
23772300 #, c-format
23782301 msgid "Only %d JACK output ports were found but %d are required."
2379 msgstr "Знайдено лише %d вивідні JACK-порти, але необхідно знайти %d."
2302 msgstr ""
23802303
23812304 #: src/jack/jack-ng.cc:172
23822305 #, c-format
23882311 "JACK supports only floating-point audio. You must change the output bit "
23892312 "depth to floating-point in Audacious settings."
23902313 msgstr ""
2391 "JACK підтримує лише floating-point звук. Ви маєте змінити вивідну бітову "
2392 "глибину на floating-point у Audacious'ових налаштуваннях."
23932314
23942315 #: src/jack/jack-ng.cc:205
23952316 msgid "Failed to connect to the JACK server; is it running?"
2396 msgstr "Не вдалося під'єднатися до серверу JACK; чи він працює?"
2317 msgstr ""
23972318
23982319 #: src/jack/jack-ng.cc:281
23992320 #, c-format
24012322 "The JACK server requires a sample rate of %d Hz, but Audacious is playing at "
24022323 "%d Hz. Please use the Sample Rate Converter effect to correct the mismatch."
24032324 msgstr ""
2404 "JACK-сервер потребує частоту дискредитації у %d Гц, проте відтворення в "
2405 "Audacious має %d Гц. Будь ласка, використайте ефект конвертору частоти "
2406 "дискретизації для усунення невідповідності."
24072325
24082326 #: src/ladspa/plugin.cc:415
24092327 #, c-format
24222340 msgstr ""
24232341 "<small>Якщо шляхів кілька, розділяйте їх двокрапками.\n"
24242342 "Пошук відбувається за вказаними шляхами та змінною LADSPA_PATH.\n"
2425 "Вказавши шляхи, натисніть Enter для пошуку втулків.</small>"
2343 "Вказавши шляхи, натисніть Enter для пошуку плаґінів.</small>"
24262344
24272345 #: src/ladspa/plugin.cc:502
24282346 msgid "Available plugins:"
2429 msgstr "Наявні втулки:"
2347 msgstr "Наявні плаґіни:"
24302348
24312349 #: src/ladspa/plugin.cc:515 src/modplug/plugin_main.cc:95
24322350 #: src/modplug/plugin_main.cc:98 src/modplug/plugin_main.cc:101
24362354
24372355 #: src/ladspa/plugin.cc:521
24382356 msgid "Enabled plugins:"
2439 msgstr "Ввімкнені втулки:"
2357 msgstr "Увімкнені плаґіни:"
24402358
24412359 #: src/ladspa/plugin.cc:537
24422360 msgid "Settings"
24472365 "LADSPA Host for Audacious\n"
24482366 "Copyright 2011 John Lindgren"
24492367 msgstr ""
2450 "Гост LADSPA,\n"
2368 "Хост LADSPA,\n"
24512369 "написаний Джоном Ліндґреном у 2011 році."
24522370
24532371 #: src/ladspa/plugin.h:78
24542372 msgid "LADSPA Host"
2455 msgstr "Гост LADSPA"
2373 msgstr "Хост LADSPA"
24562374
24572375 #: src/lirc/lirc.cc:55
24582376 msgid "LIRC Plugin"
2459 msgstr "Втулок LIRC"
2377 msgstr "Плаґін LIRC"
24602378
24612379 #: src/lirc/lirc.cc:379
24622380 msgid ""
24732391 "\n"
24742392 "For more information about LIRC, see http://lirc.org."
24752393 msgstr ""
2476 "Втулок надає можливість керувати відтворенням\n"
2394 "Плаґін надає можливість керувати відтворенням\n"
24772395 "дистанційно (за допомогою LIRC).\n"
24782396 "\n"
24792397 "Автори портування до Audacious:\n"
24932411
24942412 #: src/lirc/lirc.cc:391
24952413 msgid "Reconnect to LIRC server"
2496 msgstr "Переприєднатись до LIRC-серверу"
2414 msgstr "Переприєднатись до LIRC серверу"
24972415
24982416 #: src/lirc/lirc.cc:393
24992417 msgid "Wait before reconnecting:"
25012419
25022420 #: src/lyricwiki/lyricwiki.cc:42 src/lyricwiki-qt/lyricwiki.cc:70
25032421 msgid "LyricWiki Plugin"
2504 msgstr "Втулок LyricWiki"
2422 msgstr "Плаґін LyricWiki"
25052423
25062424 #: src/lyricwiki/lyricwiki.cc:132 src/lyricwiki-qt/lyricwiki.cc:151
25072425 #: src/lyricwiki-qt/lyricwiki.cc:337
25432461
25442462 #: src/lyricwiki/lyricwiki.cc:351 src/lyricwiki-qt/lyricwiki.cc:442
25452463 msgid "Edit lyrics ..."
2546 msgstr "Коригувати текст пісні ..."
2464 msgstr "Корегувати текст пісні ..."
25472465
25482466 #: src/m3u/m3u.cc:32
25492467 msgid "M3U Playlists"
25722490 "or tact://60*3/4 to play 60 bpm in 3/4 tacts"
25732491 msgstr ""
25742492 "Генератор такту,\n"
2575 "написаний Мартіном Штравсом <mys@faveve.uni-stuttgart.de>.\n"
2576 "\n"
2577 "Використовується при відкритті ланки у форматі:\n"
2493 "написаний Мартіном Штраусом <mys@faveve.uni-stuttgart.de>.\n"
2494 "\n"
2495 "Використовується при відкритті посилання в форматі:\n"
25782496 "tact://bpm*чисельник/знаменник\n"
25792497 "\n"
25802498 "Наприклад, tact://77 — 77 ударів за хвилину,\n"
2581 "tact://60*3/4 — 60 ударів на хвилину з тактом 3/4."
2499 "tact://60*3/4 — 60 ударів за хвилину з тактом 3/4."
25822500
25832501 #: src/mixer/mixer.cc:38
25842502 msgid "Channel Mixer"
25902508 "Copyright 2011-2012 John Lindgren and Michał Lipski"
25912509 msgstr ""
25922510 "Мікшер каналів,\n"
2593 "написаний у 2011–2012 роках Джоном Ліндґреном та Михайлом Липським."
2511 "написаний у 2011–2012 роках Джоном Ліндґреном та Michał Lipski."
25942512
25952513 #: src/mixer/mixer.cc:231
25962514 msgid "<b>Channel Mixer</b>"
26022520
26032521 #: src/mms/mms.cc:35
26042522 msgid "MMS Plugin"
2605 msgstr "Втулок MMS"
2523 msgstr "Плаґін MMS"
26062524
26072525 #: src/mms/mms.cc:82
26082526 msgid "Error connecting to MMS server"
2609 msgstr "Хиба підключення до MMS-серверу"
2527 msgstr "Хиба підключення до MMS серверу"
26102528
26112529 #: src/modplug/modplugbmp.h:57
26122530 msgid "ModPlug (Module Player)"
26462564
26472565 #: src/modplug/plugin_main.cc:67
26482566 msgid "<b>Sample rate</b>"
2649 msgstr "<b>Частота дискретизації</b>"
2567 msgstr "<b>Висота семплів</b>"
26502568
26512569 #: src/modplug/plugin_main.cc:68
26522570 msgid "22 kHz"
26712589
26722590 #: src/modplug/plugin_main.cc:81
26732591 msgid "Cutoff:"
2674 msgstr "Зріз:"
2592 msgstr "Границя:"
26752593
26762594 #: src/modplug/plugin_main.cc:94
26772595 msgid "<b>Reverb</b>"
27112629
27122630 #: src/modplug/plugin_main.cc:115
27132631 msgid "To repeat forever, set the repeat count to -1."
2714 msgstr "Для нескінченного повторення, встановіть кількість повторень в -1."
2632 msgstr "Для безкінечного повторення, встановіть кількість повторень в -1."
27152633
27162634 #: src/modplug/plugin_main.cc:128 src/sid/xs_config.cc:106
27172635 msgid "These settings will take effect when Audacious is restarted."
27192637
27202638 #: src/mpg123/mpg123.cc:54
27212639 msgid "MPG123 Plugin"
2722 msgstr "Втулок MPG123"
2640 msgstr "Плаґін MPG123"
27232641
27242642 #: src/mpg123/mpg123.cc:80
27252643 msgid "<b>Advanced</b>"
2726 msgstr "<b>Розширені</b>"
2644 msgstr "<b>Додаткові</b>"
27272645
27282646 #: src/mpg123/mpg123.cc:81
27292647 msgid "Use accurate length calculation (slow)"
2730 msgstr "Використовувати точне підрахування часу (повільно)"
2648 msgstr ""
27312649
27322650 #: src/mpg123/mpg123.cc:245
27332651 msgid "Surround"
27392657
27402658 #: src/neon/neon.cc:97
27412659 msgid "Neon HTTP/HTTPS Plugin"
2742 msgstr "Втулок Neon HTTP/HTTPS"
2660 msgstr "Плаґін Neon HTTP/HTTPS"
27432661
27442662 #: src/neon/neon.cc:526
27452663 msgid "Error parsing redirect"
2746 msgstr "Хиба парсування перенаправлень"
2664 msgstr ""
27472665
27482666 #: src/neon/neon.cc:540
27492667 msgid "Unknown HTTP error"
27512669
27522670 #: src/neon/neon.cc:574
27532671 msgid "Error parsing URL"
2754 msgstr "Хиба парсування URL"
2672 msgstr ""
27552673
27562674 #: src/neon/neon.cc:637
27572675 msgid "Too many redirects"
27882706 "You should have received a copy of the GNU General Public License along with "
27892707 "this program. If not, see <http://www.gnu.org/licenses/>."
27902708 msgstr ""
2791 "Плагін сповіщень для Audacious\n"
2792 "Авторське право (C) 2010 Maximilian Bogner\n"
2709 "Плагін сповіщень для Audacious⏎\n"
2710 "Авторське право (C) 2010 Maximilian Bogner⏎\n"
27932711 "Авторське право (C) 2011-2013 John Lindgren та Jean-Alexandre Anglès "
2794 "d'Auriac\n"
2795 "\n"
2796 "Цей втулок є вільним програмним забезпеченням — ви можете розповсюджувати та/"
2712 "d'Auriac⏎\n"
2713 "⏎\n"
2714 "Цей плагін є вільним програмним забезпеченням — ви можете розповсюджувати та/"
27972715 "чи модифікувати його відповідно до умов Загальної публічної ліцензії GNU "
27982716 "третьої або (на ваш розсуд) будь-якої новішої версії у тому вигляді, в якому "
2799 "її опублікував Фонд вільного програмного забезпечення.\n"
2800 "\n"
2801 "Цей втулок розповсюджується зі сподіванням, що він виявиться корисним, але "
2717 "її опублікував Фонд вільного програмного забезпечення.⏎\n"
2718 "⏎\n"
2719 "Цей плагін розповсюджується зі сподіванням, що він виявиться корисним, але "
28022720 "БЕЗ ЖОДНОЇ ГАРАНТІЇ; навіть без умовної гарантії КОМЕРЦІЙНОЇ ПРИДАТНОСТІ чи "
28032721 "ПРИДАТНОСТІ ДО ПЕВНОГО ЗАСТОСУВАННЯ. Зверніться до Загальної публічної "
2804 "ліцензії GNU за подробицями.\n"
2805 "\n"
2722 "ліцензії GNU за подробицями.⏎\n"
2723 "⏎\n"
28062724 "Ви мали отримати копію Загальної публічної ліцензії GNU разом із цією "
28072725 "програмою. В іншому випадку, дивіться <http://www.gnu.org/licenses/>."
28082726
28362754
28372755 #: src/oss4/plugin.cc:78
28382756 msgid "Audio device:"
2839 msgstr "Авдіоприлад:"
2757 msgstr "Аудіоприлад:"
28402758
28412759 #: src/oss4/plugin.cc:81
28422760 msgid "Use alternate device:"
28522770
28532771 #: src/oss4/plugin.cc:89
28542772 msgid "Enable exclusive mode to prevent virtual mixing."
2855 msgstr "Діяти в ексклюзивному режимові, уникаючи віртуального мікшування."
2773 msgstr "Діяти в ексклюзивному режимі, уникаючи віртуального мікшування."
28562774
28572775 #: src/oss4/plugin.cc:101
28582776 msgid ""
28622780 "I would like to thank people on #audacious, especially Tony Vroon and John "
28632781 "Lindgren and of course the authors of the previous OSS plugin."
28642782 msgstr ""
2865 "Втулок виводу OSS4 для Audacious,\n"
2783 "Плаґін виводу OSS4 для Audacious,\n"
28662784 "за авторством Michał Lipski,\n"
28672785 "написаний у 2010–2012 роках\n"
28682786 "\n"
28692787 "Дякуємо #audacious, особливо Тоні Врунові, Джонові Ліндґрену й, звісно, "
2870 "авторам попереднього втулку OSS."
2788 "авторам попереднього плаґіну OSS."
28712789
28722790 #: src/playlist-manager/playlist-manager.cc:37
28732791 #: src/playlist-manager-qt/playlist-manager-qt.cc:40
28822800 #: src/playlist-manager/playlist-manager.cc:220
28832801 #: src/playlist-manager-qt/playlist-manager-qt.cc:364
28842802 msgid "_Remove"
2885 msgstr "_Усунути"
2803 msgstr "_Видалити"
28862804
28872805 #: src/playlist-manager/playlist-manager.cc:221
28882806 #: src/playlist-manager-qt/playlist-manager-qt.cc:359
28892807 msgid "Ren_ame"
2890 msgstr "Змінити_назву"
2808 msgstr "Пере_йменувати"
28912809
28922810 #: src/pls/pls.cc:35
28932811 msgid "PLS Playlists"
29192837 "this program; if not, write to the Free Software Foundation, Inc., 51 "
29202838 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
29212839 msgstr ""
2922 "Втулок виводу PulseAudio\n"
2923 "\n"
2924 "Ця програма є вільним програмним забезпеченням — ви можете розповсюджувати "
2925 "та/чи модифікувати її відповідно до умов Загальної публічної ліцензії 2-гої "
2926 "GNU (або будь-якої новішої версії) у тому вигляді, в якому її опублікував. "
2927 "Фонд вільного програмного забезпечення.\n"
2928 "\n"
2929 "Програма розповсюджується зі сподіванням, що вона виявиться корисною, але "
2930 "БЕЗ ЖОДНОЇ ГАРАНТІЇ; навіть без умовної гарантії КОМЕРЦІЙНОЇ ПРИДАТНОСТІ чи "
2931 "ПРИДАТНОСТІ ДО ПЕВНОГО ЗАСТОСУВАННЯ. Зверніться до Загальної публічної "
2932 "ліцензії GNU за подробицями.\n"
2933 "\n"
2934 "Ви мали отримати копію Загальної публічної ліцензії GNU разом із цією "
2935 "програмою. Якщо ви не отримали копії, зверніться за наступною адресою: Free "
2936 "Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA "
2937 "02110-1301, USA"
29382840
29392841 #: src/qtaudio/qtaudio.cc:44
29402842 msgid "QtMultimedia Output"
2941 msgstr "Вивід QtMultimedia"
2843 msgstr "Вихід QtMultimedia"
29422844
29432845 #: src/qtaudio/qtaudio.cc:72
29442846 msgid ""
29482850 "Based on SDL Output Plugin for Audacious\n"
29492851 "Copyright 2010 John Lindgren"
29502852 msgstr ""
2951 "Вивідний втулок QtMultimedia Audio для Audacious\n"
2952 "Копірайт 2014 William Pitcock\n"
2953 "\n"
2954 "Побудовано не виводовому втулкові SDL для Audacious\n"
2955 "Копірайт 2010 John Lindgren"
29562853
29572854 #: src/qtglspectrum/gl-spectrum.cc:41
29582855 msgid ""
29662863 "\n"
29672864 "License: GPLv2+"
29682865 msgstr ""
2969 "OpenGL спектровий аналізатор для Audacious\n"
2970 "Копірайт 2013 Christophe Budé, John Lindgren, and Carlo Bramini\n"
2971 "Копірайт 2014 William Pitcock\n"
2972 "\n"
2973 "За основу взято втулок XMMS:\n"
2974 "Копірайт 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson та "
2975 "4Front Technologies\n"
2976 "\n"
2977 "Ліцензія: GPLv2+"
29782866
29792867 #: src/qtui/main_window.cc:110 src/skins/menus.cc:107 src/skins-qt/menus.cc:98
29802868 msgid "Stop After This Song"
2981 msgstr "Зупинити після цієї стежки"
2869 msgstr "Зупинити після цієї доріжки"
29822870
29832871 #: src/qtui/menus.cc:69
29842872 msgid "_Open Folder ..."
2985 msgstr "_Відкрити теку ..."
2873 msgstr "_відкрити теку ..."
29862874
29872875 #: src/qtui/menus.cc:72
29882876 msgid "_Add Folder ..."
2989 msgstr "_Додати теку ..."
2877 msgstr "_додати теку ..."
29902878
29912879 #: src/qtui/menus.cc:80
29922880 msgid "_Log Inspector ..."
2993 msgstr "_Перевіряльник лоґу ..."
2881 msgstr "_перевіряльник лоґу ..."
29942882
29952883 #: src/qtui/menus.cc:145
29962884 msgid "_Find ..."
2997 msgstr "_Знайти ..."
2885 msgstr "_знайти ..."
29982886
29992887 #: src/qtui/menus.cc:171 src/skins/menus.cc:80 src/skins-qt/menus.cc:70
30002888 msgid "Audio Settings ..."
30102898
30112899 #: src/qtui/playlist_model.cc:36
30122900 msgid "Entry Number"
3013 msgstr "Списковий номер"
2901 msgstr "Унести номер"
30142902
30152903 #: src/qtui/playlist_model.cc:41
30162904 msgid "Album Artist"
30222910
30232911 #: src/qtui/playlist_model.cc:46
30242912 msgid "File Path"
3025 msgstr "Шлях файлу"
2913 msgstr "Тропа файлу"
30262914
30272915 #: src/qtui/playlist_model.cc:47
30282916 msgid "File Name"
30542942
30552943 #: src/resample/resample.cc:187
30562944 msgid "Skip/repeat samples"
3057 msgstr "Пропуск/повтор фраґментів"
2945 msgstr "Пропуск/повтор фрагментів"
30582946
30592947 #: src/resample/resample.cc:188
30602948 msgid "Linear interpolation"
31413029 "Your scrobbles are being saved on your computer temporarily. They will be "
31423030 "submitted as soon as Audacious is allowed access."
31433031 msgstr ""
3144 "Прослуховування збережено на комп'ютерові. Вони будуть відіслані щойно "
3032 "Прослуховування були збережені на комп'ютері. Вони будуть відіслані щойно "
31453033 "Audacious дозволить доступ."
31463034
31473035 #: src/scrobbler2/config_window.cc:33
31483036 #, c-format
31493037 msgid "Permission granted. Scrobbling for user %s."
3150 msgstr "Дозвіл надано. Скроблення для користувача %s."
3038 msgstr "Дозвіл надано. Скроблінґування для користувача %s."
31513039
31523040 #: src/scrobbler2/config_window.cc:37
31533041 msgid ""
31543042 "Permission denied. Open the following URL in a browser, allow Audacious "
31553043 "access to your account, and then click 'Check Permission' again:"
31563044 msgstr ""
3157 "Дозвіл відхилено. Відкрийте сторінку в переглядачеві, дозвольте "
3158 "Audacious'осові доступ до вашої обліківки, а потім знову клацніть "
3159 "\"Перевірка дозволу\":"
3045 "Дозвіл відхилено. Відкрийте цю адресу сторінки у переглядачеві, дозвольте "
3046 "Audacious'осу доступ до вашої обліківки, а потім знову клацніть \"Перевірка "
3047 "дозволу\":"
31603048
31613049 #: src/scrobbler2/config_window.cc:47
31623050 msgid "There was a problem contacting Last.fm."
31733061 #: src/scrobbler2/config_window.cc:91
31743062 msgid "You need to allow Audacious to scrobble tracks to your Last.fm account."
31753063 msgstr ""
3176 "Ви маєте надати дозвіл Audacious'ові для скроблення стежок до обліківки Last."
3177 "fm."
3064 "Ви маєте надати дозвіл Audacious'осові для скроблінґування стежок до "
3065 "обліківки Last.fm."
31783066
31793067 #: src/scrobbler2/scrobbler.cc:29
31803068 msgid "Scrobbler 2.0"
31853073 "The Scrobbler plugin could not be started.\n"
31863074 "There might be a problem with your installation."
31873075 msgstr ""
3188 "Втулок скроблеру не можливо запустити.\n"
3189 "Можливо це проблема зі встановленою програмою."
3076 "Модуль скроблера не може бути запущений.\n"
3077 "Можливо це проблема з встановленою програмою."
31903078
31913079 #: src/scrobbler2/scrobbler.cc:289
31923080 msgid ""
31983086 "project.\n"
31993087 "\n"
32003088 msgstr ""
3201 "Втулок скроблеру для Audacious 2.0 від Pitxyoki,\n"
3089 "Модуль скроблера для Audacious 2.0 від Pitxyoki,\n"
32023090 "\n"
32033091 "Авторське право © 2012-2013 Luís M. Picciochi Oliveira <Pitxyoki@Gmail.com>\n"
32043092 "\n"
32053093 "Велика подяка John Lindgren за простягнуту для допомоги руку на початку "
3206 "цього проєкту.\n"
3094 "цього проекту.\n"
32073095 "\n"
32083096
32093097 #: src/scrobbler2/scrobbler_communication.cc:639
32113099 "Audacious is now using an improved version of the Last.fm Scrobbler.\n"
32123100 "Please check the Preferences for the Scrobbler plugin."
32133101 msgstr ""
3214 "Наразі Audacious використовує покращену версію скроблеру Last.fm.\n"
3215 "Будь ласка, перевірте налаштування для втулку Scrobbler."
3102 "На даний час Audacious використовує покращену версію скробблера Last.fm.⏎\n"
3103 "Будь-ласка перевірте Налаштування для плаґіна Scrobbler."
32163104
32173105 #: src/sdlout/sdlout.cc:43
32183106 msgid "SDL Output"
32233111 "SDL Output Plugin for Audacious\n"
32243112 "Copyright 2010 John Lindgren"
32253113 msgstr ""
3226 "Втулок виводу в SDL,\n"
3114 "Плаґін виводу в SDL,\n"
32273115 "написаний Джоном Ліндґреном у 2010 році."
32283116
32293117 #: src/search-tool-qt/search-tool-qt.cc:87 src/search-tool/search-tool.cc:74
32303118 msgid "Number of results to show:"
3231 msgstr "Кількість результатів для показу:"
3119 msgstr ""
32323120
32333121 #: src/search-tool-qt/search-tool-qt.cc:90 src/search-tool/search-tool.cc:77
32343122 msgid "Rescan library at startup"
3235 msgstr "Пересканувати каталог при запускові"
3123 msgstr ""
32363124
32373125 #: src/search-tool-qt/search-tool-qt.cc:305
32383126 #: src/search-tool-qt/search-tool-qt.cc:316 src/search-tool/search-tool.cc:149
32963184 "To import your music library into Audacious, choose a folder and then click "
32973185 "the \"refresh\" icon."
32983186 msgstr ""
3299 "Аби імпортувати свою музичну бібліотеку до Audacious, виберіть теку й "
3187 "Щоб імпортувати свою музичну бібліотеку до Audacious, виберіть теку й "
33003188 "натисніть на значок оновлення."
33013189
33023190 #: src/search-tool-qt/search-tool-qt.cc:889 src/search-tool/search-tool.cc:793
33033191 msgid "Please wait ..."
3304 msgstr "Зачекайте ..."
3192 msgstr "Зачекайте..."
33053193
33063194 #: src/search-tool/search-tool.cc:821
33073195 msgid "Choose Folder"
33293217
33303218 #: src/sid/xs_config.cc:73
33313219 msgid "Emulate filter"
3332 msgstr "Емулювати фільтр"
3220 msgstr "Емулювати фільтер"
33333221
33343222 #: src/sid/xs_config.cc:75
33353223 msgid "Clock speed:"
33803268 "Silence Removal Plugin for Audacious\n"
33813269 "Copyright 2014 John Lindgren"
33823270 msgstr ""
3383 "Втулок усунення тиші для Audacious\n"
3271 "Плаґін усунення тиші для Audacious\n"
33843272 "Copyright 2014 Джон Ліндґрен"
33853273
33863274 #: src/silence-removal/silence-removal.cc:67
35263414
35273415 #: src/skins/menus.cc:84 src/skins-qt/menus.cc:74
35283416 msgid "Open Files ..."
3529 msgstr "Відкрити файли ..."
3417 msgstr "Відкрити файли..."
35303418
35313419 #: src/skins/menus.cc:85 src/skins-qt/menus.cc:76
35323420 msgid "Open URL ..."
3533 msgstr "Відкрити адресу ..."
3421 msgstr "Відкрити адресу..."
35343422
35353423 #: src/skins/menus.cc:88 src/skins-qt/menus.cc:79
35363424 msgid "Playback"
35423430
35433431 #: src/skins/menus.cc:90 src/skins-qt/menus.cc:81
35443432 msgid "Output"
3545 msgstr "Вивід"
3433 msgstr "Вихід"
35463434
35473435 #: src/skins/menus.cc:91 src/skins-qt/menus.cc:82
35483436 msgid "View"
35563444
35573445 #: src/skins/menus.cc:95 src/skins-qt/menus.cc:86
35583446 msgid "About ..."
3559 msgstr "Візитівка ..."
3447 msgstr "Про ..."
35603448
35613449 #: src/skins/menus.cc:96 src/skins-qt/menus.cc:87
35623450 msgid "Settings ..."
35693457 #: src/skins/menus.cc:101 src/skins/menus.cc:231 src/skins-qt/menus.cc:92
35703458 #: src/skins-qt/menus.cc:225
35713459 msgid "Song Info ..."
3572 msgstr "Інформація про стежку ..."
3460 msgstr "Інформація про доріжку..."
35733461
35743462 #: src/skins/menus.cc:105 src/skins-qt/menus.cc:96
35753463 msgid "Shuffle by Album"
35773465
35783466 #: src/skins/menus.cc:106 src/skins-qt/menus.cc:97
35793467 msgid "No Playlist Advance"
3580 msgstr "Не просуватися у спискові відтворення"
3468 msgstr "Не просуватися у списку відтворення"
35813469
35823470 #: src/skins/menus.cc:115 src/skins-qt/menus.cc:106
35833471 msgid "Set A-B Repeat"
35893477
35903478 #: src/skins/menus.cc:118 src/skins-qt/menus.cc:110
35913479 msgid "Jump to Song ..."
3592 msgstr "Перейти до стежки ..."
3480 msgstr "Перейти до доріжки..."
35933481
35943482 #: src/skins/menus.cc:119 src/skins-qt/menus.cc:111
35953483 msgid "Jump to Time ..."
3596 msgstr "Перейти до часу ..."
3484 msgstr "Перейти до часу..."
35973485
35983486 #: src/skins/menus.cc:123 src/skins-qt/menus.cc:116
35993487 msgid "Play/Resume"
36013489
36023490 #: src/skins/menus.cc:125 src/skins-qt/menus.cc:118
36033491 msgid "New Playlist"
3604 msgstr "Новий список відтворення"
3492 msgstr "Новий список відтворення"
36053493
36063494 #: src/skins/menus.cc:126 src/skins-qt/menus.cc:119
36073495 msgid "Rename Playlist ..."
3608 msgstr "Змінити плейлистову назву ..."
3496 msgstr "Перейменувати список..."
36093497
36103498 #: src/skins/menus.cc:127 src/skins-qt/menus.cc:120
36113499 msgid "Remove Playlist"
3612 msgstr "Усунути список"
3500 msgstr "Видалити список"
36133501
36143502 #: src/skins/menus.cc:129 src/skins-qt/menus.cc:122
36153503 msgid "Previous Playlist"
36213509
36223510 #: src/skins/menus.cc:132 src/skins-qt/menus.cc:125
36233511 msgid "Import Playlist ..."
3624 msgstr "Імпортувати список відтворення ..."
3512 msgstr "Імпортувати список відтворення..."
36253513
36263514 #: src/skins/menus.cc:133 src/skins-qt/menus.cc:126
36273515 msgid "Export Playlist ..."
3628 msgstr "Експортувати список відтворення ..."
3516 msgstr "Експортувати список відтворення..."
36293517
36303518 #: src/skins/menus.cc:135 src/skins-qt/menus.cc:128
36313519 msgid "Playlist Manager ..."
3632 msgstr "Керування списками відтворення ..."
3520 msgstr "Керування списками відтворення..."
36333521
36343522 #: src/skins/menus.cc:136 src/skins-qt/menus.cc:129
36353523 msgid "Queue Manager ..."
3636 msgstr "Керування чергою ..."
3524 msgstr "Керування чергою..."
36373525
36383526 #: src/skins/menus.cc:138 src/skins-qt/menus.cc:131
36393527 msgid "Refresh Playlist"
36573545
36583546 #: src/skins/menus.cc:149 src/skins-qt/menus.cc:143
36593547 msgid "On All Workspaces"
3660 msgstr "На всіх робочих просторах"
3548 msgstr "На всіх робочих столах"
36613549
36623550 #: src/skins/menus.cc:151 src/skins-qt/menus.cc:146
36633551 msgid "Roll Up Player"
36733561
36743562 #: src/skins/menus.cc:161 src/skins-qt/menus.cc:156
36753563 msgid "Add URL ..."
3676 msgstr "Додати адресу ..."
3564 msgstr "Додати адресу..."
36773565
36783566 #: src/skins/menus.cc:162 src/skins-qt/menus.cc:158
36793567 msgid "Add Files ..."
3680 msgstr "Додати файли ..."
3568 msgstr "Додати файли..."
36813569
36823570 #: src/skins/menus.cc:166 src/skins/menus.cc:194 src/skins/menus.cc:209
36833571 #: src/skins-qt/menus.cc:162 src/skins-qt/menus.cc:188
36893577 #: src/skins-qt/menus.cc:163 src/skins-qt/menus.cc:195
36903578 #: src/skins-qt/menus.cc:210
36913579 msgid "By File Name"
3692 msgstr "За назвою файлу"
3580 msgstr "По назві файлу"
36933581
36943582 #: src/skins/menus.cc:168 src/skins/menus.cc:202 src/skins/menus.cc:217
36953583 #: src/skins-qt/menus.cc:164 src/skins-qt/menus.cc:196
37113599
37123600 #: src/skins/menus.cc:178 src/skins-qt/menus.cc:174
37133601 msgid "Remove Duplicates"
3714 msgstr "Вилучити дублікати"
3602 msgstr "Видалити дублікати"
37153603
37163604 #: src/skins/menus.cc:180 src/skins-qt/menus.cc:176
37173605 msgid "Remove Unselected"
37233611
37243612 #: src/skins/menus.cc:185
37253613 msgid "Search and Select"
3726 msgstr "Пошук і вибрання"
3614 msgstr "Пошук і виділення"
37273615
37283616 #: src/skins/menus.cc:187 src/skins-qt/menus.cc:181
37293617 msgid "Invert Selection"
3730 msgstr "Інвертувати вибрання"
3618 msgstr "Інвертувати виділення"
37313619
37323620 #: src/skins/menus.cc:188 src/skins-qt/menus.cc:182
37333621 msgid "Select None"
3734 msgstr "Зняти вибрання"
3622 msgstr "Зняти виділення"
37353623
37363624 #: src/skins/menus.cc:189 src/skins-qt/menus.cc:183
37373625 msgid "Select All"
37403628 #: src/skins/menus.cc:193 src/skins/menus.cc:208 src/skins-qt/menus.cc:187
37413629 #: src/skins-qt/menus.cc:202
37423630 msgid "By Track Number"
3743 msgstr "За номером стежки"
3631 msgstr "За номером доріжки"
37443632
37453633 #: src/skins/menus.cc:195 src/skins/menus.cc:210 src/skins-qt/menus.cc:189
37463634 #: src/skins-qt/menus.cc:204
37653653 #: src/skins/menus.cc:199 src/skins/menus.cc:213 src/skins-qt/menus.cc:193
37663654 #: src/skins-qt/menus.cc:207
37673655 msgid "By Genre"
3768 msgstr "За напрямком"
3656 msgstr "По напрямку"
37693657
37703658 #: src/skins/menus.cc:200 src/skins/menus.cc:215 src/skins-qt/menus.cc:194
37713659 #: src/skins-qt/menus.cc:209
38613749
38623750 #: src/skins-qt/skins_cfg.cc:205 src/skins/skins_cfg.cc:189
38633751 msgid "<b>Skin</b>"
3864 msgstr "<b>Жупан</b>"
3752 msgstr "<b>Оболонка</b>"
38653753
38663754 #: src/skins-qt/skins_cfg.cc:209 src/skins/skins_cfg.cc:191
38673755 msgid "<b>Fonts</b>"
39373825
39383826 #: src/skins-qt/skins_cfg.cc:242 src/skins/skins_cfg.cc:224
39393827 msgid "Fastest"
3940 msgstr "Найшвидше"
3828 msgstr "Дуже швидке"
39413829
39423830 #: src/skins-qt/skins_cfg.cc:246 src/skins/skins_cfg.cc:228
39433831 msgid "Dots"
40093897
40103898 #: src/skins-qt/skinselector.cc:98 src/skins/skinselector.cc:111
40113899 msgid "Archived Winamp 2.x skin"
4012 msgstr "Заархівлений жупан Winamp 2.x"
3900 msgstr "Заархівований жупан Winamp 2.x"
40133901
40143902 #: src/skins-qt/skinselector.cc:102 src/skins/skinselector.cc:115
40153903 msgid "Unarchived Winamp 2.x skin"
4016 msgstr "Розархівлений жупан Winamp 2.x"
3904 msgstr "Неархівований жупан Winamp 2.x"
40173905
40183906 #: src/skins/search-select.cc:75
40193907 msgid "Search entries in active playlist"
4020 msgstr "Пошук у чинному спискові відтворення"
3908 msgstr "Пошук в активному списку відтворення"
40213909
40223910 #: src/skins/search-select.cc:76
40233911 msgid "Search"
40303918 "expressions work, simply insert a literal portion of what you're searching "
40313919 "for."
40323920 msgstr ""
4033 "Аби шукати стежки в спискові відтворення, заповніть одне чи більше полів. "
3921 "Щоб шукати доріжки в списку відтворення, заповніть одне чи більше полів. "
40343922 "Можна використовувати літери, цифри, інші знаки, регулярні вирази. Поля "
40353923 "нечутливі до регістру."
40363924
40523940
40533941 #: src/skins/search-select.cc:115
40543942 msgid "Clear previous selection before searching"
4055 msgstr "Зняти попереднє вибрання перед пошуком"
3943 msgstr "Зняти попереднє виділення перед пошуком"
40563944
40573945 #: src/skins/search-select.cc:118
40583946 msgid "Automatically toggle queue for matching entries"
40643952
40653953 #: src/sndfile/plugin.cc:37
40663954 msgid "Sndfile Plugin"
4067 msgstr "Втулок Sndfile"
3955 msgstr "Плаґін Sndfile"
40683956
40693957 #: src/sndfile/plugin.cc:361
40703958 msgid ""
40873975 "this program; if not, write to the Free Software Foundation, Inc., 51 "
40883976 "Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA."
40893977 msgstr ""
4090 "Автор втулку — Тоні Врун <chainsaw@gentoo.org>.\n"
3978 "Автор плаґіну — Тоні Врун <chainsaw@gentoo.org>.\n"
40913979 "\n"
40923980 "За основу взято xmms_sndfile,\n"
40933981 "написаний у 2000–2002 роках Еріком де Кастро Лопо.\n"
41113999
41124000 #: src/sndio/sndio.cc:43
41134001 msgid "Sndio Output"
4114 msgstr "Вивід Sndio"
4002 msgstr "Вихід Sndio"
41154003
41164004 #: src/sndio/sndio.cc:98
41174005 msgid "Device (blank for default):"
41404028
41414029 #: src/songchange/song_change.cc:33
41424030 msgid "Song Change"
4143 msgstr "Зміна стежки"
4031 msgstr "Зміна доріжки"
41444032
41454033 #: src/songchange/song_change.cc:268
41464034 msgid "<b>Commands</b>"
4147 msgstr "<b>Команди</b>"
4035 msgstr "<b>Накази</b>"
41484036
41494037 #: src/songchange/song_change.cc:270
41504038 msgid "Command to run when starting a new song:"
41524040
41534041 #: src/songchange/song_change.cc:273
41544042 msgid "Command to run at the end of a song:"
4155 msgstr "Оберіть команду, яку задіяти наприкінці пісні:"
4043 msgstr ""
41564044
41574045 #: src/songchange/song_change.cc:276
41584046 msgid "Command to run at the end of the playlist:"
4159 msgstr "Оберіть команду, яку задіяти наприкінці списку відтворення:"
4047 msgstr ""
41604048
41614049 #: src/songchange/song_change.cc:279
41624050 msgid "Command to run when song title changes (for network streams):"
41634051 msgstr ""
4164 "Оберіть команду, яку задіяти коли змінюється назва пісні (для стримового "
4165 "прослуховування):"
41664052
41674053 #: src/songchange/song_change.cc:282
41684054 msgid ""
41694055 "You can use the following format codes, which will be replaced before "
41704056 "running the command (not all are useful for the end-of-playlist command):"
41714057 msgstr ""
4172 "Ви можете використовувати наступні форматові коди, які зміняться перед "
4173 "початком команди (не всі вони є корисними для команди кінцевого-списку-"
4174 "відтворення):"
41754058
41764059 #: src/songchange/song_change.cc:285
41774060 msgid ""
41874070 "%t: Playlist position\n"
41884071 "%T: Title (unformatted)"
41894072 msgstr ""
4190 "%a: Виконавець\n"
4191 "%b: Альбом\n"
4192 "%c: Кількість каналів\n"
4193 "%f: Назва файлу (весь шлях)\n"
4194 "%F: Частота (Герців)\n"
4195 "%l: Довжина (мілісекунд)\n"
4196 "%n або %s: Змінена назва (див. налаштування списку відтворення)\n"
4197 "%p: Наразі грає (1 або 0)\n"
4198 "%r: Рівень (бітів на секунду)\n"
4199 "%t: Положення списку відтворення\n"
4200 "%T: Назва (незмінена)"
42014073
42024074 #: src/songchange/song_change.cc:296
42034075 msgid ""
42044076 "Parameters passed to the shell should be enclosed in quotation marks. "
42054077 "Unquoted parameters may lead to unexpected results."
42064078 msgstr ""
4207 "Параметри передані до командного процесору мають бути у лапках. Безлапкові "
4208 "параметри можуть призвести до неочікуваних наслідків."
42094079
42104080 #: src/song-info-qt/song-info.cc:33
42114081 msgid "Song Info"
42234093 "Based on Sample Rate Converter Plugin:\n"
42244094 "Copyright 2010-2012 John Lindgren"
42254095 msgstr ""
4226 "Втулок ресемплеру SoX для Audacious\n"
4096 "Модуль ресемплера SoX для Audacious\n"
42274097 "Авторське право 2013 Michał Lipski\n"
42284098 "\n"
4229 "Базується на кодові втулку Sample Rate Converter:\n"
4099 "Базується на коді модуля Sample Rate Converter:\n"
42304100 "Авторське право 2010-2012 John Lindgren"
42314101
42324102 #: src/soxr/sox-resampler.cc:163
42474117
42484118 #: src/soxr/sox-resampler.cc:168
42494119 msgid "Ultra High"
4250 msgstr "Найвища"
4120 msgstr ""
42514121
42524122 #: src/soxr/sox-resampler.cc:172
42534123 msgid "Minimum"
4254 msgstr "Мінімальна"
4124 msgstr ""
42554125
42564126 #: src/soxr/sox-resampler.cc:173
42574127 msgid "Intermediate"
4258 msgstr "Середня"
4128 msgstr ""
42594129
42604130 #: src/soxr/sox-resampler.cc:174
42614131 msgid "Linear"
4262 msgstr "Лінійна"
4132 msgstr ""
42634133
42644134 #: src/soxr/sox-resampler.cc:178
42654135 msgid "Quality:"
42674137
42684138 #: src/soxr/sox-resampler.cc:181
42694139 msgid "Phase:"
4270 msgstr "Фейзер:"
4140 msgstr ""
42714141
42724142 #: src/soxr/sox-resampler.cc:185
42734143 msgid "Allow aliasing"
4274 msgstr "Дозволити аліаси"
4144 msgstr ""
42754145
42764146 #: src/soxr/sox-resampler.cc:187
42774147 msgid "Use steep filter"
4278 msgstr "Використовувати стрімкий фільтр"
4148 msgstr ""
42794149
42804150 #: src/speedpitch/speed-pitch.cc:54
42814151 msgid "Speed and Pitch"
42874157
42884158 #: src/speedpitch/speed-pitch.cc:248
42894159 msgid "Decouple from pitch"
4290 msgstr "Від'єднати від тону"
4160 msgstr ""
42914161
42924162 #: src/speedpitch/speed-pitch.cc:250 src/speedpitch/speed-pitch.cc:258
42934163 msgid "Multiplier:"
4294 msgstr "Множник:"
4164 msgstr ""
42954165
42964166 #: src/speedpitch/speed-pitch.cc:254
42974167 msgid "<b>Pitch</b>"
4298 msgstr "<b>Тонова висота</b>"
4168 msgstr ""
42994169
43004170 #: src/statusicon-qt/statusicon.cc:45 src/statusicon/statusicon.cc:47
43014171 msgid "Status Icon"
4302 msgstr "Значок у смужці стану"
4172 msgstr "Значок у лотку"
43034173
43044174 #: src/statusicon-qt/statusicon.cc:66
43054175 msgid ""
43124182 "This plugin provides a status icon, placed in\n"
43134183 "the system tray area of the window manager."
43144184 msgstr ""
4315 "Втулок смужки стану (частковий порт з інтефейсу Qt)\n"
4316 "\n"
4317 "Копірайт 2005-2007 Giacomo Lozito <james@develia.org>\n"
4318 "Копірайт 2010 Міхайло Липський <tallica@o2.pl>\n"
4185 "Status Icon Plugin (partial port for Qt interface)\n"
4186 "\n"
4187 "Copyright 2005-2007 Giacomo Lozito <james@develia.org>\n"
4188 "Copyright 2010 Міхав Ліпскі <tallica@o2.pl>\n"
43194189 "Copyright 2015 Євген Паскевич <eugene@raptor.kiev.ua>\n"
43204190 "\n"
4321 "Втулок надає ікону стану, яка знаходиться на\n"
4322 "смужці стану віндовс-менеджеру"
4191 "Плаґін надає ікону стану, яка знаходиться у\n"
4192 "системній таці віндовс менеджера"
43234193
43244194 #: src/statusicon-qt/statusicon.cc:88 src/statusicon/statusicon.cc:381
43254195 msgid "<b>Mouse Scroll Action</b>"
43314201
43324202 #: src/statusicon-qt/statusicon.cc:92 src/statusicon/statusicon.cc:385
43334203 msgid "Change playing song"
4334 msgstr "Зміна поточної стежки"
4204 msgstr "Зміна поточної доріжки"
43354205
43364206 #: src/statusicon-qt/statusicon.cc:95 src/statusicon/statusicon.cc:388
43374207 msgid "<b>Other Settings</b>"
43434213
43444214 #: src/statusicon-qt/statusicon.cc:98 src/statusicon/statusicon.cc:391
43454215 msgid "Close to the system tray"
4346 msgstr "Замість закриття згортати до смужки стану"
4216 msgstr "Замість закриття згортати до лотка"
43474217
43484218 #: src/statusicon-qt/statusicon.cc:100 src/statusicon/statusicon.cc:393
43494219 msgid "Advance in playlist when scrolling upward"
43634233 "This plugin provides a status icon, placed in\n"
43644234 "the system tray area of the window manager."
43654235 msgstr ""
4366 "Втулок сповіщення й керування Audacious через смужку стану\n"
4367 "\n"
4368 "2005–2007 — Джакомо Лоцито <james@develia.org>\n"
4236 "Плаґін сповіщення й керування Audacious через системний лоток\n"
4237 "\n"
4238 "2005–2007 — Джакомо Лоціто <james@develia.org>\n"
43694239 "2010 — Michał Lipski <tallica@o2.pl>"
43704240
43714241 #: src/stereo_plugin/stereo.cc:19
43794249 "By Johan Levin, 1999"
43804250 msgstr ""
43814251 "Розширене стерео,\n"
4382 "втулок написаний у 1999 році (автор — Johan Levin)."
4252 "плаґін написаний у 1999 році (автор — Johan Levin)."
43834253
43844254 #: src/stereo_plugin/stereo.cc:44
43854255 msgid "<b>Extra Stereo</b>"
44104280 "автори: Håvard Kvålen <mys@faveve.uni-stuttgart.de>,\n"
44114281 "Daniel J. Peng <danielpeng@bigfoot.com>.\n"
44124282 "\n"
4413 "Використовується при відкритті ланки у форматі:\n"
4283 "Використовується при відкритті посилання в форматі:\n"
44144284 "tone://частота1;[частота2;...]\n"
44154285 "\n"
44164286 "Наприклад, tone://2000;2005 — послідовне відтворення тонів з частотою 2000 "
44504320 msgstr ""
44514321 "Декодер Ogg Vorbis\n"
44524322 "\n"
4453 "на основі втулку від Xiph.org Foundation:\n"
4323 "на основі плаґіну від Xiph.org Foundation:\n"
44544324 "http://www.xiph.org/\n"
44554325 "\n"
4456 "Автор джерельного коду —\n"
4457 "Тоні Арчері <bascule@inferno.tusculum.edu>\n"
4326 "Автор початкового коду —\n"
4327 "Tony Arcieri <bascule@inferno.tusculum.edu>\n"
44584328 "\n"
44594329 "У розробці брали участь:\n"
4460 "Крис Монтґомері <monty@xiph.org>\n"
4461 "Пітер Алм <peter@xmms.org>\n"
4462 "Майкл Сміт <msmith@labyrinth.edu.au>\n"
4463 "Джек Моффітт <jack@icecast.org>\n"
4464 "Йорн Бааєн <jorn@nl.linux.org>\n"
4465 "Гавард Квален <havardk@xmms.org>\n"
4466 "Жан-Карло Паскат <gcp@sjeng.org>\n"
4467 "Євген Заґідуллін <e.asphyx@gmail.com>"
4330 "Chris Montgomery <monty@xiph.org>\n"
4331 "Peter Alm <peter@xmms.org>\n"
4332 "Michael Smith <msmith@labyrinth.edu.au>\n"
4333 "Jack Moffitt <jack@icecast.org>\n"
4334 "Jorn Baayen <jorn@nl.linux.org>\n"
4335 "Håvard Kvålen <havardk@xmms.org>\n"
4336 "Gian-Carlo Pascutto <gcp@sjeng.org>\n"
4337 "Eugene Zagidullin <e.asphyx@gmail.com>"
44684338
44694339 #: src/vorbis/vorbis.h:18
44704340 msgid "Ogg Vorbis Decoder"
44894359 "Player Freq: %P\n"
44904360 "Year: %y"
44914361 msgstr ""
4492 "Назва: %t\n"
4493 "Автор: %a\n"
4494 "З: %f\n"
4495 "Трекер: %T\n"
4496 "Коментар: %C\n"
4497 "Тип чипу: %c\n"
4498 "Стерео: %s\n"
4499 "Зациклення: %l\n"
4500 "Чипова част.: %F\n"
4501 "Програвачева част.: %P\n"
4502 "Рік: %y"
45034362
45044363 #: src/vtx/vtx.cc:38
45054364 msgid "VTX Decoder"
45144373 "Відтворювач файлів Vortex Сашнова Олександра <sashnov@ngs.ru>.\n"
45154374 "За основу взято in_vtx.dll Романа Щербакова <v_soft@microfor.ru>.\n"
45164375 "\n"
4517 "Втулок для Audacious'у створив Павел Виметалек <pvymetalek@seznam.cz>."
4376 "Плаґін для Audacious створив Павел Виметалек <pvymetalek@seznam.cz>."
45184377
45194378 #: src/waveout/waveout.cc:43
45204379 msgid "Win32 waveOut"
45254384 "Win32 waveOut Plugin for Audacious\n"
45264385 "Copyright 2016 John Lindgren"
45274386 msgstr ""
4528 "Втулок Win32 waveOut для Audacious\n"
4387 "Win32 waveOut плаґін для Audacious\n"
45294388 "Copyright 2016 Джон Ліндґрен"
45304389
45314390 #: src/wavpack/wavpack.cc:24
45344393
45354394 #: src/wavpack/wavpack.cc:211
45364395 msgid "lossy (hybrid)"
4537 msgstr "з втратами (гібрид)"
4396 msgstr "зі втратами (гібрид)"
45384397
45394398 #: src/wavpack/wavpack.cc:213
45404399 msgid "lossy"
4541 msgstr "з втратами"
4400 msgstr "зі втратами"
45424401
45434402 #: src/wavpack/wavpack.cc:251
45444403 msgid ""
45484407 msgstr ""
45494408 "Автор — Вільям Піткок <nenolod@nenolod.net> (2006 рік).\n"
45504409 "\n"
4551 "Деякий код написав Майлс Еґен."
4410 "Деякий код написав Майлс Еґан."
45524411
45534412 #: src/xsf/plugin.cc:50
45544413 msgid "2SF Decoder"
45754434 #~ "\n"
45764435 #~ "Copyright (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>"
45774436 #~ msgstr ""
4578 #~ "Втулок мініатюр GNOME\n"
4437 #~ "Плаґін мініатюр GNOME\n"
45794438 #~ "Дозволяє керувати програвачем з мініатюрами GNOME\n"
45804439 #~ "\n"
45814440 #~ "Copyright (C) 2007-2008 Саша Глюсяк <contact@saschahlusiak.de>"
1212 {
1313 public:
1414 static const char * const exts[];
15 static const char * const mimes[];
1516
1617 static constexpr PluginInfo info = {
1718 N_("AAC (Raw) Decoder"),
1920 };
2021
2122 constexpr AACDecoder () : InputPlugin (info, InputInfo ()
22 .with_exts (exts)) {}
23 .with_exts (exts)
24 .with_mimes (mimes)) {}
2325
2426 bool is_our_file (const char * filename, VFSFile & file);
2527 bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
2931 EXPORT AACDecoder aud_plugin_instance;
3032
3133 const char * const AACDecoder::exts[] = {"aac", nullptr};
34 const char * const AACDecoder::mimes[] = {"audio/aac", nullptr};
3235
3336 /*
3437 * BUFFER_SIZE is the highest amount of memory that can be pulled.
0 faad_dep = cxx.find_library('faad', has_headers: ['neaacdec.h'])
1
2
3 if faad_dep.found()
4 shared_module('aac-raw',
5 'aac.cc',
6 dependencies: [audacious_dep, faad_dep, audtag_dep],
7 include_directories: [src_inc],
8 install: true,
9 install_dir: input_plugin_dir,
10 )
11 endif
12
88
99 LD = ${CXX}
1010 CFLAGS += ${PLUGIN_CFLAGS}
11 # FIXME: Turning off warnings for now; this code is awful
12 CXXFLAGS += ${PLUGIN_CFLAGS} -Wno-sign-compare -Wno-shift-negative-value
13 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${ADLIB_CFLAGS} -I../..
14 LIBS += ${ADLIB_LIBS}
11 CXXFLAGS += ${PLUGIN_CFLAGS}
12 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GTK_CFLAGS} ${QT_CFLAGS} ${ADLIB_CFLAGS} -I../..
13 LIBS += ${QT_LIBS} ${GTK_LIBS} ${ADLIB_LIBS}
2525 #include <adplug/adplug.h>
2626 #include <adplug/emuopl.h>
2727 #include <adplug/silentopl.h>
28 #ifdef HAVE_ADPLUG_NEMUOPL_H
29 # include <adplug/nemuopl.h>
30 #endif
31 #ifdef HAVE_ADPLUG_WEMUOPL_H
32 # include <adplug/wemuopl.h>
33 #endif
34 #ifdef HAVE_ADPLUG_KEMUOPL_H
35 # include <adplug/kemuopl.h>
36 #endif
2837 #include <adplug/players.h>
2938
3039 #include <libaudcore/audstrings.h>
3746
3847 #define CFG_ID "AdPlug"
3948
49 #define ADPLUG_MAME 0
50 #ifdef HAVE_ADPLUG_NEMUOPL_H
51 # define ADPLUG_NUKED 1
52 #endif
53 #ifdef HAVE_ADPLUG_WEMUOPL_H
54 # define ADPLUG_WOODY 2
55 #endif
56 #ifdef HAVE_ADPLUG_KEMUOPL_H
57 # define ADPLUG_KS 3
58 #endif
59
4060 class AdPlugXMMS : public InputPlugin
4161 {
4262 public:
43 static const char * const exts[];
44 static const char * const defaults[];
45 static const PreferencesWidget widgets[];
46 static const PluginPreferences prefs;
47
48 static constexpr PluginInfo info = {
49 N_("AdPlug (AdLib Player)"),
50 PACKAGE,
51 nullptr,
52 & prefs
53 };
54
55 constexpr AdPlugXMMS () : InputPlugin (info, InputInfo ()
56 .with_exts (exts)) {}
57
58 bool init ();
59 void cleanup ();
60
61 bool is_our_file (const char * filename, VFSFile & file);
62 bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
63 bool play (const char * filename, VFSFile & file);
63 static const char * const exts[];
64 static const char * const defaults[];
65 static const PreferencesWidget widgets[];
66 static const PluginPreferences prefs;
67
68 static constexpr PluginInfo info = {
69 N_("AdPlug (AdLib Player)"),
70 PACKAGE,
71 nullptr,
72 & prefs
73 };
74
75 constexpr AdPlugXMMS () : InputPlugin (info, InputInfo ()
76 .with_exts (exts)) {}
77
78 bool init ();
79 void cleanup ();
80
81 bool is_our_file (const char * filename, VFSFile & file);
82 bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
83 bool play (const char * filename, VFSFile & file);
6484 };
6585
6686 EXPORT AdPlugXMMS aud_plugin_instance;
6787
6888 const char * const AdPlugXMMS::exts[] = {
69 "a2m", "adl", "amd", "bam", "cff", "cmf", "d00", "dfm", "dmo", "dro",
70 "dtm", "hsc", "hsp", "ins", "jbm", "ksm", "laa", "lds", "m", "mad",
71 "mkj", "msc", "rad", "raw", "rix", "rol", "s3m", "sa2", "sat", "sci",
72 "sng", "wlf", "xad", "xsm", nullptr
89 "a2m", "adl", "amd", "bam", "cff", "cmf", "d00", "dfm", "dmo", "dro",
90 "dtm", "hsc", "hsp", "ins", "jbm", "ksm", "laa", "lds", "m", "mad",
91 "mkj", "msc", "rad", "raw", "rix", "rol", "s3m", "sa2", "sat", "sci",
92 "sng", "wlf", "xad", "xsm", nullptr
7393 };
7494
7595 /***** Defines *****/
7797 // Sound buffer size in samples
7898 #define SNDBUFSIZE 512
7999
80 // AdPlug's 8 and 16 bit audio formats
81 #define FORMAT_8 FMT_U8
82 #define FORMAT_16 FMT_S16_NE
100 // 4 byte sample size (16 bit depth & stereo)
101 #define SAMPLESIZE 4
83102
84103 // Default file name of AdPlug's database file
85104 #define ADPLUGDB_FILE "adplug.db"
91110
92111 // Player variables
93112 static struct {
94 CPlayer *p = nullptr;
95 CAdPlugDatabase *db = nullptr;
113 SmartPtr<CPlayer> p;
114 SmartPtr<CAdPlugDatabase> db;
96115 unsigned int subsong = 0, songlength = 0;
97116 String filename;
98117 } plr;
156175 {
157176 dbg_printf ("adplug_play(\"%s\"): ", filename);
158177
159 bool bit16 = aud_get_bool (CFG_ID, "16bit");
160 bool stereo = aud_get_bool (CFG_ID, "Stereo");
178 int emulator = aud_get_int (CFG_ID, "Emulator");
161179 int freq = aud_get_int (CFG_ID, "Frequency");
162180 bool endless = aud_get_bool (CFG_ID, "Endless");
163181
164182 // Set XMMS main window information
165183 dbg_printf ("xmms, ");
166 int sampsize = (bit16 ? 2 : 1) * (stereo ? 2 : 1);
167 set_stream_bitrate (freq * sampsize * 8);
184 set_stream_bitrate (freq * SAMPLESIZE * 8);
168185
169186 // open output plugin
170187 dbg_printf ("open, ");
171 open_audio (bit16 ? FORMAT_16 : FORMAT_8, freq, stereo ? 2 : 1);
172
173 CEmuopl opl (freq, bit16, stereo);
188 open_audio (FMT_S16_NE, freq, 2);
189
190 SmartPtr<Copl> opl;
191 switch (emulator) {
192 #ifdef HAVE_ADPLUG_NEMUOPL_H
193 case ADPLUG_NUKED:
194 opl.capture(new CNemuopl (freq));
195 break;
196 #endif
197 #ifdef HAVE_ADPLUG_WEMUOPL_H
198 case ADPLUG_WOODY:
199 opl.capture(new CWemuopl (freq, true, true));
200 break;
201 #endif
202 #ifdef HAVE_ADPLUG_KEMUOPL_H
203 case ADPLUG_KS:
204 opl.capture(new CKemuopl (freq, true, true));
205 break;
206 #endif
207 case ADPLUG_MAME:
208 default:
209 opl.capture(new CEmuopl (freq, true, true));
210 // otherwise sound only comes out of left
211 static_cast<CEmuopl *>(opl.get())->settype(Copl::TYPE_OPL2);
212 }
213
174214 long toadd = 0, i, towrite;
175215 char *sndbuf, *sndbufpos;
176216 bool playing = true; // Song self-end indicator.
178218 // Try to load module
179219 dbg_printf ("factory, ");
180220 CFileVFSProvider fp (fd);
181 if (!(plr.p = CAdPlug::factory (filename, &opl, CAdPlug::players, fp)))
221 if (!(plr.p.capture(CAdPlug::factory (filename, opl.get (), CAdPlug::players, fp))))
182222 {
183223 dbg_printf ("error!\n");
184224 // MessageBox("AdPlug :: Error", "File could not be opened!", "Ok");
195235
196236 // Allocate audio buffer
197237 dbg_printf ("buffer, ");
198 sndbuf = (char *) malloc (SNDBUFSIZE * sampsize);
238 // 4 byte sample size
239 sndbuf = (char *) malloc (SNDBUFSIZE * 4);
199240
200241 // Rewind player to right subsong
201242 dbg_printf ("rewind, ");
240281 time += (int) (1000 / plr.p->getrefresh ());
241282 }
242283 i = std::min (towrite, (long) (toadd / plr.p->getrefresh () + 4) & ~3);
243 opl.update ((short *) sndbufpos, i);
244 sndbufpos += i * sampsize;
284 opl->update ((short *) sndbufpos, i);
285 sndbufpos += i * SAMPLESIZE;
245286 towrite -= i;
246287 toadd -= (long) (plr.p->getrefresh () * i);
247288 }
248289
249 write_audio (sndbuf, SNDBUFSIZE * sampsize);
290 write_audio (sndbuf, SNDBUFSIZE * SAMPLESIZE);
250291 }
251292
252293 // free everything and exit
253294 dbg_printf ("free");
254 delete plr.p;
255 plr.p = 0;
295 plr.p.clear ();
256296 free (sndbuf);
257297 dbg_printf (".\n");
258298 return true;
259299 }
260300
261 // sampsize macro not useful anymore.
262 #undef sampsize
263
264301 /***** Informational *****/
265302
266303 bool AdPlugXMMS::is_our_file (const char * filename, VFSFile & fd)
286323 /***** Configuration file handling *****/
287324
288325 const char * const AdPlugXMMS::defaults[] = {
289 "16bit", "TRUE",
290 "Stereo", "FALSE",
291326 "Frequency", "44100",
292327 "Endless", "FALSE",
328 "Emulator", "0",
293329 nullptr};
294330
331 /***** Configuration UI *****/
332
333 static const ComboItem plugin_combo[] = {
334 ComboItem ("Tatsuyuki Satoh 0.72 (MAME, 2003)", ADPLUG_MAME),
335 #ifdef HAVE_ADPLUG_NEMUOPL_H
336 ComboItem ("Nuked OPL3 (Nuke.YKT, 2018)", ADPLUG_NUKED),
337 #endif
338 #ifdef HAVE_ADPLUG_WEMUOPL_H
339 ComboItem ("WoodyOPL (DOSBox, 2016)", ADPLUG_WOODY),
340 #endif
341 #ifdef HAVE_ADPLUG_KEMUOPL_H
342 ComboItem ("Ken Silverman (2001)", ADPLUG_KS),
343 #endif
344 };
345
295346 const PreferencesWidget AdPlugXMMS::widgets[] = {
296 WidgetLabel (N_("<b>Output</b>")),
297 WidgetCheck (N_("16-bit output (if unchecked, output is 8-bit)"),
298 WidgetBool (CFG_ID, "16bit")),
299 WidgetCheck (N_("Duplicate mono output to two channels"),
300 WidgetBool (CFG_ID, "Stereo")),
301 WidgetSpin (N_("Sample rate"),
302 WidgetInt (CFG_ID, "Frequency"), {8000, 192000, 50, N_("Hz")}),
303 WidgetLabel (N_("<b>Miscellaneous</b>")),
304 WidgetCheck (N_("Repeat song in endless loop"),
305 WidgetBool (CFG_ID, "Endless"))
347 WidgetLabel (N_("<b>Output</b>")),
348 WidgetCombo (N_("OPL Emulator:"),
349 WidgetInt (CFG_ID, "Emulator"),
350 {{plugin_combo}}),
351 WidgetSpin (N_("Sample rate"),
352 WidgetInt (CFG_ID, "Frequency"), {8000, 192000, 50, N_("Hz")}),
353 WidgetLabel (N_("<b>Miscellaneous</b>")),
354 WidgetCheck (N_("Repeat song in endless loop"),
355 WidgetBool (CFG_ID, "Endless"))
306356 };
307357
308358 const PluginPreferences AdPlugXMMS::prefs = {{widgets}};
323373
324374 if (VFSFile::test_file (userdb.c_str (), VFS_EXISTS))
325375 {
326 plr.db = new CAdPlugDatabase;
376 plr.db.capture(new CAdPlugDatabase);
327377 plr.db->load (userdb); // load user's database
328378 dbg_printf (" (userdb=\"%s\")", userdb.c_str());
329 CAdPlug::set_database (plr.db);
379 CAdPlug::set_database (plr.db.get ());
330380 }
331381 }
332382 }
339389 {
340390 // Close database
341391 dbg_printf ("db, ");
342 if (plr.db)
343 delete plr.db;
344
392 plr.db.clear ();
345393 plr.filename = String ();
346394 }
1818
1919 #ifndef ADPLUG_XMMS_H
2020 #define ADPLUG_XMMS_H
21
22 #include "config.h"
2123
2224 #include <libbinio/binio.h>
2325 #include <adplug/fprovide.h>
0 adplug_dep = dependency('adplug', required: false)
1
2
3 if adplug_dep.found()
4 adplug_inc = '-I' + adplug_dep.get_pkgconfig_variable('includedir')
5 if cxx.has_header('adplug/nemuopl.h', args: adplug_inc)
6 conf.set10('HAVE_ADPLUG_NEMUOPL_H', true)
7 endif
8 if cxx.has_header('adplug/wemuopl.h', args: adplug_inc)
9 conf.set10('HAVE_ADPLUG_WEMUOPL_H', true)
10 endif
11 if cxx.has_header('adplug/kemuopl.h', args: adplug_inc)
12 conf.set10('HAVE_ADPLUG_KEMUOPL_H', true)
13 endif
14
15
16 shared_module('adplug',
17 'adplug-xmms.cc',
18 dependencies: [audacious_dep, adplug_dep, audtag_dep],
19 include_directories: [src_inc],
20 install: true,
21 install_dir: input_plugin_dir,
22 )
23 endif
1616 * the use of this software.
1717 */
1818
19 #include <QApplication>
1920 #include <QLabel>
2021 #include <QPixmap>
2122
2324 #include <libaudcore/i18n.h>
2425 #include <libaudcore/plugin.h>
2526 #include <libaudcore/hook.h>
27 #include <libaudcore/templates.h>
2628
2729 #include <libaudqt/libaudqt.h>
2830
5759 void update_art ()
5860 {
5961 origPixmap = QPixmap (audqt::art_request_current (0, 0));
62 qreal r = qApp->devicePixelRatio ();
63 origPixmap.setDevicePixelRatio (r);
6064 origSize = origPixmap.size ();
6165 drawArt ();
6266 }
9498
9599 void drawArt ()
96100 {
97 if (origSize.width () <= size ().width () - MARGIN &&
98 origSize.height () <= size ().height() - MARGIN)
101 qreal r = qApp->devicePixelRatio();
102 if (aud::abs(r - 1.0) <= 0.01 &&
103 origSize.width () <= size ().width () - MARGIN &&
104 origSize.height () <= size ().height() - MARGIN) {
105 // If device pixel ratio is close to 1:1 (within 1%) and art is
106 // smaller than widget, set pixels directly w/o scaling
99107 setPixmap (origPixmap);
100 else
101 setPixmap (origPixmap.scaled (size ().width () - MARGIN, size ().height () - MARGIN,
102 Qt::KeepAspectRatio, Qt::SmoothTransformation));
108 } else {
109 // Otherwise scale image with device pixel ratio, but limit size to
110 // widget dimensions.
111 auto width = std::min(r * (size().width() - MARGIN),
112 r * origSize.width());
113 auto height = std::min(r * (size().height() - MARGIN),
114 r * origSize.height());
115
116 setPixmap (origPixmap.scaled (width, height, Qt::KeepAspectRatio,
117 Qt::SmoothTransformation));
118 }
103119
104120 #ifdef Q_OS_MAC
105121 repaint();
0 shared_module('albumart-qt',
1 'albumart.cc',
2 dependencies: [audacious_dep, qt_dep, audqt_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
6
347347 alsa_channels = channels;
348348 alsa_rate = rate;
349349
350 total_buffer = aud_get_int (nullptr, "output_buffer_size");
350 total_buffer = aud_get_int ("output_buffer_size");
351351 useconds = 1000 * aud::min (1000, total_buffer / 2);
352352 direction = 0;
353353 CHECK_STR (error, snd_pcm_hw_params_set_buffer_time_near, alsa_handle,
417417
418418 length = aud::min (length, alsa_buffer.space ());
419419 alsa_buffer.copy_in ((const char *) data, length);
420
421 AUDDBG ("Buffer fill levels: low = %d%%, high = %d%%.\n",
422 (alsa_buffer.len () - length) * 100 / alsa_buffer.size (),
423 alsa_buffer.len () * 100 / alsa_buffer.size ());
420424
421425 if (! alsa_paused)
422426 pthread_cond_broadcast (& alsa_cond);
0 alsa_dep = dependency('alsa', version: '>= 1.0.16')
1
2
3 if alsa_dep.found()
4 shared_module('alsa',
5 'alsa.cc',
6 'config.cc',
7 dependencies: [audacious_dep, alsa_dep, glib_dep],
8 install: true,
9 install_dir: output_plugin_dir
10 )
11 endif
12
1414 LD = ${CXX}
1515
1616 CFLAGS += ${PLUGIN_CFLAGS}
17 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${FLUIDSYNTH_CFLAGS} -I../..
18 LIBS += ${FLUIDSYNTH_LIBS} -lm
17 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${FLUIDSYNTH_CFLAGS} ${GLIB_CFLAGS} -I../..
18 LIBS += ${FLUIDSYNTH_LIBS} ${GLIB_LIBS} -lm
1919
2020 ifeq ($(USE_GTK),yes)
2121 CPPFLAGS += ${GTK_CFLAGS}
2222 LIBS += ${GTK_LIBS}
2323 endif
24
25 ifeq ($(USE_QT),yes)
26 CPPFLAGS += ${QT_CFLAGS}
27 LIBS += ${QT_LIBS} -laudqt
28 endif
3535 public:
3636 static const char about[];
3737 static const char * const exts[];
38 static const char * const mimes[];
3839
3940 static constexpr PluginInfo info = {
4041 N_("AMIDI-Plug (MIDI Player)"),
4445 };
4546
4647 constexpr AMIDIPlug () : InputPlugin (info, InputInfo ()
47 .with_exts (exts)) {}
48 .with_exts (exts)
49 .with_mimes (mimes)) {}
4850
4951 bool init ();
5052 void cleanup ();
7375 EXPORT AMIDIPlug aud_plugin_instance;
7476
7577 const char * const AMIDIPlug::exts[] = {"mid", "midi", "rmi", "rmid", nullptr};
78 const char * const AMIDIPlug::mimes[] = {"audio/midi", nullptr};
7679
7780 void AMIDIPlug::cleanup ()
7881 {
1919
2020 #include "i_configure-fluidsynth.h"
2121
22 #ifdef USE_GTK
23
2422 #include <stdlib.h>
2523 #include <string.h>
2624 #include <sys/stat.h>
2725
28 #include <glib/gstdio.h>
29 #include <gtk/gtk.h>
30
26 #include <libaudcore/audstrings.h>
3127 #include <libaudcore/i18n.h>
3228 #include <libaudcore/runtime.h>
29 #include <libaudcore/index.h>
30
31 #include <glib/gstdio.h>
3332
3433 #include "i_configure.h"
34
35 #ifdef USE_GTK
36
37 #include <gtk/gtk.h>
3538
3639 enum
3740 {
276279 }
277280
278281 #endif // USE_GTK
282
283 #ifdef USE_QT
284
285 #include <QHBoxLayout>
286 #include <QVBoxLayout>
287 #include <QAbstractListModel>
288 #include <QTreeView>
289 #include <QPushButton>
290
291 #include <libaudqt/libaudqt.h>
292
293 /* soundfont settings - soundfont files - listview */
294 class SoundFontListModel : public QAbstractListModel
295 {
296 public:
297 enum {
298 FileName = 0,
299 FileSize,
300 NColumns
301 };
302
303 void update ();
304 void commit ();
305 void delete_selected (QModelIndexList);
306 void shift_selected (QModelIndexList, int);
307 void append (const char *);
308
309 SoundFontListModel (QObject * parent = nullptr) : QAbstractListModel (parent) { update (); }
310 ~SoundFontListModel ();
311
312 protected:
313 int rowCount (const QModelIndex &) const { return m_file_names.len (); }
314 int columnCount (const QModelIndex &) const { return NColumns; }
315 QVariant data (const QModelIndex & index, int role) const;
316 QVariant headerData (int section, Qt::Orientation, int role) const;
317
318 Qt::ItemFlags flags (const QModelIndex & index) const
319 {
320 if (index.isValid ())
321 return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
322 else
323 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
324 }
325
326 private:
327 Index <String> m_file_names;
328 Index <int> m_file_sizes;
329 };
330
331 SoundFontListModel::~SoundFontListModel ()
332 {
333 m_file_names.clear ();
334 m_file_sizes.clear ();
335 }
336
337 void SoundFontListModel::append (const char * filename)
338 {
339 QAbstractItemModel::beginResetModel ();
340
341 int filesize = -1;
342 GStatBuf finfo;
343
344 if (g_stat (filename, &finfo) == 0)
345 filesize = finfo.st_size;
346
347 m_file_names.append (String (filename));
348 m_file_sizes.append (filesize);
349
350 commit ();
351 QAbstractItemModel::endResetModel ();
352 }
353
354 void SoundFontListModel::update ()
355 {
356 String soundfont_file = aud_get_str ("amidiplug", "fsyn_soundfont_file");
357
358 if (soundfont_file[0])
359 {
360 char ** sffiles = g_strsplit (soundfont_file, ";", 0);
361 int i = 0;
362
363 while (sffiles[i] != nullptr)
364 {
365 append (sffiles[i]);
366 i++;
367 }
368
369 g_strfreev (sffiles);
370 }
371 }
372
373 void SoundFontListModel::commit ()
374 {
375 std::string sflist_string;
376
377 for (auto str : m_file_names)
378 {
379 if (sflist_string[0])
380 sflist_string.append (";");
381
382 sflist_string.append (str);
383 }
384
385 aud_set_str ("amidiplug", "fsyn_soundfont_file", sflist_string.c_str ());
386
387 /* reset backend at beginning of next song to apply changes */
388 __sync_bool_compare_and_swap (& backend_settings_changed, false, true);
389 }
390
391 void SoundFontListModel::delete_selected (QModelIndexList selections)
392 {
393 if (selections.empty ())
394 return;
395
396 QAbstractItemModel::beginResetModel ();
397
398 auto index = selections.first ();
399
400 m_file_names.remove (index.row (), 1);
401 m_file_sizes.remove (index.row (), 1);
402
403 commit ();
404 QAbstractItemModel::endResetModel ();
405 }
406
407 void SoundFontListModel::shift_selected (QModelIndexList selections, int direction)
408 {
409 if (selections.empty ())
410 return;
411
412 QAbstractItemModel::beginResetModel ();
413
414 auto index = selections.first ();
415
416 int from_row = index.row ();
417 int to_row = index.row () + direction;
418
419 if (to_row < 0)
420 return;
421
422 String filename[2] = { m_file_names[from_row], m_file_names[to_row] };
423 int filesize[2] = { m_file_sizes[from_row], m_file_sizes[to_row] };
424
425 m_file_names[from_row] = filename[1];
426 m_file_names[to_row] = filename[0];
427
428 m_file_sizes[from_row] = filesize[1];
429 m_file_sizes[to_row] = filesize[0];
430
431 commit ();
432 QAbstractItemModel::endResetModel ();
433 }
434
435 QVariant SoundFontListModel::data (const QModelIndex & index, int role) const
436 {
437 int col = index.column ();
438 if (col < 0 || col >= NColumns)
439 return QVariant ();
440
441 switch (role)
442 {
443 case Qt::DisplayRole:
444 switch (col)
445 {
446 case FileName:
447 return QString ((const char *) m_file_names[index.row ()]);
448
449 case FileSize:
450 return QString (int_to_str (m_file_sizes[index.row ()]));
451
452 default:
453 return QVariant ();
454 }
455
456 break;
457 default:
458 break;
459 }
460
461 return QVariant ();
462 }
463
464 QVariant SoundFontListModel::headerData (int section, Qt::Orientation, int role) const
465 {
466 if (role != Qt::DisplayRole)
467 return QVariant ();
468
469 switch (section) {
470 case FileName:
471 return QString (_("File name"));
472
473 case FileSize:
474 return QString (_("Size (bytes)"));
475
476 default:
477 return QVariant ();
478 }
479 }
480
481 class SoundFontWidget : public QWidget
482 {
483 public:
484 SoundFontWidget (QWidget * parent = nullptr);
485
486 private:
487 QVBoxLayout * m_vbox_layout;
488 QTreeView * m_view;
489 SoundFontListModel * m_model;
490 QWidget * m_bbox;
491 QHBoxLayout * m_bbox_layout;
492 QPushButton * m_button_sf_add;
493 QPushButton * m_button_sf_del;
494 QPushButton * m_button_sf_up;
495 QPushButton * m_button_sf_down;
496 };
497
498 SoundFontWidget::SoundFontWidget (QWidget * parent) :
499 QWidget (parent),
500 m_vbox_layout (audqt::make_vbox (this)),
501 m_view (new QTreeView (this)),
502 m_model (new SoundFontListModel (m_view)),
503 m_bbox (new QWidget (this)),
504 m_bbox_layout (audqt::make_hbox (m_bbox)),
505 m_button_sf_add (new QPushButton (m_bbox)),
506 m_button_sf_del (new QPushButton (m_bbox)),
507 m_button_sf_up (new QPushButton (m_bbox)),
508 m_button_sf_down (new QPushButton (m_bbox))
509 {
510 m_button_sf_add->setIcon (audqt::get_icon ("list-add"));
511 m_button_sf_del->setIcon (audqt::get_icon ("list-remove"));
512 m_button_sf_up->setIcon (audqt::get_icon ("go-up"));
513 m_button_sf_down->setIcon (audqt::get_icon ("go-down"));
514
515 m_bbox_layout->addWidget (m_button_sf_add);
516 m_bbox_layout->addWidget (m_button_sf_del);
517 m_bbox_layout->addWidget (m_button_sf_up);
518 m_bbox_layout->addWidget (m_button_sf_down);
519
520 m_bbox->setLayout (m_bbox_layout);
521
522 m_view->setModel (m_model);
523 m_view->setRootIsDecorated (false);
524
525 m_vbox_layout->addWidget (m_view);
526 m_vbox_layout->addWidget (m_bbox);
527
528 setLayout (m_vbox_layout);
529
530 QObject::connect (m_button_sf_add, & QPushButton::clicked, [this] () {
531 auto dialog = new QFileDialog (this, _("AMIDI-Plug - select SoundFont file"));
532 dialog->setFileMode (QFileDialog::ExistingFiles);
533 audqt::window_bring_to_front (dialog);
534
535 QObject::connect (dialog, & QFileDialog::accepted, [this, dialog] () {
536 for (auto & fn : dialog->selectedFiles ())
537 m_model->append (fn.toUtf8 ());
538 });
539 });
540
541 QObject::connect (m_button_sf_del, & QPushButton::clicked, [=] () {
542 m_model->delete_selected (m_view->selectionModel ()->selectedIndexes ());
543 });
544
545 QObject::connect (m_button_sf_up, & QPushButton::clicked, [=] () {
546 m_model->shift_selected (m_view->selectionModel ()->selectedIndexes (), -1);
547 });
548
549 QObject::connect (m_button_sf_down, & QPushButton::clicked, [=] () {
550 m_model->shift_selected (m_view->selectionModel ()->selectedIndexes (), 1);
551 });
552 }
553
554 void * create_soundfont_list_qt ()
555 {
556 return new SoundFontWidget;
557 }
558
559 #endif // USE_QT
2121 #define _I_CONFIGURE_FLUIDSYNTH_H 1
2222
2323 void * create_soundfont_list ();
24 void * create_soundfont_list_qt ();
2425
2526 #endif /* !_I_CONFIGURE_FLUIDSYNTH_H */
141141 #ifdef USE_GTK
142142 WidgetCustomGTK (create_soundfont_list),
143143 #endif
144 #ifdef USE_QT
145 WidgetCustomQt (create_soundfont_list_qt),
146 #endif
144147 WidgetLabel (N_("<b>Synthesizer</b>")),
145148 WidgetBox ({{gain_widgets}, true}),
146149 WidgetBox ({{polyphony_widgets}, true}),
0 fluidsynth_dep = dependency('fluidsynth', version: '>= 1.0.6', required: false)
1
2
3 amidiplug_sources = [
4 'amidi-plug.cc',
5 'backend-fluidsynth/b-fluidsynth.cc',
6 'i_midi.cc',
7 'i_configure.cc',
8 'i_configure-fluidsynth.cc',
9 'i_fileinfo.cc'
10 ]
11
12
13 if fluidsynth_dep.found()
14 shared_module('amidi-plug',
15 amidiplug_sources,
16 dependencies: [audacious_dep, fluidsynth_dep, glib_dep, qt_dep, audqt_dep],
17 install: true,
18 install_dir: input_plugin_dir
19 )
20 endif
0 shared_module('asx',
1 'asx.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: container_plugin_dir
5 )
6
0 shared_module('asx3',
1 'asx3.cc',
2 dependencies: [audacious_dep, xml_dep],
3 install: true,
4 install_dir: container_plugin_dir
5 )
6
0 shared_module('audpl',
1 'audpl.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: container_plugin_dir
5 )
0 PLUGIN = blur_scope-qt${PLUGIN_SUFFIX}
1
2 SRCS = blur_scope.cc
3
4 include ../../buildsys.mk
5 include ../../extra.mk
6
7 plugindir := ${plugindir}/${VISUALIZATION_PLUGIN_DIR}
8
9 LD = ${CXX}
10 CFLAGS += ${PLUGIN_CFLAGS}
11 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GLIB_CFLAGS} ${QT_CFLAGS} -I../..
12 LIBS += ${GLIB_LIBS} ${QT_LIBS} -lm -laudqt
0 /*
1 * Blur Scope plugin for Audacious
2 * Copyright (C) 2010-2012 John Lindgren
3 * Copyright (C) 2019 William Pitcock
4 *
5 * Based on BMP - Cross-platform multimedia player:
6 * Copyright (C) 2003-2004 BMP development team.
7 *
8 * Based on XMMS:
9 * Copyright (C) 1998-2003 XMMS development team.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 */
25
26 #include <math.h>
27 #include <string.h>
28 #include <glib-2.0/glib.h>
29
30 #include <QWidget>
31 #include <QImage>
32 #include <QPainter>
33
34 #include "libaudqt/colorbutton.h"
35
36 #include <libaudcore/i18n.h>
37 #include <libaudcore/runtime.h>
38 #include <libaudcore/plugin.h>
39 #include <libaudcore/preferences.h>
40
41 static void /* QWidget */ * bscope_get_color_chooser ();
42
43 static const PreferencesWidget bscope_widgets[] = {
44 WidgetLabel (N_("<b>Color</b>")),
45 WidgetCustomQt (bscope_get_color_chooser)
46 };
47
48 static const PluginPreferences bscope_prefs = {{bscope_widgets}};
49
50 static const char * const bscope_defaults[] = {
51 "color", aud::numeric_string<0xFF3F7F>::str,
52 nullptr};
53
54 static int bscope_color;
55
56 class BlurScopeWidget : public QWidget {
57 public:
58 BlurScopeWidget (QWidget * parent = nullptr);
59 ~BlurScopeWidget ();
60
61 void resize (int w, int h);
62
63 void clear ();
64 void blur ();
65 void draw_vert_line (int x, int y1, int y2);
66
67 protected:
68 void resizeEvent (QResizeEvent *);
69 void paintEvent (QPaintEvent *);
70
71 private:
72 int m_width = 0, m_height = 0, m_image_size = 0;
73 uint32_t * m_image = nullptr, * m_corner = nullptr;
74 };
75
76 static BlurScopeWidget *s_widget = nullptr;
77
78 BlurScopeWidget::BlurScopeWidget (QWidget * parent) :
79 QWidget (parent)
80 {
81 resize (width (), height ());
82 }
83
84 BlurScopeWidget::~BlurScopeWidget ()
85 {
86 g_free(m_image);
87 m_image = nullptr;
88 s_widget = nullptr;
89 }
90
91 void BlurScopeWidget::paintEvent (QPaintEvent *)
92 {
93 QImage img((unsigned char *) m_image, m_width, m_height, QImage::Format_RGB32);
94 QPainter p (this);
95
96 p.drawImage (0, 0, img);
97 }
98
99 void BlurScopeWidget::resizeEvent (QResizeEvent *)
100 {
101 resize (width (), height ());
102 }
103
104 void BlurScopeWidget::resize (int w, int h)
105 {
106 m_width = w;
107 m_height = h;
108 m_image_size = (m_width << 2) * (m_height + 2);
109 m_image = (uint32_t *) g_realloc (m_image, m_image_size);
110 memset (m_image, 0, m_image_size);
111 m_corner = m_image + m_width + 1;
112 }
113
114 void BlurScopeWidget::clear ()
115 {
116 memset (m_image, 0, m_image_size);
117 update ();
118 }
119
120 void BlurScopeWidget::blur ()
121 {
122 for (int y = 0; y < m_height; y ++)
123 {
124 uint32_t * p = m_corner + m_width * y;
125 uint32_t * end = p + m_width;
126 uint32_t * plast = p - m_width;
127 uint32_t * pnext = p + m_width;
128
129 /* We do a quick and dirty average of four color values, first masking
130 * off the lowest two bits. Over a large area, this masking has the net
131 * effect of subtracting 1.5 from each value, which by a happy chance
132 * is just right for a gradual fade effect. */
133 for (; p < end; p ++)
134 * p = ((* plast ++ & 0xFCFCFC) + (p[-1] & 0xFCFCFC) + (p[1] &
135 0xFCFCFC) + (* pnext ++ & 0xFCFCFC)) >> 2;
136 }
137 }
138
139 void BlurScopeWidget::draw_vert_line (int x, int y1, int y2)
140 {
141 int y, h;
142
143 if (y1 < y2) {y = y1 + 1; h = y2 - y1;}
144 else if (y2 < y1) {y = y2; h = y1 - y2;}
145 else {y = y1; h = 1;}
146
147 uint32_t * p = m_corner + y * m_width + x;
148
149 for (; h --; p += m_width)
150 * p = bscope_color;
151 }
152
153 class BlurScopeQt : public VisPlugin
154 {
155 public:
156 static constexpr PluginInfo info = {
157 N_("Blur Scope"),
158 PACKAGE,
159 nullptr,
160 & bscope_prefs,
161 PluginQtOnly
162 };
163
164 constexpr BlurScopeQt () : VisPlugin (info, Visualizer::MonoPCM) {}
165
166 bool init ();
167 void cleanup ();
168
169 void * get_qt_widget ();
170
171 void clear ();
172 void render_mono_pcm (const float * pcm);
173 };
174
175 EXPORT BlurScopeQt aud_plugin_instance;
176
177 bool BlurScopeQt::init ()
178 {
179 aud_config_set_defaults ("BlurScope", bscope_defaults);
180 bscope_color = aud_get_int ("BlurScope", "color");
181
182 return true;
183 }
184
185 void BlurScopeQt::cleanup ()
186 {
187 aud_set_int ("BlurScope", "color", bscope_color);
188 }
189
190 void BlurScopeQt::clear ()
191 {
192 if (s_widget)
193 s_widget->clear ();
194 }
195
196 void BlurScopeQt::render_mono_pcm (const float * pcm)
197 {
198 g_assert(s_widget);
199
200 s_widget->blur ();
201
202 int width = s_widget->width ();
203 int height = s_widget->height ();
204
205 int prev_y = (0.5 + pcm[0]) * height;
206 prev_y = aud::clamp (prev_y, 0, height - 1);
207
208 for (int i = 0; i < width; i ++)
209 {
210 int y = (0.5 + pcm[i * 512 / width]) * height;
211 y = aud::clamp (y, 0, height - 1);
212 s_widget->draw_vert_line (i, prev_y, y);
213 prev_y = y;
214 }
215
216 s_widget->update ();
217 }
218
219 void * BlurScopeQt::get_qt_widget ()
220 {
221 if (s_widget)
222 return s_widget;
223
224 s_widget = new BlurScopeWidget ();
225 return s_widget;
226 }
227
228 class ColorChooserWidget : public audqt::ColorButton
229 {
230 protected:
231 void onColorChanged () override;
232 };
233
234 void ColorChooserWidget::onColorChanged ()
235 {
236 QColor col (color ());
237 int r, g, b;
238
239 col.getRgb(&r, &g, &b);
240
241 bscope_color = r << 16 | g << 8 | b;
242 }
243
244 static void * bscope_get_color_chooser ()
245 {
246 int r, g, b;
247
248 r = (bscope_color & 0xff0000) >> 16;
249 g = (bscope_color & 0xff00) >> 8;
250 b = (bscope_color & 0xff);
251
252 QColor color = QColor::fromRgb(r, g, b);
253
254 auto chooser = new ColorChooserWidget ();
255 chooser->setColor (color);
256
257 return chooser;
258 }
0 shared_module('blur_scope-qt',
1 'blur_scope.cc',
2 dependencies: [audacious_dep, qt_dep, glib_dep, audqt_dep],
3 install: true,
4 install_dir: visualization_plugin_dir
5 )
6
99 LD = ${CXX}
1010 CFLAGS += ${PLUGIN_CFLAGS}
1111 CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../.. ${GTK_CFLAGS}
12 LIBS += -lm ${GTK_LIBS}
12 LIBS += -lm ${GTK_LIBS} -laudgui
6060 static int bars[MAX_BANDS + 1];
6161 static int delay[MAX_BANDS + 1];
6262
63 static void calculate_xscale ()
64 {
65 for (int i = 0; i <= bands; i ++)
66 xscale[i] = powf (256, (float) i / bands) - 0.5f;
67 }
68
6963 void CairoSpectrum::render_freq (const float * freq)
7064 {
7165 if (! bands)
7367
7468 for (int i = 0; i < bands; i ++)
7569 {
76 int a = ceilf (xscale[i]);
77 int b = floorf (xscale[i + 1]);
78 float n = 0;
79
80 if (b < a)
81 n += freq[b] * (xscale[i + 1] - xscale[i]);
82 else
83 {
84 if (a > 0)
85 n += freq[a - 1] * (a - xscale[i]);
86 for (; a < b; a ++)
87 n += freq[a];
88 if (b < 256)
89 n += freq[b] * (xscale[i + 1] - b);
90 }
91
92 /* fudge factor to make the graph have the same overall height as a
93 12-band one no matter how many bands there are */
94 n *= (float) bands / 12;
95
9670 /* 40 dB range */
97 int x = 40 + 20 * log10f (n);
71 int x = 40 + compute_freq_band (freq, xscale, i, bands);
9872 x = aud::clamp (x, 0, 40);
9973
10074 bars[i] -= aud::max (0, VIS_FALLOFF - delay[i]);
12296 gtk_widget_queue_draw (spect_widget);
12397 }
12498
125 static void rgb_to_hsv (float r, float g, float b, float * h, float * s, float * v)
126 {
127 float max, min;
128
129 max = r;
130 if (g > max)
131 max = g;
132 if (b > max)
133 max = b;
134
135 min = r;
136 if (g < min)
137 min = g;
138 if (b < min)
139 min = b;
140
141 * v = max;
142
143 if (max == min)
144 {
145 * h = 0;
146 * s = 0;
147 return;
148 }
149
150 if (r == max)
151 * h = 1 + (g - b) / (max - min);
152 else if (g == max)
153 * h = 3 + (b - r) / (max - min);
154 else
155 * h = 5 + (r - g) / (max - min);
156
157 * s = (max - min) / max;
158 }
159
160 static void hsv_to_rgb (float h, float s, float v, float * r, float * g, float * b)
161 {
162 for (; h >= 2; h -= 2)
163 {
164 float * p = r;
165 r = g;
166 g = b;
167 b = p;
168 }
169
170 if (h < 1)
171 {
172 * r = 1;
173 * g = 0;
174 * b = 1 - h;
175 }
176 else
177 {
178 * r = 1;
179 * g = h - 1;
180 * b = 0;
181 }
182
183 * r = v * (1 - s * (1 - * r));
184 * g = v * (1 - s * (1 - * g));
185 * b = v * (1 - s * (1 - * b));
186 }
187
188 static void get_color (GtkWidget * widget, int i, float * r, float * g, float * b)
189 {
190 GdkColor * c = (gtk_widget_get_style (widget))->base + GTK_STATE_SELECTED;
191 float h, s, v;
192
193 rgb_to_hsv (c->red / 65535.0, c->green / 65535.0, c->blue / 65535.0, & h, & s, & v);
194
195 if (s < 0.1) /* monochrome theme? use blue instead */
196 h = 4.6;
197
198 s = 1 - 0.9 * i / (bands - 1);
199 v = 0.75 + 0.25 * i / (bands - 1);
200
201 hsv_to_rgb (h, s, v, r, g, b);
202 }
203
20499 static void draw_background (GtkWidget * area, cairo_t * cr)
205100 {
206101 GtkAllocation alloc;
212107
213108 static void draw_visualizer (GtkWidget *widget, cairo_t *cr)
214109 {
110 auto & c = (gtk_widget_get_style (widget))->base[GTK_STATE_SELECTED];
111
215112 for (int i = 0; i < bands; i++)
216113 {
217114 int x = ((width / bands) * i) + 2;
218115 float r, g, b;
219116
220 get_color (widget, i, & r, & g, & b);
117 audgui_vis_bar_color (c, i, bands, r, g, b);
221118 cairo_set_source_rgb (cr, r, g, b);
222119 cairo_rectangle (cr, x + 1, height - (bars[i] * height / 40),
223120 (width / bands) - 1, (bars[i] * height / 40));
233130
234131 bands = width / 10;
235132 bands = aud::clamp(bands, 12, MAX_BANDS);
236 calculate_xscale ();
133 Visualizer::compute_log_xscale (xscale, bands);
237134
238135 return true;
239136 }
0 shared_module('cd-menu-items',
1 'cd-menu-items.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
268268
269269 playing = true;
270270
271 int buffer_size = aud_get_int (nullptr, "output_buffer_size");
271 int buffer_size = aud_get_int ("output_buffer_size");
272272 int speed = aud_get_int ("CDDA", "disc_speed");
273273 speed = aud::clamp (speed, MIN_DISC_SPEED, MAX_DISC_SPEED);
274274 int sectors = aud::clamp (buffer_size / 2, 50, 250) * speed * 75 / 1000;
619619 String path = aud_get_str ("CDDA", "cddbpath");
620620 int port = aud_get_int ("CDDA", "cddbport");
621621
622 if (aud_get_bool (nullptr, "use_proxy"))
622 if (aud_get_bool ("use_proxy"))
623623 {
624 String prhost = aud_get_str (nullptr, "proxy_host");
625 int prport = aud_get_int (nullptr, "proxy_port");
626 String pruser = aud_get_str (nullptr, "proxy_user");
627 String prpass = aud_get_str (nullptr, "proxy_pass");
624 String prhost = aud_get_str ("proxy_host");
625 int prport = aud_get_int ("proxy_port");
626 String pruser = aud_get_str ("proxy_user");
627 String prpass = aud_get_str ("proxy_pass");
628628
629629 cddb_http_proxy_enable (pcddb_conn);
630630 cddb_set_http_proxy_server_name (pcddb_conn, prhost);
0 shared_module('cdaudio-ng',
1 'cdaudio-ng.cc',
2 dependencies: [audacious_dep, libcdio_dep, libcdio_cdda_dep, libcddb_dep],
3 install: true,
4 install_dir: input_plugin_dir
5 )
0 shared_module('compressor',
1 'compressor.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
0 #mesondefine PACKAGE
1 #mesondefine BUILDSTAMP
2 #mesondefine VERSION
3 #mesondefine COPYRIGHT
4 #mesondefine EXPORT
5 #mesondefine PLUGIN_SUFFIX
6
7 #define PACKAGE_VERSION VERSION
8 #define ICONV_CONST
9
10 #mesondefine INSTALL_BINDIR
11 #mesondefine INSTALL_DATADIR
12 #mesondefine INSTALL_PLUGINDIR
13 #mesondefine INSTALL_LOCALEDIR
14 #mesondefine INSTALL_DESKTOPFILE
15 #mesondefine INSTALL_ICONFILE
16
17 #mesondefine USE_DBUS
18 #mesondefine USE_QT
19
20 #mesondefine HAVE_FFMPEG
21 #mesondefine HAVE_LIBAV
22
23 #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32
24 #define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_32
25
26 #mesondefine FILEWRITER_MP3
27 #mesondefine FILEWRITER_FLAC
28 #mesondefine FILEWRITER_VORBIS
29
30 #mesondefine HAVE_LIBCUE2
31
32 #mesondefine HAVE_ADPLUG_NEMUOPL_H
33 #mesondefine HAVE_ADPLUG_WEMUOPL_H
34 #mesondefine HAVE_ADPLUG_KEMUOPL_H
0 gme_sources = [
1 'Ay_Apu.cc',
2 'Ay_Cpu.cc',
3 'Ay_Emu.cc',
4 'Blip_Buffer.cc',
5 'Classic_Emu.cc',
6 'Data_Reader.cc',
7 'Dual_Resampler.cc',
8 'Effects_Buffer.cc',
9 'Fir_Resampler.cc',
10 'Gbs_Emu.cc',
11 'Gb_Apu.cc',
12 'Gb_Cpu.cc',
13 'Gb_Oscs.cc',
14 'gme.cc',
15 'Gme_File.cc',
16 'Gym_Emu.cc',
17 'Gzip_Reader.cc',
18 'Hes_Apu.cc',
19 'Hes_Cpu.cc',
20 'Hes_Emu.cc',
21 'Kss_Cpu.cc',
22 'Kss_Emu.cc',
23 'Kss_Scc_Apu.cc',
24 'M3u_Playlist.cc',
25 'Multi_Buffer.cc',
26 'Music_Emu.cc',
27 'Nes_Apu.cc',
28 'Nes_Cpu.cc',
29 'Nes_Fme7_Apu.cc',
30 'Nes_Namco_Apu.cc',
31 'Nes_Oscs.cc',
32 'Nes_Vrc6_Apu.cc',
33 'Nsfe_Emu.cc',
34 'Nsf_Emu.cc',
35 'Sap_Apu.cc',
36 'Sap_Cpu.cc',
37 'Sap_Emu.cc',
38 'Sms_Apu.cc',
39 'Snes_Spc.cc',
40 'Spc_Cpu.cc',
41 'Spc_Dsp.cc',
42 'Spc_Emu.cc',
43 'Spc_Filter.cc',
44 'Vgm_Emu.cc',
45 'Vgm_Emu_Impl.cc',
46 'Ym2413_Emu.cc',
47 'Ym2612_Emu.cc',
48 'Zlib_Inflater.cc'
49 ]
50
51
52 plugin_sources = [
53 'Vfs_File.cc',
54 'Audacious_Driver.cc',
55 'configure.cc',
56 'plugin.cc'
57 ]
58
59
60 shared_module('console',
61 gme_sources,
62 plugin_sources,
63 dependencies: [audacious_dep, zlib_dep],
64 install: true,
65 install_dir: input_plugin_dir
66 )
420420
421421 buffer_bytes_per_channel = m.mBytesPerChannel;
422422
423 int buffer_size = buffer_bytes_per_channel * chan * (aud_get_int (nullptr, "output_buffer_size") * rate / 1000);
423 int buffer_size = buffer_bytes_per_channel * chan * (aud_get_int ("output_buffer_size") * rate / 1000);
424424 buffer.alloc (buffer_size);
425425
426426 prebuffer_flag = true;
0 shared_module('crossfade',
1 'crossfade.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
0 shared_module('crystalizer',
1 'crystalizer.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
0 cue2_dep = dependency('libcue', version: '>= 2.0', required: false)
1
2
3 if cue2_dep.found()
4 cue_dep = cue2_dep
5 conf.set10('HAVE_LIBCUE2', true)
6 else
7 cue1_dep = dependency('libcue')
8
9 if cue1_dep.found()
10 cue_dep = cue1_dep
11 endif
12 endif
13
14
15 if cue_dep.found()
16 shared_module('cue',
17 'cue.cc',
18 dependencies: [audacious_dep, cue_dep],
19 install: true,
20 install_dir: container_plugin_dir
21 )
22 endif
257257
258258 bool DeleteFiles::init ()
259259 {
260 #if ! GLIB_CHECK_VERSION (2, 36, 0)
261260 g_type_init ();
262 #endif
263261
264262 aud_config_set_defaults ("delete_files", defaults);
265263
0 shared_module('delete-files',
1 'delete-files.cc',
2 dependencies: [audacious_dep, gio_dep, qt_dep, audqt_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
6
0 shared_module('echo',
1 'echo.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
680680 nullptr
681681 };
682682
683 const char * const FFaudio::mimes[] = {"application/ogg", nullptr};
683 const char * const FFaudio::mimes[] = {
684 "application/ogg",
685 "audio/mp4",
686 nullptr
687 };
0 if get_option('ffaudio') == 'ffmpeg'
1 conf.set10('HAVE_FFMPEG', true)
2
3 libavcodec_req = '>= 53.40.0'
4 libavformat_req = '>= 53.25.0'
5 libavutil_req = '>= 51.27.0'
6 else
7 conf.set10('HAVE_LIBAV', true)
8
9 libavcodec_req = '>= 53.25.0'
10 libavformat_req = '>= 53.17.0'
11 libavutil_req = '>= 51.18.0'
12 endif
13
14
15 libavcodec_dep = dependency('libavcodec', version: libavcodec_req)
16 libavformat_dep = dependency('libavformat', version: libavformat_req)
17 libavutil_dep = dependency('libavutil', version: libavutil_req)
18
19
20 if libavcodec_dep.found()
21 shared_module('ffaudio',
22 'ffaudio-core.cc',
23 'ffaudio-io.cc',
24 dependencies: [audacious_dep, libavcodec_dep, libavformat_dep, libavutil_dep, audtag_dep],
25 install: true,
26 install_dir: input_plugin_dir
27 )
28 endif
305305 convert_init (fmt, out_fmt);
306306
307307 output_file = safe_create (filename);
308 if (output_file && plugin->open (output_file, {out_fmt, rate, nch}, in_tuple))
309 return true;
308 if (output_file)
309 {
310 if (plugin->open (output_file, {out_fmt, rate, nch}, in_tuple))
311 return true;
312 }
313 else
314 {
315 error = String (str_printf (_("Error opening %s:\n%s"),
316 (const char *) filename, output_file.error ()));
317 }
310318
311319 plugin = nullptr;
312320 output_file = VFSFile ();
0 filewriter_deps = [audacious_dep, glib_dep]
1 filewriter_srcs = [
2 'convert.cc',
3 'filewriter.cc',
4 'wav.cc'
5 ]
6
7 if get_option('filewriter-flac') and flac_dep.found()
8 filewriter_deps += [flac_dep]
9 filewriter_srcs += ['flac.cc']
10
11 conf.set10('FILEWRITER_FLAC', true)
12 endif
13
14 if get_option('filewriter-ogg') and ogg_dep.found()
15 filewriter_deps += [ogg_dep, vorbis_dep, vorbisenc_dep, vorbisfile_dep]
16 filewriter_srcs += ['vorbis.cc']
17
18 conf.set10('FILEWRITER_VORBIS', true)
19 endif
20
21 if get_option('filewriter-mp3')
22 lame_dep = cxx.find_library('mp3lame', has_headers: ['lame/lame.h'])
23 filewriter_deps += [lame_dep]
24 filewriter_srcs += ['mp3.cc']
25
26 conf.set10('FILEWRITER_MP3', true)
27 endif
28
29 shared_module('filewriter',
30 filewriter_srcs,
31 dependencies: filewriter_deps,
32 install: true,
33 install_dir: output_plugin_dir
34 )
2929 public:
3030 static const char about[];
3131 static const char *const exts[];
32 static const char *const mimes[];
3233
3334 static constexpr PluginInfo info = {
3435 N_("FLAC Decoder"),
3738 };
3839
3940 constexpr FLACng() : InputPlugin(info, InputInfo(FlagWritesTag)
40 .with_priority(1)
41 .with_exts(exts)) {}
41 .with_priority(_AUD_PLUGIN_DEFAULT_PRIO + 1)
42 .with_exts(exts)
43 .with_mimes(mimes)) {}
4244
4345 bool init();
4446 void cleanup();
0 flac_dep = dependency('flac', version: '>= 1.2.1')
1
2
3 if flac_dep.found()
4 shared_module('flacng',
5 'plugin.cc',
6 'tools.cc',
7 'seekable_stream_callbacks.cc',
8 'metadata.cc',
9 dependencies: [audacious_dep, flac_dep],
10 include_directories: [src_inc],
11 install: true,
12 install_dir: input_plugin_dir,
13 )
14 endif
15
166166 insert_str_tuple_to_vc(vc_block, tuple, Tuple::AlbumArtist, "ALBUMARTIST");
167167 insert_str_tuple_to_vc(vc_block, tuple, Tuple::Genre, "GENRE");
168168 insert_str_tuple_to_vc(vc_block, tuple, Tuple::Comment, "COMMENT");
169 insert_str_tuple_to_vc(vc_block, tuple, Tuple::Description, "DESCRIPTION");
170 insert_str_tuple_to_vc(vc_block, tuple, Tuple::MusicBrainzID, "musicbrainz_trackid");
169171
170172 insert_int_tuple_to_vc(vc_block, tuple, Tuple::Year, "DATE");
171173 insert_int_tuple_to_vc(vc_block, tuple, Tuple::Track, "TRACKNUMBER");
199201
200202 ERR:
201203 status = FLAC__metadata_chain_status(chain);
202 AUDERR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
204 AUDERR("An error occurred: %s\n", FLAC__Metadata_ChainStatusString[status]);
203205 ERR_RETURN:
204206 FLAC__metadata_chain_delete(chain);
205207 return false;
227229 {"ALBUMARTIST", Tuple::AlbumArtist},
228230 {"TITLE", Tuple::Title},
229231 {"COMMENT", Tuple::Comment},
230 {"GENRE", Tuple::Genre}
232 {"GENRE", Tuple::Genre},
233 {"DESCRIPTION", Tuple::Description},
234 {"musicbrainz_trackid", Tuple::MusicBrainzID},
231235 };
232236
233237 for (auto & tfield : tfields)
365369 status = FLAC__metadata_chain_status(chain);
366370 FLAC__metadata_chain_delete(chain);
367371
368 AUDERR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
372 AUDERR("An error occurred: %s\n", FLAC__Metadata_ChainStatusString[status]);
369373 return false;
370374 }
170170 "http://www.skytale.net/projects/bmp-flac2/");
171171
172172 const char *const FLACng::exts[] = { "flac", "fla", nullptr };
173
174 const char *const FLACng::mimes[] = { "audio/flac", "audio/x-flac", nullptr };
201201
202202 VFSImpl * GIOTransport::fopen (const char * filename, const char * mode, String & error)
203203 {
204 #if ! GLIB_CHECK_VERSION (2, 36, 0)
205204 g_type_init ();
206 #endif
207205
208206 try { return new GIOFile (filename, mode); }
209207 catch (GIOFile::OpenError & ex)
0 gio_dep = dependency('gio-2.0', version: glib_req, required: true)
1
2
3 shared_module('gio',
4 'gio.cc',
5 dependencies: [audacious_dep, gio_dep],
6 install: true,
7 install_dir: transport_plugin_dir
8 )
9
4747 void popup_menu_tab (unsigned button, uint32_t time, Playlist playlist);
4848 void activate_search_tool ();
4949 void activate_playlist_manager ();
50 void update_step_size ();
5150
5251 #endif
9393 MenuCommand (N_("_Stop"), "media-playback-stop", '.', CTRL, aud_drct_stop),
9494 MenuCommand (N_("Pre_vious"), "media-skip-backward", GDK_KEY_Up, ALT, aud_drct_pl_prev),
9595 MenuCommand (N_("_Next"), "media-skip-forward", GDK_KEY_Down, ALT, aud_drct_pl_next),
96 MenuCommand (N_("Previous Album"), nullptr, NONE, aud_drct_pl_prev_album),
97 MenuCommand (N_("Next Album"), nullptr, NONE, aud_drct_pl_next_album),
9698 MenuSep (),
9799 MenuToggle (N_("_Repeat"), nullptr, 'r', CTRL, nullptr, "repeat", nullptr, "set repeat"),
98100 MenuToggle (N_("S_huffle"), nullptr, 's', CTRL, nullptr, "shuffle", nullptr, "set shuffle"),
4343 WidgetCheck (N_("Show column headers"),
4444 WidgetBool ("gtkui", "playlist_headers", redisplay_playlists)),
4545 WidgetLabel (N_("<b>Miscellaneous</b>")),
46 WidgetSpin (N_("Arrow keys seek by:"),
47 WidgetFloat ("gtkui", "step_size", update_step_size),
48 {0.1, 60, 0.1, N_("seconds")}),
4946 WidgetCheck (N_("Scroll on song change"),
5047 WidgetBool ("gtkui", "autoscroll"))
5148 };
5555 "playlist_columns", "title artist album queued length",
5656 "playlist_headers", "TRUE",
5757 "show_remaining_time", "FALSE",
58 "step_size", "5",
5958
6059 "player_x", "-1000",
6160 "player_y", "-1000",
6261 "player_width", "768",
6362 "player_height", "480",
63 "player_maximized", "FALSE",
6464
6565 nullptr
6666 };
135135
136136 static void save_window_size ()
137137 {
138 if (aud_get_bool ("gtkui", "player_maximized"))
139 return;
140
138141 int x, y, w, h;
139142 gtk_window_get_position ((GtkWindow *) window, & x, & y);
140143 gtk_window_get_size ((GtkWindow *) window, & w, & h);
156159
157160 if (x > -1000 && y > -1000)
158161 gtk_window_move ((GtkWindow *) window, x, y);
162
163 if (aud_get_bool ("gtkui", "player_maximized"))
164 gtk_window_maximize ((GtkWindow *) window);
165 }
166
167 static gboolean window_state_cb (GtkWidget *, GdkEventWindowState * event)
168 {
169 if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
170 aud_set_bool ("gtkui", "player_maximized",
171 !! (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED));
172
173 return false;
159174 }
160175
161176 static gboolean window_delete ()
415430 gtk_widget_hide (slider);
416431 }
417432
418 void update_step_size ()
419 {
420 double step_size = aud_get_double ("gtkui", "step_size");
421 gtk_range_set_increments ((GtkRange *) slider, step_size * 1000, step_size * 1000);
433 static void update_step_size ()
434 {
435 int step_size = aud_get_int ("step_size");
436 // set half the step size because GTK doubles it for scroll events
437 gtk_range_set_increments ((GtkRange *) slider, step_size * 500, step_size * 500);
438 }
439
440 static void update_volume_delta ()
441 {
442 int volume_delta = aud_get_int ("volume_delta");
443 GtkAdjustment * adjustment = gtk_scale_button_get_adjustment ((GtkScaleButton *) volume);
444 gtk_adjustment_set_step_increment (adjustment, volume_delta);
445 gtk_adjustment_set_page_increment (adjustment, volume_delta);
422446 }
423447
424448 static void pause_cb ()
532556 return true;
533557 case GDK_KEY_Left:
534558 if (aud_drct_get_playing ())
535 do_seek (aud_drct_get_time () - aud_get_double ("gtkui", "step_size") * 1000);
559 do_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
536560 return true;
537561 case GDK_KEY_Right:
538562 if (aud_drct_get_playing ())
539 do_seek (aud_drct_get_time () + aud_get_double ("gtkui", "step_size") * 1000);
563 do_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
540564 return true;
541565 }
542566
571595 {
572596 case GDK_KEY_Left:
573597 if (aud_drct_get_playing ())
574 do_seek (aud_drct_get_time () - aud_get_double ("gtkui", "step_size") * 1000);
598 do_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
575599 break;
576600 case GDK_KEY_Right:
577601 if (aud_drct_get_playing ())
578 do_seek (aud_drct_get_time () + aud_get_double ("gtkui", "step_size") * 1000);
602 do_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
579603 break;
580604 default:
581605 return false;
634658 gtk_widget_set_visible ((GtkWidget *) button_record, aud_drct_get_record_enabled ());
635659
636660 gtk_toggle_tool_button_set_active ((GtkToggleToolButton *) button_record,
637 aud_get_bool (nullptr, "record"));
661 aud_get_bool ("record"));
638662 gtk_toggle_tool_button_set_active ((GtkToggleToolButton *) button_repeat,
639 aud_get_bool (nullptr, "repeat"));
663 aud_get_bool ("repeat"));
640664 gtk_toggle_tool_button_set_active ((GtkToggleToolButton *) button_shuffle,
641 aud_get_bool (nullptr, "shuffle"));
665 aud_get_bool ("shuffle"));
642666 }
643667
644668 static void toggle_repeat (GtkToggleToolButton * button)
645669 {
646 aud_set_bool (nullptr, "repeat", gtk_toggle_tool_button_get_active (button));
670 aud_set_bool ("repeat", gtk_toggle_tool_button_get_active (button));
647671 }
648672
649673 static void toggle_shuffle (GtkToggleToolButton * button)
650674 {
651 aud_set_bool (nullptr, "shuffle", gtk_toggle_tool_button_get_active (button));
675 aud_set_bool ("shuffle", gtk_toggle_tool_button_get_active (button));
652676 }
653677
654678 static void toggle_record (GtkToggleToolButton * button)
655679 {
656 aud_set_bool (nullptr, "record", gtk_toggle_tool_button_get_active (button));
680 aud_set_bool ("record", gtk_toggle_tool_button_get_active (button));
657681 }
658682
659683 static void toggle_search_tool (GtkToggleToolButton * button)
693717 hook_associate ("set record", update_toggles, nullptr);
694718 hook_associate ("set shuffle", update_toggles, nullptr);
695719 hook_associate ("set repeat", update_toggles, nullptr);
720 hook_associate ("set step_size", (HookFunction) update_step_size, nullptr);
721 hook_associate ("set volume_delta", (HookFunction) update_volume_delta, nullptr);
696722 hook_associate ("config save", (HookFunction) config_save, nullptr);
697723 }
698724
712738 hook_dissociate ("set record", update_toggles);
713739 hook_dissociate ("set shuffle", update_toggles);
714740 hook_dissociate ("set repeat", update_toggles);
741 hook_dissociate ("set step_size", (HookFunction) update_step_size);
742 hook_dissociate ("set volume_delta", (HookFunction) update_volume_delta);
715743 hook_dissociate ("config save", (HookFunction) config_save);
716744 }
717745
858886 GtkIconSize icon_size = gtk_tool_shell_get_icon_size ((GtkToolShell *) toolbar);
859887 g_object_set ((GObject *) volume, "size", icon_size, nullptr);
860888 gtk_button_set_relief ((GtkButton *) volume, GTK_RELIEF_NONE);
889 int delta = aud_get_int ("volume_delta");
861890 gtk_scale_button_set_adjustment ((GtkScaleButton *) volume,
862 (GtkAdjustment *) gtk_adjustment_new (0, 0, 100, 1, 5, 0));
891 (GtkAdjustment *) gtk_adjustment_new (0, 0, 100, delta, delta, 0));
863892 gtk_widget_set_can_focus (volume, false);
864893
865894 gtk_scale_button_set_value ((GtkScaleButton *) volume, aud_drct_get_volume_main ());
900929
901930 g_signal_connect (window, "map-event", (GCallback) pl_notebook_grab_focus, nullptr);
902931 g_signal_connect (window, "delete-event", (GCallback) window_delete, nullptr);
932 g_signal_connect (window, "window-state-event", (GCallback) window_state_cb, nullptr);
903933 g_signal_connect (window, "key-press-event", (GCallback) window_keypress_cb, nullptr);
904934 g_signal_connect (pl_notebook, "key-press-event", (GCallback) playlist_keypress_cb, nullptr);
905935
8787
8888 for (int i = 0; i < VIS_BANDS; i ++)
8989 {
90 int a = ceilf (xscale[i]);
91 int b = floorf (xscale[i + 1]);
92 float n = 0;
93
94 if (b < a)
95 n += freq[b] * (xscale[i + 1] - xscale[i]);
96 else
97 {
98 if (a > 0)
99 n += freq[a - 1] * (a - xscale[i]);
100 for (; a < b; a ++)
101 n += freq[a];
102 if (b < 256)
103 n += freq[b] * (xscale[i + 1] - b);
104 }
105
10690 /* 40 dB range */
107 float x = 40 + 20 * log10f (n);
91 float x = 40 + compute_freq_band (freq, xscale, i, VIS_BANDS);
10892
10993 bars[i] -= aud::max (0, VIS_FALLOFF - delay[i]);
11094
135119
136120 static void clear (GtkWidget * widget, cairo_t * cr)
137121 {
138 double r = 1, g = 1, b = 1;
139
140 /* In a dark theme, try to match the tone of the base color */
141 auto & c = (gtk_widget_get_style (widget))->base[GTK_STATE_NORMAL];
142 int v = aud::max (aud::max (c.red, c.green), c.blue);
143
144 if (v >= 10*256 && v < 80*256)
145 {
146 r = (double)c.red / v;
147 g = (double)c.green / v;
148 b = (double)c.blue / v;
149 }
150
151122 GtkAllocation alloc;
152123 gtk_widget_get_allocation (widget, & alloc);
153124
154 cairo_pattern_t * gradient = cairo_pattern_create_linear (0, 0, 0, alloc.height);
155 cairo_pattern_add_color_stop_rgb (gradient, 0, 0.25 * r, 0.25 * g, 0.25 * b);
156 cairo_pattern_add_color_stop_rgb (gradient, 0.5, 0.15 * r, 0.15 * g, 0.15 * b);
157 cairo_pattern_add_color_stop_rgb (gradient, 0.5, 0.1 * r, 0.1 * g, 0.1 * b);
158 cairo_pattern_add_color_stop_rgb (gradient, 1, 0, 0, 0);
125 auto & c = (gtk_widget_get_style (widget))->base[GTK_STATE_NORMAL];
126 cairo_pattern_t * gradient = audgui_dark_bg_gradient (c, alloc.height);
159127
160128 cairo_set_source (cr, gradient);
161129 cairo_rectangle (cr, 0, 0, alloc.width, alloc.height);
186154
187155 /****************************************************************************/
188156
189 static void rgb_to_hsv (float r, float g, float b, float * h, float * s,
190 float * v)
191 {
192 float max, min;
193
194 max = r;
195 if (g > max)
196 max = g;
197 if (b > max)
198 max = b;
199
200 min = r;
201 if (g < min)
202 min = g;
203 if (b < min)
204 min = b;
205
206 * v = max;
207
208 if (max == min)
209 {
210 * h = 0;
211 * s = 0;
212 return;
213 }
214
215 if (r == max)
216 * h = 1 + (g - b) / (max - min);
217 else if (g == max)
218 * h = 3 + (b - r) / (max - min);
219 else
220 * h = 5 + (r - g) / (max - min);
221
222 * s = (max - min) / max;
223 }
224
225 static void hsv_to_rgb (float h, float s, float v, float * r, float * g,
226 float * b)
227 {
228 for (; h >= 2; h -= 2)
229 {
230 float * p = r;
231 r = g;
232 g = b;
233 b = p;
234 }
235
236 if (h < 1)
237 {
238 * r = 1;
239 * g = 0;
240 * b = 1 - h;
241 }
242 else
243 {
244 * r = 1;
245 * g = h - 1;
246 * b = 0;
247 }
248
249 * r = v * (1 - s * (1 - * r));
250 * g = v * (1 - s * (1 - * g));
251 * b = v * (1 - s * (1 - * b));
252 }
253
254 static void get_color (GtkWidget * widget, int i, float * r, float * g, float * b)
255 {
157 static int expose_vis_cb (GtkWidget * widget, GdkEventExpose * event)
158 {
159 cairo_t * cr = gdk_cairo_create (gtk_widget_get_window (widget));
256160 auto & c = (gtk_widget_get_style (widget))->base[GTK_STATE_SELECTED];
257 float h, s, v;
258
259 rgb_to_hsv (c.red / 65535.0, c.green / 65535.0, c.blue / 65535.0, & h, & s, & v);
260
261 if (s < 0.1) /* monochrome theme? use blue instead */
262 h = 4.6;
263
264 s = 1 - 0.9 * i / (VIS_BANDS - 1);
265 v = 0.75 + 0.25 * i / (VIS_BANDS - 1);
266
267 hsv_to_rgb (h, s, v, r, g, b);
268 }
269
270 static int expose_vis_cb (GtkWidget * widget, GdkEventExpose * event)
271 {
272 cairo_t * cr = gdk_cairo_create (gtk_widget_get_window (widget));
273161
274162 clear (widget, cr);
275163
280168 int m = aud::min (VIS_CENTER + v, HEIGHT);
281169
282170 float r, g, b;
283 get_color (widget, i, & r, & g, & b);
171 audgui_vis_bar_color (c, i, VIS_BANDS, r, g, b);
284172
285173 cairo_set_source_rgb (cr, r, g, b);
286174 cairo_rectangle (cr, x, VIS_CENTER - v, BAND_WIDTH, v);
8888 true // comment
8989 };
9090
91 static const Playlist::SortType pw_col_sort_types[PW_COLS] = {
92 Playlist::n_sort_types, // entry number
93 Playlist::Title, // title
94 Playlist::Artist, // artist
95 Playlist::Date, // year
96 Playlist::Album, // album
97 Playlist::AlbumArtist, // album artist
98 Playlist::Track, // track
99 Playlist::Genre, // genre
100 Playlist::n_sort_types, // queue position
101 Playlist::Length, // length
102 Playlist::Path, // path
103 Playlist::Filename, // file name
104 Playlist::FormattedTitle, // custom title
105 Playlist::n_sort_types, // bitrate
106 Playlist::Comment // comment
107 };
108
91109 struct PlaylistWidgetData
92110 {
93111 Playlist list;
252270 audgui_infopopup_hide ();
253271
254272 data->popup_pos = pos;
255 data->popup_timer.queue (aud_get_int (nullptr, "filepopup_delay") * 100,
273 data->popup_timer.queue (aud_get_int ("filepopup_delay") * 100,
256274 aud::obj_member<PlaylistWidgetData, & PlaylistWidgetData::show_popup>, data);
257275 }
258276
266284 return;
267285 }
268286
269 if (aud_get_bool (nullptr, "show_filepopup_for_tuple") && data->popup_pos != row)
287 if (aud_get_bool ("show_filepopup_for_tuple") && data->popup_pos != row)
270288 popup_trigger (data, row);
271289 }
272290
350368 delete data;
351369 }
352370
371 static void column_clicked_cb (GtkTreeViewColumn * column, PlaylistWidgetData * data)
372 {
373 auto sort_type_ptr = g_object_get_data ((GObject *) column, "playlist-sort-type");
374 auto sort_type = aud::from_ptr<Playlist::SortType> (sort_type_ptr);
375
376 data->list.sort_entries (sort_type);
377 }
378
353379 GtkWidget * ui_playlist_widget_new (Playlist playlist)
354380 {
355381 PlaylistWidgetData * data = new PlaylistWidgetData;
374400 int n = pw_cols[i];
375401 audgui_list_add_column (list, pw_col_label[n] ? _(pw_col_names[n]) :
376402 nullptr, i, pw_col_types[n], pw_col_min_widths[n]);
403
404 if (pw_col_sort_types[n] < Playlist::n_sort_types)
405 {
406 auto column = gtk_tree_view_get_column ((GtkTreeView *) list, i);
407 auto sort_type_ptr = aud::to_ptr (pw_col_sort_types[n]);
408
409 gtk_tree_view_column_set_clickable (column, true);
410 g_object_set_data ((GObject *) column, "playlist-sort-type", sort_type_ptr);
411 g_signal_connect (column, "clicked", (GCallback) column_clicked_cb, data);
412 }
377413 }
378414
379415 return list;
102102
103103 static void no_advance_toggled (void *, void * label)
104104 {
105 if (aud_get_bool (nullptr, "no_playlist_advance"))
105 if (aud_get_bool ("no_playlist_advance"))
106106 gtk_label_set_text ((GtkLabel *) label, _("Single mode."));
107107 else
108108 gtk_label_set_text ((GtkLabel *) label, _("Playlist mode."));
112112
113113 static void stop_after_song_toggled (void *, void * label)
114114 {
115 if (aud_get_bool (nullptr, "stop_after_current_song"))
115 if (aud_get_bool ("stop_after_current_song"))
116116 gtk_label_set_text ((GtkLabel *) label, _("Stopping after song."));
117117
118118 clear_timeout.start (1000, clear_message, label);
7272 [EVENT_PAUSE] = N_("Pause/Resume"),
7373 [EVENT_STOP] = N_("Stop"),
7474 [EVENT_NEXT_TRACK] = N_("Next track"),
75 [EVENT_FORWARD] = N_("Forward 5 seconds"),
76 [EVENT_BACKWARD] = N_("Rewind 5 seconds"),
75 [EVENT_FORWARD] = N_("Step forward"),
76 [EVENT_BACKWARD] = N_("Step backward"),
7777 [EVENT_MUTE] = N_("Mute"),
7878 [EVENT_VOL_UP] = N_("Volume up"),
7979 [EVENT_VOL_DOWN] = N_("Volume down"),
7979 N_("Global Hotkey Plugin\n"
8080 "Control the player with global key combinations or multimedia keys.\n\n"
8181 "Copyright (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>\n\n"
82 "Contributers include:\n"
82 "Contributors include:\n"
8383 "Copyright (C) 2006-2007 Vladimir Paskov <vlado.paskov@gmail.com>\n"
8484 "Copyright (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>,\n"
8585 " Bryn Davies <curious@ihug.com.au>,\n"
143143 return true;
144144 }
145145
146 /* decreace volume */
146 /* decrease volume */
147147 if (event == EVENT_VOL_DOWN)
148148 {
149149 if (mute)
153153 mute = false;
154154 }
155155
156 if ((current_volume -= plugin_cfg.vol_decrement) < 0)
156 if ((current_volume -= aud_get_int ("volume_delta")) < 0)
157157 {
158158 current_volume = 0;
159159 }
177177 mute = false;
178178 }
179179
180 if ((current_volume += plugin_cfg.vol_increment) > 100)
180 if ((current_volume += aud_get_int ("volume_delta")) > 100)
181181 {
182182 current_volume = 100;
183183 }
229229 /* forward */
230230 if (event == EVENT_FORWARD)
231231 {
232 aud_drct_seek (aud_drct_get_time () + 5000);
232 aud_drct_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
233233 return true;
234234 }
235235
236236 /* backward */
237237 if (event == EVENT_BACKWARD)
238238 {
239 int time = aud_drct_get_time ();
240 if (time > 5000) time -= 5000; /* Jump 5s back */
241 else time = 0;
242 aud_drct_seek (time);
239 aud_drct_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
243240 return true;
244241 }
245242
266263
267264 if (event == EVENT_TOGGLE_REPEAT)
268265 {
269 aud_toggle_bool (nullptr, "repeat");
266 aud_toggle_bool ("repeat");
270267 return true;
271268 }
272269
273270 if (event == EVENT_TOGGLE_SHUFFLE)
274271 {
275 aud_toggle_bool (nullptr, "shuffle");
272 aud_toggle_bool ("shuffle");
276273 return true;
277274 }
278275
279276 if (event == EVENT_TOGGLE_STOP)
280277 {
281 aud_toggle_bool (nullptr, "stop_after_current_song");
278 aud_toggle_bool ("stop_after_current_song");
282279 return true;
283280 }
284281
341338 HotkeyConfiguration *hotkey;
342339 int i,max;
343340
344 /* default volume level */
345 plugin_cfg.vol_increment = 4;
346 plugin_cfg.vol_decrement = 4;
347
348341 hotkey = &(plugin_cfg.first);
349342 hotkey->next = nullptr;
350343 hotkey->key = 0;
3939 } HotkeyConfiguration;
4040
4141 typedef struct {
42 int vol_increment;
43 int vol_decrement;
44
4542 /* keyboard */
4643 HotkeyConfiguration first;
4744 } PluginConfig;
4141 class JACKOutput : public OutputPlugin
4242 {
4343 public:
44 static const char client_name_default[];
4445 static const char * const defaults[];
4546 static const PreferencesWidget widgets[];
4647 static const PluginPreferences prefs;
103104
104105 EXPORT JACKOutput aud_plugin_instance (s_buffer);
105106
107 const char JACKOutput::client_name_default[] = "audacious";
108
106109 const char * const JACKOutput::defaults[] = {
107110 "auto_connect", "TRUE",
111 "client_name", JACKOutput::client_name_default,
112 "ports_filter", "",
113 "ports_ignore", "FALSE",
114 "ports_physical", "TRUE",
115 "ports_upmix", "2",
108116 "volume_left", "100",
109117 "volume_right", "100",
110118 nullptr
111119 };
112120
113121 const PreferencesWidget JACKOutput::widgets[] = {
122 WidgetEntry (N_("Client name:"),
123 WidgetString ("jack", "client_name")),
114124 WidgetCheck (N_("Automatically connect to output ports"),
115 WidgetBool ("jack", "auto_connect"))
125 WidgetBool ("jack", "auto_connect")),
126 WidgetLabel (N_("Filter ports (regex, use any port if blank):"),
127 WIDGET_CHILD),
128 WidgetEntry (nullptr,
129 WidgetString ("jack", "ports_filter"),
130 {false},
131 WIDGET_CHILD),
132 WidgetCheck (N_("Connect to physical ports only"),
133 WidgetBool ("jack", "ports_physical"),
134 WIDGET_CHILD),
135 WidgetSpin (N_("Upmix to"),
136 WidgetInt ("jack", "ports_upmix"),
137 {1, 96, 1, N_("ports if input has fewer channels")},
138 WIDGET_CHILD),
139 WidgetCheck (N_("Ignore insufficient number of ports"),
140 WidgetBool ("jack", "ports_ignore"),
141 WIDGET_CHILD)
116142 };
117143
118144 const PluginPreferences JACKOutput::prefs = {{widgets}};
140166 const char * * ports = nullptr;
141167 int count = 0;
142168
143 if (! (ports = jack_get_ports (m_client, nullptr, nullptr,
144 JackPortIsPhysical | JackPortIsInput)))
145 {
146 AUDERR ("jack_get_ports() failed\n");
147 goto fail;
148 }
149
150 while (ports[count])
151 count ++;
169 unsigned long ports_flags = JackPortIsInput;
170 if (aud_get_bool ("jack", "ports_physical"))
171 ports_flags |= JackPortIsPhysical;
172
173 if (! (ports = jack_get_ports (m_client, aud_get_str ("jack", "ports_filter"), nullptr, ports_flags)))
174 {
175 if (! aud_get_bool ("jack", "ports_ignore"))
176 {
177 error = String (_("No JACK output ports were found. Please check settings."));
178 goto fail;
179 }
180 }
181 else
182 {
183 while (ports[count])
184 count ++;
185 }
152186
153187 if (count < channels)
154188 {
155 error = String (str_printf (_("Only %d JACK output ports were "
156 "found but %d are required."), count, channels));
157 goto fail;
158 }
159
160 // upmix mono to stereo
161 // for all other arrangements, use a one-to-one mapping
162 if (channels == 1)
163 count = aud::min (count, 2);
164 else
165 count = aud::min (count, channels);
189 if (! aud_get_bool ("jack", "ports_ignore"))
190 {
191 error = String (str_printf (_("Only %d JACK output ports were "
192 "found but %d are required."), count, channels));
193 goto fail;
194 }
195 else
196 AUDWARN ("Not enough output ports available. Playing %d of %d channels.\n", count, channels);
197 }
198
199 // upmix
200 count = aud::min (count, aud::max (aud_get_int ("jack", "ports_upmix"), channels));
166201
167202 for (int i = 0; i < count; i ++)
168203 {
199234
200235 jack_set_error_function (error_cb);
201236
202 if (! (m_client = jack_client_open ("audacious", JackNoStartServer, nullptr)))
237 StringBuf client_name = str_copy (aud_get_str ("jack", "client_name"), jack_client_name_size () - 1);
238
239 if (! (m_client = jack_client_open (client_name[0] ? client_name : JACKOutput::client_name_default, JackNoStartServer, nullptr)))
203240 {
204241 error = String (_("Failed to connect to the JACK server; is it running?"));
205242 goto fail;
216253 }
217254 }
218255
219 buffer_time = aud_get_int (nullptr, "output_buffer_size");
256 buffer_time = aud_get_int ("output_buffer_size");
220257 m_buffer.alloc (aud::rescale (buffer_time, 1000, rate) * channels);
221258
222259 m_rate = rate;
208208 }
209209 }
210210 else if (g_ascii_strcasecmp ("SHUFFLE", c) == 0)
211 aud_toggle_bool (nullptr, "shuffle");
211 aud_toggle_bool ("shuffle");
212212 else if (g_ascii_strcasecmp ("REPEAT", c) == 0)
213 aud_toggle_bool (nullptr, "repeat");
213 aud_toggle_bool ("repeat");
214214 else if (g_ascii_strncasecmp ("FWD", c, 3) == 0)
215215 {
216216 ptr = c + 3;
214214 s = String (orig_utf8);
215215 }
216216
217 uri = String (str_printf ("http://lyrics.wikia.com/index.php?"
217 uri = String (str_printf ("https://lyrics.fandom.com/index.php?"
218218 "action=edit&title=%s", (const char *) str_encode_percent
219219 (index_to_str_list (strings, ":"))));
220220 }
223223 // Convert normal lyrics link to edit page link
224224 char * slash = strrchr (lyric, '/');
225225 if (slash)
226 uri = String (str_printf ("http://lyrics.wikia.com/index.php?"
226 uri = String (str_printf ("https://lyrics.fandom.com/index.php?"
227227 "action=edit&title=%s", slash + 1));
228228 }
229229
302302 StringBuf title_buf = str_encode_percent (state.title);
303303 StringBuf artist_buf = str_encode_percent (state.artist);
304304
305 state.uri = String (str_printf ("http://lyrics.wikia.com/api.php?"
305 state.uri = String (str_printf ("https://lyrics.fandom.com/api.php?"
306306 "action=lyrics&artist=%s&song=%s&fmt=xml", (const char *) artist_buf,
307307 (const char *) title_buf));
308308
309 update_lyrics_window (state.title, state.artist, _("Connecting to lyrics.wikia.com ..."), false);
309 update_lyrics_window (state.title, state.artist, _("Connecting to lyrics.fandom.com ..."), false);
310310 vfs_async_file_get_contents (state.uri, get_lyrics_step_2, nullptr);
311311 }
312312
00 /*
1 * Copyright (c) 2010, 2014 William Pitcock <nenolod@dereferenced.org>
1 * Copyright (c) 2010, 2014, 2019 Ariadne Conill <ariadne@dereferenced.org>
22 *
33 * Permission to use, copy, modify, and/or distribute this software for any
44 * purpose with or without fee is hereby granted, provided that the above
1717 * POSSIBILITY OF SUCH DAMAGE.
1818 */
1919
20 #include <errno.h>
21
2022 #include <glib.h>
23 #include <glib/gstdio.h>
2124 #include <string.h>
2225
2326 #include <QApplication>
2427 #include <QContextMenuEvent>
2528 #include <QDesktopServices>
29 #include <QJsonDocument>
30 #include <QJsonObject>
2631 #include <QMenu>
2732 #include <QTextCursor>
2833 #include <QTextDocument>
3843 #include <libaudcore/i18n.h>
3944 #include <libaudcore/plugin.h>
4045 #include <libaudcore/plugins.h>
46 #include <libaudcore/preferences.h>
4147 #include <libaudcore/audstrings.h>
4248 #include <libaudcore/hook.h>
4349 #include <libaudcore/vfs_async.h>
4551
4652 #include <libaudqt/libaudqt.h>
4753
48 typedef struct {
54 struct LyricsState {
4955 String filename; /* of song file */
5056 String title, artist;
51 String uri; /* URI we are trying to retrieve */
52 } LyricsState;
53
54 static LyricsState state;
57 String lyrics;
58
59 enum Source {
60 None,
61 Local,
62 LyricWiki,
63 LyricsOVH
64 } source;
65
66 bool error;
67 };
68
69 static LyricsState g_state;
5570
5671 class TextEdit : public QTextEdit
5772 {
6580 class LyricWikiQt : public GeneralPlugin
6681 {
6782 public:
83 static const char * const defaults[];
84 static const PluginPreferences prefs;
85 static const PreferencesWidget widgets[];
6886 static constexpr PluginInfo info = {
69 N_("LyricWiki Plugin"),
87 N_("Lyrics"),
7088 PACKAGE,
7189 nullptr, // about
72 nullptr, // prefs
90 & prefs,
7391 PluginQtOnly
7492 };
7593
7694 constexpr LyricWikiQt () : GeneralPlugin (info, false) {}
95
96 bool init ();
7797 void * get_qt_widget ();
7898 };
7999
80100 EXPORT LyricWikiQt aud_plugin_instance;
101
102 const char * const LyricWikiQt::defaults[] = {
103 "remote-source", "lyricwiki",
104 "enable-file-provider", "TRUE",
105 "enable-cache", "TRUE",
106 nullptr
107 };
108
109 static const ComboItem remote_sources[] = {
110 ComboItem(N_("Nowhere"), "nowhere"),
111 ComboItem(N_("LyricWiki"), "lyricwiki"),
112 ComboItem(N_("lyrics.ovh"), "lyrics.ovh")
113 };
114
115 const PreferencesWidget LyricWikiQt::widgets[] = {
116 WidgetLabel(N_("<b>Internet Sources</b>")),
117 WidgetCombo(N_("Fetch lyrics from:"),
118 WidgetString ("lyricwiki", "remote-source"),
119 {{remote_sources}}),
120 WidgetCheck(N_("Store fetched lyrics in local cache"),
121 WidgetBool ("lyricwiki", "enable-cache")),
122 WidgetLabel(N_("<b>Local Storage</b>")),
123 WidgetCheck(N_("Load lyric files (.lrc) from local storage"),
124 WidgetBool ("lyricwiki", "enable-file-provider"))
125 };
126
127 const PluginPreferences LyricWikiQt::prefs = {{widgets}};
128
129 bool LyricWikiQt::init ()
130 {
131 aud_config_set_defaults ("lyricwiki", defaults);
132
133 return true;
134 }
135
136 static void update_lyrics_window (const char * title, const char * artist, const char * lyrics);
137 static void update_lyrics_window_message (LyricsState state, const char * message);
138 static void update_lyrics_window_error (const char * message);
139 static void update_lyrics_window_notfound (LyricsState state);
140
141 // LyricProvider encapsulates an entire strategy for fetching lyrics,
142 // for example from LyricWiki or local storage.
143 class LyricProvider {
144 public:
145 virtual bool match (LyricsState state) = 0;
146 virtual void fetch (LyricsState state) = 0;
147 virtual String edit_uri (LyricsState state) = 0;
148 };
149
150 // FileProvider provides a strategy for fetching and saving lyrics
151 // in local files. It also manages the local lyrics cache.
152 class FileProvider : public LyricProvider {
153 public:
154 FileProvider() {};
155
156 bool match (LyricsState state);
157 void fetch (LyricsState state);
158 String edit_uri (LyricsState state) { return String (); }
159 void save (LyricsState state);
160 void cache (LyricsState state);
161 void cache_fetch (LyricsState state);
162
163 private:
164 String local_uri_for_entry (LyricsState state);
165 String cache_uri_for_entry (LyricsState state);
166 };
167
168 static FileProvider file_provider;
169
170 static void persist_state (LyricsState state)
171 {
172 g_state = state;
173 g_state.error = false;
174
175 if (g_state.source == LyricsState::Source::Local || ! aud_get_bool("lyricwiki", "enable-cache"))
176 return;
177
178 file_provider.cache (state);
179 }
180
181 void FileProvider::cache (LyricsState state)
182 {
183 auto uri = cache_uri_for_entry (state);
184 bool exists = VFSFile::test_file (uri, VFS_IS_REGULAR);
185 if (exists)
186 return;
187
188 AUDINFO ("Add to cache: %s\n", (const char *) uri);
189 VFSFile::write_file (uri, state.lyrics, strlen (state.lyrics));
190 }
191
192 #ifdef S_IRGRP
193 #define DIRMODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
194 #else
195 #define DIRMODE (S_IRWXU)
196 #endif
197
198 String FileProvider::cache_uri_for_entry (LyricsState state)
199 {
200 auto user_dir = aud_get_path (AudPath::UserDir);
201 StringBuf base_path = filename_build ({user_dir, "lyrics"});
202 StringBuf artist_path = filename_build ({base_path, state.artist});
203
204 if (g_mkdir_with_parents (artist_path, DIRMODE) < 0)
205 AUDERR ("Failed to create %s: %s\n", (const char *) artist_path, strerror (errno));
206
207 StringBuf title_path = str_concat({filename_build({artist_path, state.title}), ".lrc"});
208
209 return String (filename_to_uri (title_path));
210 }
211
212 String FileProvider::local_uri_for_entry (LyricsState state)
213 {
214 if (strcmp (uri_get_scheme (state.filename), "file"))
215 return String ();
216
217 // it's a local file: convert our URI to a local path
218 StringBuf filename = uri_to_filename (state.filename);
219
220 // strip off the extension
221 char * ext = strrchr((char *) filename, '.');
222 if (! ext)
223 return String ();
224 *ext = '\0';
225
226 // combine the mangled filename and '.lrc' extension
227 return String (filename_to_uri (str_concat ({filename, ".lrc"})));
228 }
229
230 void FileProvider::fetch (LyricsState state)
231 {
232 String path = local_uri_for_entry (state);
233 if (! path)
234 return;
235
236 auto data = VFSFile::read_file (path, VFS_APPEND_NULL);
237 if (! data.len())
238 return;
239
240 state.lyrics = String (data.begin ());
241 state.source = LyricsState::Source::Local;
242
243 update_lyrics_window (state.title, state.artist, state.lyrics);
244 persist_state (state);
245 }
246
247 void FileProvider::cache_fetch (LyricsState state)
248 {
249 String path = cache_uri_for_entry (state);
250 if (! path)
251 return;
252
253 auto data = VFSFile::read_file (path, VFS_APPEND_NULL);
254 if (! data.len())
255 return;
256
257 state.lyrics = String (data.begin ());
258 state.source = LyricsState::Source::Local;
259
260 update_lyrics_window (state.title, state.artist, state.lyrics);
261 persist_state (state);
262 }
263
264 bool FileProvider::match (LyricsState state)
265 {
266 String path = local_uri_for_entry (state);
267 if (! path)
268 return false;
269
270 AUDINFO("Checking for local lyric file: '%s'\n", (const char *) path);
271
272 bool exists = VFSFile::test_file(path, VFS_IS_REGULAR);
273 if (exists)
274 {
275 fetch (state);
276 return true;
277 }
278
279 path = cache_uri_for_entry (state);
280 if (! path)
281 return false;
282
283 AUDINFO("Checking for cache lyric file: '%s'\n", (const char *) path);
284
285 exists = VFSFile::test_file(path, VFS_IS_REGULAR);
286 if (exists)
287 cache_fetch (state);
288
289 return exists;
290 }
291
292 void FileProvider::save (LyricsState state)
293 {
294 if (! state.lyrics)
295 return;
296
297 String path = local_uri_for_entry (state);
298 if (! path)
299 return;
300
301 AUDINFO("Saving lyrics to local file: '%s'\n", (const char *) path);
302
303 VFSFile::write_file (path, state.lyrics, strlen (state.lyrics));
304 }
305
306 // LyricWikiProvider provides a strategy for fetching lyrics from
307 // LyricWiki.
308 class LyricWikiProvider : public LyricProvider {
309 public:
310 LyricWikiProvider() {};
311
312 bool match (LyricsState state);
313 void fetch (LyricsState state);
314 String edit_uri (LyricsState state);
315
316 private:
317 LyricsState scrape_edit_page(LyricsState state, const char * buf, int64_t len);
318 LyricsState scrape_match_api(const char * buf, int64_t len);
319 String match_uri (LyricsState state);
320 };
321
322 static LyricWikiProvider lyricwiki_provider;
323
324 String LyricWikiProvider::edit_uri (LyricsState state)
325 {
326 StringBuf title_buf, artist_buf;
327
328 title_buf = str_copy (state.title);
329 str_replace_char (title_buf, ' ', '_');
330 title_buf = str_encode_percent (title_buf, -1);
331
332 artist_buf = str_copy (state.artist);
333 str_replace_char (artist_buf, ' ', '_');
334 artist_buf = str_encode_percent (artist_buf, -1);
335
336 return String (str_printf ("https://lyrics.fandom.com/index.php?action=edit&title=%s:%s",
337 (const char *) artist_buf, (const char *) title_buf));
338 }
339
340 String LyricWikiProvider::match_uri (LyricsState state)
341 {
342 StringBuf title_buf, artist_buf;
343
344 title_buf = str_copy (state.title);
345 title_buf = str_encode_percent (title_buf, -1);
346
347 artist_buf = str_copy (state.artist);
348 artist_buf = str_encode_percent (artist_buf, -1);
349
350 return String (str_printf ("https://lyrics.fandom.com/api.php?action=lyrics&artist=%s&title=%s&fmt=xml",
351 (const char *) artist_buf, (const char *) title_buf));
352 }
353
354 void LyricWikiProvider::fetch (LyricsState state)
355 {
356 String uri = edit_uri (state);
357
358 auto handle_edit_page = [=] (const char *, const Index<char> & buf) {
359 if (! buf.len ())
360 {
361 update_lyrics_window_error (str_printf (_("Unable to fetch %s"), (const char *) uri));
362 return;
363 }
364
365 LyricsState new_state = scrape_edit_page (state, buf.begin (), buf.len ());
366
367 if (! new_state.lyrics)
368 {
369 update_lyrics_window_notfound (new_state);
370 return;
371 }
372
373 // we have to inject our original artist and title back because otherwise
374 // the lyrics will cache wrong.
375 new_state.artist = g_state.artist;
376 new_state.title = g_state.title;
377
378 update_lyrics_window (new_state.title, new_state.artist, new_state.lyrics);
379 persist_state (new_state);
380 };
381
382 vfs_async_file_get_contents (uri, handle_edit_page);
383 }
384
385 bool LyricWikiProvider::match (LyricsState state)
386 {
387 String uri = match_uri (state);
388
389 auto handle_match_api = [=] (const char *, const Index<char> & buf) {
390 if (! buf.len ())
391 {
392 update_lyrics_window_error (str_printf (_("Unable to fetch %s"), (const char *) uri));
393 return;
394 }
395
396 LyricsState new_state = scrape_match_api (buf.begin (), buf.len ());
397 if (! new_state.artist || ! new_state.title)
398 {
399 update_lyrics_window_error (str_printf (_("Unable to fetch %s"), (const char *) uri));
400 return;
401 }
402
403 fetch (new_state);
404 };
405
406 vfs_async_file_get_contents (uri, handle_match_api);
407 update_lyrics_window_message (state, _("Looking for lyrics ..."));
408
409 return true;
410 }
81411
82412 /*
83413 * Suppress libxml warnings, because lyricwiki does not generate anything near
87417 {
88418 }
89419
90 static CharPtr scrape_lyrics_from_lyricwiki_edit_page (const char * buf, int64_t len)
420 LyricsState LyricWikiProvider::scrape_edit_page (LyricsState state, const char * buf, int64_t len)
91421 {
92422 xmlDocPtr doc;
93423 CharPtr ret;
151481
152482 g_match_info_free (match_info);
153483 g_regex_unref (reg);
154
155 if (! ret)
156 {
157 reg = g_regex_new
158 ("#REDIRECT \\[\\[([^:]*):(.*)]]",
159 (GRegexCompileFlags) (G_REGEX_MULTILINE | G_REGEX_DOTALL),
160 (GRegexMatchFlags) 0, nullptr);
161 if (g_regex_match (reg, (char *) lyric, G_REGEX_MATCH_NEWLINE_ANY, & match_info))
162 {
163 state.artist = String (g_match_info_fetch (match_info, 1));
164 state.title = String (g_match_info_fetch (match_info, 2));
165 state.uri = String ();
166 }
167
168 g_match_info_free (match_info);
169 g_regex_unref (reg);
170 }
171484 }
172485
173486 xmlFree (lyric);
176489 xmlFreeDoc (doc);
177490 }
178491
179 return ret;
180 }
181
182 static String scrape_uri_from_lyricwiki_search_result (const char * buf, int64_t len)
492 LyricsState new_state;
493
494 new_state.filename = state.filename;
495 new_state.artist = state.artist;
496 new_state.title = state.title;
497 new_state.lyrics = String (ret);
498 new_state.source = LyricsState::Source::LyricWiki;
499
500 return new_state;
501 }
502
503 LyricsState LyricWikiProvider::scrape_match_api (const char * buf, int64_t len)
183504 {
184505 xmlDocPtr doc;
185 String uri;
506 LyricsState result;
186507
187508 /*
188509 * workaround buggy lyricwiki search output where it cuts the lyrics
217538
218539 for (cur = root->xmlChildrenNode; cur; cur = cur->next)
219540 {
220 if (xmlStrEqual(cur->name, (xmlChar *) "url"))
221 {
222 auto lyric = (char *) xmlNodeGetContent (cur);
223
224 // If the lyrics are unknown, LyricWiki returns a broken link
225 // to the edit page. Extract the song ID (artist:title) from
226 // the URI and recreate a working link.
227 char * title = strstr (lyric, "title=");
228 if (title)
229 {
230 title += 6;
231
232 // Strip trailing "&action=edit"
233 char * amp = strchr (title, '&');
234 if (amp)
235 * amp = 0;
236
237 // Spaces get replaced with plus signs for some reason.
238 str_replace_char (title, '+', ' ');
239
240 // LyricWiki interprets UTF-8 as ISO-8859-1, then "converts"
241 // it to UTF-8 again. Worse, it will sometimes corrupt only
242 // the song title in this way while leaving the artist name
243 // intact. So we have to percent-decode the URI, split the
244 // two strings apart, repair them separately, and then
245 // rebuild the URI.
246 auto strings = str_list_to_index (str_decode_percent (title), ":");
247 for (String & s : strings)
248 {
249 StringBuf orig_utf8 = str_convert (s, -1, "UTF-8", "ISO-8859-1");
250 if (orig_utf8 && g_utf8_validate (orig_utf8, -1, nullptr))
251 s = String (orig_utf8);
252 }
253
254 uri = String (str_printf ("http://lyrics.wikia.com/index.php?"
255 "action=edit&title=%s", (const char *) str_encode_percent
256 (index_to_str_list (strings, ":"))));
257 }
258 else
259 {
260 // Convert normal lyrics link to edit page link
261 char * slash = strrchr (lyric, '/');
262 if (slash && ! strstr (slash, "lyrics.wikia.com"))
263 uri = String (str_printf ("http://lyrics.wikia.com/index.php?"
264 "action=edit&title=%s", slash + 1));
265 else
266 uri = String ("N/A");
267 }
268
269 xmlFree ((xmlChar *) lyric);
270 }
541 xmlChar * content = xmlNodeGetContent (cur);
542
543 if (xmlStrEqual(cur->name, (xmlChar *) "artist"))
544 result.artist = String ((const char *) xmlNodeGetContent (cur));
545 else if (xmlStrEqual(cur->name, (xmlChar *) "song"))
546 result.title = String ((const char *) xmlNodeGetContent (cur));
547
548 if (content)
549 xmlFree (content);
271550 }
272551
273552 xmlFreeDoc (doc);
274553 }
275554
276 return uri;
277 }
278
279 static void update_lyrics_window (const char * title, const char * artist, const char * lyrics);
280
281 static void get_lyrics_step_1 ();
282
283 static void get_lyrics_step_3 (const char * uri, const Index<char> & buf, void *)
284 {
285 if (! state.uri || strcmp (state.uri, uri))
286 return;
287
288 if (! buf.len ())
289 {
290 update_lyrics_window (_("Error"), nullptr,
291 str_printf (_("Unable to fetch %s"), uri));
292 return;
293 }
294
295 CharPtr lyrics = scrape_lyrics_from_lyricwiki_edit_page (buf.begin (), buf.len ());
296
297 if (! state.uri)
298 {
299 get_lyrics_step_1 ();
300 return;
301 }
302
303 if (! lyrics)
304 {
305 update_lyrics_window (_("Error"), nullptr,
306 str_printf (_("Unable to parse %s"), uri));
307 return;
308 }
309
310 update_lyrics_window (state.title, state.artist, lyrics);
311 }
312
313 static void get_lyrics_step_2 (const char * uri1, const Index<char> & buf, void *)
314 {
315 if (! state.uri || strcmp (state.uri, uri1))
316 return;
317
318 if (! buf.len ())
319 {
320 update_lyrics_window (_("Error"), nullptr,
321 str_printf (_("Unable to fetch %s"), uri1));
322 return;
323 }
324
325 String uri = scrape_uri_from_lyricwiki_search_result (buf.begin (), buf.len ());
326
327 if (! uri)
328 {
329 update_lyrics_window (_("Error"), nullptr,
330 str_printf (_("Unable to parse %s"), uri1));
331 return;
332 }
333 else if (uri == String ("N/A"))
334 {
335 update_lyrics_window (state.title, state.artist,
336 _("No lyrics available"));
337 return;
338 }
339
340 state.uri = uri;
341
342 update_lyrics_window (state.title, state.artist, _("Looking for lyrics ..."));
343 vfs_async_file_get_contents (uri, get_lyrics_step_3, nullptr);
344 }
345
346 static void get_lyrics_step_1 ()
347 {
348 if (! state.artist || ! state.title)
349 {
350 update_lyrics_window (_("Error"), nullptr, _("Missing song metadata"));
351 return;
352 }
353
354 StringBuf title_buf = str_encode_percent (state.title);
355 StringBuf artist_buf = str_encode_percent (state.artist);
356
357 state.uri = String (str_printf ("http://lyrics.wikia.com/api.php?"
358 "action=lyrics&artist=%s&song=%s&fmt=xml", (const char *) artist_buf,
359 (const char *) title_buf));
360
361 update_lyrics_window (state.title, state.artist, _("Connecting to lyrics.wikia.com ..."));
362 vfs_async_file_get_contents (state.uri, get_lyrics_step_2, nullptr);
555 // FIXME: don't use g_state
556 result.filename = g_state.filename;
557
558 return result;
559 }
560
561 // LyricsOVHProvider provides a strategy for fetching lyrics using the
562 // lyrics.ovh search engine.
563 class LyricsOVHProvider : public LyricProvider {
564 public:
565 LyricsOVHProvider() {};
566
567 bool match (LyricsState state);
568 void fetch (LyricsState state);
569 String edit_uri (LyricsState state) { return String (); }
570 };
571
572 bool LyricsOVHProvider::match (LyricsState state)
573 {
574 fetch (state);
575 return true;
576 }
577
578 void LyricsOVHProvider::fetch (LyricsState state)
579 {
580 auto handle_result_cb = [=] (const char *filename, const Index<char> & buf) {
581 if (! buf.len ())
582 {
583 update_lyrics_window_error(str_printf(_("Unable to fetch %s"), filename));
584 return;
585 }
586
587 QByteArray json = QByteArray (buf.begin (), buf.len ());
588 QJsonDocument doc = QJsonDocument::fromJson (json);
589
590 if (doc.isNull () || ! doc.isObject ())
591 {
592 update_lyrics_window_error(str_printf(_("Unable to parse %s"), filename));
593 return;
594 }
595
596 LyricsState new_state = g_state;
597 new_state.lyrics = String ();
598
599 auto obj = doc.object ();
600 if (obj.contains ("lyrics"))
601 {
602 auto str = obj["lyrics"].toString();
603 if (! str.isNull ())
604 {
605 auto raw_data = str.toLocal8Bit();
606 new_state.lyrics = String (raw_data.data ());
607 }
608 }
609 else
610 {
611 update_lyrics_window_notfound (new_state);
612 return;
613 }
614
615 new_state.source = LyricsState::Source::LyricsOVH;
616
617 update_lyrics_window (new_state.title, new_state.artist, new_state.lyrics);
618 persist_state (new_state);
619 };
620
621 auto artist = str_copy (state.artist);
622 artist = str_encode_percent (state.artist, -1);
623
624 auto title = str_copy (state.title);
625 title = str_encode_percent (state.title, -1);
626
627 auto uri = str_concat({"https://api.lyrics.ovh/v1/", artist, "/", title});
628
629 vfs_async_file_get_contents(uri, handle_result_cb);
630 update_lyrics_window_message (state, _("Looking for lyrics ..."));
631 }
632
633 static LyricsOVHProvider lyrics_ovh_provider;
634
635 static LyricProvider * remote_source ()
636 {
637 auto source = aud_get_str ("lyricwiki", "remote-source");
638
639 if (! strcmp (source, "lyricwiki"))
640 return &lyricwiki_provider;
641
642 if (! strcmp (source, "lyrics.ovh"))
643 return &lyrics_ovh_provider;
644
645 return nullptr;
363646 }
364647
365648 static QTextEdit * textedit;
649
650 static void update_lyrics_window_message (LyricsState state, const char * message)
651 {
652 update_lyrics_window (state.title, state.artist, message);
653 }
654
655 static void update_lyrics_window_error (const char * message)
656 {
657 update_lyrics_window (_("Error"), nullptr, message);
658 g_state.error = true;
659 }
660
661 static void update_lyrics_window_notfound (LyricsState state)
662 {
663 update_lyrics_window (state.title, state.artist, _("Lyrics could not be found."));
664 g_state.error = true;
665 }
366666
367667 static void update_lyrics_window (const char * title, const char * artist, const char * lyrics)
368668 {
387687 {
388688 /* FIXME: cancel previous VFS requests (not possible with current API) */
389689
390 state.filename = aud_drct_get_filename ();
690 g_state.filename = aud_drct_get_filename ();
391691
392692 Tuple tuple = aud_drct_get_tuple ();
393 state.title = tuple.get_str (Tuple::Title);
394 state.artist = tuple.get_str (Tuple::Artist);
395
396 state.uri = String ();
397
398 get_lyrics_step_1 ();
693 g_state.title = tuple.get_str (Tuple::Title);
694 g_state.artist = tuple.get_str (Tuple::Artist);
695
696 if (! aud_get_bool ("lyricwiki", "enable-file-provider") || ! file_provider.match (g_state))
697 {
698 if (! g_state.artist || ! g_state.title)
699 {
700 update_lyrics_window_error (_("Missing title and/or artist."));
701 return;
702 }
703
704 auto rsrc = remote_source ();
705 if (rsrc)
706 rsrc->match (g_state);
707 }
399708 }
400709
401710 static void lw_cleanup (QObject * object = nullptr)
402711 {
403 state.filename = String ();
404 state.title = String ();
405 state.artist = String ();
406 state.uri = String ();
712 g_state.filename = String ();
713 g_state.title = String ();
714 g_state.artist = String ();
407715
408716 hook_dissociate ("tuple change", (HookFunction) lyricwiki_playback_began);
409717 hook_dissociate ("playback ready", (HookFunction) lyricwiki_playback_began);
433741
434742 void TextEdit::contextMenuEvent (QContextMenuEvent * event)
435743 {
436 if (! state.uri)
744 if (! g_state.artist || ! g_state.title)
437745 return QTextEdit::contextMenuEvent (event);
438746
439747 QMenu * menu = createStandardContextMenu ();
440748 menu->addSeparator ();
441 QAction * edit = menu->addAction (_("Edit lyrics ..."));
749
750 QAction * edit = menu->addAction (_("Edit Lyrics ..."));
442751 QObject::connect (edit, & QAction::triggered, [] () {
443 QDesktopServices::openUrl (QUrl ((const char *) state.uri));
752 QUrl url = QUrl ((const char *) lyricwiki_provider.edit_uri (g_state));
753 QDesktopServices::openUrl (url);
444754 });
755
756 if (g_state.lyrics && g_state.source != LyricsState::Source::Local && ! g_state.error)
757 {
758 QAction * save = menu->addAction (_("Save Locally"));
759 QObject::connect (save, & QAction::triggered, [] () {
760 file_provider.save (g_state);
761 });
762 }
763
764 if (g_state.source == LyricsState::Source::Local || g_state.error)
765 {
766 QAction * refresh = menu->addAction (_("Refresh"));
767 QObject::connect (refresh, & QAction::triggered, [] () {
768 auto rsrc = remote_source ();
769 if (rsrc)
770 rsrc->match (g_state);
771 });
772 }
773
445774 menu->exec (event->globalPos ());
446 delete menu;
447 }
775 menu->deleteLater ();
776 }
0 shared_module('lyricwiki-qt',
1 'lyricwiki.cc',
2 dependencies: [audacious_dep, qt_dep, glib_dep, xml_dep, audqt_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
6
0 shared_module('m3u',
1 'm3u.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: container_plugin_dir
5 )
6
0 src_inc = include_directories('.')
1
2
3 config_h_full_path = join_paths(meson.current_build_dir(), 'config.h')
4
5
6 if cc.get_id() == 'gcc' or cc.get_id() == 'clang'
7 add_project_arguments('-include', config_h_full_path, language: 'c')
8 add_project_arguments('-include', config_h_full_path, language: 'cpp')
9 else
10 error('Please implement -include handling for your chosen compiler.')
11 endif
12
13
14 # input plugins
15 subdir('metronom')
16 subdir('psf')
17 subdir('tonegen')
18 subdir('vtx')
19 subdir('xsf')
20 subdir('console')
21
22
23 # effect plugins
24 subdir('compressor')
25 subdir('crossfade')
26 subdir('crystalizer')
27 subdir('mixer')
28 subdir('silence-removal')
29 subdir('stereo_plugin')
30 subdir('voice_removal')
31 subdir('echo_plugin')
32
33 if samplerate_dep.found()
34 if get_option('resample')
35 subdir('resample')
36 endif
37
38 if get_option('speedpitch')
39 subdir('speedpitch')
40 endif
41 endif
42
43
44 # transport plugins
45 subdir('gio')
46 if get_option('neon')
47 subdir('neon')
48 endif
49 if get_option('mms')
50 subdir('mms')
51 endif
52
53
54 # playlist (container) plugins
55 subdir('audpl')
56 subdir('asx')
57 subdir('m3u')
58 subdir('pls')
59 if xml_dep.found()
60 subdir('asx3')
61 subdir('xspf')
62 endif
63 if get_option('cue')
64 subdir('cue')
65 endif
66
67
68 # Qt-specific plugins
69 if get_option('qt')
70 subdir('blur_scope-qt')
71 subdir('qt-spectrum')
72
73 subdir('qtui')
74 subdir('skins-qt')
75
76 subdir('albumart-qt')
77 subdir('lyricwiki-qt')
78 subdir('playlist-manager-qt')
79 subdir('search-tool-qt')
80 subdir('song-info-qt')
81 subdir('statusicon-qt')
82 subdir('streamtuner')
83
84 subdir('delete-files')
85 subdir('skins-data')
86
87 subdir('qtaudio')
88
89 if get_option('vumeter')
90 subdir('vumeter-qt')
91 endif
92 endif
93
94
95 # general plugins
96 if cdaudio_enabled
97 subdir('cd-menu-items')
98 endif
99
100 if get_option('songchange')
101 subdir('songchange')
102 endif
103
104 if get_option('scrobbler2') and xml_dep.found()
105 subdir('scrobbler2')
106 endif
107
108 if get_option('dbus') and get_option('mpris2')
109 subdir('mpris2')
110 endif
111
112 if get_option('notify') and get_option('qt')
113 subdir('notify')
114 endif
115
116
117 # input plugins
118 if get_option('mpg123')
119 subdir('mpg123')
120 endif
121
122 if get_option('ffaudio') in ['libav', 'ffmpeg']
123 subdir('ffaudio')
124 endif
125
126 if get_option('adplug')
127 subdir('adplug')
128 endif
129
130 if get_option('flac')
131 subdir('flac')
132 endif
133
134 if get_option('vorbis')
135 subdir('vorbis')
136 endif
137
138 if get_option('faad')
139 subdir('aac')
140 endif
141
142 if get_option('modplug')
143 subdir('modplug')
144 endif
145
146 if get_option('openmpt')
147 subdir('openmpt')
148 endif
149
150 if get_option('wavpack')
151 subdir('wavpack')
152 endif
153
154 if get_option('sndfile')
155 subdir('sndfile')
156 endif
157
158 if cdaudio_enabled
159 subdir('cdaudio')
160 endif
161
162 if get_option('amidiplug')
163 subdir('amidiplug')
164 endif
165
166 if get_option('sid')
167 subdir('sid')
168 endif
169
170
171 # output plugins
172 if get_option('pulse')
173 subdir('pulse')
174 endif
175 if host_machine.system() == 'linux' and get_option('alsa')
176 subdir('alsa')
177 endif
178 if get_option('filewriter')
179 subdir('filewriter')
180 endif
181
182
183 # config.h stuff
184 configure_file(input: 'config.h.meson',
185 output: 'config.h',
186 configuration: conf)
0 shared_module('metronom',
1 'metronom.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: input_plugin_dir
5 )
6
0 shared_module('mixer',
1 'mixer.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
0 mms_dep = dependency('libmms', version: '>= 0.3', required: false)
1
2
3 if mms_dep.found()
4 shared_module('mms',
5 'mms.cc',
6 dependencies: [audacious_dep, mms_dep, glib_dep],
7 install: true,
8 install_dir: transport_plugin_dir
9 )
10 endif
0 modplug_dep = dependency('libmodplug', required: false)
1
2
3 modplug_archive_sources = [
4 'archive/arch_raw.cc',
5 'archive/archive.cc',
6 'archive/open.cc'
7 ]
8
9
10 modplug_plugin_sources = [
11 'modplugbmp.cc',
12 'plugin_main.cc'
13 ]
14
15
16 if modplug_dep.found()
17 shared_module('modplug',
18 modplug_archive_sources,
19 modplug_plugin_sources,
20 dependencies: [audacious_dep, modplug_dep],
21 include_directories: [src_inc],
22 install: true,
23 install_dir: input_plugin_dir,
24 )
25 endif
26
164164
165165 if(mModProps.mPreamp)
166166 {
167 //apply preamp
168 if(mModProps.mBits == 16)
169 {
170 unsigned n = mBufSize >> 1;
171 for(unsigned i = 0; i < n; i++) {
172 short old = ((short*)mBuffer)[i];
173 ((short*)mBuffer)[i] *= (short int)mPreampFactor;
174 // detect overflow and clip!
175 if ((old & 0x8000) !=
176 (((short*)mBuffer)[i] & 0x8000))
177 ((short*)mBuffer)[i] = old | 0x7FFF;
178
179 }
180 }
181 else
182 {
183 for(unsigned i = 0; i < mBufSize; i++) {
184 unsigned char old = ((unsigned char*)mBuffer)[i];
185 ((unsigned char*)mBuffer)[i] *= (short int)mPreampFactor;
186 // detect overflow and clip!
187 if ((old & 0x80) !=
188 (((unsigned char*)mBuffer)[i] & 0x80))
189 ((unsigned char*)mBuffer)[i] = old | 0x7F;
190 }
167 unsigned n = mBufSize >> 1;
168
169 for(unsigned i = 0; i < n; i++) {
170 short old = ((short*)mBuffer)[i];
171 ((short*)mBuffer)[i] *= (short int)mPreampFactor;
172
173 // detect overflow and clip!
174 if ((old & 0x8000) != (((short*)mBuffer)[i] & 0x8000))
175 ((short*)mBuffer)[i] = old | 0x7FFF;
191176 }
192177 }
193178
214199 mBufSize *= mModProps.mFrequency;
215200 mBufSize /= 1000; //milliseconds
216201 mBufSize *= mModProps.mChannels;
217 mBufSize *= mModProps.mBits / 8;
202 mBufSize *= 2;
218203
219204 mBuffer = new unsigned char[mBufSize];
220205
221206 CSoundFile::SetWaveConfig
222207 (
223208 mModProps.mFrequency,
224 mModProps.mBits,
209 16,
225210 mModProps.mChannels
226211 );
227212 CSoundFile::SetWaveConfigEx
274259
275260 set_stream_bitrate(mSoundFile->GetNumChannels() * 1000);
276261
277 int fmt = (mModProps.mBits == 16) ? FMT_S16_NE : FMT_U8;
278 open_audio(fmt, mModProps.mFrequency, mModProps.mChannels);
262 open_audio(FMT_S16_NE, mModProps.mFrequency, mModProps.mChannels);
279263
280264 PlayLoop();
281265
2323 nullptr };
2424
2525 const char * const ModplugXMMS::defaults[] = {
26 "Bits", "16",
2726 "Channels", "2",
2827 "ResamplingMode", aud::numeric_string<SRCMODE_POLYPHASE>::str,
2928 "Frequency", "44100",
5251 };
5352
5453 static const PreferencesWidget quality_widgets[] = {
55 WidgetLabel (N_("<b>Resolution</b>")),
56 WidgetRadio (N_("8-bit"), WidgetInt (MODPLUG_CFGID, "Bits"), {8}),
57 WidgetRadio (N_("16-bit"), WidgetInt (MODPLUG_CFGID, "Bits"), {16}),
5854 WidgetLabel (N_("<b>Channels</b>")),
5955 WidgetRadio (N_("Mono"), WidgetInt (MODPLUG_CFGID, "Channels"), {1}),
6056 WidgetRadio (N_("Stereo"), WidgetInt (MODPLUG_CFGID, "Channels"), {2}),
133129 {
134130 aud_config_set_defaults (MODPLUG_CFGID, defaults);
135131
136 mModProps.mBits = aud_get_int (MODPLUG_CFGID, "Bits");
137132 mModProps.mChannels = aud_get_int (MODPLUG_CFGID, "Channels");
138133 mModProps.mResamplingMode = aud_get_int (MODPLUG_CFGID, "ResamplingMode");
139134 mModProps.mFrequency = aud_get_int (MODPLUG_CFGID, "Frequency");
11 #define MODPLUG_SETTINGS_H
22
33 typedef struct {
4 int mBits;
54 int mChannels;
65 int mResamplingMode;
76 int mFrequency;
0 mpg123_dep = dependency('libmpg123', version: '>= 1.12')
1
2
3 if mpg123_dep.found()
4 shared_module('madplug',
5 'mpg123.cc',
6 dependencies: [audacious_dep, mpg123_dep, audtag_dep],
7 include_directories: [src_inc],
8 install: true,
9 install_dir: input_plugin_dir,
10 )
11 endif
12
2828 #include "config.h"
2929
3030 #ifdef DEBUG_MPG123_IO
31 # define MPG123_IODBG(...) AUDDBG(__VA_ARGS__)
31 #define MPG123_IODBG(...) AUDDBG(__VA_ARGS__)
3232 #else
33 # define MPG123_IODBG(...) do { } while (0)
33 #define MPG123_IODBG(...)
3434 #endif
3535
3636 #define WANT_VFS_STDIO_COMPAT
37 #include <audacious/audtag.h>
3738 #include <libaudcore/audstrings.h>
38 #include <libaudcore/runtime.h>
3939 #include <libaudcore/i18n.h>
4040 #include <libaudcore/plugin.h>
4141 #include <libaudcore/preferences.h>
42 #include <audacious/audtag.h>
42 #include <libaudcore/runtime.h>
4343
4444 class MPG123Plugin : public InputPlugin
4545 {
4646 public:
4747 static const char * const exts[];
4848 static const char * const defaults[];
49 static const char * const mimes[];
4950 static const PreferencesWidget widgets[];
5051 static const PluginPreferences prefs;
5152
52 static constexpr PluginInfo info = {
53 N_("MPG123 Plugin"),
54 PACKAGE,
55 nullptr,
56 & prefs
57 };
58
59 constexpr MPG123Plugin() : InputPlugin (info, InputInfo (FlagWritesTag)
60 .with_exts (exts)) {}
61
62 bool init ();
63 void cleanup ();
64
65 bool is_our_file (const char * filename, VFSFile & file);
66 bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
67 bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple);
68 bool play (const char * filename, VFSFile & file);
53 static constexpr PluginInfo info = {N_("MPG123 Plugin"), PACKAGE, nullptr,
54 &prefs};
55 static constexpr InputInfo iinfo =
56 InputInfo(FlagWritesTag).with_exts(exts).with_mimes(mimes);
57
58 constexpr MPG123Plugin() : InputPlugin(info, iinfo) {}
59
60 bool init();
61 void cleanup();
62
63 bool is_our_file(const char * filename, VFSFile & file);
64 bool read_tag(const char * filename, VFSFile & file, Tuple & tuple,
65 Index<char> * image);
66 bool write_tuple(const char * filename, VFSFile & file,
67 const Tuple & tuple);
68 bool play(const char * filename, VFSFile & file);
6969 };
7070
7171 EXPORT MPG123Plugin aud_plugin_instance;
7272
73 const char * const MPG123Plugin::defaults[] = {
74 "full_scan", "FALSE",
75 nullptr
76 };
73 const char * const MPG123Plugin::mimes[] = {
74 "audio/mp3", "audio/mpeg", "audio/x-mp3", "audio/x-mpeg", nullptr};
75
76 const char * const MPG123Plugin::defaults[] = {"full_scan", "FALSE", //
77 nullptr};
7778
7879 const PreferencesWidget MPG123Plugin::widgets[] = {
79 WidgetLabel (N_("<b>Advanced</b>")),
80 WidgetCheck (N_("Use accurate length calculation (slow)"),
81 WidgetBool ("mpg123", "full_scan"))
82 };
80 WidgetLabel(N_("<b>Advanced</b>")),
81 WidgetCheck(N_("Use accurate length calculation (slow)"),
82 WidgetBool("mpg123", "full_scan"))};
8383
8484 const PluginPreferences MPG123Plugin::prefs = {{widgets}};
8585
86 #define DECODE_OPTIONS (MPG123_QUIET | MPG123_GAPLESS | MPG123_SEEKBUFFER | MPG123_FUZZY)
86 #define DECODE_OPTIONS \
87 (MPG123_QUIET | MPG123_GAPLESS | MPG123_SEEKBUFFER | MPG123_FUZZY)
8788
8889 // this is a macro so that the printed line number is meaningful
89 #define print_mpg123_error(filename, decoder) \
90 AUDERR ("mpg123 error in %s: %s\n", filename, mpg123_strerror (decoder))
91
92 static ssize_t replace_read (void * file, void * buffer, size_t length)
93 {
94 return ((VFSFile *) file)->fread (buffer, 1, length);
95 }
96
97 static off_t replace_lseek (void * file, off_t to, int whence)
98 {
99 if (((VFSFile *) file)->fseek (to, to_vfs_seek_type (whence)) < 0)
90 #define print_mpg123_error(filename, decoder) \
91 AUDERR("mpg123 error in %s: %s\n", filename, mpg123_strerror(decoder))
92
93 static ssize_t replace_read(void * file, void * buffer, size_t length)
94 {
95 return ((VFSFile *)file)->fread(buffer, 1, length);
96 }
97
98 static off_t replace_lseek(void * file, off_t to, int whence)
99 {
100 if (((VFSFile *)file)->fseek(to, to_vfs_seek_type(whence)) < 0)
100101 return -1;
101102
102 return ((VFSFile *) file)->ftell ();
103 }
104
105 static off_t replace_lseek_dummy (void * file, off_t to, int whence)
103 return ((VFSFile *)file)->ftell();
104 }
105
106 static off_t replace_lseek_dummy(void * file, off_t to, int whence)
106107 {
107108 return -1;
108109 }
109110
110 bool MPG123Plugin::init ()
111 {
112 aud_config_set_defaults ("mpg123", defaults);
111 bool MPG123Plugin::init()
112 {
113 aud_config_set_defaults("mpg123", defaults);
113114
114115 AUDDBG("initializing mpg123 library\n");
115116 mpg123_init();
117118 return true;
118119 }
119120
120 void MPG123Plugin::cleanup ()
121 void MPG123Plugin::cleanup()
121122 {
122123 AUDDBG("deinitializing mpg123 library\n");
123124 mpg123_exit();
127128 {
128129 mpg123_handle * dec = nullptr;
129130
130 bool init (const char * filename, VFSFile & file, bool probing, bool stream);
131
132 ~DecodeState()
133 { mpg123_delete (dec); }
131 DecodeState(const char * filename, VFSFile & file, bool probing,
132 bool stream);
133 ~DecodeState() { mpg123_delete(dec); }
134
135 bool valid() const { return dec != nullptr; }
134136
135137 long rate;
136138 int channels, encoding;
139141 float buf[4096];
140142 };
141143
142 bool DecodeState::init (const char * filename, VFSFile & file, bool probing, bool stream)
143 {
144 dec = mpg123_new (nullptr, nullptr);
145 mpg123_param (dec, MPG123_ADD_FLAGS, DECODE_OPTIONS, 0);
146 mpg123_replace_reader_handle (dec, replace_read,
147 stream ? replace_lseek_dummy : replace_lseek, nullptr);
144 DecodeState::DecodeState(const char * filename, VFSFile & file, bool probing,
145 bool stream)
146 {
147 dec = mpg123_new(nullptr, nullptr);
148 mpg123_param(dec, MPG123_ADD_FLAGS, DECODE_OPTIONS, 0);
149 mpg123_replace_reader_handle(dec, replace_read,
150 stream ? replace_lseek_dummy : replace_lseek,
151 nullptr);
148152
149153 /* be strict about junk data in file during content probe */
150154 if (probing)
151 mpg123_param (dec, MPG123_RESYNC_LIMIT, 0, 0);
152
153 mpg123_format_none (dec);
154
155 for (int rate : {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})
156 mpg123_format (dec, rate, MPG123_MONO | MPG123_STEREO, MPG123_ENC_FLOAT_32);
157
158 if (mpg123_open_handle (dec, & file) < 0)
155 mpg123_param(dec, MPG123_RESYNC_LIMIT, 0, 0);
156
157 mpg123_format_none(dec);
158
159 auto rates = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000};
160 for (int rate : rates)
161 mpg123_format(dec, rate, MPG123_MONO | MPG123_STEREO,
162 MPG123_ENC_FLOAT_32);
163
164 if (mpg123_open_handle(dec, &file) < 0)
159165 goto err;
160166
161 if (! stream && aud_get_bool ("mpg123", "full_scan") && mpg123_scan (dec) < 0)
167 if (!stream && aud_get_bool("mpg123", "full_scan") && mpg123_scan(dec) < 0)
162168 goto err;
163169
164170 while (1)
165171 {
166 if (mpg123_getformat (dec, & rate, & channels, & encoding) < 0)
172 if (mpg123_getformat(dec, &rate, &channels, &encoding) < 0)
167173 goto err;
168174
169 int ret = mpg123_read (dec, (unsigned char *) buf, sizeof buf, & bytes_read);
175 int ret =
176 mpg123_read(dec, (unsigned char *)buf, sizeof buf, &bytes_read);
170177
171178 if (ret == MPG123_NEW_FORMAT)
172179 continue;
173180 if (ret < 0)
174181 goto err;
175182
176 if (mpg123_info (dec, & info) < 0)
183 if (mpg123_info(dec, &info) < 0)
177184 goto err;
178185
179 return dec;
186 return;
180187 }
181188
182189 err:
183190 if (probing)
184 AUDDBG ("mpg123 error in %s: %s\n", filename, mpg123_strerror (dec));
191 AUDDBG("mpg123 error in %s: %s\n", filename, mpg123_strerror(dec));
185192 else
186 AUDERR ("mpg123 error in %s: %s\n", filename, mpg123_strerror (dec));
187
188 mpg123_delete (dec);
193 AUDERR("mpg123 error in %s: %s\n", filename, mpg123_strerror(dec));
194
195 mpg123_delete(dec);
189196 dec = nullptr;
190
191 return false;
192197 }
193198
194199 // with better buffering in Audacious 3.7, this is now safe for streams
195 static bool detect_id3 (VFSFile & file)
200 static bool detect_id3(VFSFile & file)
196201 {
197202 bool is_id3 = false;
198203 char id3buf[3];
199204
200 if (file.fread (id3buf, 1, 3) == 3)
201 is_id3 = ! memcmp (id3buf, "ID3", 3);
202
203 if (file.fseek (0, VFS_SEEK_SET) < 0)
205 if (file.fread(id3buf, 1, 3) == 3)
206 is_id3 = !memcmp(id3buf, "ID3", 3);
207
208 if (file.fseek(0, VFS_SEEK_SET) < 0)
204209 is_id3 = false;
205210
206211 return is_id3;
207212 }
208213
209 static StringBuf make_format_string (const mpg123_frameinfo * info)
214 static StringBuf make_format_string(const mpg123_frameinfo * info)
210215 {
211216 static const char * vers[] = {"1", "2", "2.5"};
212 return str_printf ("MPEG-%s layer %d", vers[info->version], info->layer);
213 }
214
215 bool MPG123Plugin::is_our_file (const char * filename, VFSFile & file)
216 {
217 bool stream = (file.fsize () < 0);
217 return str_printf("MPEG-%s layer %d", vers[info->version], info->layer);
218 }
219
220 bool MPG123Plugin::is_our_file(const char * filename, VFSFile & file)
221 {
222 bool stream = (file.fsize() < 0);
218223
219224 /* Some MP3s begin with enormous ID3 tags, which fill up the whole probe
220225 * buffer and thus hide any MP3 content. As a workaround, assume that an
221226 * ID3 tag means an MP3 file. --jlindgren */
222 if (detect_id3 (file))
227 if (detect_id3(file))
223228 return true;
224229
225 DecodeState s;
226 if (! s.init (filename, file, true, stream))
227 return false;
228
229 AUDDBG ("Accepted as %s: %s.\n", (const char *) make_format_string (& s.info), filename);
230 return true;
231 }
232
233 static bool read_mpg123_info (const char * filename, VFSFile & file, Tuple & tuple)
234 {
235 int64_t size = file.fsize ();
230 DecodeState s(filename, file, true, stream);
231 if (!s.valid())
232 return false;
233
234 auto fmt = make_format_string(&s.info);
235 AUDDBG("Accepted as %s: %s.\n", &fmt[0], filename);
236 return true;
237 }
238
239 static bool read_mpg123_info(const char * filename, VFSFile & file,
240 Tuple & tuple)
241 {
242 int64_t size = file.fsize();
236243 bool stream = (size < 0);
237244
238 DecodeState s;
239 if (! s.init (filename, file, false, stream))
240 return false;
241
242 tuple.set_str (Tuple::Codec, make_format_string (& s.info));
243 tuple.set_str (Tuple::Quality, str_printf ("%s, %d Hz", (s.channels == 2) ?
244 _("Stereo") : (s.channels > 2) ? _("Surround") : _("Mono"), (int) s.rate));
245 tuple.set_int (Tuple::Bitrate, s.info.bitrate);
246
247 if (! stream)
248 {
249 int64_t samples = mpg123_length (s.dec);
250 int length = (s.rate > 0) ? samples * 1000 / s.rate : 0;
245 DecodeState s(filename, file, false, stream);
246 if (!s.valid())
247 return false;
248
249 tuple.set_int(Tuple::Bitrate, s.info.bitrate);
250 tuple.set_str(Tuple::Codec, make_format_string(&s.info));
251
252 const char * chan_str = (s.channels == 2)
253 ? _("Stereo")
254 : (s.channels > 2) ? _("Surround") : _("Mono");
255 tuple.set_str(Tuple::Quality,
256 str_printf("%s, %d Hz", chan_str, (int)s.rate));
257
258 if (!stream && s.rate > 0)
259 {
260 int64_t samples = mpg123_length(s.dec);
261 int length = aud::rescale<int64_t>(samples, s.rate, 1000);
251262
252263 if (length > 0)
253264 {
254 tuple.set_int (Tuple::Length, length);
255 tuple.set_int (Tuple::Bitrate, 8 * size / length);
256 }
257 }
258
259 return true;
260 }
261
262 bool MPG123Plugin::read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image)
263 {
264 bool stream = (file.fsize () < 0);
265
266 if (! read_mpg123_info (filename, file, tuple))
265 tuple.set_int(Tuple::Length, length);
266 tuple.set_int(Tuple::Bitrate, aud::rdiv<int64_t>(8 * size, length));
267 }
268 }
269
270 return true;
271 }
272
273 bool MPG123Plugin::read_tag(const char * filename, VFSFile & file,
274 Tuple & tuple, Index<char> * image)
275 {
276 bool stream = (file.fsize() < 0);
277
278 if (!read_mpg123_info(filename, file, tuple))
267279 return false;
268280
269281 if (stream)
270 tuple.fetch_stream_info (file);
282 tuple.fetch_stream_info(file);
271283 else
272284 {
273 if (file.fseek (0, VFS_SEEK_SET) != 0)
285 if (file.fseek(0, VFS_SEEK_SET) != 0)
274286 return false;
275287
276 audtag::read_tag (file, tuple, image);
277 }
278
279 return true;
280 }
281
282 bool MPG123Plugin::play (const char * filename, VFSFile & file)
283 {
284 bool stream = (file.fsize () < 0);
288 audtag::read_tag(file, tuple, image);
289 }
290
291 return true;
292 }
293
294 bool MPG123Plugin::play(const char * filename, VFSFile & file)
295 {
296 bool stream = (file.fsize() < 0);
285297
286298 Tuple tuple;
287299 if (stream)
288300 {
289 tuple = get_playback_tuple ();
290 if (detect_id3 (file) && audtag::read_tag (file, tuple, nullptr))
291 set_playback_tuple (tuple.ref ());
292 }
293
294 DecodeState s;
295 if (! s.init (filename, file, false, stream))
301 tuple = get_playback_tuple();
302 if (detect_id3(file) && audtag::read_tag(file, tuple, nullptr))
303 set_playback_tuple(tuple.ref());
304 }
305
306 DecodeState s(filename, file, false, stream);
307 if (!s.valid())
296308 return false;
297309
298310 int bitrate = s.info.bitrate * 1000;
299311 int bitrate_sum = 0, bitrate_count = 0;
300312 int error_count = 0;
301313
302 set_stream_bitrate (bitrate);
303
304 if (stream && tuple.fetch_stream_info (file))
305 set_playback_tuple (tuple.ref ());
306
307 open_audio (FMT_FLOAT, s.rate, s.channels);
308
309 while (! check_stop ())
310 {
311 int seek = check_seek ();
314 set_stream_bitrate(bitrate);
315
316 if (stream && tuple.fetch_stream_info(file))
317 set_playback_tuple(tuple.ref());
318
319 open_audio(FMT_FLOAT, s.rate, s.channels);
320
321 while (!check_stop())
322 {
323 int seek = check_seek();
312324
313325 if (seek >= 0)
314326 {
315 if (mpg123_seek (s.dec, (int64_t) seek * s.rate / 1000, SEEK_SET) < 0)
316 print_mpg123_error (filename, s.dec);
327 int64_t sample = aud::rescale<int64_t>(seek, 1000, s.rate);
328 if (mpg123_seek(s.dec, sample, SEEK_SET) < 0)
329 print_mpg123_error(filename, s.dec);
317330
318331 s.bytes_read = 0;
319332 }
320333
321 mpg123_info (s.dec, & s.info);
334 mpg123_info(s.dec, &s.info);
322335 bitrate_sum += s.info.bitrate;
323 bitrate_count ++;
324
325 if (bitrate_sum / bitrate_count != bitrate && bitrate_count >= 16)
326 {
327 set_stream_bitrate (bitrate_sum / bitrate_count * 1000);
328 bitrate = bitrate_sum / bitrate_count;
336 bitrate_count++;
337
338 int new_bitrate = aud::rdiv(bitrate_sum, bitrate_count);
339 if (new_bitrate != bitrate && bitrate_count >= 16)
340 {
341 set_stream_bitrate(new_bitrate * 1000);
342 bitrate = new_bitrate;
329343 bitrate_sum = 0;
330344 bitrate_count = 0;
331345 }
332346
333 if (stream && tuple.fetch_stream_info (file))
334 set_playback_tuple (tuple.ref ());
335
336 if (! s.bytes_read)
337 {
338 int ret = mpg123_read (s.dec, (unsigned char *) s.buf, sizeof s.buf, & s.bytes_read);
347 if (stream && tuple.fetch_stream_info(file))
348 set_playback_tuple(tuple.ref());
349
350 if (!s.bytes_read)
351 {
352 int ret = mpg123_read(s.dec, (unsigned char *)s.buf, sizeof s.buf,
353 &s.bytes_read);
339354
340355 if (ret == MPG123_DONE || ret == MPG123_ERR_READER)
341356 break;
343358 if (ret < 0)
344359 {
345360 // log only the first error
346 if (! error_count)
347 print_mpg123_error (filename, s.dec);
361 if (!error_count)
362 print_mpg123_error(filename, s.dec);
348363
349364 // generally unreported errors are bad, but due to the number of
350365 // MP3s with junk data at the end, RESYNC_FAIL just becomes a
351366 // nuisance, so silence it
352 if (++ error_count >= 10)
353 return (mpg123_errcode (s.dec) == MPG123_RESYNC_FAIL);
367 if (++error_count >= 10)
368 return (mpg123_errcode(s.dec) == MPG123_RESYNC_FAIL);
354369 }
355370 }
356371
358373 {
359374 error_count = 0;
360375
361 write_audio (s.buf, s.bytes_read);
376 write_audio(s.buf, s.bytes_read);
362377 s.bytes_read = 0;
363378 }
364379 }
366381 return true;
367382 }
368383
369 bool MPG123Plugin::write_tuple (const char * filename, VFSFile & file, const Tuple & tuple)
370 {
371 if (file.fsize () < 0) // stream?
372 return false;
373
374 return audtag::write_tuple (file, tuple, audtag::TagType::ID3v2);
375 }
376
377 const char * const MPG123Plugin::exts[] = { "mp3", "mp2", "mp1", "bmu", nullptr };
384 bool MPG123Plugin::write_tuple(const char * filename, VFSFile & file,
385 const Tuple & tuple)
386 {
387 if (file.fsize() < 0) // stream?
388 return false;
389
390 return audtag::write_tuple(file, tuple, audtag::TagType::ID3v2);
391 }
392
393 const char * const MPG123Plugin::exts[] = {"mp3", "mp2", "mp1", "bmu", nullptr};
0 gnome = import('gnome')
1
2
3 gio_dep = dependency('gio-2.0', required: true)
4 aud_dbus_deps = [gio_dep]
5
6
7 if host_machine.system() != 'windows'
8 gio_unix_dep = dependency('gio-unix-2.0', required: true)
9 aud_dbus_deps += [gio_unix_dep]
10 endif
11
12
13 mpris2_core_src = gnome.gdbus_codegen('object-core',
14 sources: 'mpris2.xml',
15 interface_prefix: 'org.mpris.',
16 namespace: 'Mpris'
17 )
18
19
20 mpris2_player_src = gnome.gdbus_codegen('object-player',
21 sources: 'mpris2-player.xml',
22 interface_prefix: 'org.mpris.',
23 namespace: 'Mpris'
24 )
25
26
27 shared_module('mpris2',
28 mpris2_core_src,
29 mpris2_player_src,
30 'plugin.cc',
31 dependencies: [audacious_dep, glib_dep] + aud_dbus_deps,
32 install: true,
33 install_dir: general_plugin_dir
34 )
33 <property name="CanRaise" type="b" access="read"/>
44 <property name="DesktopEntry" type="s" access="read"/>
55 <property name="Identity" type="s" access="read"/>
6 <property name="SupportedUriSchemes" type="as" access="read"/>
7 <property name="SupportedMimeTypes" type="as" access="read"/>
68 <method name="Quit"/>
79 <method name="Raise"/>
810 </interface>
299299
300300 bool MPRIS2Plugin::init ()
301301 {
302 #if ! GLIB_CHECK_VERSION (2, 36, 0)
303302 g_type_init ();
304 #endif
305303
306304 GError * error = nullptr;
307305 GDBusConnection * bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, & error);
317315 (GBusNameOwnerFlags) 0, nullptr, nullptr, nullptr, nullptr);
318316
319317 object_core = (GObject *) mpris_media_player2_skeleton_new ();
318
319 // build the schemes array
320 auto schemes = VFSFile::supported_uri_schemes ();
321 auto mimes = aud_plugin_get_supported_mime_types ();
320322
321323 g_object_set (object_core,
322324 "can-quit", (gboolean) true,
323325 "can-raise", (gboolean) true,
324326 "desktop-entry", "audacious",
325327 "identity", "Audacious",
328 "supported-uri-schemes", schemes.begin (),
329 "supported-mime-types", mimes.begin (),
326330 nullptr);
327331
328332 g_signal_connect (object_core, "handle-quit", (GCallback) quit_cb, nullptr);
0 neon_dep = dependency('neon', version: '>= 0.27', required: false)
1
2
3 if neon_dep.found()
4 shared_module('neon',
5 'neon.cc',
6 'cert_verification.cc',
7 dependencies: [audacious_dep, neon_dep, glib_dep],
8 install: true,
9 install_dir: transport_plugin_dir
10 )
11 endif
192192 NeonFile::NeonFile (const char * url) :
193193 m_url (url)
194194 {
195 int buffer_kb = aud_get_int (nullptr, "net_buffer_kb");
195 int buffer_kb = aud_get_int ("net_buffer_kb");
196196 m_rb.alloc (1024 * aud::clamp (buffer_kb, 16, 1024));
197197 }
198198
433433 static int neon_proxy_auth_cb (void * userdata, const char * realm, int attempt,
434434 char * username, char * password)
435435 {
436 String value = aud_get_str (nullptr, "proxy_user");
436 String value = aud_get_str ("proxy_user");
437437 g_strlcpy (username, value, NE_ABUFSIZ);
438438
439 value = aud_get_str (nullptr, "proxy_pass");
439 value = aud_get_str ("proxy_pass");
440440 g_strlcpy (password, value, NE_ABUFSIZ);
441441
442442 return attempt;
553553 int ret;
554554 String proxy_host;
555555 int proxy_port = 0;
556
557 bool use_proxy = aud_get_bool (nullptr, "use_proxy");
558 bool use_proxy_auth = aud_get_bool (nullptr, "use_proxy_auth");
556 String proxy_user (""); // ne_session_socks_proxy requires non NULL user and password
557 String proxy_pass ("");
558 bool socks_proxy = false;
559 ne_sock_sversion socks_type = NE_SOCK_SOCKSV4A;
560
561 bool use_proxy = aud_get_bool ("use_proxy");
562 bool use_proxy_auth = aud_get_bool ("use_proxy_auth");
559563
560564 if (use_proxy)
561565 {
562 proxy_host = aud_get_str (nullptr, "proxy_host");
563 proxy_port = aud_get_int (nullptr, "proxy_port");
566 proxy_host = aud_get_str ("proxy_host");
567 proxy_port = aud_get_int ("proxy_port");
568 socks_proxy = aud_get_bool ("socks_proxy");
569
570 if (use_proxy_auth)
571 {
572 proxy_user = aud_get_str ("proxy_user");
573 proxy_pass = aud_get_str ("proxy_pass");
574 }
575
576 if (socks_proxy)
577 {
578 socks_type = aud_get_int ("socks_type") == 0 ? NE_SOCK_SOCKSV4A : NE_SOCK_SOCKSV5;
579 }
564580 }
565581
566582 m_redircount = 0;
596612 if (use_proxy)
597613 {
598614 AUDDBG ("<%p> Using proxy: %s:%d\n", this, (const char *) proxy_host, proxy_port);
599 ne_session_proxy (m_session, proxy_host, proxy_port);
615 if (socks_proxy)
616 {
617 ne_session_socks_proxy (m_session, socks_type, proxy_host, proxy_port, proxy_user, proxy_pass);
618 }
619 else
620 {
621 ne_session_proxy (m_session, proxy_host, proxy_port);
622 }
600623
601624 if (use_proxy_auth)
602625 {
0 notify_dep = dependency('libnotify', required: false)
1
2
3 if notify_dep.found()
4 shared_module('notify',
5 'event.cc',
6 'notify.cc',
7 'osd.cc',
8 dependencies: [audacious_dep, notify_dep, qt_dep, audqt_dep],
9 install: true,
10 install_dir: general_plugin_dir
11 )
12 endif
0 PLUGIN = openmpt${PLUGIN_SUFFIX}
1
2 SRCS = mpt.cc \
3 mptwrap.cc
4
5 include ../../buildsys.mk
6 include ../../extra.mk
7
8 plugindir := ${plugindir}/${INPUT_PLUGIN_DIR}
9
10 LD = ${CXX}
11 CFLAGS += ${PLUGIN_CFLAGS}
12 CXXFLAGS += ${PLUGIN_CFLAGS}
13 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${OPENMPT_CFLAGS} -I../..
14 LIBS += ${OPENMPT_LIBS}
0 openmpt_dep = dependency('libopenmpt', version: '>= 0.2', required: false)
1
2
3 if openmpt_dep.found()
4 shared_module('openmpt',
5 'mpt.cc',
6 'mptwrap.cc',
7 dependencies: [audacious_dep, openmpt_dep],
8 include_directories: [src_inc],
9 install: true,
10 install_dir: input_plugin_dir,
11 )
12 endif
0 /*-
1 * Copyright (c) 2015-2019 Chris Spiegel
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <libaudcore/i18n.h>
27 #include <libaudcore/plugin.h>
28 #include <libaudcore/preferences.h>
29 #include <libaudcore/runtime.h>
30
31 #include "mptwrap.h"
32
33 static bool force_apply = false;
34
35 static constexpr const char *CFG_SECTION = "openmpt";
36 static constexpr const char *SETTING_STEREO_SEPARATION = "stereo_separation";
37 static constexpr const char *SETTING_INTERPOLATOR = "interpolator";
38
39 class MPTPlugin : public InputPlugin
40 {
41 public:
42 static const char about[];
43 static const char *const exts[];
44 static const PreferencesWidget widgets[];
45 static const PluginPreferences prefs;
46
47 static constexpr PluginInfo info =
48 {
49 N_("OpenMPT (Module Player)"),
50 PACKAGE,
51 about,
52 &prefs,
53 };
54
55 static constexpr auto iinfo = InputInfo(0)
56 /* For continuity, be at a lower priority than modplug for the time being */
57 .with_priority(_AUD_PLUGIN_DEFAULT_PRIO + 1)
58 .with_exts(exts);
59
60 constexpr MPTPlugin() : InputPlugin(info, iinfo) { }
61
62 bool init()
63 {
64 static constexpr const char * defaults[] =
65 {
66 SETTING_STEREO_SEPARATION, aud::numeric_string<MPTWrap::default_stereo_separation>::str,
67 SETTING_INTERPOLATOR, aud::numeric_string<MPTWrap::default_interpolator>::str,
68 nullptr,
69 };
70
71 aud_config_set_defaults(CFG_SECTION, defaults);
72
73 return true;
74 }
75
76 bool is_our_file(const char *filename, VFSFile &file)
77 {
78 MPTWrap mpt;
79 return mpt.open(file);
80 }
81
82 bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *)
83 {
84 MPTWrap mpt;
85 if (!mpt.open(file))
86 return false;
87
88 tuple.set_filename(filename);
89 tuple.set_format(mpt.format(), mpt.channels(), mpt.rate(), 0);
90
91 tuple.set_int(Tuple::Length, mpt.duration());
92 tuple.set_str(Tuple::Title, mpt.title());
93
94 return true;
95 }
96
97 bool play(const char *filename, VFSFile &file)
98 {
99 MPTWrap mpt;
100 if (!mpt.open(file))
101 return false;
102
103 force_apply = true;
104
105 open_audio(FMT_FLOAT, mpt.rate(), mpt.channels());
106
107 while (!check_stop())
108 {
109 float buffer[16384];
110 int seek_value = check_seek();
111
112 if (seek_value >= 0)
113 mpt.seek(seek_value);
114
115 if (force_apply)
116 {
117 mpt.set_interpolator(aud_get_int(CFG_SECTION, SETTING_INTERPOLATOR));
118 mpt.set_stereo_separation(aud_get_int(CFG_SECTION, SETTING_STEREO_SEPARATION));
119 force_apply = false;
120 }
121
122 auto n = mpt.read(buffer, aud::n_elems(buffer));
123 if (n == 0)
124 break;
125
126 write_audio(buffer, n * sizeof buffer[0]);
127 }
128
129 return true;
130 }
131 };
132
133 const char MPTPlugin::about[] = N_("Module player based on libopenmpt\n\nWritten by: Chris Spiegel <cspiegel@gmail.com>");
134
135 const char *const MPTPlugin::exts[] =
136 {
137 "669", "amf", "ams", "dbm", "digi", "dmf", "dsm", "far", "gdm", "ice", "imf",
138 "it", "j2b", "m15", "mdl", "med", "mmcmp", "mms", "mo3", "mod", "mptm", "mt2",
139 "mtm", "nst", "okt", "plm", "ppm", "psm", "pt36", "ptm", "s3m", "sfx", "sfx2",
140 "st26", "stk", "stm", "ult", "umx", "wow", "xm", "xpk",
141 nullptr
142 };
143
144 static void values_changed()
145 {
146 force_apply = true;
147 }
148
149 const PreferencesWidget MPTPlugin::widgets[] =
150 {
151 WidgetSpin(
152 N_("Stereo separation:"),
153 WidgetInt(CFG_SECTION, SETTING_STEREO_SEPARATION, values_changed),
154 { 0.0, 100.0, 1.0, N_("%") }
155 ),
156
157 WidgetCombo(
158 N_("Interpolation:"),
159 WidgetInt(CFG_SECTION, SETTING_INTERPOLATOR, values_changed),
160 { MPTWrap::interpolators }
161 )
162 };
163
164 const PluginPreferences MPTPlugin::prefs = {{ widgets }};
165
166 EXPORT MPTPlugin aud_plugin_instance;
0 /*-
1 * Copyright (c) 2015-2019 Chris Spiegel
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <algorithm>
27 #include <iterator>
28
29 #define WANT_VFS_STDIO_COMPAT
30 #include <libopenmpt/libopenmpt_version.h>
31 #include "mptwrap.h"
32
33 constexpr ComboItem MPTWrap::interpolators[];
34 constexpr openmpt_stream_callbacks MPTWrap::callbacks;
35
36 static String to_aud_str(const char * str)
37 {
38 String aud_str(str);
39 openmpt_free_string(str);
40 return aud_str;
41 }
42
43 bool MPTWrap::open(VFSFile &file)
44 {
45 #if OPENMPT_API_VERSION_MAJOR <= 0 && OPENMPT_API_VERSION_MINOR < 3
46 auto m = openmpt_module_create(callbacks, &file, openmpt_log_func_silent,
47 nullptr, nullptr);
48 #else
49 auto m = openmpt_module_create2(callbacks, &file, openmpt_log_func_silent,
50 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
51 #endif
52
53 if (m == nullptr)
54 return false;
55
56 mod.capture(m);
57
58 openmpt_module_select_subsong(mod.get(), -1);
59
60 m_duration = openmpt_module_get_duration_seconds(mod.get()) * 1000;
61 m_title = to_aud_str(openmpt_module_get_metadata(mod.get(), "title"));
62 m_format = to_aud_str(openmpt_module_get_metadata(mod.get(), "type_long"));
63
64 return true;
65 }
66
67 size_t MPTWrap::stream_read(void *instance, void *buf, size_t n)
68 {
69 return VFS(instance)->fread(buf, 1, n);
70 }
71
72 int MPTWrap::stream_seek(void *instance, int64_t offset, int whence)
73 {
74 VFSSeekType w = to_vfs_seek_type(whence);
75 return VFS(instance)->fseek(offset, w) >= 0 ? 0 : -1;
76 }
77
78 int64_t MPTWrap::stream_tell(void *instance)
79 {
80 return VFS(instance)->ftell();
81 }
82
83 bool MPTWrap::is_valid_interpolator(int interpolator_value)
84 {
85 return std::any_of(std::begin(interpolators), std::end(interpolators),
86 [interpolator_value](const ComboItem &ci) { return ci.num == interpolator_value; });
87 }
88
89 void MPTWrap::set_interpolator(int interpolator_value)
90 {
91 if (is_valid_interpolator(interpolator_value))
92 openmpt_module_set_render_param(mod.get(),
93 OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, interpolator_value);
94 }
95
96 bool MPTWrap::is_valid_stereo_separation(int separation)
97 {
98 return separation >= 0 && separation <= 100;
99 }
100
101 void MPTWrap::set_stereo_separation(int separation)
102 {
103 if (is_valid_stereo_separation(separation))
104 openmpt_module_set_render_param(mod.get(),
105 OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT, separation);
106 }
107
108 int64_t MPTWrap::read(float *buf, int64_t bufcnt)
109 {
110 auto n = openmpt_module_read_interleaved_float_stereo(mod.get(), rate(),
111 bufcnt / channels(), buf);
112
113 return n * channels();
114 }
115
116 void MPTWrap::seek(int pos)
117 {
118 openmpt_module_set_position_seconds(mod.get(), pos / 1000.0);
119 }
0 /*-
1 * Copyright (c) 2015-2019 Chris Spiegel
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #ifndef AUDACIOUS_MPT_MPTWRAP_H
27 #define AUDACIOUS_MPT_MPTWRAP_H
28
29 #include <libaudcore/i18n.h>
30 #include <libaudcore/preferences.h>
31 #include <libaudcore/vfs.h>
32
33 #include <libopenmpt/libopenmpt.h>
34 #include <libopenmpt/libopenmpt_stream_callbacks_file.h>
35
36 class MPTWrap
37 {
38 public:
39 static constexpr int interp_none = 1;
40 static constexpr int interp_linear = 2;
41 static constexpr int interp_cubic = 4;
42 static constexpr int interp_windowed = 8;
43
44 static constexpr int default_interpolator = interp_windowed;
45 static constexpr int default_stereo_separation = 70;
46
47 static constexpr ComboItem interpolators[] =
48 {
49 {N_("None"), interp_none},
50 {N_("Linear"), interp_linear},
51 {N_("Cubic"), interp_cubic},
52 {N_("Windowed sinc"), interp_windowed}
53 };
54
55 static bool is_valid_interpolator(int);
56 void set_interpolator(int);
57
58 static bool is_valid_stereo_separation(int);
59 void set_stereo_separation(int);
60
61 bool open(VFSFile &);
62 int64_t read(float *, int64_t);
63 void seek(int pos);
64
65 static constexpr int rate() { return 48000; }
66 static constexpr int channels() { return 2; }
67
68 int duration() const { return m_duration; }
69 const String & title() const { return m_title; }
70 const String & format() const { return m_format; }
71
72 private:
73 static size_t stream_read(void *, void *, size_t);
74 static int stream_seek(void *, int64_t, int);
75 static int64_t stream_tell(void *);
76 static VFSFile *VFS(void *instance) { return reinterpret_cast<VFSFile *>(instance); }
77
78 static constexpr openmpt_stream_callbacks callbacks = { stream_read, stream_seek, stream_tell };
79
80 SmartPtr<openmpt_module, openmpt_module_destroy> mod;
81
82 int m_duration = 0;
83 String m_title;
84 String m_format;
85 };
86
87 #endif
0 shared_module('playlist-manager-qt',
1 'playlist-manager-qt.cc',
2 dependencies: [audacious_dep, qt_dep, audqt_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
6
2424 #include <QIcon>
2525 #include <QMouseEvent>
2626 #include <QToolButton>
27 #include <QTreeView>
2827
2928 #include <libaudcore/hook.h>
3029 #include <libaudcore/i18n.h>
3130 #include <libaudcore/playlist.h>
3231 #include <libaudcore/plugin.h>
3332 #include <libaudqt/libaudqt.h>
33 #include <libaudqt/treeview.h>
3434
3535 class PlaylistManagerQt : public GeneralPlugin
3636 {
105105 QFont m_bold;
106106 };
107107
108 class PlaylistsView : public QTreeView
108 class PlaylistsView : public audqt::TreeView
109109 {
110110 public:
111111 PlaylistsView ();
116116 if (event->type () == QEvent::FontChange)
117117 m_model.setFont (font ());
118118
119 QTreeView::changeEvent (event);
119 audqt::TreeView::changeEvent (event);
120120 }
121121
122122 void currentChanged (const QModelIndex & current, const QModelIndex & previous) override;
123 void keyPressEvent (QKeyEvent * event) override;
124 void mouseDoubleClickEvent (QMouseEvent * event) override;
125123 void dropEvent (QDropEvent * event) override;
126124
127125 private:
130128 void update (Playlist::UpdateLevel level);
131129 void update_sel ();
132130
133 void play_current ()
134 { Playlist::by_index (currentIndex ().row ()).start_playback (); }
131 void activate (const QModelIndex & index) override
132 {
133 if (index.isValid ())
134 Playlist::by_index (index.row ()).start_playback ();
135 }
135136
136137 const HookReceiver<PlaylistsView, Playlist::UpdateLevel>
137138 update_hook {"playlist update", this, & PlaylistsView::update};
264265
265266 void PlaylistsView::currentChanged (const QModelIndex & current, const QModelIndex & previous)
266267 {
267 QTreeView::currentChanged (current, previous);
268 audqt::TreeView::currentChanged (current, previous);
268269 if (! m_in_update)
269270 Playlist::by_index (current.row ()).activate ();
270 }
271
272 void PlaylistsView::keyPressEvent (QKeyEvent * event)
273 {
274 auto CtrlShiftAlt = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
275 if (! (event->modifiers () & CtrlShiftAlt))
276 {
277 switch (event->key ())
278 {
279 case Qt::Key_Enter:
280 case Qt::Key_Return:
281 play_current ();
282 return;
283 default:
284 break;
285 }
286 }
287
288 QTreeView::keyPressEvent (event);
289 }
290
291 void PlaylistsView::mouseDoubleClickEvent (QMouseEvent * event)
292 {
293 if (event->button () == Qt::LeftButton)
294 play_current ();
295271 }
296272
297273 void PlaylistsView::dropEvent (QDropEvent * event)
0 shared_module('pls',
1 'pls.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: container_plugin_dir
5 )
6
+0
-21
src/psf/eng_protos.h less more
0 #include <stdint.h>
1 #include <libaudcore/tuple.h>
2
3 int32_t psf2_start(uint8_t *, uint32_t length);
4 int32_t psf2_execute(void (*update)(const void *, int));
5 int32_t psf2_stop(void);
6 int32_t psf2_command(int32_t, int32_t);
7 int32_t psf2_fill_info(Tuple *);
8 int psf2_seek(uint32_t);
9
10 int32_t psf_start(uint8_t *buffer, uint32_t length);
11 int32_t psf_execute(void (*update)(const void *, int));
12 int psf_seek(uint32_t);
13 int32_t psf_stop(void);
14
15 int32_t spx_start(uint8_t *buffer, uint32_t length);
16 int32_t spx_execute(void (*update)(const void *, int));
17 int spx_seek(uint32_t);
18 int32_t spx_stop(void);
19
20 extern bool stop_flag;
3030 #include <libaudcore/audstrings.h>
3131
3232 #include "ao.h"
33 #include "eng_protos.h"
3433 #include "cpuintrf.h"
3534 #include "psx.h"
3635
3736 #include "peops/stdafx.h"
3837 #include "peops/externals.h"
39 #include "peops/regs.h"
4038 #include "peops/registers.h"
4139 #include "peops/spu.h"
4240
5048 static char psfby[256];
5149 int psf_refresh = -1;
5250
53
54 // main RAM
55 extern uint32_t psx_ram[((2*1024*1024)/4)+4];
56 extern uint32_t psx_scratch[0x400];
57 extern uint32_t initial_ram[((2*1024*1024)/4)+4];
58 extern uint32_t initial_scratch[0x400];
5951 static uint32_t initialPC, initialGP, initialSP;
60
61 extern void mips_init( void );
62 extern void mips_reset( void *param );
63 extern int mips_execute( int cycles );
64 extern void mips_set_info(uint32_t state, union cpuinfo *info);
65 extern void psx_hw_init(void);
66 extern void psx_hw_slice(void);
67 extern void psx_hw_frame(void);
68 extern void setlength(int32_t stop, int32_t fade);
6952
7053 int32_t psf_start(uint8_t *buffer, uint32_t length)
7154 {
4949 #include <libaudcore/audstrings.h>
5050
5151 #include "ao.h"
52 #include "eng_protos.h"
5352 #include "cpuintrf.h"
5453 #include "psx.h"
5554
7372 static corlett_t *c = nullptr;
7473
7574 // main RAM
76 extern uint32_t psx_ram[(2*1024*1024)/4];
77 extern uint32_t initial_ram[(2*1024*1024)/4];
7875 static uint32_t initialPC, initialSP;
7976 static uint32_t loadAddr, lengthMS, fadeMS;
8077
8279 static Index<char> lib_raw_file;
8380 static uint32_t fssize[MAX_FS];
8481 static int num_fs;
85
86 extern void mips_init( void );
87 extern void mips_reset( void *param );
88 extern int mips_execute( int cycles );
89 extern void mips_set_info(uint32_t state, union cpuinfo *info);
90 extern void psx_hw_init(void);
91 extern void ps2_hw_slice(void);
92 extern void ps2_hw_frame(void);
93 extern void setlength2(int32_t stop, int32_t fade);
9482
9583 static void do_iopmod(uint8_t *start, uint32_t offset)
9684 {
117105 uint32_t type, addr, offset, size, shent;
118106 // uint32_t phoff, phentsize, phnum, shstrndx, name, flags;
119107 uint32_t totallen;
120 int i, rec;
108 uint32_t i;
109 uint32_t rec;
121110 // FILE *f;
122111
123112 if (loadAddr & 3)
271260
272261 static uint32_t load_file_ex(uint8_t *top, uint8_t *start, uint32_t len, const char *file, uint8_t *buf, uint32_t buflen)
273262 {
274 int32_t numfiles, i, j;
263 uint32_t numfiles, i, j;
275264 uint8_t *cptr;
276265 uint32_t offs, uncomp, bsize, cofs, uofs;
277266 uint32_t X;
3535 #include <stdlib.h>
3636
3737 #include "ao.h"
38 #include "eng_protos.h"
3938 #include "cpuintrf.h"
4039 #include "psx.h"
4140
4241 #include "peops/stdafx.h"
4342 #include "peops/externals.h"
44 #include "peops/regs.h"
4543 #include "peops/registers.h"
4644 #include "peops/spu.h"
47
48 extern int SPUinit(void);
49 extern int SPUopen(void);
50 extern int SPUclose(void);
51 extern void SPUinjectRAMImage(unsigned short *source);
52
53 extern void setlength(int32_t stop, int32_t fade);
5445
5546 static uint8_t *start_of_file, *song_ptr;
5647 static uint32_t cur_tick, cur_event, num_events, next_tick, end_tick;
0 plugin_sources = [
1 'corlett.cc',
2 'plugin.cc',
3 'eng_psf.cc',
4 'eng_psf2.cc',
5 'eng_spx.cc',
6 'psx.cc',
7 'psx_hw.cc'
8 ]
9
10
11 peops_sources = [
12 'peops/spu.cc'
13 ]
14
15
16 peops2_sources = [
17 'peops2/dma.cc',
18 'peops2/registers.cc',
19 'peops2/spu.cc'
20 ]
21
22
23 shared_module('psf',
24 plugin_sources,
25 peops_sources,
26 peops2_sources,
27 dependencies: [audacious_dep, zlib_dep],
28 install: true,
29 install_dir: input_plugin_dir
30 )
31
2424 //*************************************************************************//
2525
2626 #include "../peops/stdafx.h"
27 #include "../peops/dma.h"
2728
2829 #define _IN_DMA
2930
2323 //
2424 //*************************************************************************//
2525
26 #include <stdint.h>
2627
27 u16 CALLBACK SPUreadDMA(void);
28 void CALLBACK SPUreadDMAMem(u16 * pusPSXMem,int iSize);
29 void CALLBACK SPUwriteDMA(u16 val);
30 void CALLBACK SPUwriteDMAMem(u16 * pusPSXMem,int iSize);
28 void SPUwriteDMAMem(uint32_t usPSXMem, int iSize);
29 void SPUreadDMAMem(uint32_t usPSXMem, int iSize);
4343
4444 #include "../peops/externals.h"
4545 #include "../peops/registers.h"
46 #include "../peops/regs.h"
4746
4847 static void SoundOn(int start,int end,u16 val);
4948 static void SoundOff(int start,int end,u16 val);
150150 #define H_SPU_ADSRLevel22 0x0d68
151151 #define H_SPU_ADSRLevel23 0x0d78
152152
153 uint16_t SPUreadRegister(uint32_t reg);
154 void SPUwriteRegister(uint32_t reg, uint16_t val);
+0
-28
src/psf/peops/regs.h less more
0 /***************************************************************************
1 regs.h - description
2 -------------------
3 begin : Wed May 15 2002
4 copyright : (C) 2002 by Pete Bernert
5 email : BlackDove@addcom.de
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. See also the license.txt file for *
14 * additional informations. *
15 * *
16 ***************************************************************************/
17
18 //*************************************************************************//
19 // History of changes:
20 //
21 // 2002/05/15 - Pete
22 // - generic cleanup for the Peops release
23 //
24 //*************************************************************************//
25
26
27 void SPUwriteRegister(u32 reg, u16 val);
8080
8181 #include "../peops/stdafx.h"
8282 #include "../peops/externals.h"
83 #include "../peops/regs.h"
8483 #include "../peops/registers.h"
8584 #include "../peops/spu.h"
8685
8887 // Currently it is too aggressive, destroying the rhythm of some songs
8988 // See http://redmine.audacious-media-player.org/issues/201
9089 // #define ENABLE_SILENCE_SKIPPING
91
92 void SPUirq(void) ;
9390
9491 //#include "PsxMem.h"
9592 //#include "driver.h"
196193 return(0);
197194 }
198195
196 static int endless;
197 void setendless(int e)
198 {
199 endless=e;
200 }
201
199202 // Counting to 65536 results in full volume offage.
200203 void setlength(s32 stop, s32 fade)
201204 {
202 if(stop==~0)
205 if(stop==~0 || endless)
203206 {
204207 decaybegin=~0;
205208 }
460463 if(sampcount>=decaybegin)
461464 {
462465 s32 dmul;
463 if(decaybegin!=~0) // Is anyone REALLY going to be playing a song
466 if(decaybegin!=~0U) // Is anyone REALLY going to be playing a song
464467 // for 13 hours?
465468 {
466469 if(sampcount>=decayend)
572575 // SETUPSTREAMS: init most of the spu buffers
573576 ////////////////////////////////////////////////////////////////////////
574577
575 void SetupStreams(void)
578 static void SetupStreams(void)
576579 {
577580 int i;
578581
593596 // REMOVESTREAMS: free most buffer
594597 ////////////////////////////////////////////////////////////////////////
595598
596 void RemoveStreams(void)
599 static void RemoveStreams(void)
597600 {
598601 free(pSpuBuffer); // free mixing buffer
599602 pSpuBuffer=nullptr;
2323 //
2424 //*************************************************************************//
2525
26 void sexyd_update(unsigned char* pSound,long lBytes);
26 void SPUirq(void);
2727
28 int SPUasync(u32 cycles, void (*update)(const void *, int));
28 int psf_seek(uint32_t t);
29 void setendless(int e);
30 void setlength(int32_t stop, int32_t fade);
31
32 int SPUasync(uint32_t cycles, void (*update)(const void *, int));
2933 void SPU_flushboot(void);
3034 int SPUinit(void);
3135 int SPUopen(void);
3236 int SPUclose(void);
3337 int SPUshutdown(void);
34 void SPUinjectRAMImage(u16 *pIncoming);
35 void SPUreadDMAMem(u32 usPSXMem,int iSize);
36 void SPUwriteDMAMem(u32 usPSXMem,int iSize);
37 u16 SPUreadRegister(u32 reg);
38
38 void SPUinjectRAMImage(uint16_t *pIncoming);
39 void SPUreadDMAMem(uint32_t usPSXMem, int iSize);
40 void SPUwriteDMAMem(uint32_t usPSXMem, int iSize);
41 uint16_t SPUreadRegister(uint32_t reg);
4242
4343 unsigned long RateTable[160];
4444
45 void InitADSR(void) // INIT ADSR
45 static void InitADSR(void) // INIT ADSR
4646 {
4747 unsigned long r,rs,rd;int i;
4848
6565
6666 ////////////////////////////////////////////////////////////////////////
6767
68 void StartADSR(int ch) // MIX ADSR
68 static void StartADSR(int ch) // MIX ADSR
6969 {
7070 s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars
7171 s_chan[ch].ADSRX.State=0;
7474
7575 ////////////////////////////////////////////////////////////////////////
7676
77 int MixADSR(int ch) // MIX ADSR
77 static int MixADSR(int ch) // MIX ADSR
7878 {
7979 if(s_chan[ch].bStop) // should be stopped:
8080 { // do release
3030
3131 #define _IN_DMA
3232
33 #include "../peops2/dma.h"
3334 #include "../peops2/externals.h"
3435 #include "../peops2/registers.h"
3536 //#include "debug.h"
2323 //
2424 //*************************************************************************//
2525
26 #include <stdint.h>
27
2628 void InterruptDMA4(void);
27 void InterruptDMA7(void);
28
29 void InterruptDMA7(void);
30
31 void SPU2readDMA4Mem(uint32_t usPSXMem,int iSize);
32 void SPU2writeDMA4Mem(uint32_t usPSXMem,int iSize);
33 void SPU2readDMA7Mem(uint32_t usPSXMem,int iSize);
34 void SPU2writeDMA7Mem(uint32_t usPSXMem,int iSize);
35 void SPU2interruptDMA4(void);
36 void SPU2interruptDMA7(void);
905905 return regArea[r>>1];
906906 }
907907
908 #if 0
908909 EXPORT_GCC void CALLBACK SPU2writePS1Port(unsigned long reg, unsigned short val)
909910 {
910911 const u32 r=reg&0xfff;
11081109
11091110 return 0;
11101111 }
1112 #endif
11111113
11121114 ////////////////////////////////////////////////////////////////////////
11131115 // SOUND ON register write
103103 #define PS2_C1_SPUend2 (0x400 + 0x342)
104104
105105 #define H_SPUReverbAddr 0x0da2
106
106
107107 #define H_SPUirqAddr 0x0da4
108
108
109109 #define H_SPUaddr 0x0da6
110
110
111111 #define H_SPUdata 0x0da8
112
112
113113 #define H_SPUctrl 0x0daa
114
114
115115 #define H_SPUstat 0x0dae
116
116
117117 #define H_SPUmvolL 0x0d80
118
118
119119 #define H_SPUmvolR 0x0d82
120
120
121121 #define H_SPUrvolL 0x0d84
122
122
123123 #define H_SPUrvolR 0x0d86
124
124
125125 #define H_SPUon1 0x0d88
126
126
127127 #define H_SPUon2 0x0d8a
128
128
129129 #define H_SPUoff1 0x0d8c
130
130
131131 #define H_SPUoff2 0x0d8e
132
132
133133 #define H_FMod1 0x0d90
134
134
135135 #define H_FMod2 0x0d92
136
136
137137 #define H_Noise1 0x0d94
138
138
139139 #define H_Noise2 0x0d96
140
140
141141 #define H_RVBon1 0x0d98
142
142
143143 #define H_RVBon2 0x0d9a
144144 #define H_SPUMute1 0x0d9c
145145 #define H_SPUMute2 0x0d9e
149149 #define H_ExtRight 0x0db6
150150 #define H_Reverb 0x0dc0
151151
152 unsigned short SPU2read(unsigned long reg);
153 void SPU2write(unsigned long reg, unsigned short val);
152154
153155 //###########################################################################
154156
174176
175177 SD_S_PMON - Pitch mod; assuming identical to PS1
176178 SD_S_NON - Noise; assuming identical to PS1
177 SD_S_VMIXL, SD_S_VMIXR - Voice mix L/R. Guessing this is just a separate L/R version
179 SD_S_VMIXL, SD_S_VMIXR - Voice mix L/R. Guessing this is just a separate L/R version
178180 of the "voice enable" bits on the PS1.
179181 SD_S_VMIXEL, SD_S_VMIXER - Voice effect mix L/R. Guessing this is just a separate L/R
180182 version of the "voice reverb enable" bits on the PS1.
244246 SPU CORE1's DMA channel is 7
245247
246248 DMA channel 10 is SIF
247
249
248250 Original INTR controller at 1F801000-1F80107F
249251
250252 All interrupt handling seems to be done using the old INTR, but
367369 1D000030 (word) - read counter of some sort?
368370 1D000040 (word) - read bits 0x20, 0x40 mean something
369371 1D000060 (word) - used to detect whether the SIF interface exists
370 read must be 0x1D000060, or the top 20 bits must be zero
372 read must be 0x1D000060, or the top 20 bits must be zero
371373 */
372374
373375 /*
411413 #define IOP_INT_USB (1<<22)
412414 #define IOP_INT_EXTR (1<<23)
413415 #define IOP_INT_FWRE (1<<24)
414 #define IOP_INT_FDMA (1<<25)
416 #define IOP_INT_FDMA (1<<25)
415417
416418 // CORE0 => +0x000, CORE1 => +0x400
417419
440442 #define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right)
441443 #define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below)
442444 #define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below)
443 #define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address
445 #define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address
444446 #define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation)
445447 #define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation)
446448 #define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address
450452
451453 #define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address
452454
453 #define FB_SRC_A(cr) (0x400 * cr + 0x2E4)
454 #define FB_SRC_B(cr) (0x400 * cr + 0x2E8)
455 #define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC)
456 #define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0)
457 #define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4)
455 #define FB_SRC_A(cr) (0x400 * cr + 0x2E4)
456 #define FB_SRC_B(cr) (0x400 * cr + 0x2E8)
457 #define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC)
458 #define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0)
459 #define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4)
458460 #define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8)
459 #define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC)
460
461 #define ACC_SRC_B1(cr) (0x400 * cr + 0x300)
462 #define IIR_SRC_A0(cr) (0x400 * cr + 0x304)
463 #define IIR_SRC_A1(cr) (0x400 * cr + 0x308)
464 #define IIR_DEST_B0(cr) (0x400 * cr + 0x30C)
465 #define IIR_DEST_B1(cr) (0x400 * cr + 0x310)
466 #define ACC_SRC_C0(cr) (0x400 * cr + 0x314)
467 #define ACC_SRC_C1(cr) (0x400 * cr + 0x318)
468
469 #define ACC_SRC_D0(cr) (0x400 * cr + 0x31C)
470 #define ACC_SRC_D1(cr) (0x400 * cr + 0x320)
471 #define IIR_SRC_B1(cr) (0x400 * cr + 0x324)
472 #define IIR_SRC_B0(cr) (0x400 * cr + 0x328)
473 #define MIX_DEST_A0(cr) (0x400 * cr + 0x32C)
474 #define MIX_DEST_A1(cr) (0x400 * cr + 0x330)
475 #define MIX_DEST_B0(cr) (0x400 * cr + 0x334)
476 #define MIX_DEST_B1(cr) (0x400 * cr + 0x338)
461 #define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC)
462
463 #define ACC_SRC_B1(cr) (0x400 * cr + 0x300)
464 #define IIR_SRC_A0(cr) (0x400 * cr + 0x304)
465 #define IIR_SRC_A1(cr) (0x400 * cr + 0x308)
466 #define IIR_DEST_B0(cr) (0x400 * cr + 0x30C)
467 #define IIR_DEST_B1(cr) (0x400 * cr + 0x310)
468 #define ACC_SRC_C0(cr) (0x400 * cr + 0x314)
469 #define ACC_SRC_C1(cr) (0x400 * cr + 0x318)
470
471 #define ACC_SRC_D0(cr) (0x400 * cr + 0x31C)
472 #define ACC_SRC_D1(cr) (0x400 * cr + 0x320)
473 #define IIR_SRC_B1(cr) (0x400 * cr + 0x324)
474 #define IIR_SRC_B0(cr) (0x400 * cr + 0x328)
475 #define MIX_DEST_A0(cr) (0x400 * cr + 0x32C)
476 #define MIX_DEST_A1(cr) (0x400 * cr + 0x330)
477 #define MIX_DEST_B0(cr) (0x400 * cr + 0x334)
478 #define MIX_DEST_B1(cr) (0x400 * cr + 0x338)
477479
478480 #define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address
479481
494496 #define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left)
495497 #define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right)
496498
497 #define IIR_ALPHA(cr) (0x28 * cr + 0x774)
498 #define ACC_COEF_A(cr) (0x28 * cr + 0x776)
499 #define ACC_COEF_B(cr) (0x28 * cr + 0x778)
500 #define ACC_COEF_C(cr) (0x28 * cr + 0x77A)
501 #define ACC_COEF_D(cr) (0x28 * cr + 0x77C)
502 #define IIR_COEF(cr) (0x28 * cr + 0x77E)
503 #define FB_ALPHA(cr) (0x28 * cr + 0x780)
504 #define FB_X(cr) (0x28 * cr + 0x782)
505 #define IN_COEF_L(cr) (0x28 * cr + 0x784)
506 #define IN_COEF_R(cr) (0x28 * cr + 0x786)
499 #define IIR_ALPHA(cr) (0x28 * cr + 0x774)
500 #define ACC_COEF_A(cr) (0x28 * cr + 0x776)
501 #define ACC_COEF_B(cr) (0x28 * cr + 0x778)
502 #define ACC_COEF_C(cr) (0x28 * cr + 0x77A)
503 #define ACC_COEF_D(cr) (0x28 * cr + 0x77C)
504 #define IIR_COEF(cr) (0x28 * cr + 0x77E)
505 #define FB_ALPHA(cr) (0x28 * cr + 0x780)
506 #define FB_X(cr) (0x28 * cr + 0x782)
507 #define IN_COEF_L(cr) (0x28 * cr + 0x784)
508 #define IN_COEF_R(cr) (0x28 * cr + 0x786)
507509
508510 // CORE1 only => +0x400
509511
510 #define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
512 #define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
511513 #define SPDIF_MODE 0x7C6
512 #define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD
514 #define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD
513515 #define SPDIF_COPY 0x7CA // SPDIF Copy Protection
514516
515517 // PS1 SPU CORE
528530 #define SPU_P_RVOLL 0xD84 // effect return volume (left)
529531 #define SPU_P_RVOLR 0xD86 // effect return volume (right)
530532 #define SPU_S_KON1 0xD88 // key on
531 #define SPU_S_KON2 0xD8A //
533 #define SPU_S_KON2 0xD8A //
532534 #define SPU_S_KOFF1 0xD8C // key off
533 #define SPU_S_KOFF2 0xD8E //
535 #define SPU_S_KOFF2 0xD8E //
534536 #define SPU_S_PMON1 0xD90 // pitch modulation on
535 #define SPU_S_PMON2 0xD92 //
537 #define SPU_S_PMON2 0xD92 //
536538 #define SPU_S_NON1 0xD94 // noise generator on
537 #define SPU_S_NON2 0xD96 //
539 #define SPU_S_NON2 0xD96 //
538540 #define SPU_S_RVBON1 0xD98 // effects on
539 #define SPU_S_RVBON2 0xD9A //
541 #define SPU_S_RVBON2 0xD9A //
540542 #define SPU_S_MUTE1 0xD9C // voice mute
541 #define SPU_S_MUTE2 0xD9E //
543 #define SPU_S_MUTE2 0xD9E //
542544
543545 #define SPU_A_ESA 0xDA2 // effects work area start
544546 #define SPU_A_IRQA 0xDA4 // IRQ address
584586 #define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right)
585587 #define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below)
586588 #define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below)
587 #define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address
589 #define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address
588590 #define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation)
589591 #define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation)
590592 #define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address
598600 // Core 0 Reverb Addresses
599601
600602
601 #define FB_SRC_A(cr) (0x400 * cr + 0x2E4)
602 #define FB_SRC_B(cr) (0x400 * cr + 0x2E8)
603 #define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC)
604 #define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0)
605 #define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4)
603 #define FB_SRC_A(cr) (0x400 * cr + 0x2E4)
604 #define FB_SRC_B(cr) (0x400 * cr + 0x2E8)
605 #define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC)
606 #define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0)
607 #define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4)
606608 #define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8)
607 #define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC)
608
609 #define ACC_SRC_B1(cr) (0x400 * cr + 0x300)
610 #define IIR_SRC_A0(cr) (0x400 * cr + 0x304)
611 #define IIR_SRC_A1(cr) (0x400 * cr + 0x308)
612 #define IIR_DEST_B0(cr) (0x400 * cr + 0x30C)
613 #define IIR_DEST_B1(cr) (0x400 * cr + 0x310)
614 #define ACC_SRC_C0(cr) (0x400 * cr + 0x314)
615 #define ACC_SRC_C1(cr) (0x400 * cr + 0x318)
616
617 #define ACC_SRC_D0(cr) (0x400 * cr + 0x31C)
618 #define ACC_SRC_D1(cr) (0x400 * cr + 0x320)
619 #define IIR_SRC_B1(cr) (0x400 * cr + 0x324)
620 #define IIR_SRC_B0(cr) (0x400 * cr + 0x328)
621 #define MIX_DEST_A0(cr) (0x400 * cr + 0x32C)
622 #define MIX_DEST_A1(cr) (0x400 * cr + 0x330)
623 #define MIX_DEST_B0(cr) (0x400 * cr + 0x334)
624 #define MIX_DEST_B1(cr) (0x400 * cr + 0x338)
609 #define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC)
610
611 #define ACC_SRC_B1(cr) (0x400 * cr + 0x300)
612 #define IIR_SRC_A0(cr) (0x400 * cr + 0x304)
613 #define IIR_SRC_A1(cr) (0x400 * cr + 0x308)
614 #define IIR_DEST_B0(cr) (0x400 * cr + 0x30C)
615 #define IIR_DEST_B1(cr) (0x400 * cr + 0x310)
616 #define ACC_SRC_C0(cr) (0x400 * cr + 0x314)
617 #define ACC_SRC_C1(cr) (0x400 * cr + 0x318)
618
619 #define ACC_SRC_D0(cr) (0x400 * cr + 0x31C)
620 #define ACC_SRC_D1(cr) (0x400 * cr + 0x320)
621 #define IIR_SRC_B1(cr) (0x400 * cr + 0x324)
622 #define IIR_SRC_B0(cr) (0x400 * cr + 0x328)
623 #define MIX_DEST_A0(cr) (0x400 * cr + 0x32C)
624 #define MIX_DEST_A1(cr) (0x400 * cr + 0x330)
625 #define MIX_DEST_B0(cr) (0x400 * cr + 0x334)
626 #define MIX_DEST_B1(cr) (0x400 * cr + 0x338)
625627
626628 #define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address
627629
648650 // More CORE 0 Reverb
649651
650652
651 #define IIR_ALPHA(cr) (0x28 * cr + 0x774)
652 #define ACC_COEF_A(cr) (0x28 * cr + 0x776)
653 #define ACC_COEF_B(cr) (0x28 * cr + 0x778)
654 #define ACC_COEF_C(cr) (0x28 * cr + 0x77A)
655 #define ACC_COEF_D(cr) (0x28 * cr + 0x77C)
656 #define IIR_COEF(cr) (0x28 * cr + 0x77E)
657 #define FB_ALPHA(cr) (0x28 * cr + 0x780)
658 #define FB_X(cr) (0x28 * cr + 0x782)
659 #define IN_COEF_L(cr) (0x28 * cr + 0x784)
660 #define IN_COEF_R(cr) (0x28 * cr + 0x786)
653 #define IIR_ALPHA(cr) (0x28 * cr + 0x774)
654 #define ACC_COEF_A(cr) (0x28 * cr + 0x776)
655 #define ACC_COEF_B(cr) (0x28 * cr + 0x778)
656 #define ACC_COEF_C(cr) (0x28 * cr + 0x77A)
657 #define ACC_COEF_D(cr) (0x28 * cr + 0x77C)
658 #define IIR_COEF(cr) (0x28 * cr + 0x77E)
659 #define FB_ALPHA(cr) (0x28 * cr + 0x780)
660 #define FB_X(cr) (0x28 * cr + 0x782)
661 #define IN_COEF_L(cr) (0x28 * cr + 0x784)
662 #define IN_COEF_R(cr) (0x28 * cr + 0x786)
661663
662664
663665 // CORE 1 only
664666
665 #define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
666 #define SPDIF_MODE 0x7C6
667 #define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD
667 #define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
668 #define SPDIF_MODE 0x7C6
669 #define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD
668670 #define SPDIF_COPY 0x7CA // SPDIF Copy Protection
669671 */
670672
687689 #define SPU_P_RVOLL 0xD84 // effect return volume (left)
688690 #define SPU_P_RVOLR 0xD86 // effect return volume (right)
689691 #define SPU_S_KON1 0xD88 // key on
690 #define SPU_S_KON2 0xD8A //
692 #define SPU_S_KON2 0xD8A //
691693 #define SPU_S_KOFF1 0xD8C // key off
692 #define SPU_S_KOFF2 0xD8E //
694 #define SPU_S_KOFF2 0xD8E //
693695 #define SPU_S_PMON1 0xD90 // pitch modulation on
694 #define SPU_S_PMON2 0xD92 //
696 #define SPU_S_PMON2 0xD92 //
695697 #define SPU_S_NON1 0xD94 // noise generator on
696 #define SPU_S_NON2 0xD96 //
698 #define SPU_S_NON2 0xD96 //
697699 #define SPU_S_RVBON1 0xD98 // effects on
698 #define SPU_S_RVBON2 0xD9A //
700 #define SPU_S_RVBON2 0xD9A //
699701 #define SPU_S_MUTE1 0xD9C // voice mute
700 #define SPU_S_MUTE2 0xD9E //
702 #define SPU_S_MUTE2 0xD9E //
701703
702704 #define SPU_A_ESA 0xDA2 // effects work area start
703705 #define SPU_A_IRQA 0xDA4 // IRQ address
3838 void ReverbOn(int start,int end,unsigned short val,int iRight);
3939 void SetReverbAddr(int core);
4040
41 EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val);
42
5656 // START REVERB
5757 ////////////////////////////////////////////////////////////////////////
5858
59 void StartREVERB(int ch)
59 static void StartREVERB(int ch)
6060 {
6161 int core=ch/24;
6262
8484 // STORE REVERB
8585 ////////////////////////////////////////////////////////////////////////
8686
87 void StoreREVERB(int ch,int ns)
87 static void StoreREVERB(int ch,int ns)
8888 {
8989 int core=ch/24;
9090
141141
142142 ////////////////////////////////////////////////////////////////////////
143143
144 int MixREVERBLeft(int ns,int core)
144 static int MixREVERBLeft(int ns,int core)
145145 {
146146 if(iUseReverb==1)
147147 {
228228
229229 ////////////////////////////////////////////////////////////////////////
230230
231 int MixREVERBRight(int core)
231 static int MixREVERBRight(int core)
232232 {
233233 if(iUseReverb==1) // Neill's reverb:
234234 {
101101 #include "../peops2/externals.h"
102102 #include "../peops2/regs.h"
103103 #include "../peops2/dma.h"
104 #include "../peops2/spu.h"
104105
105106 ////////////////////////////////////////////////////////////////////////
106107 // globals
335336 return(0);
336337 }
337338
339 static int endless;
340 void setendless2(int e)
341 {
342 endless=e;
343 }
344
338345 // Counting to 65536 results in full volume offage.
339346 void setlength2(s32 stop, s32 fade)
340347 {
341 if(stop==~0)
348 if(stop==~0 || endless)
342349 {
343350 decaybegin=~0;
344351 }
741748 if(sampcount>=decaybegin)
742749 {
743750 s32 dmul;
744 if(decaybegin!=~0) // Is anyone REALLY going to be playing a song
751 if(decaybegin!=~0U) // Is anyone REALLY going to be playing a song
745752 // for 13 hours?
746753 {
747754 if(sampcount>=decayend)
992999 RemoveStreams(); // no more streaming
9931000 }
9941001
1002 #if 0
9951003 ////////////////////////////////////////////////////////////////////////
9961004 // SPUSHUTDOWN: called by main emu on final exit
9971005 ////////////////////////////////////////////////////////////////////////
10331041 {
10341042 cddavCallback = CDDAVcallback;
10351043 }
1044 #endif
2626 //
2727 //*************************************************************************//
2828
29 void setendless2(int e);
30 void setlength2(int32_t stop, int32_t fade);
2931
30 void SetupTimer(void);
31 void RemoveTimer(void);
32 EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap);
32 long SPU2init(void);
33 long SPU2open(void *pDsp);
34 void SPU2async(void (*update)(const void *, int));
35 void SPU2close(void);
3336
34 EXPORT_GCC long CALLBACK SPU2init(void);
35 EXPORT_GCC long CALLBACK SPU2open(void *pDsp);
36 EXPORT_GCC void CALLBACK SPU2async(void (*update)(const void *, int));
37 EXPORT_GCC void CALLBACK SPU2close(void);
38 EXPORT_GCC int CALLBACK psf2_seek(u32 t);
37 int psf2_seek(uint32_t t);
2929
3030 #include <libaudcore/i18n.h>
3131 #include <libaudcore/plugin.h>
32 #include <libaudcore/preferences.h>
3233 #include <libaudcore/audstrings.h>
34 #include <libaudcore/runtime.h>
3335
3436 #include "ao.h"
3537 #include "corlett.h"
36 #include "eng_protos.h"
38 #include "psx.h"
39
40 #include "peops/spu.h"
41 #include "peops2/spu.h"
3742
3843 class PSFPlugin : public InputPlugin
3944 {
4045 public:
4146 static const char *const exts[];
47 static const char *const defaults[];
48 static const PreferencesWidget widgets[];
49 static const PluginPreferences prefs;
4250
4351 static constexpr PluginInfo info = {
4452 N_("OpenPSF PSF1/PSF2 Decoder"),
45 PACKAGE
53 PACKAGE,
54 nullptr,
55 & prefs
56
4657 };
4758
4859 constexpr PSFPlugin() : InputPlugin(info, InputInfo()
4960 .with_exts(exts)) {}
61
62 bool init();
5063
5164 bool is_our_file(const char *filename, VFSFile &file);
5265 bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
8093 {spx_start, spx_stop, psf_seek, spx_execute},
8194 };
8295
96 const char* const PSFPlugin::defaults[] =
97 {
98 "ignore_length", "FALSE",
99 nullptr
100 };
101
102 bool PSFPlugin::init()
103 {
104 aud_config_set_defaults("psf", defaults);
105 return true;
106 }
107
83108 static PSFEngineFunctors *f;
84109 static String dirpath;
85110
152177
153178 Index<char> buf = file.read_all ();
154179
180 bool ignore_len = aud_get_bool("psf", "ignore_length");
181
155182 PSFEngine eng = psf_probe(buf.begin(), buf.len());
156183 if (eng == ENG_NONE || eng == ENG_COUNT)
157184 {
158185 error = true;
159186 goto cleanup;
160187 }
188
189 if(eng == ENG_PSF1 || eng == ENG_SPX)
190 setendless(ignore_len);
191
192 if(eng == ENG_PSF2)
193 setendless2(ignore_len);
161194
162195 f = &psf_functor_map[eng];
163196
230263 }
231264
232265 const char *const PSFPlugin::exts[] = { "psf", "minipsf", "psf2", "minipsf2", "spu", "spx", nullptr };
266
267 const PreferencesWidget PSFPlugin::widgets[] = {
268 WidgetLabel(N_("<b>OpenPSF Configuration</b>")),
269 WidgetCheck(N_("Ignore length from file"), WidgetBool("psf", "ignore_length")),
270 };
271
272 const PluginPreferences PSFPlugin::prefs = {{widgets}};
5959 #define CAUSE_CE1 ( 1L << 28 )
6060 #define CAUSE_CE2 ( 2L << 28 )
6161 #define CAUSE_BD ( 1L << 31 )
62
63 extern void psx_bios_hle(uint32_t pc);
64 extern void psx_iop_call(uint32_t pc, uint32_t callnum);
65 extern uint8_t program_read_byte_32le(offs_t address);
66 extern uint16_t program_read_word_32le(offs_t address);
67 extern uint32_t program_read_dword_32le(offs_t address);
68 extern void program_write_byte_32le(offs_t address, uint8_t data);
69 extern void program_write_word_32le(offs_t address, uint16_t data);
70 extern void program_write_dword_32le(offs_t address, uint32_t data);
7162
7263 static uint8_t mips_reg_layout[] =
7364 {
212203 };
213204
214205 #if 1
215 void GTELOG(const char *a,...)
206 static void GTELOG(const char *a,...)
216207 {
217208 va_list va;
218209 char s_text[ 1024 ];
232223 static void docop2( int gteop );
233224 static void mips_exception( int exception );
234225
235 void mips_stop( void )
226 static void mips_stop( void )
236227 {
237228 #ifdef MAME_DEBUG
238229 extern int debug_key_pressed;
17221713 * Return a formatted string for a register
17231714 ****************************************************************************/
17241715
1725 offs_t mips_dasm( char *buffer, offs_t pc )
1716 static offs_t mips_dasm( char *buffer, offs_t pc )
17261717 {
17271718 offs_t ret;
17281719 change_pc( pc );
44 //#include "driver.h"
55
66 typedef void genf(void);
7 typedef int offs_t;
7 typedef uint32_t offs_t;
88
99 #define cpu_readop32(pc) program_read_dword_32le(pc)
1010 #define change_pc(pc) \
284284 extern void psxcpu_get_info(uint32_t state, union cpuinfo *info);
285285 #endif
286286
287 #endif
287 /* eng_psf.cc */
288 extern int psf_refresh;
289
290 int32_t psf_start(uint8_t *buffer, uint32_t length);
291 int32_t psf_execute(void (*update)(const void *, int));
292 int32_t psf_stop(void);
293
294 /* eng_psf2.cc */
295 uint32_t psf2_load_elf(uint8_t *start, uint32_t len);
296 uint32_t psf2_load_file(const char *file, uint8_t *buf, uint32_t buflen);
297 int32_t psf2_start(uint8_t *, uint32_t length);
298 int32_t psf2_execute(void (*update)(const void *, int));
299 int32_t psf2_stop(void);
300 int32_t psf2_command(int32_t, int32_t);
301 uint32_t psf2_get_loadaddr(void);
302 void psf2_set_loadaddr(uint32_t addr);
303
304 /* eng_spx.cc */
305 int32_t spx_start(uint8_t *buffer, uint32_t length);
306 int32_t spx_execute(void (*update)(const void *, int));
307 int32_t spx_stop(void);
308
309 /* plugin.cc */
310 extern bool stop_flag;
311
312 /* psx.cc */
313 void mips_init(void);
314 void mips_reset(void *param);
315 void mips_shorten_frame(void);
316 int mips_execute(int cycles);
317 void mips_set_info(uint32_t state, union cpuinfo *info);
318 void mips_get_info(uint32_t state, union cpuinfo *info);
319 uint32_t mips_get_cause(void);
320 uint32_t mips_get_status(void);
321 void mips_set_status(uint32_t status);
322 uint32_t mips_get_ePC(void);
323 int mips_get_icount(void);
324 void mips_set_icount(int count);
325
326 /* psx_hw.cc */
327 extern uint32_t psx_ram[((2*1024*1024)/4)+4];
328 extern uint32_t psx_scratch[0x400];
329 extern uint32_t initial_ram[((2*1024*1024)/4)+4];
330 extern uint32_t initial_scratch[0x400];
331
332 void psx_hw_slice(void);
333 void ps2_hw_slice(void);
334 void psx_hw_frame(void);
335 void ps2_hw_frame(void);
336
337 void psx_hw_init(void);
338 void psx_bios_hle(uint32_t pc);
339 void psx_hw_runcounters(void);
340
341 uint8_t program_read_byte_32le(offs_t address);
342 uint16_t program_read_word_32le(offs_t address);
343 uint32_t program_read_dword_32le(offs_t address);
344
345 void program_write_byte_32le(offs_t address, uint8_t data);
346 void program_write_word_32le(offs_t address, uint16_t data);
347 void program_write_dword_32le(offs_t address, uint32_t data);
348
349 void psx_iop_call(uint32_t pc, uint32_t callnum);
350
351 #endif
5151 #include "cpuintrf.h"
5252 #include "psx.h"
5353
54 #include "peops/dma.h"
55 #include "peops/registers.h"
56 #include "peops/spu.h"
57 #include "peops2/dma.h"
58 #include "peops2/registers.h"
59
5460 #define DEBUG_HLE_BIOS (0) // debug PS1 HLE BIOS
5561 #define DEBUG_SPU (0) // debug PS1 SPU read/write
5662 #define DEBUG_SPU2 (0) // debug PS2 SPU read/write
6066
6167 #define LE32(x) FROM_LE32(x)
6268
63 extern void mips_get_info(uint32_t state, union cpuinfo *info);
64 extern void mips_set_info(uint32_t state, union cpuinfo *info);
65 extern int psxcpu_verbose;
66 extern uint16_t SPUreadRegister(uint32_t reg);
67 extern void SPUwriteRegister(uint32_t reg, uint16_t val);
68 extern void SPUwriteDMAMem(uint32_t usPSXMem,int iSize);
69 extern void SPUreadDMAMem(uint32_t usPSXMem,int iSize);
70 extern void mips_shorten_frame(void);
71 extern int mips_execute( int cycles );
72 extern uint32_t psf2_load_file(const char *file, uint8_t *buf, uint32_t buflen);
73 extern uint32_t psf2_load_elf(uint8_t *start, uint32_t len);
74 void psx_hw_runcounters(void);
75 int mips_get_icount(void);
76 void mips_set_icount(int count);
77
78 extern int psf_refresh;
79
80 // SPU2
81 extern void SPU2write(unsigned long reg, unsigned short val);
82 extern unsigned short SPU2read(unsigned long reg);
83 extern void SPU2readDMA4Mem(uint32_t usPSXMem,int iSize);
84 extern void SPU2writeDMA4Mem(uint32_t usPSXMem,int iSize);
85 extern void SPU2readDMA7Mem(uint32_t usPSXMem,int iSize);
86 extern void SPU2writeDMA7Mem(uint32_t usPSXMem,int iSize);
87 extern void SPU2interruptDMA4(void);
88 extern void SPU2interruptDMA7(void);
89
9069 #define MAX_FILE_SLOTS (32)
9170
9271 static volatile int softcall_target = 0;
9372 static int filestat[MAX_FILE_SLOTS];
9473 static uint8_t *filedata[MAX_FILE_SLOTS];
9574 static uint32_t filesize[MAX_FILE_SLOTS], filepos[MAX_FILE_SLOTS];
96 uint32_t psf2_get_loadaddr(void);
97 void psf2_set_loadaddr(uint32_t addr);
9875 static void call_irq_routine(uint32_t routine, uint32_t parameter);
9976 static int intr_susp = 0;
10077
235212 #define EvMdNOINTR 0x2000
236213
237214 // PSX main RAM
238 uint32_t psx_ram[(2*1024*1024)/4];
215 uint32_t psx_ram[(2*1024*1024)/4+4];
239216 uint32_t psx_scratch[0x400];
240217 // backup image to restart songs
241 uint32_t initial_ram[(2*1024*1024)/4];
218 uint32_t initial_ram[(2*1024*1024)/4+4];
242219 uint32_t initial_scratch[0x400];
243220
244221 static uint32_t spu_delay, dma_icr, irq_data, irq_mask, dma_timer, WAI;
467444 }
468445 }
469446
470 void psx_irq_set(uint32_t irq)
447 static void psx_irq_set(uint32_t irq)
471448 {
472449 irq_data |= irq;
473450
476453
477454 static uint32_t gpu_stat = 0;
478455
479 uint32_t psx_hw_read(offs_t offset, uint32_t mem_mask)
480 {
481 if (offset >= 0x00000000 && offset <= 0x007fffff)
456 static uint32_t psx_hw_read(offs_t offset, uint32_t mem_mask)
457 {
458 if (offset <= 0x007fffff)
482459 {
483460 offset &= 0x1fffff;
484461 return LE32(psx_ram[offset>>2]);
669646 dma7_delay = 80;
670647 }
671648
672 void psx_hw_write(offs_t offset, uint32_t data, uint32_t mem_mask)
649 static void psx_hw_write(offs_t offset, uint32_t data, uint32_t mem_mask)
673650 {
674651 union cpuinfo mipsinfo;
675652
676 if (offset >= 0x00000000 && offset <= 0x007fffff)
653 if (offset <= 0x007fffff)
677654 {
678655 offset &= 0x1fffff;
679656 // if (offset < 0x10000) printf("Write %x to kernel @ %x\n", data, offset);
951928 };
952929
953930 static uint32_t heap_addr, entry_int = 0;
954
955 extern uint32_t mips_get_cause(void);
956 extern uint32_t mips_get_status(void);
957 extern void mips_set_status(uint32_t status);
958 extern uint32_t mips_get_ePC(void);
959931
960932 static uint32_t irq_regs[37];
961933
10371009 irq_mutex = 0;
10381010 }
10391011
1040 void psx_bios_exception(uint32_t pc)
1012 static void psx_bios_exception(uint32_t pc)
10411013 {
10421014 uint32_t a0, status;
10431015 union cpuinfo mipsinfo;
32153187
32163188 // filter out ESC characters
32173189 {
3218 int ch;
3190 size_t ch;
32193191
32203192 for (ch = 0; ch < strlen(out); ch++)
32213193 {
32663238 if (psf2_load_file(mname, tempmem, 2*1024*1024) != 0xffffffff)
32673239 {
32683240 uint32_t start;
3269 int i;
3241 uint32_t i;
32703242
32713243 start = psf2_load_elf(tempmem, 2*1024*1024);
32723244
0 pulse_dep = dependency('libpulse', version: '>= 0.9.5', required: false)
1
2
3 if pulse_dep.found()
4 shared_module('pulse_audio',
5 'pulse_audio.cc',
6 dependencies: [audacious_dep, pulse_dep, glib_dep],
7 install: true,
8 install_dir: output_plugin_dir
9 )
10 endif
11
1919 USA.
2020 ***/
2121
22 #include <condition_variable>
23 #include <mutex>
24
2522 #include <pulse/pulseaudio.h>
2623
24 #include <libaudcore/i18n.h>
25 #include <libaudcore/plugin.h>
2726 #include <libaudcore/runtime.h>
28 #include <libaudcore/plugin.h>
29 #include <libaudcore/i18n.h>
30
31 using scoped_lock = std::unique_lock<std::mutex>;
27 #include <libaudcore/threads.h>
28 #include <libaudcore/preferences.h>
3229
3330 class PulseOutput : public OutputPlugin
3431 {
3532 public:
3633 static const char about[];
34 static const PreferencesWidget widgets[];
35 static const PluginPreferences prefs;
36 static const char * const prefs_defaults[];
37 static const String default_context_name;
38 static const String default_stream_name;
3739
3840 static constexpr PluginInfo info = {
3941 N_("PulseAudio Output"),
4042 PACKAGE,
41 about
43 about,
44 & prefs
4245 };
4346
4447 constexpr PulseOutput () : OutputPlugin (info, 8) {}
6467
6568 EXPORT PulseOutput aud_plugin_instance;
6669
67 static std::mutex pulse_mutex;
68 static std::condition_variable pulse_cond;
70 const PreferencesWidget PulseOutput::widgets[] = {
71 WidgetEntry (N_("Context name:"),
72 WidgetString ("pulse", "context_name")),
73 WidgetEntry (N_("Stream name:"),
74 WidgetString ("pulse", "stream_name")),
75 };
76
77 const PluginPreferences PulseOutput::prefs = {{widgets}};
78
79 const String PulseOutput::default_context_name = String ("Audacious");
80 const String PulseOutput::default_stream_name = String ("Audacious");
81
82 const char * const PulseOutput::prefs_defaults[] = {
83 "context_name", PulseOutput::default_context_name,
84 "stream_name", PulseOutput::default_stream_name,
85 nullptr
86 };
87
88 static aud::mutex pulse_mutex;
89 static aud::condvar pulse_cond;
6990
7091 static pa_context * context = nullptr;
7192 static pa_stream * stream = nullptr;
88109 /* Cooperative polling method. Only one thread calls the actual poll function,
89110 * and dispatches the events received. Any other threads simply wait for the
90111 * first thread to finish. */
91 static void poll_events (scoped_lock & lock)
112 static void poll_events (aud::mutex::holder & lock)
92113 {
93114 if (polling)
94115 pulse_cond.wait (lock);
112133
113134 /* Wait for an asynchronous operation to complete. Return immediately if the
114135 * connection dies. */
115 static bool finish (pa_operation * op, scoped_lock & lock)
136 static bool finish (pa_operation * op, aud::mutex::holder & lock)
116137 {
117138 pa_operation_state_t state;
118139 while ((state = pa_operation_get_state (op)) != PA_OPERATION_DONE && alive ())
173194 * (int * ) userdata = success;
174195 }
175196
176 static void get_volume_locked ()
197 static void get_volume_locked (aud::mutex::holder & lock)
177198 {
178199 if (! polling)
179200 {
198219
199220 StereoVolume PulseOutput::get_volume ()
200221 {
201 scoped_lock lock (pulse_mutex);
222 auto lock = pulse_mutex.take ();
202223
203224 if (connected)
204 get_volume_locked ();
225 get_volume_locked (lock);
205226
206227 return saved_volume;
207228 }
208229
209 static void set_volume_locked (scoped_lock & lock)
230 static void set_volume_locked (aud::mutex::holder & lock)
210231 {
211232 if (volume.channels != 1)
212233 {
230251
231252 void PulseOutput::set_volume (StereoVolume v)
232253 {
233 scoped_lock lock (pulse_mutex);
254 auto lock = pulse_mutex.take ();
234255
235256 saved_volume = v;
236257 saved_volume_changed = true;
241262
242263 void PulseOutput::pause (bool pause)
243264 {
244 scoped_lock lock (pulse_mutex);
265 auto lock = pulse_mutex.take ();
245266
246267 int success = 0;
247268 CHECK (pa_stream_cork, stream, pause, stream_success_cb);
249270
250271 int PulseOutput::get_delay ()
251272 {
252 scoped_lock lock (pulse_mutex);
273 auto lock = pulse_mutex.take ();
253274
254275 pa_usec_t usec;
255276 int neg;
262283
263284 void PulseOutput::drain ()
264285 {
265 scoped_lock lock (pulse_mutex);
286 auto lock = pulse_mutex.take ();
266287
267288 int success = 0;
268289 CHECK (pa_stream_drain, stream, stream_success_cb);
270291
271292 void PulseOutput::flush ()
272293 {
273 scoped_lock lock (pulse_mutex);
294 auto lock = pulse_mutex.take ();
274295
275296 int success = 0;
276297 CHECK (pa_stream_flush, stream, stream_success_cb);
283304
284305 void PulseOutput::period_wait ()
285306 {
286 scoped_lock lock (pulse_mutex);
307 auto lock = pulse_mutex.take ();
287308
288309 int success = 0;
289310 CHECK (pa_stream_trigger, stream, stream_success_cb);
295316
296317 int PulseOutput::write_audio (const void * ptr, int length)
297318 {
298 scoped_lock lock (pulse_mutex);
319 auto lock = pulse_mutex.take ();
299320 int ret = 0;
300321
301322 length = aud::min ((size_t) length, pa_stream_writable_size (stream));
309330 return ret;
310331 }
311332
312 static void close_audio_locked (scoped_lock & lock)
333 static void close_audio_locked (aud::mutex::holder & lock)
313334 {
314335 /* wait for any parallel tasks (e.g. set_volume()) to complete */
315336 while (polling)
340361
341362 void PulseOutput::close_audio ()
342363 {
343 scoped_lock lock (pulse_mutex);
364 auto lock = pulse_mutex.take ();
344365 close_audio_locked (lock);
345366 }
346367
378399
379400 static void set_buffer_attr (pa_buffer_attr & buffer, const pa_sample_spec & ss)
380401 {
381 int buffer_ms = aud_get_int (nullptr, "output_buffer_size");
402 int buffer_ms = aud_get_int ("output_buffer_size");
382403 size_t buffer_size = pa_usec_to_bytes ((pa_usec_t) 1000 * buffer_ms, & ss);
383404
384405 buffer.maxlength = (uint32_t) -1;
388409 buffer.fragsize = buffer_size;
389410 }
390411
391 static bool create_context (scoped_lock & lock)
412 static String get_context_name ()
413 {
414 String context_name = aud_get_str ("pulse", "context_name");
415 if (context_name == String (""))
416 {
417 return PulseOutput::default_context_name;
418 }
419 return context_name;
420 }
421
422 static bool create_context (aud::mutex::holder & lock)
392423 {
393424 if (! (mainloop = pa_mainloop_new ()))
394425 {
396427 return false;
397428 }
398429
399 if (! (context = pa_context_new (pa_mainloop_get_api (mainloop), "Audacious")))
430 if (! (context = pa_context_new (pa_mainloop_get_api (mainloop), get_context_name ())))
400431 {
401432 AUDERR ("Failed to allocate context\n");
402433 return false;
424455 return true;
425456 }
426457
427 static bool create_stream (scoped_lock & lock, const pa_sample_spec & ss)
428 {
429 if (! (stream = pa_stream_new (context, "Audacious", & ss, nullptr)))
458 static String get_stream_name ()
459 {
460 String stream_name = aud_get_str ("pulse", "stream_name");
461 if (stream_name == String (""))
462 {
463 return PulseOutput::default_stream_name;
464 }
465 return stream_name;
466 }
467
468 static bool create_stream (aud::mutex::holder & lock, const pa_sample_spec & ss)
469 {
470 if (! (stream = pa_stream_new (context, get_stream_name (), & ss, nullptr)))
430471 {
431472 REPORT ("pa_stream_new");
432473 return false;
459500 return true;
460501 }
461502
462 static bool subscribe_events (scoped_lock & lock)
503 static bool subscribe_events (aud::mutex::holder & lock)
463504 {
464505 pa_context_set_subscribe_callback (context, subscribe_cb, nullptr);
465506
480521
481522 bool PulseOutput::open_audio (int fmt, int rate, int nch, String & error)
482523 {
483 scoped_lock lock (pulse_mutex);
524 auto lock = pulse_mutex.take ();
484525
485526 pa_sample_spec ss;
486527 if (! set_sample_spec (ss, fmt, rate, nch))
500541 if (saved_volume_changed)
501542 set_volume_locked (lock);
502543 else
503 get_volume_locked ();
544 get_volume_locked (lock);
504545
505546 return true;
506547 }
507548
508549 bool PulseOutput::init ()
509550 {
551 aud_config_set_defaults ("pulse", prefs_defaults);
552
510553 /* check for a running server and get initial volume */
511554 String error;
512555 if (! open_audio (FMT_S16_NE, 44100, 2, error))
0 PLUGIN = qt-spectrum${PLUGIN_SUFFIX}
1
2 SRCS = qt-spectrum.cc
3
4 include ../../buildsys.mk
5 include ../../extra.mk
6
7 plugindir := ${plugindir}/${VISUALIZATION_PLUGIN_DIR}
8
9 LD = ${CXX}
10 CFLAGS += ${PLUGIN_CFLAGS}
11 CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../.. ${QT_CFLAGS}
12 LIBS += -lm ${QT_LIBS} -laudqt
0 shared_module('qt-spectrum',
1 'qt-spectrum.cc',
2 dependencies: [audacious_dep, qt_dep, audqt_dep],
3 install: true,
4 install_dir: visualization_plugin_dir
5 )
0 /*
1 * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
11 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
15 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
16 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17 * POSSIBILITY OF SUCH DAMAGE.
18 */
19
20 #include <math.h>
21 #include <string.h>
22
23 #include <QWidget>
24 #include <QPainter>
25
26 #include <libaudcore/hook.h>
27 #include <libaudcore/i18n.h>
28 #include <libaudcore/interface.h>
29 #include <libaudcore/plugin.h>
30 #include <libaudqt/libaudqt.h>
31
32 #define MAX_BANDS (256)
33 #define VIS_DELAY 2 /* delay before falloff in frames */
34 #define VIS_FALLOFF 2 /* falloff in pixels per frame */
35
36 static float xscale[MAX_BANDS + 1];
37 static int bands;
38 static int bars[MAX_BANDS + 1];
39 static int delay[MAX_BANDS + 1];
40
41 class SpectrumWidget : public QWidget
42 {
43 public:
44 SpectrumWidget (QWidget * parent = nullptr);
45 ~SpectrumWidget ();
46
47 protected:
48 void resizeEvent (QResizeEvent *);
49 void paintEvent (QPaintEvent *);
50
51 private:
52 void paint_background (QPainter &);
53 void paint_spectrum (QPainter &);
54 };
55
56 static SpectrumWidget * spect_widget = nullptr;
57
58 SpectrumWidget::SpectrumWidget (QWidget * parent) :
59 QWidget (parent)
60 {
61 }
62
63 SpectrumWidget::~SpectrumWidget ()
64 {
65 spect_widget = nullptr;
66 }
67
68 void SpectrumWidget::paint_background (QPainter & p)
69 {
70 auto & base = palette ().color (QPalette::Window);
71 p.fillRect (0, 0, width (), height (), base);
72 }
73
74 void SpectrumWidget::paint_spectrum (QPainter & p)
75 {
76 for (int i = 0; i < bands; i++)
77 {
78 int x = ((width () / bands) * i) + 2;
79 auto color = audqt::vis_bar_color (palette ().color (QPalette::Highlight), i, bands);
80
81 p.fillRect (x + 1, height () - (bars[i] * height () / 40),
82 (width () / bands) - 1, (bars[i] * height () / 40), color);
83 }
84 }
85
86 void SpectrumWidget::resizeEvent (QResizeEvent * event)
87 {
88 bands = width () / 10;
89 bands = aud::clamp(bands, 12, MAX_BANDS);
90 Visualizer::compute_log_xscale (xscale, bands);
91 update ();
92 }
93
94 void SpectrumWidget::paintEvent (QPaintEvent * event)
95 {
96 QPainter p (this);
97
98 paint_background (p);
99 paint_spectrum (p);
100 }
101
102 class QtSpectrum : public VisPlugin
103 {
104 public:
105 static constexpr PluginInfo info = {
106 N_("Spectrum Analyzer"),
107 PACKAGE,
108 nullptr, // about
109 nullptr, // prefs
110 PluginQtOnly
111 };
112
113 constexpr QtSpectrum () : VisPlugin (info, Visualizer::Freq) {}
114
115 void * get_qt_widget ();
116
117 void clear ();
118 void render_freq (const float * freq);
119 };
120
121 EXPORT QtSpectrum aud_plugin_instance;
122
123 void QtSpectrum::render_freq (const float * freq)
124 {
125 if (! bands)
126 return;
127
128 for (int i = 0; i < bands; i ++)
129 {
130 /* 40 dB range */
131 int x = 40 + compute_freq_band (freq, xscale, i, bands);
132 x = aud::clamp (x, 0, 40);
133
134 bars[i] -= aud::max (0, VIS_FALLOFF - delay[i]);
135
136 if (delay[i])
137 delay[i]--;
138
139 if (x > bars[i])
140 {
141 bars[i] = x;
142 delay[i] = VIS_DELAY;
143 }
144 }
145
146 if (spect_widget)
147 spect_widget->update ();
148 }
149
150 void QtSpectrum::clear ()
151 {
152 memset (bars, 0, sizeof bars);
153 memset (delay, 0, sizeof delay);
154
155 if (spect_widget)
156 spect_widget->update ();
157 }
158
159 void * QtSpectrum::get_qt_widget ()
160 {
161 if (spect_widget)
162 return spect_widget;
163
164 spect_widget = new SpectrumWidget ();
165 return spect_widget;
166 }
0 qt_multimedia_dep = dependency('qt5', version: qt_req, modules: ['Multimedia'])
1
2
3 if qt_multimedia_dep.found()
4 shared_module('qtaudio',
5 'qtaudio.cc',
6 dependencies: [audacious_dep, qt_multimedia_dep],
7 install: true,
8 install_dir: output_plugin_dir
9 )
10 endif
161161
162162 bytes_per_sec = FMT_SIZEOF (format) * chan * rate;
163163
164 int buffer_ms = aud_get_int (nullptr, "output_buffer_size");
164 int buffer_ms = aud_get_int ("output_buffer_size");
165165 int buffer_size = FMT_SIZEOF (format) * chan * aud::rescale (buffer_ms, 1000, rate);
166166
167167 paused = false;
3232 static constexpr int FadeSteps = 10;
3333
3434 static constexpr int VisBands = 12;
35 static constexpr int VisDelay = 2; /* delay before falloff in frames */
35 static constexpr int VisDelay = 2; /* delay before falloff in frames */
3636 static constexpr int VisFalloff = 2; /* falloff in decibels per frame */
3737
3838 struct BarColors
4242
4343 struct PixelSizes
4444 {
45 int Spacing, IconSize, Height, BandWidth, BandSpacing, VisWidth, VisScale, VisCenter;
46
47 PixelSizes (int dpi) :
48 Spacing (aud::rescale (dpi, 12, 1)),
49 IconSize (2 * aud::rescale (dpi, 3, 1)), // should be divisible by 2
50 Height (IconSize + 2 * Spacing),
51 BandWidth (aud::rescale (dpi, 16, 1)),
52 BandSpacing (aud::rescale (dpi, 48, 1)),
53 VisWidth (VisBands * (BandWidth + BandSpacing) - BandSpacing + 2 * Spacing),
54 VisScale (aud::rescale (IconSize, 8, 5)),
55 VisCenter (VisScale + Spacing) {}
45 int Spacing, IconSize, Height, BandWidth, BandSpacing, VisWidth, VisScale,
46 VisCenter;
47
48 PixelSizes(int dpi)
49 : Spacing(aud::rescale(dpi, 12, 1)),
50 IconSize(2 * aud::rescale(dpi, 3, 1)), // should be divisible by 2
51 Height(IconSize + 2 * Spacing), BandWidth(aud::rescale(dpi, 16, 1)),
52 BandSpacing(aud::rescale(dpi, 48, 1)),
53 VisWidth(VisBands * (BandWidth + BandSpacing) - BandSpacing +
54 2 * Spacing),
55 VisScale(aud::rescale(IconSize, 8, 5)), VisCenter(VisScale + Spacing)
56 {
57 }
5658 };
5759
5860 class InfoVis : public QWidget, Visualizer
5961 {
6062 public:
61 InfoVis (QWidget * parent = nullptr);
62 ~InfoVis ();
63
64 void enable (bool enabled);
65
66 const QGradient & gradient () const
67 { return m_gradient; }
68 const PixelSizes & pixelSizes () const
69 { return ps; }
63 InfoVis(QWidget * parent = nullptr);
64 ~InfoVis();
65
66 void enable(bool enabled);
67
68 const QGradient & gradient() const { return m_gradient; }
69 const PixelSizes & pixelSizes() const { return ps; }
7070
7171 protected:
72 void render_freq (const float * freq);
73 void clear ();
74
75 void changeEvent (QEvent * event);
76 void paintEvent (QPaintEvent *);
72 void render_freq(const float * freq);
73 void clear();
74
75 void changeEvent(QEvent * event);
76 void paintEvent(QPaintEvent *);
7777
7878 private:
79 void update_colors ();
79 void update_colors();
8080
8181 const PixelSizes ps;
8282 QLinearGradient m_gradient;
8383 BarColors m_bar_colors[VisBands];
8484
85 float m_bars[VisBands] {};
86 char m_delay[VisBands] {};
85 float m_bars[VisBands]{};
86 char m_delay[VisBands]{};
8787 };
8888
89 static BarColors get_bar_colors (const QColor & highlight, int i)
90 {
91 qreal h, s, v;
92 highlight.getHsvF (& h, & s, & v);
93
94 if (s < 0.1) /* monochrome theme? use blue instead */
95 h = 0.67;
96
97 s = 1 - 0.9 * i / (VisBands - 1);
98 v = 0.75 + 0.25 * i / (VisBands - 1);
99
100 return {
101 QColor::fromHsvF (h, s, v),
102 QColor::fromHsvF (h, s, v * 0.3)
103 };
104 }
105
106 static QGradientStops get_gradient_stops (const QColor & base)
107 {
108 QColor mid = QColor (64, 64, 64);
109 QColor dark = QColor (38, 38, 38);
110 QColor darker = QColor (26, 26, 26);
111
112 /* In a dark theme, try to match the tone of the base color */
113 int v = base.value ();
114 if (v >= 10 && v < 80)
115 {
116 int r = base.red (), g = base.green (), b = base.blue ();
117 mid = QColor (r * 64 / v, g * 64 / v, b * 64 / v);
118 dark = QColor (r * 38 / v, g * 38 / v, b * 38 / v);
119 darker = QColor (r * 26 / v, g * 26 / v, b * 26 / v);
120 }
121
122 return {
123 {0, mid},
124 {0.499, dark},
125 {0.5, darker},
126 {1, Qt::black}
127 };
128 }
129
130 void InfoVis::update_colors ()
131 {
132 auto & base = palette ().color (QPalette::Window);
133 auto & highlight = palette ().color (QPalette::Highlight);
134
135 m_gradient.setStops (get_gradient_stops (base));
136
137 for (int i = 0; i < VisBands; i ++)
138 m_bar_colors[i] = get_bar_colors (highlight, i);
139 }
140
141 InfoVis::InfoVis (QWidget * parent) :
142 QWidget (parent),
143 Visualizer (Freq),
144 ps (audqt::sizes.OneInch),
145 m_gradient (0, 0, 0, ps.Height)
146 {
147 update_colors ();
148 setAttribute (Qt::WA_OpaquePaintEvent);
149 resize (ps.VisWidth + 2 * ps.Spacing, ps.Height);
150 }
151
152 InfoVis::~InfoVis ()
153 {
154 enable (false);
155 }
156
157 void InfoVis::render_freq (const float * freq)
89 void InfoVis::update_colors()
90 {
91 auto & base = palette().color(QPalette::Window);
92 auto & highlight = palette().color(QPalette::Highlight);
93
94 m_gradient.setStops(audqt::dark_bg_gradient(base));
95
96 for (int i = 0; i < VisBands; i++)
97 {
98 m_bar_colors[i].main = audqt::vis_bar_color(highlight, i, VisBands);
99 m_bar_colors[i].shadow = m_bar_colors[i].main.darker(333);
100 }
101 }
102
103 InfoVis::InfoVis(QWidget * parent)
104 : QWidget(parent), Visualizer(Freq), ps(audqt::sizes.OneInch),
105 m_gradient(0, 0, 0, ps.Height)
106 {
107 update_colors();
108 setAttribute(Qt::WA_OpaquePaintEvent);
109 resize(ps.VisWidth + 2 * ps.Spacing, ps.Height);
110 }
111
112 InfoVis::~InfoVis() { enable(false); }
113
114 void InfoVis::render_freq(const float * freq)
158115 {
159116 /* xscale[i] = pow (256, i / VIS_BANDS) - 0.5; */
160 const float xscale[VisBands + 1] = {0.5, 1.09, 2.02, 3.5, 5.85, 9.58,
161 15.5, 24.9, 39.82, 63.5, 101.09, 160.77, 255.5};
162
163 for (int i = 0; i < VisBands; i ++)
164 {
165 int a = ceilf (xscale[i]);
166 int b = floorf (xscale[i + 1]);
167 float n = 0;
168
169 if (b < a)
170 n += freq[b] * (xscale[i + 1] - xscale[i]);
171 else
172 {
173 if (a > 0)
174 n += freq[a - 1] * (a - xscale[i]);
175 for (; a < b; a ++)
176 n += freq[a];
177 if (b < 256)
178 n += freq[b] * (xscale[i + 1] - b);
179 }
180
117 const float xscale[VisBands + 1] = {0.5, 1.09, 2.02, 3.5, 5.85,
118 9.58, 15.5, 24.9, 39.82, 63.5,
119 101.09, 160.77, 255.5};
120
121 for (int i = 0; i < VisBands; i++)
122 {
181123 /* 40 dB range */
182 float x = 40 + 20 * log10f (n);
183
184 m_bars[i] -= aud::max (0, VisFalloff - m_delay[i]);
124 float x = 40 + compute_freq_band(freq, xscale, i, VisBands);
125
126 m_bars[i] -= aud::max(0, VisFalloff - m_delay[i]);
185127
186128 if (m_delay[i])
187 m_delay[i] --;
129 m_delay[i]--;
188130
189131 if (x > m_bars[i])
190132 {
193135 }
194136 }
195137
196 repaint ();
197 }
198
199 void InfoVis::clear ()
200 {
201 memset (m_bars, 0, sizeof m_bars);
202 memset (m_delay, 0, sizeof m_delay);
203
204 update ();
205 }
206
207 void InfoVis::changeEvent (QEvent * event)
208 {
209 if (event->type () == QEvent::PaletteChange)
210 update_colors ();
211
212 QWidget::changeEvent (event);
213 }
214
215 void InfoVis::paintEvent (QPaintEvent *)
216 {
217 QPainter p (this);
218 p.fillRect (0, 0, ps.VisWidth, ps.Height, m_gradient);
219
220 for (int i = 0; i < VisBands; i ++)
138 repaint();
139 }
140
141 void InfoVis::clear()
142 {
143 memset(m_bars, 0, sizeof m_bars);
144 memset(m_delay, 0, sizeof m_delay);
145
146 update();
147 }
148
149 void InfoVis::changeEvent(QEvent * event)
150 {
151 if (event->type() == QEvent::PaletteChange)
152 update_colors();
153
154 QWidget::changeEvent(event);
155 }
156
157 void InfoVis::paintEvent(QPaintEvent *)
158 {
159 QPainter p(this);
160 p.fillRect(0, 0, ps.VisWidth, ps.Height, m_gradient);
161
162 for (int i = 0; i < VisBands; i++)
221163 {
222164 int x = ps.Spacing + i * (ps.BandWidth + ps.BandSpacing);
223 int v = aud::clamp ((int) (m_bars[i] * ps.VisScale / 40), 0, ps.VisScale);
224 int m = aud::min (ps.VisCenter + v, ps.Height);
225
226 p.fillRect (x, ps.VisCenter - v, ps.BandWidth, v, m_bar_colors[i].main);
227 p.fillRect (x, ps.VisCenter, ps.BandWidth, m - ps.VisCenter, m_bar_colors[i].shadow);
228 }
229 }
230
231 void InfoVis::enable (bool enabled)
165 int v = aud::clamp((int)(m_bars[i] * ps.VisScale / 40), 0, ps.VisScale);
166 int m = aud::min(ps.VisCenter + v, ps.Height);
167
168 p.fillRect(x, ps.VisCenter - v, ps.BandWidth, v, m_bar_colors[i].main);
169 p.fillRect(x, ps.VisCenter, ps.BandWidth, m - ps.VisCenter,
170 m_bar_colors[i].shadow);
171 }
172 }
173
174 void InfoVis::enable(bool enabled)
232175 {
233176 if (enabled)
234 aud_visualizer_add (this);
177 aud_visualizer_add(this);
235178 else
236179 {
237 aud_visualizer_remove (this);
238 clear ();
239 }
240 }
241
242 InfoBar::InfoBar (QWidget * parent) :
243 QWidget (parent),
244 m_vis (new InfoVis (this)),
245 ps (m_vis->pixelSizes ()),
246 m_stopped (true)
247 {
248 update_vis ();
249 setFixedHeight (ps.Height);
180 aud_visualizer_remove(this);
181 clear();
182 }
183 }
184
185 InfoBar::InfoBar(QWidget * parent)
186 : QWidget(parent), m_vis(new InfoVis(this)), ps(m_vis->pixelSizes()),
187 m_stopped(true)
188 {
189 update_vis();
190 setFixedHeight(ps.Height);
250191
251192 for (SongData & d : sd)
252193 {
253 d.title.setTextFormat (Qt::PlainText);
254 d.artist.setTextFormat (Qt::PlainText);
255 d.album.setTextFormat (Qt::PlainText);
194 d.title.setTextFormat(Qt::PlainText);
195 d.artist.setTextFormat(Qt::PlainText);
196 d.album.setTextFormat(Qt::PlainText);
256197 d.alpha = 0;
257198 }
258199
259 if (aud_drct_get_ready ())
200 if (aud_drct_get_ready())
260201 {
261202 m_stopped = false;
262 update_title ();
263 update_album_art ();
203 update_title();
204 update_album_art();
264205
265206 /* skip fade-in */
266207 sd[Cur].alpha = FadeSteps;
267208 }
268209 }
269210
270 void InfoBar::resizeEvent (QResizeEvent *)
211 void InfoBar::resizeEvent(QResizeEvent *)
271212 {
272213 for (SongData & d : sd)
273 d.title.setText (QString ());
274
275 m_vis->move (width () - ps.VisWidth, 0);
276 }
277
278 void InfoBar::paintEvent (QPaintEvent *)
279 {
280 QPainter p (this);
281
282 p.fillRect (0, 0, width () - ps.VisWidth, ps.Height, m_vis->gradient ());
214 d.title.setText(QString());
215
216 m_vis->move(width() - ps.VisWidth, 0);
217 }
218
219 void InfoBar::paintEvent(QPaintEvent *)
220 {
221 QPainter p(this);
222
223 p.fillRect(0, 0, width() - ps.VisWidth, ps.Height, m_vis->gradient());
283224
284225 for (SongData & d : sd)
285226 {
286 p.setOpacity ((qreal) d.alpha / FadeSteps);
287
288 if (! d.art.isNull ())
227 p.setOpacity((qreal)d.alpha / FadeSteps);
228
229 if (!d.art.isNull())
289230 {
290 auto sz = d.art.size () / d.art.devicePixelRatio ();
291 int left = ps.Spacing + (ps.IconSize - sz.width ()) / 2;
292 int top = ps.Spacing + (ps.IconSize - sz.height ()) / 2;
293 p.drawPixmap (left, top, d.art);
231 auto sz = d.art.size() / d.art.devicePixelRatio();
232 int left = ps.Spacing + (ps.IconSize - sz.width()) / 2;
233 int top = ps.Spacing + (ps.IconSize - sz.height()) / 2;
234 p.drawPixmap(left, top, d.art);
294235 }
295236
296 QFont font = p.font ();
297 font.setPointSize (18);
298 p.setFont (font);
299
300 if (d.title.text ().isNull () && ! d.orig_title.isNull ())
237 QFont font = p.font();
238 font.setPointSize(18);
239 p.setFont(font);
240
241 if (d.title.text().isNull() && !d.orig_title.isNull())
301242 {
302 QFontMetrics metrics = p.fontMetrics ();
303 d.title = QStaticText(metrics.elidedText (d.orig_title, Qt::ElideRight,
304 width () - ps.VisWidth - ps.Height - ps.Spacing));
243 QFontMetrics metrics = p.fontMetrics();
244 d.title = QStaticText(metrics.elidedText(
245 d.orig_title, Qt::ElideRight,
246 width() - ps.VisWidth - ps.Height - ps.Spacing));
305247 }
306248
307 p.setPen (QColor (255, 255, 255));
308 p.drawStaticText (ps.Height, ps.Spacing, d.title);
309
310 font.setPointSize (9);
311 p.setFont (font);
312
313 p.drawStaticText (ps.Height, ps.Spacing + ps.IconSize / 2, d.artist);
314
315 p.setPen (QColor (179, 179, 179));
316 p.drawStaticText (ps.Height, ps.Spacing + ps.IconSize * 3 / 4, d.album);
317 }
318 }
319
320 void InfoBar::update_title ()
321 {
322 Tuple tuple = aud_drct_get_tuple ();
323
324 sd[Cur].title.setText (QString ());
325 sd[Cur].orig_title = tuple.get_str (Tuple::Title);
326 sd[Cur].artist.setText ((const char *) tuple.get_str (Tuple::Artist));
327 sd[Cur].album.setText ((const char *) tuple.get_str (Tuple::Album));
328
329 update ();
330 }
331
332 void InfoBar::update_album_art ()
333 {
334 sd[Cur].art = audqt::art_request_current (ps.IconSize, ps.IconSize);
335 }
336
337 void InfoBar::next_song ()
338 {
339 sd[Prev] = std::move (sd[Cur]);
249 p.setPen(QColor(255, 255, 255));
250 p.drawStaticText(ps.Height, ps.Spacing, d.title);
251
252 font.setPointSize(9);
253 p.setFont(font);
254
255 p.drawStaticText(ps.Height, ps.Spacing + ps.IconSize / 2, d.artist);
256
257 p.setPen(QColor(179, 179, 179));
258 p.drawStaticText(ps.Height, ps.Spacing + ps.IconSize * 3 / 4, d.album);
259 }
260 }
261
262 void InfoBar::update_title()
263 {
264 Tuple tuple = aud_drct_get_tuple();
265
266 sd[Cur].title.setText(QString());
267 sd[Cur].orig_title = tuple.get_str(Tuple::Title);
268 sd[Cur].artist.setText((const char *)tuple.get_str(Tuple::Artist));
269 sd[Cur].album.setText((const char *)tuple.get_str(Tuple::Album));
270
271 update();
272 }
273
274 void InfoBar::update_album_art()
275 {
276 sd[Cur].art = audqt::art_request_current(ps.IconSize, ps.IconSize);
277 }
278
279 void InfoBar::next_song()
280 {
281 sd[Prev] = std::move(sd[Cur]);
340282 sd[Cur].alpha = 0;
341283 }
342284
343 void InfoBar::do_fade ()
285 void InfoBar::do_fade()
344286 {
345287 bool done = true;
346288
347 if (aud_drct_get_playing () && sd[Cur].alpha < FadeSteps)
348 {
349 sd[Cur].alpha ++;
289 if (aud_drct_get_playing() && sd[Cur].alpha < FadeSteps)
290 {
291 sd[Cur].alpha++;
350292 done = false;
351293 }
352294
353295 if (sd[Prev].alpha > 0)
354296 {
355 sd[Prev].alpha --;
297 sd[Prev].alpha--;
356298 done = false;
357299 }
358300
359 update ();
301 update();
360302
361303 if (done)
362 fade_timer.stop ();
363 }
364
365 void InfoBar::playback_ready_cb ()
366 {
367 if (! m_stopped)
368 next_song ();
304 fade_timer.stop();
305 }
306
307 void InfoBar::playback_ready_cb()
308 {
309 if (!m_stopped)
310 next_song();
369311
370312 m_stopped = false;
371 update_title ();
372 update_album_art ();
373
374 update ();
375 fade_timer.start ();
376 }
377
378 void InfoBar::playback_stop_cb ()
379 {
380 next_song ();
313 update_title();
314 update_album_art();
315
316 update();
317 fade_timer.start();
318 }
319
320 void InfoBar::playback_stop_cb()
321 {
322 next_song();
381323 m_stopped = true;
382324
383 update ();
384 fade_timer.start ();
385 }
386
387 void InfoBar::update_vis ()
388 {
389 m_vis->enable (aud_get_bool ("qtui", "infoarea_show_vis"));
390 }
325 update();
326 fade_timer.start();
327 }
328
329 void InfoBar::update_vis()
330 {
331 m_vis->enable(aud_get_bool("qtui", "infoarea_show_vis"));
332 }
3030 class InfoBar : public QWidget
3131 {
3232 public:
33 InfoBar (QWidget * parent = nullptr);
33 InfoBar(QWidget * parent = nullptr);
3434
35 void resizeEvent (QResizeEvent *);
36 void paintEvent (QPaintEvent *);
35 void resizeEvent(QResizeEvent *);
36 void paintEvent(QPaintEvent *);
3737
3838 private:
39 void update_title ();
40 void update_album_art ();
41 void next_song ();
42 void do_fade ();
39 void update_title();
40 void update_album_art();
41 void next_song();
42 void do_fade();
4343
44 void playback_ready_cb ();
45 void playback_stop_cb ();
46 void update_vis ();
44 void playback_ready_cb();
45 void playback_stop_cb();
46 void update_vis();
4747
48 const HookReceiver<InfoBar>
49 hook1 {"tuple change", this, & InfoBar::update_title},
50 hook2 {"playback ready", this, & InfoBar::playback_ready_cb},
51 hook3 {"playback stop", this, & InfoBar::playback_stop_cb},
52 hook4 {"qtui toggle infoarea_vis", this, & InfoBar::update_vis};
48 const HookReceiver<InfoBar> hook1{"tuple change", this,
49 &InfoBar::update_title},
50 hook2{"playback ready", this, &InfoBar::playback_ready_cb},
51 hook3{"playback stop", this, &InfoBar::playback_stop_cb},
52 hook4{"qtui toggle infoarea_vis", this, &InfoBar::update_vis};
5353
54 const Timer<InfoBar>
55 fade_timer {TimerRate::Hz30, this, & InfoBar::do_fade};
54 const Timer<InfoBar> fade_timer{TimerRate::Hz30, this, &InfoBar::do_fade};
5655
5756 InfoVis * m_vis;
5857 const PixelSizes & ps;
5958
60 struct SongData {
59 struct SongData
60 {
6161 QPixmap art;
6262 QString orig_title;
6363 QStaticText title, artist, album;
6464 int alpha;
6565 };
6666
67 enum {Prev = 0, Cur = 1}; /* index into SongData array */
67 enum
68 {
69 Prev = 0,
70 Cur = 1
71 }; /* index into SongData array */
6872
6973 SongData sd[2];
7074 bool m_stopped;
2020
2121 #include <libaudcore/drct.h>
2222 #include <libaudcore/i18n.h>
23 #include <libaudcore/plugins.h>
2324 #include <libaudcore/runtime.h>
24 #include <libaudcore/plugins.h>
2525
2626 #include <libaudqt/libaudqt.h>
2727
4646 class PluginWidget : public QDockWidget
4747 {
4848 public:
49 PluginWidget (PluginHandle * plugin) :
50 m_plugin (plugin)
51 {
52 setObjectName (aud_plugin_get_basename (plugin));
53 setWindowTitle (aud_plugin_get_name (plugin));
54 setContextMenuPolicy (Qt::PreventContextMenu);
55 }
56
57 PluginHandle * plugin () const { return m_plugin; }
49 PluginWidget(PluginHandle * plugin) : m_plugin(plugin)
50 {
51 setObjectName(aud_plugin_get_basename(plugin));
52 setWindowTitle(aud_plugin_get_name(plugin));
53 setContextMenuPolicy(Qt::PreventContextMenu);
54 }
55
56 PluginHandle * plugin() const { return m_plugin; }
5857
5958 protected:
60 void closeEvent (QCloseEvent * event)
61 {
62 aud_plugin_enable (m_plugin, false);
63 event->ignore ();
59 void closeEvent(QCloseEvent * event)
60 {
61 aud_plugin_enable(m_plugin, false);
62 event->ignore();
6463 }
6564
6665 private:
6766 PluginHandle * m_plugin;
6867 };
6968
70 static QString get_config_name ()
71 {
72 int instance = aud_get_instance ();
73 return (instance == 1) ?
74 QString ("audacious") :
75 QString ("audacious-%1").arg (instance);
76 }
77
78 static void toggle_search_tool (bool enable)
79 {
80 auto search_tool = aud_plugin_lookup_basename ("search-tool-qt");
69 static QString get_config_name()
70 {
71 int instance = aud_get_instance();
72 return (instance == 1) ? QString("audacious")
73 : QString("audacious-%1").arg(instance);
74 }
75
76 static void toggle_search_tool(bool enable)
77 {
78 auto search_tool = aud_plugin_lookup_basename("search-tool-qt");
8179 if (search_tool)
82 aud_plugin_enable (search_tool, enable);
83 }
84
85 MainWindow::MainWindow () :
86 m_config_name (get_config_name ()),
87 m_dialogs (this),
88 m_menubar (qtui_build_menubar (this)),
89 m_playlist_tabs (new PlaylistTabs (this)),
90 m_center_widget (new QWidget (this)),
91 m_center_layout (audqt::make_vbox (m_center_widget, 0)),
92 m_infobar (new InfoBar (this)),
93 m_statusbar (new StatusBar (this)),
94 m_search_tool (aud_plugin_lookup_basename ("search-tool-qt")),
95 m_playlist_manager (aud_plugin_lookup_basename ("playlist-manager-qt"))
96 {
97 auto slider = new TimeSlider (this);
80 aud_plugin_enable(search_tool, enable);
81 }
82
83 MainWindow::MainWindow()
84 : m_config_name(get_config_name()), m_dialogs(this),
85 m_menubar(qtui_build_menubar(this)),
86 m_playlist_tabs(new PlaylistTabs(this)),
87 m_center_widget(new QWidget(this)),
88 m_center_layout(audqt::make_vbox(m_center_widget, 0)),
89 m_infobar(new InfoBar(this)), m_statusbar(new StatusBar(this)),
90 m_search_tool(aud_plugin_lookup_basename("search-tool-qt")),
91 m_playlist_manager(aud_plugin_lookup_basename("playlist-manager-qt"))
92 {
93 auto slider = new TimeSlider(this);
9894
9995 const ToolBarItem items[] = {
100 ToolBarAction ("edit-find", N_("Search Library"), N_("Search Library"), toggle_search_tool, & m_search_action),
101 ToolBarAction ("document-open", N_("Open Files"), N_("Open Files"),
102 [] () { audqt::fileopener_show (audqt::FileMode::Open); }),
103 ToolBarAction ("list-add", N_("Add Files"), N_("Add Files"),
104 [] () { audqt::fileopener_show (audqt::FileMode::Add); }),
105 ToolBarSeparator (),
106 ToolBarAction ("media-skip-backward", N_("Previous"), N_("Previous"), aud_drct_pl_prev),
107 ToolBarAction ("media-playback-start", N_("Play"), N_("Play"), aud_drct_play_pause, & m_play_pause_action),
108 ToolBarAction ("media-playback-stop", N_("Stop"), N_("Stop"), aud_drct_stop, & m_stop_action),
109 ToolBarAction ("media-playback-stop", N_("Stop After This Song"), N_("Stop After This Song"),
110 [] (bool on) { aud_set_bool (nullptr, "stop_after_current_song", on); }, & m_stop_after_action),
111 ToolBarAction ("media-skip-forward", N_("Next"), N_("Next"), aud_drct_pl_next),
112 ToolBarAction ("media-record", N_("Record Stream"), N_("Record Stream"),
113 [] (bool on) { aud_set_bool (nullptr, "record", on); }, & m_record_action),
114 ToolBarSeparator (),
115 ToolBarCustom (slider),
116 ToolBarCustom (slider->label ()),
117 ToolBarSeparator (),
118 ToolBarAction ("media-playlist-repeat", N_("Repeat"), N_("Repeat"),
119 [] (bool on) { aud_set_bool (nullptr, "repeat", on); }, & m_repeat_action),
120 ToolBarAction ("media-playlist-shuffle", N_("Shuffle"), N_("Shuffle"),
121 [] (bool on) { aud_set_bool (nullptr, "shuffle", on); }, & m_shuffle_action),
122 ToolBarCustom (audqt::volume_button_new (this))
123 };
124
125 addToolBar (Qt::TopToolBarArea, new ToolBar (this, items));
96 ToolBarAction("edit-find", N_("Search Library"), N_("Search Library"),
97 toggle_search_tool, &m_search_action),
98 ToolBarAction("document-open", N_("Open Files"), N_("Open Files"),
99 []() { audqt::fileopener_show(audqt::FileMode::Open); }),
100 ToolBarAction("list-add", N_("Add Files"), N_("Add Files"),
101 []() { audqt::fileopener_show(audqt::FileMode::Add); }),
102 ToolBarSeparator(),
103 ToolBarAction("media-skip-backward", N_("Previous"), N_("Previous"),
104 aud_drct_pl_prev),
105 ToolBarAction("media-playback-start", N_("Play"), N_("Play"),
106 aud_drct_play_pause, &m_play_pause_action),
107 ToolBarAction("media-playback-stop", N_("Stop"), N_("Stop"),
108 aud_drct_stop, &m_stop_action),
109 ToolBarAction(
110 "media-playback-stop", N_("Stop After This Song"),
111 N_("Stop After This Song"),
112 [](bool on) { aud_set_bool("stop_after_current_song", on); },
113 &m_stop_after_action),
114 ToolBarAction("media-skip-forward", N_("Next"), N_("Next"),
115 aud_drct_pl_next),
116 ToolBarAction(
117 "media-record", N_("Record Stream"), N_("Record Stream"),
118 [](bool on) { aud_set_bool("record", on); }, &m_record_action),
119 ToolBarSeparator(),
120 ToolBarCustom(slider),
121 ToolBarCustom(slider->label()),
122 ToolBarSeparator(),
123 ToolBarAction(
124 "media-playlist-repeat", N_("Repeat"), N_("Repeat"),
125 [](bool on) { aud_set_bool("repeat", on); }, &m_repeat_action),
126 ToolBarAction(
127 "media-playlist-shuffle", N_("Shuffle"), N_("Shuffle"),
128 [](bool on) { aud_set_bool("shuffle", on); }, &m_shuffle_action),
129 ToolBarCustom(audqt::volume_button_new(this))};
130
131 addToolBar(Qt::TopToolBarArea, new ToolBar(this, items));
126132
127133 if (m_search_tool)
128 aud_plugin_add_watch (m_search_tool, plugin_watcher, this);
134 aud_plugin_add_watch(m_search_tool, plugin_watcher, this);
129135 else
130 m_search_action->setVisible (false);
131
132 update_toggles ();
133
134 setStatusBar (m_statusbar);
135 setCentralWidget (m_center_widget);
136
137 m_center_layout->addWidget (m_playlist_tabs);
138 m_center_layout->addWidget (m_infobar);
139
140 setMenuBar (m_menubar);
141 setDockNestingEnabled (true);
142 add_dock_plugins ();
143
144 if (aud_drct_get_playing ())
145 {
146 playback_begin_cb ();
147 if (aud_drct_get_ready ())
148 title_change_cb ();
136 m_search_action->setVisible(false);
137
138 update_toggles();
139
140 setStatusBar(m_statusbar);
141 setCentralWidget(m_center_widget);
142
143 m_center_layout->addWidget(m_playlist_tabs);
144 m_center_layout->addWidget(m_infobar);
145
146 setMenuBar(m_menubar);
147 setDockNestingEnabled(true);
148 add_dock_plugins();
149
150 if (aud_drct_get_playing())
151 {
152 playback_begin_cb();
153 if (aud_drct_get_ready())
154 title_change_cb();
149155 }
150156 else
151 playback_stop_cb ();
152
153 read_settings ();
154 update_visibility ();
157 playback_stop_cb();
158
159 read_settings();
160 update_visibility();
155161
156162 /* set initial keyboard focus on the playlist */
157 m_playlist_tabs->currentPlaylistWidget ()->setFocus (Qt::OtherFocusReason);
158 }
159
160 MainWindow::~MainWindow ()
161 {
162 QSettings settings (m_config_name, "QtUi");
163 settings.setValue ("geometry", saveGeometry ());
164 settings.setValue ("windowState", saveState ());
165
166 remove_dock_plugins ();
163 m_playlist_tabs->currentPlaylistWidget()->setFocus(Qt::OtherFocusReason);
164 }
165
166 MainWindow::~MainWindow()
167 {
168 QSettings settings(m_config_name, "QtUi");
169 settings.setValue("geometry", saveGeometry());
170 settings.setValue("windowState", saveState());
171
172 remove_dock_plugins();
167173
168174 if (m_search_tool)
169 aud_plugin_remove_watch (m_search_tool, plugin_watcher, this);
170 }
171
172 void MainWindow::closeEvent (QCloseEvent * e)
175 aud_plugin_remove_watch(m_search_tool, plugin_watcher, this);
176 }
177
178 void MainWindow::closeEvent(QCloseEvent * e)
173179 {
174180 bool handled = false;
175181
176 hook_call ("window close", & handled);
177
178 if (! handled)
179 aud_quit ();
180
181 e->ignore ();
182 }
183
184 void MainWindow::keyPressEvent (QKeyEvent * event)
185 {
186 auto CtrlShiftAlt = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
187 if (! (event->modifiers () & CtrlShiftAlt) && event->key () == Qt::Key_Escape)
188 {
189 auto widget = m_playlist_tabs->currentPlaylistWidget ();
182 hook_call("window close", &handled);
183
184 if (!handled)
185 aud_quit();
186
187 e->ignore();
188 }
189
190 void MainWindow::keyPressEvent(QKeyEvent * event)
191 {
192 auto CtrlShiftAlt =
193 Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
194 if (!(event->modifiers() & CtrlShiftAlt) && event->key() == Qt::Key_Escape)
195 {
196 auto widget = m_playlist_tabs->currentPlaylistWidget();
190197
191198 /* on the first press, set focus to the playlist */
192 if (! widget->hasFocus ())
199 if (!widget->hasFocus())
193200 {
194 widget->setFocus (Qt::OtherFocusReason);
201 widget->setFocus(Qt::OtherFocusReason);
195202 return;
196203 }
197204
198205 /* on the second press, scroll to the current entry */
199 if (widget->scrollToCurrent (true))
206 if (widget->scrollToCurrent(true))
200207 return;
201208
202209 /* on the third press, switch to the playing playlist */
203 Playlist::playing_playlist ().activate ();
210 Playlist::playing_playlist().activate();
204211
205212 /* ensure currentPlaylistWidget() is up to date */
206 Playlist::process_pending_update ();
207 widget = m_playlist_tabs->currentPlaylistWidget ();
208
209 widget->scrollToCurrent (true);
213 Playlist::process_pending_update();
214 widget = m_playlist_tabs->currentPlaylistWidget();
215
216 widget->scrollToCurrent(true);
210217 return;
211218 }
212219
213 QMainWindow::keyPressEvent (event);
214 }
215
216 void MainWindow::read_settings ()
217 {
218 QSettings settings (m_config_name, "QtUi");
219
220 if (! restoreGeometry (settings.value ("geometry").toByteArray ()))
221 resize (audqt::to_native_dpi (768), audqt::to_native_dpi (480));
222
223 restoreState (settings.value ("windowState").toByteArray ());
224 }
225
226 void MainWindow::set_title (const QString & title)
227 {
228 int instance = aud_get_instance ();
220 QMainWindow::keyPressEvent(event);
221 }
222
223 void MainWindow::read_settings()
224 {
225 QSettings settings(m_config_name, "QtUi");
226
227 if (!restoreGeometry(settings.value("geometry").toByteArray()))
228 resize(audqt::to_native_dpi(768), audqt::to_native_dpi(480));
229
230 restoreState(settings.value("windowState").toByteArray());
231 }
232
233 void MainWindow::set_title(const QString & title)
234 {
235 int instance = aud_get_instance();
229236 if (instance == 1)
230 QMainWindow::setWindowTitle (title);
237 QMainWindow::setWindowTitle(title);
231238 else
232 QMainWindow::setWindowTitle (QString ("%1 (%2)").arg (title).arg (instance));
233 }
234
235 void MainWindow::update_toggles ()
239 QMainWindow::setWindowTitle(
240 QString("%1 (%2)").arg(title).arg(instance));
241 }
242
243 void MainWindow::update_toggles()
236244 {
237245 if (m_search_tool)
238 m_search_action->setChecked (aud_plugin_get_enabled (m_search_tool));
239
240 bool stop_after = aud_get_bool (nullptr, "stop_after_current_song");
241 m_stop_action->setVisible (! stop_after);
242 m_stop_after_action->setVisible (stop_after);
243 m_stop_after_action->setChecked (stop_after);
244
245 m_record_action->setVisible (aud_drct_get_record_enabled ());
246 m_record_action->setChecked (aud_get_bool (nullptr, "record"));
247
248 m_repeat_action->setChecked (aud_get_bool (nullptr, "repeat"));
249 m_shuffle_action->setChecked (aud_get_bool (nullptr, "shuffle"));
250 }
251
252 void MainWindow::update_visibility ()
253 {
254 m_menubar->setVisible (aud_get_bool ("qtui", "menu_visible"));
255 m_infobar->setVisible (aud_get_bool ("qtui", "infoarea_visible"));
256 m_statusbar->setVisible (aud_get_bool ("qtui", "statusbar_visible"));
257 }
258
259 void MainWindow::update_play_pause ()
260 {
261 if (! aud_drct_get_playing () || aud_drct_get_paused ())
262 {
263 m_play_pause_action->setIcon (audqt::get_icon ("media-playback-start"));
264 m_play_pause_action->setText (_("Play"));
265 m_play_pause_action->setToolTip (_("Play"));
246 m_search_action->setChecked(aud_plugin_get_enabled(m_search_tool));
247
248 bool stop_after = aud_get_bool("stop_after_current_song");
249 m_stop_action->setVisible(!stop_after);
250 m_stop_after_action->setVisible(stop_after);
251 m_stop_after_action->setChecked(stop_after);
252
253 m_record_action->setVisible(aud_drct_get_record_enabled());
254 m_record_action->setChecked(aud_get_bool("record"));
255
256 m_repeat_action->setChecked(aud_get_bool("repeat"));
257 m_shuffle_action->setChecked(aud_get_bool("shuffle"));
258 }
259
260 void MainWindow::update_visibility()
261 {
262 m_menubar->setVisible(aud_get_bool("qtui", "menu_visible"));
263 m_infobar->setVisible(aud_get_bool("qtui", "infoarea_visible"));
264 m_statusbar->setVisible(aud_get_bool("qtui", "statusbar_visible"));
265 }
266
267 void MainWindow::update_play_pause()
268 {
269 if (!aud_drct_get_playing() || aud_drct_get_paused())
270 {
271 m_play_pause_action->setIcon(audqt::get_icon("media-playback-start"));
272 m_play_pause_action->setText(_("Play"));
273 m_play_pause_action->setToolTip(_("Play"));
266274 }
267275 else
268276 {
269 m_play_pause_action->setIcon (audqt::get_icon ("media-playback-pause"));
270 m_play_pause_action->setText (_("Pause"));
271 m_play_pause_action->setToolTip (_("Pause"));
272 }
273 }
274
275 void MainWindow::title_change_cb ()
276 {
277 auto title = aud_drct_get_title ();
277 m_play_pause_action->setIcon(audqt::get_icon("media-playback-pause"));
278 m_play_pause_action->setText(_("Pause"));
279 m_play_pause_action->setToolTip(_("Pause"));
280 }
281 }
282
283 void MainWindow::title_change_cb()
284 {
285 auto title = aud_drct_get_title();
278286 if (title)
279287 {
280 set_title (QString (title) + QString (" - Audacious"));
281 m_buffering_timer.stop ();
282 }
283 }
284
285 void MainWindow::playback_begin_cb ()
286 {
287 update_play_pause ();
288
289 auto last_widget = m_playlist_tabs->playlistWidget (m_last_playing.index ());
288 set_title(QString(title) + QString(" - Audacious"));
289 m_buffering_timer.stop();
290 }
291 }
292
293 void MainWindow::playback_begin_cb()
294 {
295 update_play_pause();
296
297 auto last_widget = m_playlist_tabs->playlistWidget(m_last_playing.index());
290298 if (last_widget)
291 last_widget->updatePlaybackIndicator ();
292
293 auto playing = Playlist::playing_playlist ();
294 auto widget = m_playlist_tabs->playlistWidget (playing.index ());
299 last_widget->updatePlaybackIndicator();
300
301 auto playing = Playlist::playing_playlist();
302 auto widget = m_playlist_tabs->playlistWidget(playing.index());
295303 if (widget)
296 widget->scrollToCurrent ();
304 widget->scrollToCurrent();
297305 if (widget && widget != last_widget)
298 widget->updatePlaybackIndicator ();
306 widget->updatePlaybackIndicator();
299307
300308 m_last_playing = playing;
301309
302 m_buffering_timer.queue (250, aud::obj_member<MainWindow, & MainWindow::buffering_cb>, this);
303 }
304
305 void MainWindow::buffering_cb ()
306 {
307 set_title (_("Buffering ..."));
308 }
309
310 void MainWindow::pause_cb ()
311 {
312 update_play_pause ();
313
314 auto widget = m_playlist_tabs->playlistWidget (m_last_playing.index ());
310 m_buffering_timer.queue(
311 250, aud::obj_member<MainWindow, &MainWindow::buffering_cb>, this);
312 }
313
314 void MainWindow::buffering_cb() { set_title(_("Buffering ...")); }
315
316 void MainWindow::pause_cb()
317 {
318 update_play_pause();
319
320 auto widget = m_playlist_tabs->playlistWidget(m_last_playing.index());
315321 if (widget)
316 widget->updatePlaybackIndicator ();
317 }
318
319 void MainWindow::playback_stop_cb ()
320 {
321 set_title ("Audacious");
322 m_buffering_timer.stop ();
323
324 update_play_pause ();
325
326 auto last_widget = m_playlist_tabs->playlistWidget (m_last_playing.index ());
322 widget->updatePlaybackIndicator();
323 }
324
325 void MainWindow::playback_stop_cb()
326 {
327 set_title("Audacious");
328 m_buffering_timer.stop();
329
330 update_play_pause();
331
332 auto last_widget = m_playlist_tabs->playlistWidget(m_last_playing.index());
327333 if (last_widget)
328 last_widget->updatePlaybackIndicator ();
329
330 m_last_playing = Playlist ();
331 }
332
333 PluginWidget * MainWindow::find_dock_plugin (PluginHandle * plugin)
334 last_widget->updatePlaybackIndicator();
335
336 m_last_playing = Playlist();
337 }
338
339 PluginWidget * MainWindow::find_dock_plugin(PluginHandle * plugin)
334340 {
335341 for (PluginWidget * w : m_dock_widgets)
336342 {
337 if (w->plugin () == plugin)
343 if (w->plugin() == plugin)
338344 return w;
339345 }
340346
341347 return nullptr;
342348 }
343349
344 void MainWindow::show_dock_plugin (PluginHandle * plugin)
345 {
346 aud_plugin_enable (plugin, true);
347 aud_plugin_send_message (plugin, "grab focus", nullptr, 0);
348 }
349
350 void MainWindow::add_dock_plugin_cb (PluginHandle * plugin)
351 {
352 QWidget * widget = (QWidget *) aud_plugin_get_qt_widget (plugin);
353 if (! widget)
350 void MainWindow::show_dock_plugin(PluginHandle * plugin)
351 {
352 aud_plugin_enable(plugin, true);
353 aud_plugin_send_message(plugin, "grab focus", nullptr, 0);
354 }
355
356 void MainWindow::add_dock_plugin_cb(PluginHandle * plugin)
357 {
358 QWidget * widget = (QWidget *)aud_plugin_get_qt_widget(plugin);
359 if (!widget)
354360 return;
355361
356 auto w = find_dock_plugin (plugin);
357 if (! w)
358 {
359 w = new PluginWidget (plugin);
360 m_dock_widgets.append (w);
361 }
362
363 w->setWidget (widget);
364
365 if (! restoreDockWidget (w))
366 addDockWidget (Qt::LeftDockWidgetArea, w);
367 }
368
369 void MainWindow::remove_dock_plugin_cb (PluginHandle * plugin)
370 {
371 if (auto w = find_dock_plugin (plugin))
372 {
373 removeDockWidget (w);
374 delete w->widget ();
375 }
376 }
377
378 void MainWindow::add_dock_plugins ()
379 {
380 for (PluginHandle * plugin : aud_plugin_list (PluginType::General))
381 {
382 if (aud_plugin_get_enabled (plugin))
383 add_dock_plugin_cb (plugin);
384 }
385
386 for (PluginHandle * plugin : aud_plugin_list (PluginType::Vis))
387 {
388 if (aud_plugin_get_enabled (plugin))
389 add_dock_plugin_cb (plugin);
390 }
391 }
392
393 void MainWindow::remove_dock_plugins ()
394 {
395 for (PluginHandle * plugin : aud_plugin_list (PluginType::General))
396 {
397 if (aud_plugin_get_enabled (plugin))
398 remove_dock_plugin_cb (plugin);
399 }
400
401 for (PluginHandle * plugin : aud_plugin_list (PluginType::Vis))
402 {
403 if (aud_plugin_get_enabled (plugin))
404 remove_dock_plugin_cb (plugin);
405 }
406 }
362 auto w = find_dock_plugin(plugin);
363 if (!w)
364 {
365 w = new PluginWidget(plugin);
366 m_dock_widgets.append(w);
367 }
368
369 w->setWidget(widget);
370
371 if (!restoreDockWidget(w))
372 addDockWidget(Qt::LeftDockWidgetArea, w);
373 }
374
375 void MainWindow::remove_dock_plugin_cb(PluginHandle * plugin)
376 {
377 if (auto w = find_dock_plugin(plugin))
378 {
379 removeDockWidget(w);
380 delete w->widget();
381 }
382 }
383
384 void MainWindow::add_dock_plugins()
385 {
386 for (PluginHandle * plugin : aud_plugin_list(PluginType::General))
387 {
388 if (aud_plugin_get_enabled(plugin))
389 add_dock_plugin_cb(plugin);
390 }
391
392 for (PluginHandle * plugin : aud_plugin_list(PluginType::Vis))
393 {
394 if (aud_plugin_get_enabled(plugin))
395 add_dock_plugin_cb(plugin);
396 }
397 }
398
399 void MainWindow::remove_dock_plugins()
400 {
401 for (PluginHandle * plugin : aud_plugin_list(PluginType::General))
402 {
403 if (aud_plugin_get_enabled(plugin))
404 remove_dock_plugin_cb(plugin);
405 }
406
407 for (PluginHandle * plugin : aud_plugin_list(PluginType::Vis))
408 {
409 if (aud_plugin_get_enabled(plugin))
410 remove_dock_plugin_cb(plugin);
411 }
412 }
3737 class MainWindow : public QMainWindow
3838 {
3939 public:
40 MainWindow ();
41 ~MainWindow ();
40 MainWindow();
41 ~MainWindow();
4242
4343 private:
4444 QString m_config_name;
5050 InfoBar * m_infobar;
5151 StatusBar * m_statusbar;
5252
53 PluginHandle * m_search_tool, * m_playlist_manager;
53 PluginHandle *m_search_tool, *m_playlist_manager;
5454 Index<PluginWidget *> m_dock_widgets;
5555
5656 QAction * m_search_action;
57 QAction * m_play_pause_action, * m_stop_action, * m_stop_after_action;
57 QAction *m_play_pause_action, *m_stop_action, *m_stop_after_action;
5858 QAction * m_record_action;
59 QAction * m_repeat_action, * m_shuffle_action;
59 QAction *m_repeat_action, *m_shuffle_action;
6060
6161 QueuedFunc m_buffering_timer;
6262 Playlist m_last_playing;
6363
64 void closeEvent (QCloseEvent * e);
65 void keyPressEvent (QKeyEvent * event);
64 void closeEvent(QCloseEvent * e);
65 void keyPressEvent(QKeyEvent * event);
6666
67 void read_settings ();
68 void set_title (const QString & title);
69 void update_toggles ();
70 void update_visibility ();
71 void update_play_pause ();
67 void read_settings();
68 void set_title(const QString & title);
69 void update_toggles();
70 void update_visibility();
71 void update_play_pause();
7272
73 void title_change_cb ();
74 void playback_begin_cb ();
75 void buffering_cb ();
76 void playback_ready_cb ();
77 void pause_cb ();
78 void playback_stop_cb ();
73 void title_change_cb();
74 void playback_begin_cb();
75 void buffering_cb();
76 void playback_ready_cb();
77 void pause_cb();
78 void playback_stop_cb();
7979
80 PluginWidget * find_dock_plugin (PluginHandle * plugin);
81 void show_dock_plugin (PluginHandle * plugin);
82 void add_dock_plugin_cb (PluginHandle * plugin);
83 void remove_dock_plugin_cb (PluginHandle * plugin);
84 void add_dock_plugins ();
85 void remove_dock_plugins ();
80 PluginWidget * find_dock_plugin(PluginHandle * plugin);
81 void show_dock_plugin(PluginHandle * plugin);
82 void add_dock_plugin_cb(PluginHandle * plugin);
83 void remove_dock_plugin_cb(PluginHandle * plugin);
84 void add_dock_plugins();
85 void remove_dock_plugins();
8686
87 void show_search_tool ()
88 { if (m_search_tool) show_dock_plugin (m_search_tool); }
89 void show_playlist_manager ()
90 { if (m_playlist_manager) show_dock_plugin (m_playlist_manager); }
87 void show_search_tool()
88 {
89 if (m_search_tool)
90 show_dock_plugin(m_search_tool);
91 }
92 void show_playlist_manager()
93 {
94 if (m_playlist_manager)
95 show_dock_plugin(m_playlist_manager);
96 }
9197
92 static bool plugin_watcher (PluginHandle *, void * me)
93 { ((MainWindow *) me)->update_toggles (); return true; }
98 static bool plugin_watcher(PluginHandle *, void * me)
99 {
100 ((MainWindow *)me)->update_toggles();
101 return true;
102 }
94103
95 const HookReceiver<MainWindow>
96 hook1 {"title change", this, & MainWindow::title_change_cb},
97 hook2 {"playback begin", this, & MainWindow::playback_begin_cb},
98 hook3 {"playback ready", this, & MainWindow::title_change_cb},
99 hook4 {"playback pause", this, & MainWindow::pause_cb},
100 hook5 {"playback unpause", this, & MainWindow::pause_cb},
101 hook6 {"playback stop", this, & MainWindow::playback_stop_cb},
102 hook7 {"set stop_after_current_song", this, & MainWindow::update_toggles},
103 hook8 {"enable record", this, & MainWindow::update_toggles},
104 hook9 {"set record", this, & MainWindow::update_toggles},
105 hook10 {"set repeat", this, & MainWindow::update_toggles},
106 hook11 {"set shuffle", this, & MainWindow::update_toggles},
107 hook12 {"qtui toggle menubar", this, & MainWindow::update_visibility},
108 hook13 {"qtui toggle infoarea", this, & MainWindow::update_visibility},
109 hook14 {"qtui toggle statusbar", this, & MainWindow::update_visibility},
110 hook15 {"qtui show search tool", this, & MainWindow::show_search_tool},
111 hook16 {"qtui show playlist manager", this, & MainWindow::show_playlist_manager};
104 const HookReceiver<MainWindow> hook1{"title change", this,
105 &MainWindow::title_change_cb},
106 hook2{"playback begin", this, &MainWindow::playback_begin_cb},
107 hook3{"playback ready", this, &MainWindow::title_change_cb},
108 hook4{"playback pause", this, &MainWindow::pause_cb},
109 hook5{"playback unpause", this, &MainWindow::pause_cb},
110 hook6{"playback stop", this, &MainWindow::playback_stop_cb},
111 hook7{"set stop_after_current_song", this, &MainWindow::update_toggles},
112 hook8{"enable record", this, &MainWindow::update_toggles},
113 hook9{"set record", this, &MainWindow::update_toggles},
114 hook10{"set repeat", this, &MainWindow::update_toggles},
115 hook11{"set shuffle", this, &MainWindow::update_toggles},
116 hook12{"qtui toggle menubar", this, &MainWindow::update_visibility},
117 hook13{"qtui toggle infoarea", this, &MainWindow::update_visibility},
118 hook14{"qtui toggle statusbar", this, &MainWindow::update_visibility},
119 hook15{"qtui show search tool", this, &MainWindow::show_search_tool},
120 hook16{"qtui show playlist manager", this,
121 &MainWindow::show_playlist_manager};
112122
113 const HookReceiver<MainWindow, PluginHandle *>
114 plugin_hook1 {"dock plugin enabled", this, & MainWindow::add_dock_plugin_cb},
115 plugin_hook2 {"dock plugin disabled", this, & MainWindow::remove_dock_plugin_cb};
123 const HookReceiver<MainWindow, PluginHandle *> plugin_hook1{
124 "dock plugin enabled", this, &MainWindow::add_dock_plugin_cb},
125 plugin_hook2{"dock plugin disabled", this,
126 &MainWindow::remove_dock_plugin_cb};
116127 };
117128
118129 #endif
2424 #include <libaudcore/drct.h>
2525 #include <libaudcore/hook.h>
2626 #include <libaudcore/i18n.h>
27 #include <libaudcore/runtime.h>
28 #include <libaudcore/plugins.h>
29 #include <libaudcore/drct.h>
3027 #include <libaudcore/interface.h>
3128 #include <libaudcore/playlist.h>
29 #include <libaudcore/plugins.h>
30 #include <libaudcore/runtime.h>
3231
3332 #include <libaudqt/libaudqt.h>
3433 #include <libaudqt/menu.h>
3534
36 static QMenu * services_menu () { return audqt::menu_get_by_id (AudMenuID::Main); }
37 static QMenu * services_menu_pl () { return audqt::menu_get_by_id (AudMenuID::Playlist); }
38
39 static void open_files () { audqt::fileopener_show (audqt::FileMode::Open); }
40 static void add_files () { audqt::fileopener_show (audqt::FileMode::Add); }
41 static void open_folder () { audqt::fileopener_show (audqt::FileMode::OpenFolder); }
42 static void add_folder () { audqt::fileopener_show (audqt::FileMode::AddFolder); }
43 static void open_url () { audqt::urlopener_show (true); }
44 static void add_url () { audqt::urlopener_show (false); }
45
46 static void pl_find () { hook_call ("qtui find", nullptr); }
47 static void pl_rename () { hook_call ("qtui rename playlist", nullptr); }
48 static void pl_close () { audqt::playlist_confirm_delete (Playlist::active_playlist ()); }
49 static void pl_import () { audqt::fileopener_show (audqt::FileMode::ImportPlaylist); }
50 static void pl_export () { audqt::fileopener_show (audqt::FileMode::ExportPlaylist); }
51
52 static void configure_effects () { audqt::prefswin_show_plugin_page (PluginType::Effect); }
53 static void configure_output () { audqt::prefswin_show_plugin_page (PluginType::Output); }
54 static void configure_visualizations () { audqt::prefswin_show_plugin_page (PluginType::Vis); }
55
56 static void show_search_tool () { hook_call ("qtui show search tool", nullptr); }
57 static void show_playlist_manager () { hook_call ("qtui show playlist manager", nullptr); }
58 static void toggle_menubar () { hook_call ("qtui toggle menubar", nullptr); }
59 static void toggle_infoarea () { hook_call ("qtui toggle infoarea", nullptr); }
60 static void toggle_infoarea_vis () { hook_call ("qtui toggle infoarea_vis", nullptr); }
61 static void toggle_statusbar () { hook_call ("qtui toggle statusbar", nullptr); }
62 static void toggle_remaining_time () { hook_call ("qtui toggle remaining time", nullptr); }
63
64 QMenuBar * qtui_build_menubar (QWidget * parent)
35 static QMenu * services_menu()
36 {
37 return audqt::menu_get_by_id(AudMenuID::Main);
38 }
39 static QMenu * services_menu_pl()
40 {
41 return audqt::menu_get_by_id(AudMenuID::Playlist);
42 }
43
44 static void open_files() { audqt::fileopener_show(audqt::FileMode::Open); }
45 static void add_files() { audqt::fileopener_show(audqt::FileMode::Add); }
46 static void open_folder()
47 {
48 audqt::fileopener_show(audqt::FileMode::OpenFolder);
49 }
50 static void add_folder() { audqt::fileopener_show(audqt::FileMode::AddFolder); }
51 static void open_url() { audqt::urlopener_show(true); }
52 static void add_url() { audqt::urlopener_show(false); }
53
54 static void pl_find() { hook_call("qtui find", nullptr); }
55 static void pl_rename() { hook_call("qtui rename playlist", nullptr); }
56 static void pl_close()
57 {
58 audqt::playlist_confirm_delete(Playlist::active_playlist());
59 }
60 static void pl_import()
61 {
62 audqt::fileopener_show(audqt::FileMode::ImportPlaylist);
63 }
64 static void pl_export()
65 {
66 audqt::fileopener_show(audqt::FileMode::ExportPlaylist);
67 }
68
69 static void configure_effects()
70 {
71 audqt::prefswin_show_plugin_page(PluginType::Effect);
72 }
73 static void configure_output()
74 {
75 audqt::prefswin_show_plugin_page(PluginType::Output);
76 }
77 static void configure_visualizations()
78 {
79 audqt::prefswin_show_plugin_page(PluginType::Vis);
80 }
81
82 static void show_search_tool() { hook_call("qtui show search tool", nullptr); }
83 static void show_playlist_manager()
84 {
85 hook_call("qtui show playlist manager", nullptr);
86 }
87 static void toggle_menubar() { hook_call("qtui toggle menubar", nullptr); }
88 static void toggle_infoarea() { hook_call("qtui toggle infoarea", nullptr); }
89 static void toggle_infoarea_vis()
90 {
91 hook_call("qtui toggle infoarea_vis", nullptr);
92 }
93 static void toggle_statusbar() { hook_call("qtui toggle statusbar", nullptr); }
94 static void toggle_remaining_time()
95 {
96 hook_call("qtui toggle remaining time", nullptr);
97 }
98
99 QMenuBar * qtui_build_menubar(QWidget * parent)
65100 {
66101 static const audqt::MenuItem file_items[] = {
67 audqt::MenuCommand ({N_("_Open Files ..."), "document-open", "Ctrl+O"}, open_files),
68 audqt::MenuCommand ({N_("_Open Folder ..."), "document-open"}, open_folder),
69 audqt::MenuCommand ({N_("Open _URL ..."), "folder-remote", "Ctrl+L"}, open_url),
70 audqt::MenuCommand ({N_("_Add Files ..."), "list-add", "Ctrl+Shift+O"}, add_files),
71 audqt::MenuCommand ({N_("_Add Folder ..."), "list-add"}, add_folder),
72 audqt::MenuCommand ({N_("Add U_RL ..."), "folder-remote", "Ctrl+Shift+L"}, add_url),
73 audqt::MenuSep (),
74 audqt::MenuCommand ({N_("Search _Library"), "edit-find", "Ctrl+Y"}, show_search_tool),
75 audqt::MenuSep (),
76 audqt::MenuCommand ({N_("A_bout ..."), "help-about"}, aud_ui_show_about_window),
77 audqt::MenuCommand ({N_("_Settings ..."), "preferences-system"}, aud_ui_show_prefs_window),
78 audqt::MenuSep (),
79 audqt::MenuCommand ({N_("_Log Inspector ...")}, audqt::log_inspector_show),
80 audqt::MenuSep (),
81 audqt::MenuCommand ({N_("_Quit"), "application-exit", "Ctrl+Q"}, aud_quit)
102 audqt::MenuCommand({N_("_Open Files ..."), "document-open", "Ctrl+O"},
103 open_files),
104 audqt::MenuCommand({N_("_Open Folder ..."), "document-open"},
105 open_folder),
106 audqt::MenuCommand({N_("Open _URL ..."), "folder-remote", "Ctrl+L"},
107 open_url),
108 audqt::MenuCommand({N_("_Add Files ..."), "list-add", "Ctrl+Shift+O"},
109 add_files),
110 audqt::MenuCommand({N_("_Add Folder ..."), "list-add"}, add_folder),
111 audqt::MenuCommand(
112 {N_("Add U_RL ..."), "folder-remote", "Ctrl+Shift+L"}, add_url),
113 audqt::MenuSep(),
114 audqt::MenuCommand({N_("Search _Library"), "edit-find", "Ctrl+Y"},
115 show_search_tool),
116 audqt::MenuSep(),
117 audqt::MenuCommand({N_("A_bout ..."), "help-about"},
118 aud_ui_show_about_window),
119 audqt::MenuCommand({N_("_Settings ..."), "preferences-system"},
120 aud_ui_show_prefs_window),
121 audqt::MenuSep(),
122 audqt::MenuCommand({N_("_Log Inspector ...")},
123 audqt::log_inspector_show),
124 audqt::MenuSep(),
125 audqt::MenuCommand({N_("_Quit"), "application-exit", "Ctrl+Q"},
126 aud_quit)};
127
128 static const audqt::MenuItem playback_items[] = {
129 audqt::MenuCommand({N_("_Play"), "media-playback-start", "Ctrl+Return"},
130 aud_drct_play),
131 audqt::MenuCommand({N_("Paus_e"), "media-playback-pause", "Ctrl+,"},
132 aud_drct_pause),
133 audqt::MenuCommand({N_("_Stop"), "media-playback-stop", "Ctrl+."},
134 aud_drct_stop),
135 audqt::MenuCommand({N_("Pre_vious"), "media-skip-backward", "Alt+Up"},
136 aud_drct_pl_prev),
137 audqt::MenuCommand({N_("_Next"), "media-skip-forward", "Alt+Down"},
138 aud_drct_pl_next),
139 audqt::MenuCommand({N_("Previous Album")}, aud_drct_pl_prev_album),
140 audqt::MenuCommand({N_("Next Album")}, aud_drct_pl_next_album),
141 audqt::MenuSep(),
142 audqt::MenuToggle({N_("_Repeat"), "media-playlist-repeat", "Ctrl+R"},
143 {nullptr, "repeat", "set repeat"}),
144 audqt::MenuToggle({N_("S_huffle"), "media-playlist-shuffle", "Ctrl+S"},
145 {nullptr, "shuffle", "set shuffle"}),
146 audqt::MenuToggle({N_("Shuffle by Albu_m")},
147 {nullptr, "album_shuffle", "set album_shuffle"}),
148 audqt::MenuToggle(
149 {N_("N_o Playlist Advance"), nullptr, "Ctrl+N"},
150 {nullptr, "no_playlist_advance", "set no_playlist_advance"}),
151 audqt::MenuToggle({N_("Stop A_fter This Song"), nullptr, "Ctrl+M"},
152 {nullptr, "stop_after_current_song",
153 "set stop_after_current_song"}),
154 audqt::MenuSep(),
155 audqt::MenuCommand(
156 {N_("Song _Info ..."), "dialog-information", "Ctrl+I"},
157 audqt::infowin_show_current)};
158
159 static const audqt::MenuItem dupe_items[] = {
160 audqt::MenuCommand({N_("By _Title")}, rm_dupes_title),
161 audqt::MenuCommand({N_("By _File Name")}, rm_dupes_filename),
162 audqt::MenuCommand({N_("By File _Path")}, rm_dupes_path),
82163 };
83164
84 static const audqt::MenuItem playback_items[] = {
85 audqt::MenuCommand ({N_("_Play"), "media-playback-start", "Ctrl+Return"}, aud_drct_play),
86 audqt::MenuCommand ({N_("Paus_e"), "media-playback-pause", "Ctrl+,"}, aud_drct_pause),
87 audqt::MenuCommand ({N_("_Stop"), "media-playback-stop", "Ctrl+."}, aud_drct_stop),
88 audqt::MenuCommand ({N_("Pre_vious"), "media-skip-backward", "Alt+Up"}, aud_drct_pl_prev),
89 audqt::MenuCommand ({N_("_Next"), "media-skip-forward", "Alt+Down"}, aud_drct_pl_next),
90 audqt::MenuSep (),
91 audqt::MenuToggle ({N_("_Repeat"), "media-playlist-repeat", "Ctrl+R"}, {nullptr, "repeat", "set repeat"}),
92 audqt::MenuToggle ({N_("S_huffle"), "media-playlist-shuffle", "Ctrl+S"}, {nullptr, "shuffle", "set shuffle"}),
93 audqt::MenuToggle ({N_("Shuffle by Albu_m")}, {nullptr, "album_shuffle", "set album_shuffle"}),
94 audqt::MenuToggle ({N_("N_o Playlist Advance"), nullptr, "Ctrl+N"}, {nullptr, "no_playlist_advance", "set no_playlist_advance"}),
95 audqt::MenuToggle ({N_("Stop A_fter This Song"), nullptr, "Ctrl+M"}, {nullptr, "stop_after_current_song", "set stop_after_current_song"}),
96 audqt::MenuSep (),
97 audqt::MenuCommand ({N_("Song _Info ..."), "dialog-information", "Ctrl+I"}, audqt::infowin_show_current)
98 };
99
100 static const audqt::MenuItem dupe_items[] = {
101 audqt::MenuCommand ({N_("By _Title")}, rm_dupes_title),
102 audqt::MenuCommand ({N_("By _File Name")}, rm_dupes_filename),
103 audqt::MenuCommand ({N_("By File _Path")}, rm_dupes_path),
104 };
105
106165 static const audqt::MenuItem sort_items[] = {
107 audqt::MenuCommand ({N_("By Track _Number")}, sort_track),
108 audqt::MenuCommand ({N_("By _Title")}, sort_title),
109 audqt::MenuCommand ({N_("By _Artist")}, sort_artist),
110 audqt::MenuCommand ({N_("By Al_bum")}, sort_album),
111 audqt::MenuCommand ({N_("By Albu_m Artist")}, sort_album_artist),
112 audqt::MenuCommand ({N_("By Release _Date")}, sort_date),
113 audqt::MenuCommand ({N_("By _Genre")}, sort_genre),
114 audqt::MenuCommand ({N_("By _Length")}, sort_length),
115 audqt::MenuCommand ({N_("By _File Path")}, sort_path),
116 audqt::MenuCommand ({N_("By _Custom Title")}, sort_custom_title),
117 audqt::MenuCommand ({N_("By C_omment")}, sort_comment),
118 audqt::MenuSep (),
119 audqt::MenuCommand ({N_("R_everse Order"), "view-sort-descending"}, sort_reverse),
120 audqt::MenuCommand ({N_("_Random Order")}, sort_random)
121 };
166 audqt::MenuCommand({N_("By Track _Number")}, sort_track),
167 audqt::MenuCommand({N_("By _Title")}, sort_title),
168 audqt::MenuCommand({N_("By _Artist")}, sort_artist),
169 audqt::MenuCommand({N_("By Al_bum")}, sort_album),
170 audqt::MenuCommand({N_("By Albu_m Artist")}, sort_album_artist),
171 audqt::MenuCommand({N_("By Release _Date")}, sort_date),
172 audqt::MenuCommand({N_("By _Genre")}, sort_genre),
173 audqt::MenuCommand({N_("By _Length")}, sort_length),
174 audqt::MenuCommand({N_("By _File Path")}, sort_path),
175 audqt::MenuCommand({N_("By _Custom Title")}, sort_custom_title),
176 audqt::MenuCommand({N_("By C_omment")}, sort_comment),
177 audqt::MenuSep(),
178 audqt::MenuCommand({N_("R_everse Order"), "view-sort-descending"},
179 sort_reverse),
180 audqt::MenuCommand({N_("_Random Order")}, sort_random)};
122181
123182 static const audqt::MenuItem sort_selected_items[] = {
124 audqt::MenuCommand ({N_("By Track _Number")}, sort_sel_track),
125 audqt::MenuCommand ({N_("By _Title")}, sort_sel_title),
126 audqt::MenuCommand ({N_("By _Artist")}, sort_sel_artist),
127 audqt::MenuCommand ({N_("By Al_bum")}, sort_sel_album),
128 audqt::MenuCommand ({N_("By Albu_m Artist")}, sort_sel_album_artist),
129 audqt::MenuCommand ({N_("By Release _Date")}, sort_sel_date),
130 audqt::MenuCommand ({N_("By _Genre")}, sort_sel_genre),
131 audqt::MenuCommand ({N_("By _Length")}, sort_sel_length),
132 audqt::MenuCommand ({N_("By _File Path")}, sort_sel_path),
133 audqt::MenuCommand ({N_("By _Custom Title")}, sort_sel_custom_title),
134 audqt::MenuCommand ({N_("By C_omment")}, sort_sel_comment),
135 audqt::MenuSep (),
136 audqt::MenuCommand ({N_("R_everse Order"), "view-sort-descending"}, sort_sel_reverse),
137 audqt::MenuCommand ({N_("_Random Order")}, sort_sel_random)
138 };
183 audqt::MenuCommand({N_("By Track _Number")}, sort_sel_track),
184 audqt::MenuCommand({N_("By _Title")}, sort_sel_title),
185 audqt::MenuCommand({N_("By _Artist")}, sort_sel_artist),
186 audqt::MenuCommand({N_("By Al_bum")}, sort_sel_album),
187 audqt::MenuCommand({N_("By Albu_m Artist")}, sort_sel_album_artist),
188 audqt::MenuCommand({N_("By Release _Date")}, sort_sel_date),
189 audqt::MenuCommand({N_("By _Genre")}, sort_sel_genre),
190 audqt::MenuCommand({N_("By _Length")}, sort_sel_length),
191 audqt::MenuCommand({N_("By _File Path")}, sort_sel_path),
192 audqt::MenuCommand({N_("By _Custom Title")}, sort_sel_custom_title),
193 audqt::MenuCommand({N_("By C_omment")}, sort_sel_comment),
194 audqt::MenuSep(),
195 audqt::MenuCommand({N_("R_everse Order"), "view-sort-descending"},
196 sort_sel_reverse),
197 audqt::MenuCommand({N_("_Random Order")}, sort_sel_random)};
139198
140199 static const audqt::MenuItem playlist_items[] = {
141 audqt::MenuCommand ({N_("_Play/Resume"), "media-playback-start", "Shift+Return"}, pl_play),
142 audqt::MenuCommand ({N_("_Refresh"), "view-refresh", "F5"}, pl_refresh),
143 audqt::MenuSep (),
144 audqt::MenuCommand ({N_("_Find ..."), "edit-find", "Ctrl+F"}, pl_find),
145 audqt::MenuSep (),
146 audqt::MenuSub ({N_("_Sort"), "view-sort-ascending"}, sort_items),
147 audqt::MenuSub ({N_("Sort Se_lected"), "view-sort-ascending"}, sort_selected_items),
148 audqt::MenuSub ({N_("Remove _Duplicates"), "edit-copy"}, dupe_items),
149 audqt::MenuCommand ({N_("Remove _Unavailable Files"), "dialog-warning"}, pl_remove_failed),
150 audqt::MenuSep (),
151 audqt::MenuCommand ({N_("_New"), "document-new", "Ctrl+T"}, pl_new),
152 audqt::MenuCommand ({N_("Ren_ame ..."), "insert-text", "F2"}, pl_rename),
153 audqt::MenuCommand ({N_("Remo_ve"), "edit-delete", "Ctrl+W"}, pl_close),
154 audqt::MenuSep (),
155 audqt::MenuCommand ({N_("_Import ..."), "document-open"}, pl_import),
156 audqt::MenuCommand ({N_("_Export ..."), "document-save"}, pl_export),
157 audqt::MenuSep (),
158 audqt::MenuCommand ({N_("Playlist _Manager ..."), "audio-x-generic", "Ctrl+P"}, show_playlist_manager),
159 audqt::MenuCommand ({N_("_Queue Manager ..."), nullptr, "Ctrl+U"}, audqt::queue_manager_show)
160 };
200 audqt::MenuCommand(
201 {N_("_Play/Resume"), "media-playback-start", "Shift+Return"},
202 pl_play),
203 audqt::MenuCommand({N_("_Refresh"), "view-refresh", "F5"}, pl_refresh),
204 audqt::MenuSep(),
205 audqt::MenuCommand({N_("_Find ..."), "edit-find", "Ctrl+F"}, pl_find),
206 audqt::MenuSep(),
207 audqt::MenuSub({N_("_Sort"), "view-sort-ascending"}, sort_items),
208 audqt::MenuSub({N_("Sort Se_lected"), "view-sort-ascending"},
209 sort_selected_items),
210 audqt::MenuSub({N_("Remove _Duplicates"), "edit-copy"}, dupe_items),
211 audqt::MenuCommand({N_("Remove _Unavailable Files"), "dialog-warning"},
212 pl_remove_failed),
213 audqt::MenuSep(),
214 audqt::MenuCommand({N_("_New"), "document-new", "Ctrl+T"}, pl_new),
215 audqt::MenuCommand({N_("Ren_ame ..."), "insert-text", "F2"}, pl_rename),
216 audqt::MenuCommand({N_("Remo_ve"), "edit-delete", "Ctrl+W"}, pl_close),
217 audqt::MenuSep(),
218 audqt::MenuCommand({N_("_Import ..."), "document-open"}, pl_import),
219 audqt::MenuCommand({N_("_Export ..."), "document-save"}, pl_export),
220 audqt::MenuSep(),
221 audqt::MenuCommand(
222 {N_("Playlist _Manager ..."), "audio-x-generic", "Ctrl+P"},
223 show_playlist_manager),
224 audqt::MenuCommand({N_("_Queue Manager ..."), nullptr, "Ctrl+U"},
225 audqt::queue_manager_show)};
161226
162227 static const audqt::MenuItem output_items[] = {
163 audqt::MenuCommand ({N_("Volume _Up"), "audio-volume-high", "Ctrl++"}, volume_up),
164 audqt::MenuCommand ({N_("Volume _Down"), "audio-volume-low", "Ctrl+-"}, volume_down),
165 audqt::MenuSep (),
166 audqt::MenuCommand ({N_("_Equalizer ..."), "multimedia-volume-control", "Ctrl+E"}, audqt::equalizer_show),
167 audqt::MenuCommand ({N_("E_ffects ..."), "preferences-system"}, configure_effects),
168 audqt::MenuSep (),
169 audqt::MenuToggle ({N_("Record Stream"), "media-record", "Ctrl+D"}, {nullptr, "record", "set record"}),
170 audqt::MenuCommand ({N_("Audio Settings ..."), "audio-card"}, configure_output)
171 };
228 audqt::MenuCommand({N_("Volume _Up"), "audio-volume-high", "Ctrl++"},
229 volume_up),
230 audqt::MenuCommand({N_("Volume _Down"), "audio-volume-low", "Ctrl+-"},
231 volume_down),
232 audqt::MenuSep(),
233 audqt::MenuCommand(
234 {N_("_Equalizer ..."), "multimedia-volume-control", "Ctrl+E"},
235 audqt::equalizer_show),
236 audqt::MenuCommand({N_("E_ffects ..."), "preferences-system"},
237 configure_effects),
238 audqt::MenuSep(),
239 audqt::MenuToggle({N_("Record Stream"), "media-record", "Ctrl+D"},
240 {nullptr, "record", "set record"}),
241 audqt::MenuCommand({N_("Audio Settings ..."), "audio-card"},
242 configure_output)};
172243
173244 static const audqt::MenuItem view_items[] = {
174 audqt::MenuToggle ({N_("Show _Menu Bar"), nullptr, "Shift+Ctrl+M"}, {"qtui", "menu_visible"}, toggle_menubar),
175 audqt::MenuToggle ({N_("Show I_nfo Bar"), nullptr, "Shift+Ctrl+I"}, {"qtui", "infoarea_visible"}, toggle_infoarea),
176 audqt::MenuToggle ({N_("Show Info Bar Vis_ualization")}, {"qtui", "infoarea_show_vis"}, toggle_infoarea_vis),
177 audqt::MenuToggle ({N_("Show _Status Bar"), nullptr, "Shift+Ctrl+S"}, {"qtui", "statusbar_visible"}, toggle_statusbar),
178 audqt::MenuSep (),
179 audqt::MenuToggle ({N_("Show _Remaining Time"), nullptr, "Shift+Ctrl+R"}, {"qtui", "show_remaining_time", "qtui toggle remaining time"}, toggle_remaining_time),
180 audqt::MenuSep (),
181 audqt::MenuCommand ({N_("_Visualizations ..."), "preferences-system"}, configure_visualizations)
182 };
245 audqt::MenuToggle({N_("Show _Menu Bar"), nullptr, "Shift+Ctrl+M"},
246 {"qtui", "menu_visible"}, toggle_menubar),
247 audqt::MenuToggle({N_("Show I_nfo Bar"), nullptr, "Shift+Ctrl+I"},
248 {"qtui", "infoarea_visible"}, toggle_infoarea),
249 audqt::MenuToggle({N_("Show Info Bar Vis_ualization")},
250 {"qtui", "infoarea_show_vis"}, toggle_infoarea_vis),
251 audqt::MenuToggle({N_("Show _Status Bar"), nullptr, "Shift+Ctrl+S"},
252 {"qtui", "statusbar_visible"}, toggle_statusbar),
253 audqt::MenuSep(),
254 audqt::MenuToggle(
255 {N_("Show _Remaining Time"), nullptr, "Shift+Ctrl+R"},
256 {"qtui", "show_remaining_time", "qtui toggle remaining time"},
257 toggle_remaining_time),
258 audqt::MenuSep(),
259 audqt::MenuCommand({N_("_Visualizations ..."), "preferences-system"},
260 configure_visualizations)};
183261
184262 static const audqt::MenuItem main_items[] = {
185 audqt::MenuSub ({N_("_File")}, file_items),
186 audqt::MenuSub ({N_("_Playback")}, playback_items),
187 audqt::MenuSub ({N_("P_laylist")}, playlist_items),
188 audqt::MenuSub ({N_("_Services")}, services_menu),
189 audqt::MenuSub ({N_("_Output")}, output_items),
190 audqt::MenuSub ({N_("_View")}, view_items)
191 };
192
193 return audqt::menubar_build (main_items, parent);
194 }
195
196 QMenu * qtui_build_pl_menu (QWidget * parent)
263 audqt::MenuSub({N_("_File")}, file_items),
264 audqt::MenuSub({N_("_Playback")}, playback_items),
265 audqt::MenuSub({N_("P_laylist")}, playlist_items),
266 audqt::MenuSub({N_("_Services")}, services_menu),
267 audqt::MenuSub({N_("_Output")}, output_items),
268 audqt::MenuSub({N_("_View")}, view_items)};
269
270 return audqt::menubar_build(main_items, parent);
271 }
272
273 QMenu * qtui_build_pl_menu(QWidget * parent)
197274 {
198275 static const audqt::MenuItem pl_items[] = {
199 audqt::MenuCommand ({N_("Song _Info ..."), "dialog-information", "Alt+I"}, pl_song_info),
200 audqt::MenuCommand ({N_("_Queue/Unqueue"), nullptr, "Alt+Q"}, pl_queue_toggle),
201 audqt::MenuSep (),
202 audqt::MenuCommand ({N_("_Open Containing Folder"), "folder"}, pl_open_folder),
203 audqt::MenuCommand ({N_("_Refresh Selected"), "view-refresh", "F6"}, pl_refresh_sel),
204 audqt::MenuSep (),
205 audqt::MenuCommand ({N_("Cu_t"), "edit-cut", "Ctrl+X"}, pl_cut),
206 audqt::MenuCommand ({N_("_Copy"), "edit-copy", "Ctrl+C"}, pl_copy),
207 audqt::MenuCommand ({N_("_Paste"), "edit-paste", "Ctrl+V"}, pl_paste),
208 audqt::MenuCommand ({N_("Paste at _End"), "edit-paste", "Shift+Ctrl+V"}, pl_paste_end),
209 audqt::MenuCommand ({N_("Select _All"), "edit-select-all"}, pl_select_all),
210 audqt::MenuSep (),
211 audqt::MenuSub ({N_("_Services")}, services_menu_pl)
212 };
213
214 return audqt::menu_build (pl_items, parent);
215 }
276 audqt::MenuCommand(
277 {N_("Song _Info ..."), "dialog-information", "Alt+I"},
278 pl_song_info),
279 audqt::MenuCommand({N_("_Queue/Unqueue"), nullptr, "Alt+Q"},
280 pl_queue_toggle),
281 audqt::MenuSep(),
282 audqt::MenuCommand({N_("_Open Containing Folder"), "folder"},
283 pl_open_folder),
284 audqt::MenuCommand({N_("_Refresh Selected"), "view-refresh", "F6"},
285 pl_refresh_sel),
286 audqt::MenuSep(),
287 audqt::MenuCommand({N_("Cu_t"), "edit-cut", "Ctrl+X"}, pl_cut),
288 audqt::MenuCommand({N_("_Copy"), "edit-copy", "Ctrl+C"}, pl_copy),
289 audqt::MenuCommand({N_("_Paste"), "edit-paste", "Ctrl+V"}, pl_paste),
290 audqt::MenuCommand({N_("Paste at _End"), "edit-paste", "Shift+Ctrl+V"},
291 pl_paste_end),
292 audqt::MenuCommand({N_("Select _All"), "edit-select-all"},
293 pl_select_all),
294 audqt::MenuSep(),
295 audqt::MenuSub({N_("_Services")}, services_menu_pl)};
296
297 return audqt::menu_build(pl_items, parent);
298 }
2323 class QMenuBar;
2424 class QWidget;
2525
26 QMenuBar * qtui_build_menubar (QWidget * parent);
27 QMenu * qtui_build_pl_menu (QWidget * parent);
26 QMenuBar * qtui_build_menubar(QWidget * parent);
27 QMenu * qtui_build_pl_menu(QWidget * parent);
2828
2929 #endif // MENUS_H
0 qtui_sources = [
1 'qtui.cc',
2 'dialogs-qt.cc',
3 'main_window.cc',
4 'menu-ops.cc',
5 'menus.cc',
6 'playlist-qt.cc',
7 'playlist_header.cc',
8 'playlist_model.cc',
9 'playlist_tabs.cc',
10 'info_bar.cc',
11 'search_bar.cc',
12 'status_bar.cc',
13 'tool_bar.cc',
14 'time_slider.cc',
15 'settings.cc'
16 ]
17
18
19 shared_module('qtui',
20 qtui_sources,
21 dependencies: [audacious_dep, qt_dep, audqt_dep],
22 install: true,
23 install_dir: general_plugin_dir
24 )
25
3232
3333 #include "../ui-common/menu-ops.h"
3434
35 PlaylistWidget::PlaylistWidget (QWidget * parent, Playlist playlist) :
36 QTreeView (parent),
37 m_playlist (playlist),
38 model (new PlaylistModel (this, playlist)),
39 proxyModel (new PlaylistProxyModel (this, playlist))
35 PlaylistWidget::PlaylistWidget(QWidget * parent, Playlist playlist)
36 : audqt::TreeView(parent), m_playlist(playlist),
37 model(new PlaylistModel(this, playlist)),
38 proxyModel(new PlaylistProxyModel(this, playlist))
4039 {
4140 /* setting up filtering model */
42 proxyModel->setSourceModel (model);
41 proxyModel->setSourceModel(model);
4342
4443 inUpdate = true; /* prevents changing focused row */
45 setModel (proxyModel);
44 setModel(proxyModel);
4645 inUpdate = false;
4746
48 auto header = new PlaylistHeader (this);
49 setHeader (header);
50
51 setAllColumnsShowFocus (true);
52 setAlternatingRowColors (true);
53 setAttribute (Qt::WA_MacShowFocusRect, false);
54 setUniformRowHeights (true);
55 setFrameShape (QFrame::NoFrame);
56 setSelectionMode (ExtendedSelection);
57 setDragDropMode (DragDrop);
58 setMouseTracking (true);
59
60 updateSettings ();
61 header->updateColumns ();
47 auto header = new PlaylistHeader(this);
48 setHeader(header);
49 /* this has to come after setHeader() to take effect */
50 header->setSectionsClickable(true);
51
52 setAllColumnsShowFocus(true);
53 setAlternatingRowColors(true);
54 setAttribute(Qt::WA_MacShowFocusRect, false);
55 setUniformRowHeights(true);
56 setFrameShape(QFrame::NoFrame);
57 setSelectionMode(ExtendedSelection);
58 setDragDropMode(DragDrop);
59 setMouseTracking(true);
60
61 updateSettings();
62 header->updateColumns();
6263
6364 /* get initial selection and focus from core */
6465 inUpdate = true;
65 updateSelection (0, 0);
66 updateSelection(0, 0);
6667 inUpdate = false;
6768 }
6869
69 PlaylistWidget::~PlaylistWidget ()
70 PlaylistWidget::~PlaylistWidget()
7071 {
7172 delete model;
7273 delete proxyModel;
7374 }
7475
75 QModelIndex PlaylistWidget::rowToIndex (int row)
76 QModelIndex PlaylistWidget::rowToIndex(int row)
7677 {
7778 if (row < 0)
78 return QModelIndex ();
79
80 return proxyModel->mapFromSource (model->index (row, firstVisibleColumn));
81 }
82
83 int PlaylistWidget::indexToRow (const QModelIndex & index)
84 {
85 if (! index.isValid ())
79 return QModelIndex();
80
81 return proxyModel->mapFromSource(model->index(row, firstVisibleColumn));
82 }
83
84 int PlaylistWidget::indexToRow(const QModelIndex & index)
85 {
86 if (!index.isValid())
8687 return -1;
8788
88 return proxyModel->mapToSource (index).row ();
89 }
90
91 QModelIndex PlaylistWidget::visibleIndexNear (int row)
92 {
93 QModelIndex index = rowToIndex (row);
94 if (index.isValid ())
89 return proxyModel->mapToSource(index).row();
90 }
91
92 QModelIndex PlaylistWidget::visibleIndexNear(int row)
93 {
94 QModelIndex index = rowToIndex(row);
95 if (index.isValid())
9596 return index;
9697
97 int n_entries = m_playlist.n_entries ();
98
99 for (int r = row + 1; r < n_entries; r ++)
100 {
101 index = rowToIndex (r);
102 if (index.isValid ())
98 int n_entries = m_playlist.n_entries();
99
100 for (int r = row + 1; r < n_entries; r++)
101 {
102 index = rowToIndex(r);
103 if (index.isValid())
103104 return index;
104105 }
105106
106 for (int r = row - 1; r >= 0; r --)
107 {
108 index = rowToIndex (r);
109 if (index.isValid ())
107 for (int r = row - 1; r >= 0; r--)
108 {
109 index = rowToIndex(r);
110 if (index.isValid())
110111 return index;
111112 }
112113
113114 return index;
114115 }
115116
116 void PlaylistWidget::contextMenuEvent (QContextMenuEvent * event)
117 void PlaylistWidget::activate(const QModelIndex & index)
118 {
119 if (index.isValid())
120 {
121 m_playlist.set_position(indexToRow(index));
122 m_playlist.start_playback();
123 }
124 }
125
126 void PlaylistWidget::contextMenuEvent(QContextMenuEvent * event)
117127 {
118128 if (contextMenu)
119 contextMenu->popup (event->globalPos ());
120 }
121
122 void PlaylistWidget::keyPressEvent (QKeyEvent * event)
123 {
124 auto CtrlShiftAlt = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
125 if (! (event->modifiers () & CtrlShiftAlt))
126 {
127 switch (event->key ())
129 contextMenu->popup(event->globalPos());
130 }
131
132 void PlaylistWidget::keyPressEvent(QKeyEvent * event)
133 {
134 auto CtrlShiftAlt =
135 Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
136 if (!(event->modifiers() & CtrlShiftAlt))
137 {
138 switch (event->key())
128139 {
129 case Qt::Key_Enter:
130 case Qt::Key_Return:
131 playCurrentIndex ();
132 return;
133140 case Qt::Key_Right:
134 aud_drct_seek (aud_drct_get_time () + aud_get_double ("qtui", "step_size") * 1000);
141 aud_drct_seek(aud_drct_get_time() +
142 aud_get_int("step_size") * 1000);
135143 return;
136144 case Qt::Key_Left:
137 aud_drct_seek (aud_drct_get_time () - aud_get_double ("qtui", "step_size") * 1000);
145 aud_drct_seek(aud_drct_get_time() -
146 aud_get_int("step_size") * 1000);
138147 return;
139148 case Qt::Key_Space:
140 aud_drct_play_pause ();
149 aud_drct_play_pause();
141150 return;
142151 case Qt::Key_Delete:
143 pl_remove_selected ();
152 pl_remove_selected();
144153 return;
145154 case Qt::Key_Z:
146 aud_drct_pl_prev ();
155 aud_drct_pl_prev();
147156 return;
148157 case Qt::Key_X:
149 aud_drct_play ();
158 aud_drct_play();
150159 return;
151160 case Qt::Key_C:
152 aud_drct_pause ();
161 aud_drct_pause();
153162 return;
154163 case Qt::Key_V:
155 aud_drct_stop ();
164 aud_drct_stop();
156165 return;
157166 case Qt::Key_B:
158 aud_drct_pl_next ();
167 aud_drct_pl_next();
159168 return;
160169 }
161170 }
162171
163 QTreeView::keyPressEvent (event);
164 }
165
166 void PlaylistWidget::mouseDoubleClickEvent (QMouseEvent * event)
167 {
168 QModelIndex index = indexAt (event->pos ());
169 if (! index.isValid ())
170 return;
171
172 if (event->button () == Qt::LeftButton)
173 playCurrentIndex ();
174 }
175
176 void PlaylistWidget::mouseMoveEvent (QMouseEvent * event)
177 {
178 int row = indexToRow (indexAt (event->pos ()));
172 audqt::TreeView::keyPressEvent(event);
173 }
174
175 void PlaylistWidget::mouseMoveEvent(QMouseEvent * event)
176 {
177 int row = indexToRow(indexAt(event->pos()));
179178
180179 if (row < 0)
181 hidePopup ();
182 else if (aud_get_bool (nullptr, "show_filepopup_for_tuple") && m_popup_pos != row)
183 triggerPopup (row);
184
185 QTreeView::mouseMoveEvent (event);
186 }
187
188 void PlaylistWidget::leaveEvent (QEvent * event)
189 {
190 hidePopup ();
191
192 QTreeView::leaveEvent (event);
180 hidePopup();
181 else if (aud_get_bool("show_filepopup_for_tuple") && m_popup_pos != row)
182 triggerPopup(row);
183
184 audqt::TreeView::mouseMoveEvent(event);
185 }
186
187 void PlaylistWidget::leaveEvent(QEvent * event)
188 {
189 hidePopup();
190
191 audqt::TreeView::leaveEvent(event);
193192 }
194193
195194 /* Since Qt doesn't support both DragDrop and InternalMove at once,
196195 * this hack is needed to set the drag icon to "move" for internal drags. */
197 void PlaylistWidget::dragMoveEvent (QDragMoveEvent * event)
198 {
199 if (event->source () == this)
200 event->setDropAction (Qt::MoveAction);
201
202 QTreeView::dragMoveEvent (event);
203
204 if (event->source () == this)
205 event->setDropAction (Qt::MoveAction);
206 }
207
208 void PlaylistWidget::dropEvent (QDropEvent * event)
196 void PlaylistWidget::dragMoveEvent(QDragMoveEvent * event)
197 {
198 if (event->source() == this)
199 event->setDropAction(Qt::MoveAction);
200
201 audqt::TreeView::dragMoveEvent(event);
202
203 if (event->source() == this)
204 event->setDropAction(Qt::MoveAction);
205 }
206
207 void PlaylistWidget::dropEvent(QDropEvent * event)
209208 {
210209 /* let Qt forward external drops to the PlaylistModel */
211 if (event->source () != this)
212 return QTreeView::dropEvent (event);
213
214 int from = indexToRow (currentIndex ());
210 if (event->source() != this)
211 return audqt::TreeView::dropEvent(event);
212
213 int from = indexToRow(currentIndex());
215214 if (from < 0)
216215 return;
217216
218217 int to;
219 switch (dropIndicatorPosition ())
220 {
221 case AboveItem: to = indexToRow (indexAt (event->pos ())); break;
222 case BelowItem: to = indexToRow (indexAt (event->pos ())) + 1; break;
223 case OnViewport: to = m_playlist.n_entries (); break;
224 default: return;
218 switch (dropIndicatorPosition())
219 {
220 case AboveItem:
221 to = indexToRow(indexAt(event->pos()));
222 break;
223 case BelowItem:
224 to = indexToRow(indexAt(event->pos())) + 1;
225 break;
226 case OnViewport:
227 to = m_playlist.n_entries();
228 break;
229 default:
230 return;
225231 }
226232
227233 /* Adjust the shift amount so that the selected entry closest to the
228234 * destination ends up at the destination. */
229235 if (to > from)
230 to -= m_playlist.n_selected (from, to - from);
236 to -= m_playlist.n_selected(from, to - from);
231237 else
232 to += m_playlist.n_selected (to, from - to);
233
234 m_playlist.shift_entries (from, to - from);
235
236 event->acceptProposedAction ();
237 }
238
239 void PlaylistWidget::currentChanged (const QModelIndex & current, const QModelIndex & previous)
240 {
241 QTreeView::currentChanged (current, previous);
242
243 if (! inUpdate)
244 m_playlist.set_focus (indexToRow (current));
245 }
246
247 void PlaylistWidget::selectionChanged (const QItemSelection & selected,
248 const QItemSelection & deselected)
249 {
250 QTreeView::selectionChanged (selected, deselected);
251
252 if (! inUpdate)
253 {
254 for (const QModelIndex & idx : selected.indexes ())
255 m_playlist.select_entry (indexToRow (idx), true);
256 for (const QModelIndex & idx : deselected.indexes ())
257 m_playlist.select_entry (indexToRow (idx), false);
238 to += m_playlist.n_selected(to, from - to);
239
240 m_playlist.shift_entries(from, to - from);
241
242 event->acceptProposedAction();
243 }
244
245 void PlaylistWidget::currentChanged(const QModelIndex & current,
246 const QModelIndex & previous)
247 {
248 audqt::TreeView::currentChanged(current, previous);
249
250 if (!inUpdate)
251 m_playlist.set_focus(indexToRow(current));
252 }
253
254 void PlaylistWidget::selectionChanged(const QItemSelection & selected,
255 const QItemSelection & deselected)
256 {
257 audqt::TreeView::selectionChanged(selected, deselected);
258
259 if (!inUpdate)
260 {
261 for (const QModelIndex & idx : selected.indexes())
262 m_playlist.select_entry(indexToRow(idx), true);
263 for (const QModelIndex & idx : deselected.indexes())
264 m_playlist.select_entry(indexToRow(idx), false);
258265 }
259266 }
260267
261268 /* returns true if the focus changed or the playlist scrolled */
262 bool PlaylistWidget::scrollToCurrent (bool force)
269 bool PlaylistWidget::scrollToCurrent(bool force)
263270 {
264271 bool scrolled = false;
265 int entry = m_playlist.get_position ();
266
267 if (entry >= 0 && (aud_get_bool ("qtui", "autoscroll") || force))
268 {
269 if (m_playlist.get_focus () != entry)
272 int entry = m_playlist.get_position();
273
274 if (entry >= 0 && (aud_get_bool("qtui", "autoscroll") || force))
275 {
276 if (m_playlist.get_focus() != entry)
270277 scrolled = true;
271278
272 m_playlist.select_all (false);
273 m_playlist.select_entry (entry, true);
274 m_playlist.set_focus (entry);
275
276 auto index = rowToIndex (entry);
277 auto rect = visualRect (index);
278
279 scrollTo (index);
280
281 if (visualRect (index) != rect)
279 m_playlist.select_all(false);
280 m_playlist.select_entry(entry, true);
281 m_playlist.set_focus(entry);
282
283 auto index = rowToIndex(entry);
284 auto rect = visualRect(index);
285
286 scrollTo(index);
287
288 if (visualRect(index) != rect)
282289 scrolled = true;
283290 }
284291
285292 return scrolled;
286293 }
287294
288 void PlaylistWidget::updatePlaybackIndicator ()
295 void PlaylistWidget::updatePlaybackIndicator()
289296 {
290297 if (currentPos >= 0)
291 model->entriesChanged (currentPos, 1);
292 }
293
294 void PlaylistWidget::getSelectedRanges (int rowsBefore, int rowsAfter,
295 QItemSelection & selected, QItemSelection & deselected)
296 {
297 int entries = m_playlist.n_entries ();
298 model->entriesChanged(currentPos, 1);
299 }
300
301 void PlaylistWidget::getSelectedRanges(int rowsBefore, int rowsAfter,
302 QItemSelection & selected,
303 QItemSelection & deselected)
304 {
305 int entries = m_playlist.n_entries();
298306
299307 QItemSelection ranges[2];
300308 QModelIndex first, last;
301309 bool prev = false;
302310
303 for (int row = rowsBefore; row < entries - rowsAfter; row ++)
304 {
305 auto idx = rowToIndex (row);
306 if (! idx.isValid ())
311 for (int row = rowsBefore; row < entries - rowsAfter; row++)
312 {
313 auto idx = rowToIndex(row);
314 if (!idx.isValid())
307315 continue;
308316
309 bool sel = m_playlist.entry_selected (row);
310
311 if (sel != prev && first.isValid ())
312 ranges[prev].merge (QItemSelection (first, last), QItemSelectionModel::Select);
313
314 if (sel != prev || ! first.isValid ())
317 bool sel = m_playlist.entry_selected(row);
318
319 if (sel != prev && first.isValid())
320 ranges[prev].merge(QItemSelection(first, last),
321 QItemSelectionModel::Select);
322
323 if (sel != prev || !first.isValid())
315324 first = idx;
316325
317326 last = idx;
318327 prev = sel;
319328 }
320329
321 if (first.isValid ())
322 ranges[prev].merge (QItemSelection (first, last), QItemSelectionModel::Select);
323
324 selected = std::move (ranges[true]);
325 deselected = std::move (ranges[false]);
326 }
327
328 void PlaylistWidget::updateSelection (int rowsBefore, int rowsAfter)
330 if (first.isValid())
331 ranges[prev].merge(QItemSelection(first, last),
332 QItemSelectionModel::Select);
333
334 selected = std::move(ranges[true]);
335 deselected = std::move(ranges[false]);
336 }
337
338 void PlaylistWidget::updateSelection(int rowsBefore, int rowsAfter)
329339 {
330340 QItemSelection selected, deselected;
331 getSelectedRanges (rowsBefore, rowsAfter, selected, deselected);
332
333 auto sel = selectionModel ();
334
335 if (! selected.isEmpty ())
336 sel->select (selected, sel->Select | sel->Rows);
337 if (! deselected.isEmpty ())
338 sel->select (deselected, sel->Deselect | sel->Rows);
339
340 sel->setCurrentIndex (rowToIndex (m_playlist.get_focus ()), sel->NoUpdate);
341 }
342
343 void PlaylistWidget::playlistUpdate ()
344 {
345 auto update = m_playlist.update_detail ();
341 getSelectedRanges(rowsBefore, rowsAfter, selected, deselected);
342
343 auto sel = selectionModel();
344
345 if (!selected.isEmpty())
346 sel->select(selected, sel->Select | sel->Rows);
347 if (!deselected.isEmpty())
348 sel->select(deselected, sel->Deselect | sel->Rows);
349
350 sel->setCurrentIndex(rowToIndex(m_playlist.get_focus()), sel->NoUpdate);
351 }
352
353 void PlaylistWidget::playlistUpdate()
354 {
355 auto update = m_playlist.update_detail();
346356
347357 if (update.level == Playlist::NoUpdate)
348358 return;
349359
350360 inUpdate = true;
351361
352 int entries = m_playlist.n_entries ();
362 int entries = m_playlist.n_entries();
353363 int changed = entries - update.before - update.after;
354364
355365 if (update.level == Playlist::Structure)
356366 {
357 int old_entries = model->rowCount ();
367 int old_entries = model->rowCount();
358368 int removed = old_entries - update.before - update.after;
359369
360370 if (currentPos >= old_entries - update.after)
362372 else if (currentPos >= update.before)
363373 currentPos = -1;
364374
365 model->entriesRemoved (update.before, removed);
366 model->entriesAdded (update.before, changed);
375 model->entriesRemoved(update.before, removed);
376 model->entriesAdded(update.before, changed);
367377 }
368378 else if (update.level == Playlist::Metadata || update.queue_changed)
369 model->entriesChanged (update.before, changed);
379 model->entriesChanged(update.before, changed);
370380
371381 if (update.queue_changed)
372382 {
373 for (int i = m_playlist.n_queued (); i --; )
383 for (int i = m_playlist.n_queued(); i--;)
374384 {
375 int entry = m_playlist.queue_get_entry (i);
385 int entry = m_playlist.queue_get_entry(i);
376386 if (entry < update.before || entry >= entries - update.after)
377 model->entriesChanged (entry, 1);
387 model->entriesChanged(entry, 1);
378388 }
379389 }
380390
381 int pos = m_playlist.get_position ();
391 int pos = m_playlist.get_position();
382392
383393 if (pos != currentPos)
384394 {
385395 if (currentPos >= 0)
386 model->entriesChanged (currentPos, 1);
396 model->entriesChanged(currentPos, 1);
387397 if (pos >= 0)
388 model->entriesChanged (pos, 1);
398 model->entriesChanged(pos, 1);
389399
390400 currentPos = pos;
391401 }
392402
393 updateSelection (update.before, update.after);
403 updateSelection(update.before, update.after);
394404
395405 inUpdate = false;
396406 }
397407
398 void PlaylistWidget::playCurrentIndex ()
399 {
400 m_playlist.set_position (indexToRow (currentIndex ()));
401 m_playlist.start_playback ();
402 }
403
404 void PlaylistWidget::setFilter (const char * text)
408 void PlaylistWidget::setFilter(const char * text)
405409 {
406410 // Save the current focus before filtering
407 int focus = m_playlist.get_focus ();
411 int focus = m_playlist.get_focus();
408412
409413 // Empty the model before updating the filter. This prevents Qt from
410414 // performing a series of "rows added" or "rows deleted" updates, which can
411415 // be very slow (worst case O(N^2) complexity) on a large playlist.
412 model->entriesRemoved (0, model->rowCount ());
416 model->entriesRemoved(0, model->rowCount());
413417
414418 // Update the filter
415 proxyModel->setFilter (text);
419 proxyModel->setFilter(text);
416420
417421 // Repopulate the model
418 model->entriesAdded (0, m_playlist.n_entries ());
422 model->entriesAdded(0, m_playlist.n_entries());
419423
420424 // If the previously focused row is no longer visible with the new filter,
421425 // try to find a nearby one that is, and focus it.
422 auto index = visibleIndexNear (focus);
423
424 if (index.isValid ())
425 {
426 focus = indexToRow (index);
427 m_playlist.set_focus (focus);
428 m_playlist.select_all (false);
429 m_playlist.select_entry (focus, true);
430 scrollTo (index);
431 }
432 }
433
434 void PlaylistWidget::setFirstVisibleColumn (int col)
426 auto index = visibleIndexNear(focus);
427
428 if (index.isValid())
429 {
430 focus = indexToRow(index);
431 m_playlist.set_focus(focus);
432 m_playlist.select_all(false);
433 m_playlist.select_entry(focus, true);
434 scrollTo(index);
435 }
436 }
437
438 void PlaylistWidget::setFirstVisibleColumn(int col)
435439 {
436440 inUpdate = true;
437441 firstVisibleColumn = col;
438442
439443 // make sure current and selected indexes point to a visible column
440 updateSelection (0, 0);
444 updateSelection(0, 0);
441445
442446 inUpdate = false;
443447 }
444448
445 void PlaylistWidget::moveFocus (int distance)
446 {
447 int visibleRows = proxyModel->rowCount ();
448 if (! visibleRows)
449 void PlaylistWidget::moveFocus(int distance)
450 {
451 int visibleRows = proxyModel->rowCount();
452 if (!visibleRows)
449453 return;
450454
451 int row = currentIndex ().row ();
452 row = aud::clamp (row + distance, 0, visibleRows - 1);
453 setCurrentIndex (proxyModel->index (row, 0));
454 }
455
456 void PlaylistWidget::showPopup ()
457 {
458 audqt::infopopup_show (m_playlist, m_popup_pos);
459 }
460
461 void PlaylistWidget::triggerPopup (int pos)
462 {
463 audqt::infopopup_hide ();
455 int row = currentIndex().row();
456 row = aud::clamp(row + distance, 0, visibleRows - 1);
457 setCurrentIndex(proxyModel->index(row, 0));
458 }
459
460 void PlaylistWidget::showPopup()
461 {
462 audqt::infopopup_show(m_playlist, m_popup_pos);
463 }
464
465 void PlaylistWidget::triggerPopup(int pos)
466 {
467 audqt::infopopup_hide();
464468
465469 m_popup_pos = pos;
466 m_popup_timer.queue (aud_get_int (nullptr, "filepopup_delay") * 100,
467 aud::obj_member<PlaylistWidget, & PlaylistWidget::showPopup>, this);
468 }
469
470 void PlaylistWidget::hidePopup ()
471 {
472 audqt::infopopup_hide ();
470 m_popup_timer.queue(
471 aud_get_int("filepopup_delay") * 100,
472 aud::obj_member<PlaylistWidget, &PlaylistWidget::showPopup>, this);
473 }
474
475 void PlaylistWidget::hidePopup()
476 {
477 audqt::infopopup_hide();
473478
474479 m_popup_pos = -1;
475 m_popup_timer.stop ();
476 }
477
478 void PlaylistWidget::updateSettings ()
479 {
480 setHeaderHidden (! aud_get_bool ("qtui", "playlist_headers"));
481 }
480 m_popup_timer.stop();
481 }
482
483 void PlaylistWidget::updateSettings()
484 {
485 setHeaderHidden(!aud_get_bool("qtui", "playlist_headers"));
486 }
1919 #ifndef PLAYLIST_H
2020 #define PLAYLIST_H
2121
22 #include <QTreeView>
23
2422 #include <libaudcore/hook.h>
2523 #include <libaudcore/mainloop.h>
2624 #include <libaudcore/playlist.h>
25 #include <libaudqt/treeview.h>
2726
2827 class PlaylistModel;
2928 class PlaylistProxyModel;
3029 class QContextMenuEvent;
3130 class QMenu;
3231
33 class PlaylistWidget : public QTreeView
32 class PlaylistWidget : public audqt::TreeView
3433 {
3534 public:
36 PlaylistWidget (QWidget * parent, Playlist playlist);
37 ~PlaylistWidget ();
35 PlaylistWidget(QWidget * parent, Playlist playlist);
36 ~PlaylistWidget();
3837
39 Playlist playlist () const
40 { return m_playlist; }
38 Playlist playlist() const { return m_playlist; }
4139
42 bool scrollToCurrent (bool force = false);
43 void updatePlaybackIndicator ();
44 void playlistUpdate ();
45 void playCurrentIndex ();
46 void setFilter (const char * text);
47 void setFirstVisibleColumn (int col);
48 void moveFocus (int distance);
40 bool scrollToCurrent(bool force = false);
41 void updatePlaybackIndicator();
42 void playlistUpdate();
43 void setFilter(const char * text);
44 void setFirstVisibleColumn(int col);
45 void moveFocus(int distance);
4946
50 void setContextMenu (QMenu * menu)
51 { contextMenu = menu; }
47 void setContextMenu(QMenu * menu) { contextMenu = menu; }
5248
5349 private:
5450 Playlist m_playlist;
6359 int m_popup_pos = -1;
6460 QueuedFunc m_popup_timer;
6561
66 QModelIndex rowToIndex (int row);
67 int indexToRow (const QModelIndex & index);
68 QModelIndex visibleIndexNear (int row);
62 QModelIndex rowToIndex(int row);
63 int indexToRow(const QModelIndex & index);
64 QModelIndex visibleIndexNear(int row);
6965
70 void getSelectedRanges (int rowsBefore, int rowsAfter,
71 QItemSelection & selected, QItemSelection & deselected);
72 void updateSelection (int rowsBefore, int rowsAfter);
66 void getSelectedRanges(int rowsBefore, int rowsAfter,
67 QItemSelection & selected,
68 QItemSelection & deselected);
69 void updateSelection(int rowsBefore, int rowsAfter);
7370
74 void contextMenuEvent (QContextMenuEvent * event);
75 void keyPressEvent (QKeyEvent * event);
76 void mouseDoubleClickEvent (QMouseEvent * event);
77 void mouseMoveEvent (QMouseEvent * event);
78 void leaveEvent (QEvent * event);
79 void dragMoveEvent (QDragMoveEvent * event);
80 void dropEvent (QDropEvent * event);
81 void currentChanged (const QModelIndex & current, const QModelIndex & previous);
82 void selectionChanged (const QItemSelection & selected, const QItemSelection & deselected);
71 void activate(const QModelIndex & index);
72 void contextMenuEvent(QContextMenuEvent * event);
73 void keyPressEvent(QKeyEvent * event);
74 void mouseMoveEvent(QMouseEvent * event);
75 void leaveEvent(QEvent * event);
76 void dragMoveEvent(QDragMoveEvent * event);
77 void dropEvent(QDropEvent * event);
78 void currentChanged(const QModelIndex & current,
79 const QModelIndex & previous);
80 void selectionChanged(const QItemSelection & selected,
81 const QItemSelection & deselected);
8382
84 void showPopup ();
85 void triggerPopup (int pos);
86 void hidePopup ();
83 void showPopup();
84 void triggerPopup(int pos);
85 void hidePopup();
8786
88 void updateSettings ();
87 void updateSettings();
8988
90 const HookReceiver<PlaylistWidget>
91 hook1 {"qtui update playlist settings", this, & PlaylistWidget::updateSettings};
89 const HookReceiver<PlaylistWidget> hook1{
90 "qtui update playlist settings", this, &PlaylistWidget::updateSettings};
9291 };
9392
9493 #endif
1717 */
1818
1919 #include "playlist_header.h"
20 #include "playlist-qt.h"
2021 #include "playlist_model.h"
21 #include "playlist-qt.h"
2222 #include "settings.h"
2323
2424 #include <string.h>
3434 #include <libaudqt/libaudqt.h>
3535
3636 static const char * const s_col_keys[] = {
37 "playing",
38 "number",
39 "title",
40 "artist",
41 "year",
42 "album",
43 "album-artist",
44 "track",
45 "genre",
46 "queued",
47 "length",
48 "path",
49 "filename",
50 "custom",
51 "bitrate",
52 "comment"
37 "playing", "number", "title", "artist", "year", "album",
38 "album-artist", "track", "genre", "queued", "length", "path",
39 "filename", "custom", "bitrate", "comment"};
40
41 static const int s_default_widths[] = {
42 25, // now playing
43 25, // entry number
44 275, // title
45 175, // artist
46 50, // year
47 175, // album
48 175, // album artist
49 75, // track
50 100, // genre
51 25, // queue position
52 75, // length
53 275, // path
54 275, // filename
55 275, // custom title
56 75, // bitrate
57 275 // comment
5358 };
5459
55 static const int s_default_widths[] = {
56 25, // now playing
57 25, // entry number
58 275, // title
59 175, // artist
60 50, // year
61 175, // album
62 175, // album artist
63 75, // track
64 100, // genre
65 25, // queue position
66 75, // length
67 275, // path
68 275, // filename
69 275, // custom title
70 75, // bitrate
71 275 // comment
60 static const Playlist::SortType s_sort_types[] = {
61 Playlist::n_sort_types, // now playing
62 Playlist::n_sort_types, // entry number
63 Playlist::Title, // title
64 Playlist::Artist, // artist
65 Playlist::Date, // year
66 Playlist::Album, // album
67 Playlist::AlbumArtist, // album artist
68 Playlist::Track, // track
69 Playlist::Genre, // genre
70 Playlist::n_sort_types, // queue position
71 Playlist::Length, // length
72 Playlist::Path, // path
73 Playlist::Filename, // file name
74 Playlist::FormattedTitle, // custom title
75 Playlist::n_sort_types, // bitrate
76 Playlist::Comment // comment
7277 };
7378
74 static_assert (aud::n_elems (s_col_keys) == PlaylistModel::n_cols, "update s_col_keys");
75 static_assert (aud::n_elems (s_default_widths) == PlaylistModel::n_cols, "update s_default_widths");
79 static_assert(aud::n_elems(s_col_keys) == PlaylistModel::n_cols,
80 "update s_col_keys");
81 static_assert(aud::n_elems(s_default_widths) == PlaylistModel::n_cols,
82 "update s_default_widths");
83 static_assert(aud::n_elems(s_sort_types) == PlaylistModel::n_cols,
84 "update s_sort_types");
7685
7786 static Index<int> s_cols;
7887 static int s_col_widths[PlaylistModel::n_cols];
7988
80 static void loadConfig (bool force = false)
89 static void loadConfig(bool force = false)
8190 {
8291 static bool loaded = false;
8392
84 if (loaded && ! force)
85 return;
86
87 auto columns = str_list_to_index (aud_get_str ("qtui", "playlist_columns"), " ");
88 int n_columns = aud::min (columns.len (), (int) PlaylistModel::n_cols);
89
90 s_cols.clear ();
91
92 for (int c = 0; c < n_columns; c ++)
93 if (loaded && !force)
94 return;
95
96 auto columns =
97 str_list_to_index(aud_get_str("qtui", "playlist_columns"), " ");
98 int n_columns = aud::min(columns.len(), (int)PlaylistModel::n_cols);
99
100 s_cols.clear();
101
102 for (int c = 0; c < n_columns; c++)
93103 {
94104 int i = 0;
95 while (i < PlaylistModel::n_cols && strcmp (columns[c], s_col_keys[i]))
96 i ++;
105 while (i < PlaylistModel::n_cols && strcmp(columns[c], s_col_keys[i]))
106 i++;
97107
98108 if (i < PlaylistModel::n_cols)
99 s_cols.append (i);
100 }
101
102 auto widths = str_list_to_index (aud_get_str ("qtui", "column_widths"), ", ");
103 int n_widths = aud::min (widths.len (), (int) PlaylistModel::n_cols);
104
105 for (int i = 0; i < n_widths; i ++)
106 s_col_widths[i] = audqt::to_native_dpi (str_to_int (widths[i]));
107 for (int i = n_widths; i < PlaylistModel::n_cols; i ++)
108 s_col_widths[i] = audqt::to_native_dpi (s_default_widths[i]);
109 s_cols.append(i);
110 }
111
112 auto widths = str_list_to_index(aud_get_str("qtui", "column_widths"), ", ");
113 int n_widths = aud::min(widths.len(), (int)PlaylistModel::n_cols);
114
115 for (int i = 0; i < n_widths; i++)
116 s_col_widths[i] = audqt::to_native_dpi(str_to_int(widths[i]));
117 for (int i = n_widths; i < PlaylistModel::n_cols; i++)
118 s_col_widths[i] = audqt::to_native_dpi(s_default_widths[i]);
109119
110120 loaded = true;
111121 }
112122
113 static void saveConfig ()
123 static void saveConfig()
114124 {
115125 Index<String> index;
116126 for (int col : s_cols)
117 index.append (String (s_col_keys[col]));
127 index.append(String(s_col_keys[col]));
118128
119129 int widths[PlaylistModel::n_cols];
120 for (int i = 0; i < PlaylistModel::n_cols; i ++)
121 widths[i] = audqt::to_portable_dpi (s_col_widths[i]);
122
123 aud_set_str ("qtui", "playlist_columns", index_to_str_list (index, " "));
124 aud_set_str ("qtui", "column_widths", int_array_to_str (widths, PlaylistModel::n_cols));
125 }
126
127 PlaylistHeader::PlaylistHeader (PlaylistWidget * playlist) :
128 QHeaderView (Qt::Horizontal, playlist),
129 m_playlist (playlist)
130 {
131 loadConfig ();
132
133 setSectionsMovable (true);
134 setStretchLastSection (true);
135
136 connect (this, & QHeaderView::sectionResized, this, & PlaylistHeader::sectionResized);
137 connect (this, & QHeaderView::sectionMoved, this, & PlaylistHeader::sectionMoved);
138 }
139
140 static void toggleColumn (int col, bool on)
141 {
142 int pos = s_cols.find (col);
130 for (int i = 0; i < PlaylistModel::n_cols; i++)
131 widths[i] = audqt::to_portable_dpi(s_col_widths[i]);
132
133 aud_set_str("qtui", "playlist_columns", index_to_str_list(index, " "));
134 aud_set_str("qtui", "column_widths",
135 int_array_to_str(widths, PlaylistModel::n_cols));
136 }
137
138 PlaylistHeader::PlaylistHeader(PlaylistWidget * playlist)
139 : QHeaderView(Qt::Horizontal, playlist), m_playlist(playlist)
140 {
141 loadConfig();
142
143 setSectionsMovable(true);
144 setStretchLastSection(true);
145
146 connect(this, &QHeaderView::sectionClicked, this,
147 &PlaylistHeader::sectionClicked);
148 connect(this, &QHeaderView::sectionResized, this,
149 &PlaylistHeader::sectionResized);
150 connect(this, &QHeaderView::sectionMoved, this,
151 &PlaylistHeader::sectionMoved);
152 }
153
154 static void toggleColumn(int col, bool on)
155 {
156 int pos = s_cols.find(col);
143157
144158 if (on)
145159 {
146160 if (pos >= 0)
147161 return;
148162
149 s_cols.append (col);
163 s_cols.append(col);
150164 }
151165 else
152166 {
153167 if (pos < 0)
154168 return;
155169
156 s_cols.remove (pos, 1);
157 }
158
159 saveConfig ();
170 s_cols.remove(pos, 1);
171 }
172
173 saveConfig();
160174
161175 // update all playlists
162 hook_call ("qtui update playlist columns", nullptr);
163 }
164
165 static void resetToDefaults ()
166 {
167 aud_set_str ("qtui", "playlist_columns", DEFAULT_COLUMNS);
168 aud_set_str ("qtui", "column_widths", "");
169
170 loadConfig (true);
176 hook_call("qtui update playlist columns", nullptr);
177 }
178
179 static void resetToDefaults()
180 {
181 aud_set_str("qtui", "playlist_columns", DEFAULT_COLUMNS);
182 aud_set_str("qtui", "column_widths", "");
183
184 loadConfig(true);
171185
172186 // update all playlists
173 hook_call ("qtui update playlist columns", nullptr);
174 }
175
176 void PlaylistHeader::contextMenuEvent (QContextMenuEvent * event)
177 {
178 auto menu = new QMenu (this);
187 hook_call("qtui update playlist columns", nullptr);
188 }
189
190 void PlaylistHeader::contextMenuEvent(QContextMenuEvent * event)
191 {
192 auto menu = new QMenu(this);
179193 QAction * actions[PlaylistModel::n_cols];
180194
181 for (int col = 0; col < PlaylistModel::n_cols; col ++)
182 {
183 actions[col] = new QAction (_(PlaylistModel::labels[col]), menu);
184 actions[col]->setCheckable (true);
185
186 connect (actions[col], & QAction::toggled, [col] (bool on) {
187 toggleColumn (col, on);
188 });
189
190 menu->addAction (actions[col]);
195 for (int col = 0; col < PlaylistModel::n_cols; col++)
196 {
197 actions[col] = new QAction(_(PlaylistModel::labels[col]), menu);
198 actions[col]->setCheckable(true);
199
200 connect(actions[col], &QAction::toggled,
201 [col](bool on) { toggleColumn(col, on); });
202
203 menu->addAction(actions[col]);
191204 }
192205
193206 for (int col : s_cols)
194 actions[col]->setChecked (true);
195
196 auto sep = new QAction (menu);
197 sep->setSeparator (true);
198 menu->addAction (sep);
199
200 auto reset = new QAction (_("Reset to Defaults"), menu);
201 connect (reset, & QAction::triggered, resetToDefaults);
202 menu->addAction (reset);
203
204 menu->popup (event->globalPos ());
205 }
206
207 void PlaylistHeader::updateColumns ()
207 actions[col]->setChecked(true);
208
209 auto sep = new QAction(menu);
210 sep->setSeparator(true);
211 menu->addAction(sep);
212
213 auto reset = new QAction(_("Reset to Defaults"), menu);
214 connect(reset, &QAction::triggered, resetToDefaults);
215 menu->addAction(reset);
216
217 menu->popup(event->globalPos());
218 }
219
220 void PlaylistHeader::updateColumns()
208221 {
209222 m_inUpdate = true;
210223
211 int n_shown = s_cols.len ();
224 int n_shown = s_cols.len();
212225
213226 // Due to QTBUG-33974, column #0 cannot be moved by the user.
214227 // As a workaround, hide column #0 and start the real columns at #1.
215228 // However, Qt will hide the header completely if no columns are visible.
216229 // This is bad since the user can't right-click to add any columns again.
217230 // To prevent this, show column #0 if no real columns are visible.
218 m_playlist->setColumnHidden (0, (n_shown > 0));
219
220 bool shown[PlaylistModel::n_cols] {};
231 m_playlist->setColumnHidden(0, (n_shown > 0));
232
233 bool shown[PlaylistModel::n_cols]{};
221234
222235 for (int i = 0; i < n_shown; i++)
223236 {
224237 int col = s_cols[i];
225 moveSection (visualIndex (1 + col), 1 + i);
238 moveSection(visualIndex(1 + col), 1 + i);
226239 shown[col] = true;
227240 }
228241
232245 for (int col = 0; col < PlaylistModel::n_cols; col++)
233246 {
234247 if (col != last)
235 m_playlist->setColumnWidth (1 + col, s_col_widths[col]);
236
237 m_playlist->setColumnHidden (1 + col, ! shown[col]);
248 m_playlist->setColumnWidth(1 + col, s_col_widths[col]);
249
250 m_playlist->setColumnHidden(1 + col, !shown[col]);
238251 }
239252
240253 // width of last column should be set to 0 initially,
241254 // but doing so repeatedly causes flicker
242255 if (last >= 0 && last != m_lastCol)
243 m_playlist->setColumnWidth (1 + last, 0);
256 m_playlist->setColumnWidth(1 + last, 0);
244257
245258 // this should come after all setColumnHidden() calls
246 m_playlist->setFirstVisibleColumn ((n_shown > 0) ? 1 + s_cols[0] : 0);
259 m_playlist->setFirstVisibleColumn((n_shown > 0) ? 1 + s_cols[0] : 0);
247260
248261 m_inUpdate = false;
249262 m_lastCol = last;
250263 }
251264
252 void PlaylistHeader::sectionMoved (int logicalIndex, int oldVisualIndex, int newVisualIndex)
265 void PlaylistHeader::sectionClicked(int logicalIndex)
266 {
267 int col = logicalIndex - 1;
268 if (col < 0 || col >= PlaylistModel::n_cols)
269 return;
270
271 if (s_sort_types[col] != Playlist::n_sort_types)
272 m_playlist->playlist().sort_entries(s_sort_types[col]);
273 }
274
275 void PlaylistHeader::sectionMoved(int logicalIndex, int oldVisualIndex,
276 int newVisualIndex)
253277 {
254278 if (m_inUpdate)
255279 return;
257281 int old_pos = oldVisualIndex - 1;
258282 int new_pos = newVisualIndex - 1;
259283
260 if (old_pos < 0 || old_pos > s_cols.len () || new_pos < 0 || new_pos > s_cols.len ())
284 if (old_pos < 0 || old_pos > s_cols.len() || new_pos < 0 ||
285 new_pos > s_cols.len())
261286 return;
262287
263288 int col = logicalIndex - 1;
264289 if (col != s_cols[old_pos])
265290 return;
266291
267 s_cols.remove (old_pos, 1);
268 s_cols.insert (& col, new_pos, 1);
269
270 saveConfig ();
292 s_cols.remove(old_pos, 1);
293 s_cols.insert(&col, new_pos, 1);
294
295 saveConfig();
271296
272297 // update all the other playlists
273 hook_call ("qtui update playlist columns", nullptr);
274 }
275
276 void PlaylistHeader::sectionResized (int logicalIndex, int /*oldSize*/, int newSize)
298 hook_call("qtui update playlist columns", nullptr);
299 }
300
301 void PlaylistHeader::sectionResized(int logicalIndex, int /*oldSize*/,
302 int newSize)
277303 {
278304 if (m_inUpdate)
279305 return;
283309 return;
284310
285311 // last column expands to fit, so size is not saved
286 int pos = s_cols.find (col);
287 if (pos < 0 || pos == s_cols.len () - 1)
312 int pos = s_cols.find(col);
313 if (pos < 0 || pos == s_cols.len() - 1)
288314 return;
289315
290316 s_col_widths[col] = newSize;
291317
292 saveConfig ();
318 saveConfig();
293319
294320 // update all the other playlists
295 hook_call ("qtui update playlist columns", nullptr);
296 }
321 hook_call("qtui update playlist columns", nullptr);
322 }
3030 class PlaylistHeader : public QHeaderView
3131 {
3232 public:
33 PlaylistHeader (PlaylistWidget * parent);
33 PlaylistHeader(PlaylistWidget * parent);
3434
3535 /* this should be called by the playlist after adding the header */
36 void updateColumns ();
36 void updateColumns();
3737
3838 private:
3939 PlaylistWidget * m_playlist;
4040 bool m_inUpdate = false;
4141 int m_lastCol = -1;
4242
43 void sectionMoved (int logicalIndex, int oldVisualIndex, int newVisualIndex);
44 void sectionResized (int logicalIndex, int /*oldSize*/, int newSize);
43 void sectionClicked(int logicalIndex);
44 void sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
45 void sectionResized(int logicalIndex, int /*oldSize*/, int newSize);
4546
46 void contextMenuEvent (QContextMenuEvent * event);
47 void contextMenuEvent(QContextMenuEvent * event);
4748
48 const HookReceiver<PlaylistHeader>
49 hook1 {"qtui update playlist columns", this, & PlaylistHeader::updateColumns};
49 const HookReceiver<PlaylistHeader> hook1{
50 "qtui update playlist columns", this, &PlaylistHeader::updateColumns};
5051 };
5152
5253 #endif // PLAYLIST_HEADER_H
2121 #include <QMimeData>
2222 #include <QUrl>
2323
24 #include <libaudcore/i18n.h>
2524 #include <libaudcore/audstrings.h>
2625 #include <libaudcore/drct.h>
26 #include <libaudcore/i18n.h>
2727 #include <libaudqt/libaudqt.h>
2828
2929 #include "playlist_model.h"
3131 #define ICON_SIZE 16
3232
3333 const char * const PlaylistModel::labels[] = {
34 N_("Now Playing"),
35 N_("Entry Number"),
36 N_("Title"),
37 N_("Artist"),
38 N_("Year"),
39 N_("Album"),
40 N_("Album Artist"),
41 N_("Track"),
42 N_("Genre"),
43 N_("Queue Position"),
44 N_("Length"),
45 N_("File Path"),
46 N_("File Name"),
47 N_("Custom Title"),
48 N_("Bitrate"),
49 N_("Comment")
50 };
34 N_("Now Playing"), N_("Entry Number"), N_("Title"),
35 N_("Artist"), N_("Year"), N_("Album"),
36 N_("Album Artist"), N_("Track"), N_("Genre"),
37 N_("Queue Position"), N_("Length"), N_("File Path"),
38 N_("File Name"), N_("Custom Title"), N_("Bitrate"),
39 N_("Comment")};
5140
5241 static const Tuple::Field s_fields[] = {
53 Tuple::Invalid,
54 Tuple::Invalid,
55 Tuple::Title,
56 Tuple::Artist,
57 Tuple::Year,
58 Tuple::Album,
59 Tuple::AlbumArtist,
60 Tuple::Track,
61 Tuple::Genre,
62 Tuple::Invalid,
63 Tuple::Length,
64 Tuple::Path,
65 Tuple::Basename,
66 Tuple::FormattedTitle,
67 Tuple::Bitrate,
68 Tuple::Comment
69 };
70
71 static_assert (aud::n_elems (PlaylistModel::labels) == PlaylistModel::n_cols, "update PlaylistModel::labels");
72 static_assert (aud::n_elems (s_fields) == PlaylistModel::n_cols, "update s_fields");
73
74 static inline QPixmap get_icon (const char * name)
75 {
76 qreal r = qApp->devicePixelRatio ();
77 QPixmap pm = audqt::get_icon (name).pixmap (ICON_SIZE * r);
78 pm.setDevicePixelRatio (r);
79 return pm;
80 }
81
82 PlaylistModel::PlaylistModel (QObject * parent, Playlist playlist) :
83 QAbstractListModel (parent),
84 m_playlist (playlist),
85 m_rows (playlist.n_entries ()) {}
86
87 int PlaylistModel::rowCount (const QModelIndex & parent) const
88 {
89 return m_rows;
90 }
91
92 int PlaylistModel::columnCount (const QModelIndex & parent) const
42 Tuple::Invalid, Tuple::Invalid, Tuple::Title, Tuple::Artist,
43 Tuple::Year, Tuple::Album, Tuple::AlbumArtist, Tuple::Track,
44 Tuple::Genre, Tuple::Invalid, Tuple::Length, Tuple::Path,
45 Tuple::Basename, Tuple::FormattedTitle, Tuple::Bitrate, Tuple::Comment};
46
47 static_assert(aud::n_elems(PlaylistModel::labels) == PlaylistModel::n_cols,
48 "update PlaylistModel::labels");
49 static_assert(aud::n_elems(s_fields) == PlaylistModel::n_cols,
50 "update s_fields");
51
52 static inline QPixmap get_icon(const char * name)
53 {
54 return audqt::get_icon(name).pixmap(audqt::to_native_dpi(ICON_SIZE));
55 }
56
57 PlaylistModel::PlaylistModel(QObject * parent, Playlist playlist)
58 : QAbstractListModel(parent), m_playlist(playlist),
59 m_rows(playlist.n_entries())
60 {
61 }
62
63 int PlaylistModel::rowCount(const QModelIndex & parent) const { return m_rows; }
64
65 int PlaylistModel::columnCount(const QModelIndex & parent) const
9366 {
9467 return 1 + n_cols;
9568 }
9669
97 QVariant PlaylistModel::alignment (int col) const
70 QVariant PlaylistModel::alignment(int col) const
9871 {
9972 switch (col)
10073 {
10780 }
10881 }
10982
110 QVariant PlaylistModel::data (const QModelIndex &index, int role) const
111 {
112 int col = index.column () - 1;
83 QVariant PlaylistModel::data(const QModelIndex & index, int role) const
84 {
85 int col = index.column() - 1;
11386 if (col < 0 || col >= n_cols)
114 return QVariant ();
87 return QVariant();
11588
11689 Tuple tuple;
11790 int val = -1;
12194 case Qt::DisplayRole:
12295 if (s_fields[col] != Tuple::Invalid)
12396 {
124 tuple = m_playlist.entry_tuple (index.row (), Playlist::NoWait);
125
126 switch (tuple.get_value_type (s_fields[col]))
97 tuple = m_playlist.entry_tuple(index.row(), Playlist::NoWait);
98
99 switch (tuple.get_value_type(s_fields[col]))
127100 {
128101 case Tuple::Empty:
129 return QVariant ();
102 return QVariant();
130103 case Tuple::String:
131 return QString (tuple.get_str (s_fields[col]));
104 return QString(tuple.get_str(s_fields[col]));
132105 case Tuple::Int:
133 val = tuple.get_int (s_fields[col]);
106 val = tuple.get_int(s_fields[col]);
134107 break;
135108 }
136109 }
138111 switch (col)
139112 {
140113 case NowPlaying:
141 return QVariant ();
114 return QVariant();
142115 case EntryNumber:
143 return QString ("%1").arg (index.row () + 1);
116 return QString("%1").arg(index.row() + 1);
144117 case QueuePos:
145 return queuePos (index.row ());
118 return queuePos(index.row());
146119 case Length:
147 return QString (str_format_time (val));
120 return QString(str_format_time(val));
148121 case Bitrate:
149 return QString ("%1 kbps").arg (val);
122 return QString("%1 kbps").arg(val);
150123 default:
151 return QString ("%1").arg (val);
124 return QString("%1").arg(val);
152125 }
153126
154127 case Qt::TextAlignmentRole:
155 return alignment (col);
128 return alignment(col);
156129
157130 case Qt::DecorationRole:
158 if (col == NowPlaying && index.row () == m_playlist.get_position ())
131 if (col == NowPlaying && index.row() == m_playlist.get_position())
159132 {
160133 const char * icon_name = "media-playback-stop";
161134
162 if (m_playlist == Playlist::playing_playlist ())
163 icon_name = aud_drct_get_paused () ? "media-playback-pause" :
164 "media-playback-start";
165
166 return get_icon (icon_name);
167 }
168 else if (col == NowPlaying && index.row () == 0)
135 if (m_playlist == Playlist::playing_playlist())
136 icon_name = aud_drct_get_paused() ? "media-playback-pause"
137 : "media-playback-start";
138
139 return get_icon(icon_name);
140 }
141 else if (col == NowPlaying && index.row() == 0)
169142 {
170143 /* put a blank pixmap in the top row for size calculations */
171 QPixmap blank (ICON_SIZE, ICON_SIZE);
172 blank.fill (Qt::transparent);
144 QPixmap blank(ICON_SIZE, ICON_SIZE);
145 blank.fill(Qt::transparent);
173146 return blank;
174147 }
175148 break;
176149 }
177 return QVariant ();
178 }
179
180 QVariant PlaylistModel::headerData (int section, Qt::Orientation orientation, int role) const
150 return QVariant();
151 }
152
153 QVariant PlaylistModel::headerData(int section, Qt::Orientation orientation,
154 int role) const
181155 {
182156 if (orientation != Qt::Horizontal)
183 return QVariant ();
157 return QVariant();
184158
185159 int col = section - 1;
186160 if (col < 0 || col >= n_cols)
187 return QVariant ();
161 return QVariant();
188162
189163 switch (role)
190164 {
194168 case NowPlaying:
195169 case EntryNumber:
196170 case QueuePos:
197 return QVariant ();
198 }
199
200 return QString (_(labels[col]));
171 return QVariant();
172 }
173
174 return QString(_(labels[col]));
201175
202176 case Qt::TextAlignmentRole:
203 return alignment (col);
177 return alignment(col);
204178
205179 default:
206 return QVariant ();
207 }
208 }
209
210 Qt::DropActions PlaylistModel::supportedDropActions () const
180 return QVariant();
181 }
182 }
183
184 Qt::DropActions PlaylistModel::supportedDropActions() const
211185 {
212186 return Qt::CopyAction | Qt::MoveAction;
213187 }
214188
215 Qt::ItemFlags PlaylistModel::flags (const QModelIndex & index) const
216 {
217 if (index.isValid ())
189 Qt::ItemFlags PlaylistModel::flags(const QModelIndex & index) const
190 {
191 if (index.isValid())
218192 return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
219193 else
220194 return Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
221195 }
222196
223 QStringList PlaylistModel::mimeTypes () const
224 {
225 return QStringList ("text/uri-list");
226 }
227
228 QMimeData * PlaylistModel::mimeData (const QModelIndexList & indexes) const
197 QStringList PlaylistModel::mimeTypes() const
198 {
199 return QStringList("text/uri-list");
200 }
201
202 QMimeData * PlaylistModel::mimeData(const QModelIndexList & indexes) const
229203 {
230204 /* we assume that <indexes> contains the selected entries */
231 m_playlist.cache_selected ();
205 m_playlist.cache_selected();
232206
233207 QList<QUrl> urls;
234208 int prev = -1;
235209
236210 for (auto & index : indexes)
237211 {
238 int row = index.row ();
239 if (row != prev) /* skip multiple cells in same row */
240 {
241 urls.append (QString (m_playlist.entry_filename (row)));
212 int row = index.row();
213 if (row != prev) /* skip multiple cells in same row */
214 {
215 urls.append(QString(m_playlist.entry_filename(row)));
242216 prev = row;
243217 }
244218 }
245219
246220 auto data = new QMimeData;
247 data->setUrls (urls);
221 data->setUrls(urls);
248222 return data;
249223 }
250224
251 bool PlaylistModel::dropMimeData (const QMimeData * data, Qt::DropAction action,
252 int row, int column, const QModelIndex & parent)
253 {
254 if (action != Qt::CopyAction || ! data->hasUrls ())
225 bool PlaylistModel::dropMimeData(const QMimeData * data, Qt::DropAction action,
226 int row, int column,
227 const QModelIndex & parent)
228 {
229 if (action != Qt::CopyAction || !data->hasUrls())
255230 return false;
256231
257232 Index<PlaylistAddItem> items;
258 for (auto & url : data->urls ())
259 items.append (String (url.toEncoded ()));
260
261 m_playlist.insert_items (row, std::move (items), false);
233 for (auto & url : data->urls())
234 items.append(String(url.toEncoded()));
235
236 m_playlist.insert_items(row, std::move(items), false);
262237 return true;
263238 }
264239
265 void PlaylistModel::entriesAdded (int row, int count)
240 void PlaylistModel::entriesAdded(int row, int count)
266241 {
267242 if (count < 1)
268243 return;
269244
270245 int last = row + count - 1;
271 beginInsertRows (QModelIndex (), row, last);
246 beginInsertRows(QModelIndex(), row, last);
272247 m_rows += count;
273 endInsertRows ();
274 }
275
276 void PlaylistModel::entriesRemoved (int row, int count)
248 endInsertRows();
249 }
250
251 void PlaylistModel::entriesRemoved(int row, int count)
277252 {
278253 if (count < 1)
279254 return;
280255
281256 int last = row + count - 1;
282 beginRemoveRows (QModelIndex (), row, last);
257 beginRemoveRows(QModelIndex(), row, last);
283258 m_rows -= count;
284 endRemoveRows ();
285 }
286
287 void PlaylistModel::entriesChanged (int row, int count)
259 endRemoveRows();
260 }
261
262 void PlaylistModel::entriesChanged(int row, int count)
288263 {
289264 if (count < 1)
290265 return;
291266
292267 int bottom = row + count - 1;
293 auto topLeft = createIndex (row, 0);
294 auto bottomRight = createIndex (bottom, columnCount () - 1);
295 emit dataChanged (topLeft, bottomRight);
296 }
297
298 QString PlaylistModel::queuePos (int row) const
299 {
300 int at = m_playlist.queue_find_entry (row);
268 auto topLeft = createIndex(row, 0);
269 auto bottomRight = createIndex(bottom, columnCount() - 1);
270 emit dataChanged(topLeft, bottomRight);
271 }
272
273 QString PlaylistModel::queuePos(int row) const
274 {
275 int at = m_playlist.queue_find_entry(row);
301276 if (at < 0)
302 return QString ();
277 return QString();
303278 else
304 return QString ("#%1").arg (at + 1);
279 return QString("#%1").arg(at + 1);
305280 }
306281
307282 /* ---------------------------------- */
308283
309 void PlaylistProxyModel::setFilter (const char * filter)
310 {
311 m_searchTerms = str_list_to_index (filter, " ");
312 invalidateFilter ();
313 }
314
315 bool PlaylistProxyModel::filterAcceptsRow (int source_row, const QModelIndex &) const
316 {
317 if (! m_searchTerms.len ())
284 void PlaylistProxyModel::setFilter(const char * filter)
285 {
286 m_searchTerms = str_list_to_index(filter, " ");
287 invalidateFilter();
288 }
289
290 bool PlaylistProxyModel::filterAcceptsRow(int source_row,
291 const QModelIndex &) const
292 {
293 if (!m_searchTerms.len())
318294 return true;
319295
320 Tuple tuple = m_playlist.entry_tuple (source_row);
321
322 String strings[] = {
323 tuple.get_str (Tuple::Title),
324 tuple.get_str (Tuple::Artist),
325 tuple.get_str (Tuple::Album)
326 };
296 Tuple tuple = m_playlist.entry_tuple(source_row);
297
298 String strings[] = {tuple.get_str(Tuple::Title),
299 tuple.get_str(Tuple::Artist),
300 tuple.get_str(Tuple::Album)};
327301
328302 for (auto & term : m_searchTerms)
329303 {
331305
332306 for (auto & s : strings)
333307 {
334 if (s && strstr_nocase_utf8 (s, term))
308 if (s && strstr_nocase_utf8(s, term))
335309 {
336310 found = true;
337311 break;
338312 }
339313 }
340314
341 if (! found)
315 if (!found)
342316 return false;
343317 }
344318
2727 class PlaylistModel : public QAbstractListModel
2828 {
2929 public:
30 enum {
30 enum
31 {
3132 NowPlaying,
3233 EntryNumber,
3334 Title,
4950
5051 static const char * const labels[];
5152
52 PlaylistModel (QObject * parent, Playlist playlist);
53 PlaylistModel(QObject * parent, Playlist playlist);
5354
54 int rowCount (const QModelIndex & parent = QModelIndex ()) const;
55 int columnCount (const QModelIndex & parent = QModelIndex ()) const;
56 QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
57 QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
55 int rowCount(const QModelIndex & parent = QModelIndex()) const;
56 int columnCount(const QModelIndex & parent = QModelIndex()) const;
57 QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
58 QVariant headerData(int section, Qt::Orientation orientation,
59 int role = Qt::DisplayRole) const;
5860
59 Qt::DropActions supportedDropActions () const;
60 Qt::ItemFlags flags (const QModelIndex & index) const;
61 Qt::DropActions supportedDropActions() const;
62 Qt::ItemFlags flags(const QModelIndex & index) const;
6163
62 QStringList mimeTypes () const;
63 QMimeData * mimeData (const QModelIndexList & indexes) const;
64 bool dropMimeData (const QMimeData * data, Qt::DropAction action, int row,
65 int column, const QModelIndex & parent);
64 QStringList mimeTypes() const;
65 QMimeData * mimeData(const QModelIndexList & indexes) const;
66 bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row,
67 int column, const QModelIndex & parent);
6668
67 void entriesAdded (int row, int count);
68 void entriesRemoved (int row, int count);
69 void entriesChanged (int row, int count);
69 void entriesAdded(int row, int count);
70 void entriesRemoved(int row, int count);
71 void entriesChanged(int row, int count);
7072
7173 private:
7274 Playlist m_playlist;
7375 int m_rows;
7476
75 QVariant alignment (int col) const;
76 QString queuePos (int row) const;
77 QVariant alignment(int col) const;
78 QString queuePos(int row) const;
7779 };
7880
7981 class PlaylistProxyModel : public QSortFilterProxyModel
8082 {
8183 public:
82 PlaylistProxyModel (QObject * parent, Playlist playlist) :
83 QSortFilterProxyModel (parent),
84 m_playlist (playlist) {}
84 PlaylistProxyModel(QObject * parent, Playlist playlist)
85 : QSortFilterProxyModel(parent), m_playlist(playlist)
86 {
87 }
8588
86 void setFilter (const char * filter);
89 void setFilter(const char * filter);
8790
8891 private:
89 bool filterAcceptsRow (int source_row, const QModelIndex &) const;
92 bool filterAcceptsRow(int source_row, const QModelIndex &) const;
9093
9194 Playlist m_playlist;
9295 Index<String> m_searchTerms;
1616 * the use of this software.
1717 */
1818
19 #include "playlist-qt.h"
2019 #include "playlist_tabs.h"
2120 #include "menus.h"
21 #include "playlist-qt.h"
2222 #include "search_bar.h"
23 #include "settings.h"
2324
2425 #include <QBoxLayout>
2526 #include <QKeyEvent>
2627 #include <QLineEdit>
28 #include <QMenu>
2729
2830 #include <libaudcore/drct.h>
2931 #include <libaudcore/i18n.h>
3537 class LayoutWidget : public QWidget
3638 {
3739 public:
38 LayoutWidget (QWidget * parent, Playlist playlist, QMenu * contextMenu);
39
40 PlaylistWidget * playlistWidget () const
41 { return m_playlistWidget; }
42
43 void activateSearch ()
44 {
45 m_searchBar->show ();
46 m_searchBar->setFocus ();
40 LayoutWidget(QWidget * parent, Playlist playlist, QMenu * contextMenu);
41
42 PlaylistWidget * playlistWidget() const { return m_playlistWidget; }
43
44 void activateSearch()
45 {
46 m_searchBar->show();
47 m_searchBar->setFocus();
4748 }
4849
4950 private:
5152 SearchBar * m_searchBar;
5253 };
5354
54 LayoutWidget::LayoutWidget (QWidget * parent, Playlist playlist, QMenu * contextMenu) :
55 QWidget (parent),
56 m_playlistWidget (new PlaylistWidget (this, playlist)),
57 m_searchBar (new SearchBar (this, m_playlistWidget))
58 {
59 auto layout = audqt::make_vbox (this, 0);
60 layout->addWidget (m_playlistWidget);
61 layout->addWidget (m_searchBar);
62
63 m_playlistWidget->setContextMenu (contextMenu);
64 m_searchBar->hide ();
55 LayoutWidget::LayoutWidget(QWidget * parent, Playlist playlist,
56 QMenu * contextMenu)
57 : QWidget(parent), m_playlistWidget(new PlaylistWidget(this, playlist)),
58 m_searchBar(new SearchBar(this, m_playlistWidget))
59 {
60 auto layout = audqt::make_vbox(this, 0);
61 layout->addWidget(m_playlistWidget);
62 layout->addWidget(m_searchBar);
63
64 m_playlistWidget->setContextMenu(contextMenu);
65 m_searchBar->hide();
6566 }
6667
6768 /* --------------------------------- */
6869
69 PlaylistTabs::PlaylistTabs (QWidget * parent) :
70 QTabWidget (parent),
71 m_pl_menu (qtui_build_pl_menu (this)),
72 m_leftbtn (nullptr),
73 m_tabbar (new PlaylistTabBar (this))
74 {
75 installEventFilter (this);
70 PlaylistTabs::PlaylistTabs(QWidget * parent)
71 : QTabWidget(parent), m_pl_menu(qtui_build_pl_menu(this)),
72 m_tabbar(new PlaylistTabBar(this))
73 {
74 installEventFilter(this);
7675
7776 // set up tab bar
78 m_tabbar->setFocusPolicy (Qt::NoFocus);
79 setTabBar (m_tabbar);
80
81 addRemovePlaylists ();
82 updateTitles ();
83 updateIcons ();
84 setCurrentIndex (Playlist::active_playlist ().index ());
85
86 connect (this, & QTabWidget::currentChanged, this, & PlaylistTabs::currentChangedTrigger);
87 }
88
89 PlaylistWidget * PlaylistTabs::currentPlaylistWidget () const
90 {
91 return ((LayoutWidget *) currentWidget ())->playlistWidget ();
92 }
93
94 PlaylistWidget * PlaylistTabs::playlistWidget (int idx) const
95 {
96 auto w = (LayoutWidget *) widget (idx);
97 return w ? w->playlistWidget () : nullptr;
98 }
99
100 void PlaylistTabs::activateSearch ()
101 {
102 ((LayoutWidget *) currentWidget ())->activateSearch ();
103 }
104
105 void PlaylistTabs::addRemovePlaylists ()
106 {
107 int tabs = count ();
108 int playlists = Playlist::n_playlists ();
109
110 for (int i = 0; i < tabs; i ++)
111 {
112 auto w = (LayoutWidget *) widget (i);
113 int list_idx = w->playlistWidget ()->playlist ().index ();
77 m_tabbar->setFocusPolicy(Qt::NoFocus);
78 setTabBar(m_tabbar);
79
80 addRemovePlaylists();
81 m_tabbar->updateTitles();
82 m_tabbar->updateIcons();
83 setCurrentIndex(Playlist::active_playlist().index());
84
85 connect(this, &QTabWidget::currentChanged, this,
86 &PlaylistTabs::currentChangedTrigger);
87 }
88
89 PlaylistWidget * PlaylistTabs::currentPlaylistWidget() const
90 {
91 return ((LayoutWidget *)currentWidget())->playlistWidget();
92 }
93
94 PlaylistWidget * PlaylistTabs::playlistWidget(int idx) const
95 {
96 auto w = (LayoutWidget *)widget(idx);
97 return w ? w->playlistWidget() : nullptr;
98 }
99
100 void PlaylistTabs::activateSearch()
101 {
102 ((LayoutWidget *)currentWidget())->activateSearch();
103 }
104
105 void PlaylistTabs::addRemovePlaylists()
106 {
107 int tabs = count();
108 int playlists = Playlist::n_playlists();
109
110 for (int i = 0; i < tabs; i++)
111 {
112 auto w = (LayoutWidget *)widget(i);
113 int list_idx = w->playlistWidget()->playlist().index();
114114
115115 if (list_idx < 0)
116116 {
117 removeTab (i);
117 removeTab(i);
118118 delete w;
119 tabs --;
120 i --;
119 tabs--;
120 i--;
121121 }
122122 else if (list_idx != i)
123123 {
124124 bool found = false;
125125
126 for (int j = i + 1; j < tabs; j ++)
126 for (int j = i + 1; j < tabs; j++)
127127 {
128 w = (LayoutWidget *) widget (j);
129 list_idx = w->playlistWidget ()->playlist ().index ();
128 w = (LayoutWidget *)widget(j);
129 list_idx = w->playlistWidget()->playlist().index();
130130
131131 if (list_idx == i)
132132 {
133 removeTab (j);
134 insertTab (i, w, QString ());
133 removeTab(j);
134 insertTab(i, w, QString());
135135 found = true;
136136 break;
137137 }
138138 }
139139
140 if (! found)
140 if (!found)
141141 {
142 insertTab (i, new LayoutWidget (this, Playlist::by_index (i), m_pl_menu), QString ());
143 tabs ++;
142 insertTab(
143 i, new LayoutWidget(this, Playlist::by_index(i), m_pl_menu),
144 QString());
145 tabs++;
144146 }
145147 }
146148 }
147149
148150 while (tabs < playlists)
149151 {
150 addTab (new LayoutWidget (this, Playlist::by_index (tabs), m_pl_menu), QString ());
151 tabs ++;
152 }
153 }
154
155 void PlaylistTabs::updateTitles ()
156 {
157 int tabs = count ();
158 for (int i = 0; i < tabs; i ++)
159 updateTabText (i);
160 }
161
162 void PlaylistTabs::updateIcons ()
152 addTab(new LayoutWidget(this, Playlist::by_index(tabs), m_pl_menu),
153 QString());
154 tabs++;
155 }
156 }
157
158 void PlaylistTabs::currentChangedTrigger(int idx)
159 {
160 Playlist::by_index(idx).activate();
161 }
162
163 bool PlaylistTabs::eventFilter(QObject * obj, QEvent * e)
164 {
165 if (e->type() == QEvent::KeyPress)
166 {
167 QKeyEvent * ke = (QKeyEvent *)e;
168
169 if (ke->key() == Qt::Key_Escape)
170 return m_tabbar->cancelRename();
171 }
172
173 return QTabWidget::eventFilter(obj, e);
174 }
175
176 void PlaylistTabs::renameCurrent()
177 {
178 auto playlist = currentPlaylistWidget()->playlist();
179
180 if (m_tabbar->isVisible())
181 m_tabbar->startRename(playlist);
182 else
183 audqt::playlist_show_rename(playlist);
184 }
185
186 void PlaylistTabs::playlist_activate_cb()
187 {
188 setCurrentIndex(Playlist::active_playlist().index());
189 m_tabbar->cancelRename();
190 }
191
192 void PlaylistTabs::playlist_update_cb(Playlist::UpdateLevel global_level)
193 {
194 if (global_level == Playlist::Structure)
195 addRemovePlaylists();
196 if (global_level >= Playlist::Metadata)
197 m_tabbar->updateTitles();
198
199 for (int i = 0; i < count(); i++)
200 playlistWidget(i)->playlistUpdate();
201
202 setCurrentIndex(Playlist::active_playlist().index());
203 }
204
205 void PlaylistTabs::playlist_position_cb(Playlist list)
206 {
207 auto widget = playlistWidget(list.index());
208 if (widget)
209 widget->scrollToCurrent();
210 }
211
212 PlaylistTabBar::PlaylistTabBar(QWidget * parent) : QTabBar(parent)
213 {
214 setMovable(true);
215 setDocumentMode(true);
216 updateSettings();
217
218 connect(this, &QTabBar::tabMoved, this, &PlaylistTabBar::tabMoved);
219 connect(this, &QTabBar::tabCloseRequested, [](int idx) {
220 audqt::playlist_confirm_delete(Playlist::by_index(idx));
221 });
222 }
223
224 void PlaylistTabBar::updateTitles()
225 {
226 int tabs = count();
227 for (int i = 0; i < tabs; i++)
228 updateTabText(i);
229 }
230
231 void PlaylistTabBar::updateIcons()
163232 {
164233 QIcon icon;
165 int playing = Playlist::playing_playlist ().index ();
234 int playing = Playlist::playing_playlist().index();
166235 if (playing >= 0)
167 icon = audqt::get_icon (aud_drct_get_paused () ? "media-playback-pause" : "media-playback-start");
168
169 int tabs = count ();
170 for (int i = 0; i < tabs; i ++)
171 setTabIcon (i, (i == playing) ? icon : QIcon ());
172 }
173
174 void PlaylistTabs::currentChangedTrigger (int idx)
175 {
176 Playlist::by_index (idx).activate ();
177 }
178
179 QLineEdit * PlaylistTabs::getTabEdit (int idx)
180 {
181 return dynamic_cast<QLineEdit *> (m_tabbar->tabButton (idx, QTabBar::LeftSide));
182 }
183
184 void PlaylistTabs::updateTabText (int idx)
185 {
186 QString title;
187
188 if (! getTabEdit (idx))
189 {
190 auto playlist = Playlist::by_index (idx);
191
192 // escape ampersands for setTabText ()
193 title = QString (playlist.get_title ()).replace ("&", "&&");
194
195 if (aud_get_bool ("qtui", "entry_count_visible"))
196 title += QString (" (%1)").arg (playlist.n_entries ());
197 }
198
199 setTabText (idx, title);
200 }
201
202 void PlaylistTabs::setupTab (int idx, QWidget * button, QWidget * * oldp)
203 {
204 QWidget * old = m_tabbar->tabButton (idx, QTabBar::LeftSide);
205 m_tabbar->setTabButton (idx, QTabBar::LeftSide, button);
206
207 if (oldp)
208 * oldp = old;
209 else
210 {
211 old->setParent (nullptr);
212 old->deleteLater ();
213 }
214
215 updateTabText (idx);
216 }
217
218 void PlaylistTabs::editTab (int idx, Playlist playlist)
219 {
220 QLineEdit * edit = getTabEdit (idx);
221
222 if (! edit)
223 {
224 edit = new QLineEdit ((const char *) playlist.get_title ());
225
226 connect (edit, & QLineEdit::returnPressed, [this, playlist, edit] ()
227 {
228 playlist.set_title (edit->text ().toUtf8 ());
229 cancelRename ();
236 icon = audqt::get_icon(aud_drct_get_paused() ? "media-playback-pause"
237 : "media-playback-start");
238
239 int tabs = count();
240 for (int i = 0; i < tabs; i++)
241 {
242 /* hide icon when editing so it doesn't get shown on the wrong side */
243 setTabIcon(i, (i == playing && !getTabEdit(i)) ? icon : QIcon());
244 }
245 }
246
247 void PlaylistTabBar::startRename(Playlist playlist)
248 {
249 int idx = playlist.index();
250 QLineEdit * edit = getTabEdit(idx);
251
252 if (!edit)
253 {
254 edit = new QLineEdit((const char *)playlist.get_title());
255
256 connect(edit, &QLineEdit::returnPressed, [this, playlist, edit]() {
257 playlist.set_title(edit->text().toUtf8());
258 cancelRename();
230259 });
231260
232 setupTab (idx, edit, & m_leftbtn);
233 }
234
235 edit->selectAll ();
236 edit->setFocus ();
237 }
238
239 bool PlaylistTabs::eventFilter (QObject * obj, QEvent * e)
240 {
241 if (e->type() == QEvent::KeyPress)
242 {
243 QKeyEvent * ke = (QKeyEvent *) e;
244
245 if (ke->key () == Qt::Key_Escape)
246 return cancelRename ();
247 }
248
249 return QTabWidget::eventFilter(obj, e);
250 }
251
252 void PlaylistTabs::renameCurrent ()
253 {
254 int idx = currentIndex ();
255 auto playlist = currentPlaylistWidget ()->playlist ();
256
257 if (! m_tabbar->isVisible ())
258 audqt::playlist_show_rename (playlist);
259 else
260 editTab (idx, playlist);
261 }
262
263 bool PlaylistTabs::cancelRename ()
261 setupTab(idx, edit, &m_leftbtn);
262 updateIcons();
263 }
264
265 edit->selectAll();
266 edit->setFocus();
267 }
268
269 bool PlaylistTabBar::cancelRename()
264270 {
265271 bool cancelled = false;
266272
267 for (int i = 0; i < count (); i ++)
268 {
269 QLineEdit * edit = getTabEdit (i);
270 if (! edit)
273 for (int i = 0; i < count(); i++)
274 {
275 QLineEdit * edit = getTabEdit(i);
276 if (!edit)
271277 continue;
272278
273 setupTab (i, m_leftbtn, nullptr);
279 setupTab(i, m_leftbtn, nullptr);
274280 m_leftbtn = nullptr;
275281 cancelled = true;
282 updateIcons();
276283 }
277284
278285 return cancelled;
279286 }
280287
281 void PlaylistTabs::playlist_activate_cb ()
282 {
283 setCurrentIndex (Playlist::active_playlist ().index ());
284 cancelRename ();
285 }
286
287 void PlaylistTabs::playlist_update_cb (Playlist::UpdateLevel global_level)
288 {
289 if (global_level == Playlist::Structure)
290 addRemovePlaylists ();
291 if (global_level >= Playlist::Metadata)
292 updateTitles ();
293
294 for (int i = 0; i < count (); i ++)
295 playlistWidget (i)->playlistUpdate ();
296
297 setCurrentIndex (Playlist::active_playlist ().index ());
298 }
299
300 void PlaylistTabs::playlist_position_cb (Playlist list)
301 {
302 auto widget = playlistWidget (list.index ());
303 if (widget)
304 widget->scrollToCurrent ();
305 }
306
307 PlaylistTabBar::PlaylistTabBar (QWidget * parent) : QTabBar (parent)
308 {
309 setMovable (true);
310 setDocumentMode (true);
311 updateSettings ();
312
313 connect (this, & QTabBar::tabMoved, this, & PlaylistTabBar::tabMoved);
314 connect (this, & QTabBar::tabCloseRequested, [] (int idx) {
315 audqt::playlist_confirm_delete (Playlist::by_index (idx));
316 });
317 }
318
319 void PlaylistTabBar::tabMoved (int from, int to)
320 {
321 Playlist::reorder_playlists (from, to, 1);
322 }
323
324 void PlaylistTabBar::mousePressEvent (QMouseEvent * e)
325 {
326 if (e->button () == Qt::MidButton)
327 {
328 int index = tabAt (e->pos ());
288 void PlaylistTabBar::mousePressEvent(QMouseEvent * e)
289 {
290 if (e->button() == Qt::MidButton)
291 {
292 int index = tabAt(e->pos());
329293 if (index >= 0)
330294 {
331 audqt::playlist_confirm_delete (Playlist::by_index (index));
332 e->accept ();
295 audqt::playlist_confirm_delete(Playlist::by_index(index));
296 e->accept();
333297 }
334298 }
335299
336 QTabBar::mousePressEvent (e);
337 }
338
339 void PlaylistTabBar::mouseDoubleClickEvent (QMouseEvent * e)
340 {
341 int idx = tabAt (e->pos ());
342 if (idx < 0 || e->button () != Qt::LeftButton)
300 QTabBar::mousePressEvent(e);
301 }
302
303 void PlaylistTabBar::mouseDoubleClickEvent(QMouseEvent * e)
304 {
305 int idx = tabAt(e->pos());
306 if (idx < 0 || e->button() != Qt::LeftButton)
343307 return;
344308
345 Playlist::by_index (idx).start_playback ();
346 }
347
348 void PlaylistTabBar::updateSettings ()
309 Playlist::by_index(idx).start_playback();
310 }
311
312 void PlaylistTabBar::contextMenuEvent(QContextMenuEvent * e)
313 {
314 int idx = tabAt(e->pos());
315 if (idx < 0)
316 return;
317
318 auto menu = new QMenu(this);
319 auto playlist = Playlist::by_index(idx);
320
321 auto play_act = new QAction(audqt::get_icon("media-playback-start"),
322 audqt::translate_str(N_("_Play")), menu);
323 auto rename_act =
324 new QAction(audqt::get_icon("insert-text"),
325 audqt::translate_str(N_("_Rename ...")), menu);
326 auto remove_act = new QAction(audqt::get_icon("edit-delete"),
327 audqt::translate_str(N_("Remo_ve")), menu);
328
329 QObject::connect(play_act, &QAction::triggered,
330 [playlist]() { playlist.start_playback(); });
331 QObject::connect(rename_act, &QAction::triggered, [this, playlist]() {
332 if (playlist.exists())
333 startRename(playlist);
334 });
335 QObject::connect(remove_act, &QAction::triggered, [playlist]() {
336 if (playlist.exists())
337 audqt::playlist_confirm_delete(playlist);
338 });
339
340 menu->addAction(play_act);
341 menu->addAction(rename_act);
342 menu->addAction(remove_act);
343 menu->setAttribute(Qt::WA_DeleteOnClose);
344 menu->popup(e->globalPos());
345 }
346
347 QLineEdit * PlaylistTabBar::getTabEdit(int idx)
348 {
349 return dynamic_cast<QLineEdit *>(tabButton(idx, QTabBar::LeftSide));
350 }
351
352 void PlaylistTabBar::updateTabText(int idx)
353 {
354 QString title;
355
356 if (!getTabEdit(idx))
357 {
358 auto playlist = Playlist::by_index(idx);
359
360 // escape ampersands for setTabText ()
361 title = QString(playlist.get_title()).replace("&", "&&");
362
363 if (aud_get_bool("qtui", "entry_count_visible"))
364 title += QString(" (%1)").arg(playlist.n_entries());
365 }
366
367 setTabText(idx, title);
368 }
369
370 void PlaylistTabBar::setupTab(int idx, QWidget * button, QWidget ** oldp)
371 {
372 QWidget * old = tabButton(idx, QTabBar::LeftSide);
373 setTabButton(idx, QTabBar::LeftSide, button);
374
375 if (oldp)
376 *oldp = old;
377 else
378 {
379 old->setParent(nullptr);
380 old->deleteLater();
381 }
382
383 updateTabText(idx);
384 }
385
386 void PlaylistTabBar::tabMoved(int from, int to)
387 {
388 Playlist::reorder_playlists(from, to, 1);
389 }
390
391 void PlaylistTabBar::updateSettings()
349392 {
350393 #if QT_VERSION >= 0x050400
351 setAutoHide (! aud_get_bool ("qtui", "playlist_tabs_visible"));
394 setAutoHide(false);
352395 #endif
353 setTabsClosable (aud_get_bool ("qtui", "close_button_visible"));
354 }
396
397 switch (aud_get_int("qtui", "playlist_tabs_visible"))
398 {
399 #if QT_VERSION >= 0x050400
400 case PlaylistTabVisibility::AutoHide:
401 setAutoHide(true);
402 break;
403 #endif
404 case PlaylistTabVisibility::Always:
405 show();
406 break;
407
408 case PlaylistTabVisibility::Never:
409 hide();
410 break;
411 }
412
413 setTabsClosable(aud_get_bool("qtui", "close_button_visible"));
414 updateTitles();
415 }
3333 class PlaylistTabs : public QTabWidget
3434 {
3535 public:
36 PlaylistTabs (QWidget * parent = nullptr);
36 PlaylistTabs(QWidget * parent = nullptr);
3737
38 PlaylistWidget * currentPlaylistWidget () const;
39 PlaylistWidget * playlistWidget (int idx) const;
38 PlaylistWidget * currentPlaylistWidget() const;
39 PlaylistWidget * playlistWidget(int idx) const;
4040
41 void editTab (int idx, Playlist playlist);
42 void currentChangedTrigger (int idx);
43 void tabEditedTrigger ();
41 void currentChangedTrigger(int idx);
42 void tabEditedTrigger();
4443
4544 protected:
46 bool eventFilter (QObject * obj, QEvent * e);
45 bool eventFilter(QObject * obj, QEvent * e);
4746
4847 private:
4948 QMenu * m_pl_menu;
50 QWidget * m_leftbtn;
5149 PlaylistTabBar * m_tabbar;
5250
53 QLineEdit * getTabEdit (int idx);
54 void updateTabText (int idx);
55 void setupTab (int idx, QWidget * button, QWidget * * oldp);
51 void activateSearch();
52 void addRemovePlaylists();
53 void renameCurrent();
5654
57 void activateSearch ();
58 void addRemovePlaylists ();
59 void updateTitles ();
60 void updateIcons ();
61 void renameCurrent ();
62 bool cancelRename ();
55 void playlist_activate_cb();
56 void playlist_update_cb(Playlist::UpdateLevel global_level);
57 void playlist_position_cb(Playlist list);
6358
64 void playlist_activate_cb ();
65 void playlist_update_cb (Playlist::UpdateLevel global_level);
66 void playlist_position_cb (Playlist list);
59 const HookReceiver<PlaylistTabs> hook1{"qtui find", this,
60 &PlaylistTabs::activateSearch},
61 hook2{"qtui rename playlist", this, &PlaylistTabs::renameCurrent};
6762
68 const HookReceiver<PlaylistTabs>
69 hook1 {"qtui find", this, & PlaylistTabs::activateSearch},
70 hook2 {"qtui rename playlist", this, & PlaylistTabs::renameCurrent},
71 hook3 {"qtui update playlist settings", this, & PlaylistTabs::updateTitles};
72
73 const HookReceiver<PlaylistTabs>
74 activate_hook {"playlist activate", this, & PlaylistTabs::playlist_activate_cb},
75 set_playing_hook {"playlist set playing", this, & PlaylistTabs::updateIcons},
76 pause_hook {"playback pause", this, & PlaylistTabs::updateIcons},
77 unpause_hook {"playback unpause", this, & PlaylistTabs::updateIcons};
78 const HookReceiver<PlaylistTabs, Playlist::UpdateLevel>
79 update_hook {"playlist update", this, & PlaylistTabs::playlist_update_cb};
80 const HookReceiver<PlaylistTabs, Playlist>
81 position_hook {"playlist position", this, & PlaylistTabs::playlist_position_cb};
63 const HookReceiver<PlaylistTabs> activate_hook{
64 "playlist activate", this, &PlaylistTabs::playlist_activate_cb};
65 const HookReceiver<PlaylistTabs, Playlist::UpdateLevel> update_hook{
66 "playlist update", this, &PlaylistTabs::playlist_update_cb};
67 const HookReceiver<PlaylistTabs, Playlist> position_hook{
68 "playlist position", this, &PlaylistTabs::playlist_position_cb};
8269 };
8370
8471 class PlaylistTabBar : public QTabBar
8572 {
8673 public:
87 PlaylistTabBar (QWidget * parent = nullptr);
74 PlaylistTabBar(QWidget * parent = nullptr);
75
76 void updateTitles();
77 void updateIcons();
78 void startRename(Playlist playlist);
79 bool cancelRename();
8880
8981 protected:
90 void tabMoved (int from, int to);
91 void mousePressEvent (QMouseEvent * e);
92 void mouseDoubleClickEvent (QMouseEvent * e);
82 void mousePressEvent(QMouseEvent * e) override;
83 void mouseDoubleClickEvent(QMouseEvent * e) override;
84 void contextMenuEvent(QContextMenuEvent * e) override;
9385
9486 private:
95 void updateSettings ();
87 QLineEdit * getTabEdit(int idx);
88 void updateTabText(int idx);
89 void setupTab(int idx, QWidget * button, QWidget ** oldp);
90 void tabMoved(int from, int to);
91 void updateSettings();
9692
97 const HookReceiver<PlaylistTabBar>
98 settings_hook {"qtui update playlist settings", this, & PlaylistTabBar::updateSettings};
93 const HookReceiver<PlaylistTabBar> pause_hook{"playback pause", this,
94 &PlaylistTabBar::updateIcons},
95 unpause_hook{"playback unpause", this, &PlaylistTabBar::updateIcons},
96 set_playing_hook{"playlist set playing", this,
97 &PlaylistTabBar::updateIcons},
98 settings_hook{"qtui update playlist settings", this,
99 &PlaylistTabBar::updateSettings};
100
101 QWidget * m_leftbtn = nullptr;
99102 };
100103
101104 #endif
2222 #include <libaudcore/plugin.h>
2323 #include <libaudcore/runtime.h>
2424
25 #include <libaudqt/iface.h>
2526 #include <libaudqt/libaudqt.h>
26 #include <libaudqt/iface.h>
2727
2828 #include "main_window.h"
2929 #include "settings.h"
3434 MainWindow * window = nullptr;
3535
3636 public:
37 constexpr QtUI () : audqt::QtIfacePlugin ({
38 N_("Qt Interface"),
39 PACKAGE,
40 nullptr,
41 & qtui_prefs,
42 PluginQtOnly
43 }) {}
37 constexpr QtUI()
38 : audqt::QtIfacePlugin(
39 {N_("Qt Interface"), PACKAGE, nullptr, &qtui_prefs, PluginQtOnly})
40 {
41 }
4442
45 bool init ()
43 bool init()
4644 {
47 audqt::init ();
48 aud_config_set_defaults ("qtui", qtui_defaults);
45 audqt::init();
46 aud_config_set_defaults("qtui", qtui_defaults);
4947 window = new MainWindow;
5048 return true;
5149 }
5250
53 void cleanup ()
51 void cleanup()
5452 {
5553 delete window;
5654 window = nullptr;
57 audqt::cleanup ();
55 audqt::cleanup();
5856 }
5957
60 void run ()
58 void run() { audqt::run(); }
59
60 void show(bool show)
6161 {
62 audqt::run ();
63 }
64
65 void show (bool show)
66 {
67 window->setVisible (show);
62 window->setVisible(show);
6863
6964 if (show)
7065 {
71 window->activateWindow ();
72 window->raise ();
66 window->activateWindow();
67 window->raise();
7368 }
7469 }
7570
76 void quit ()
77 {
78 audqt::quit ();
79 }
71 void quit() { audqt::quit(); }
8072 };
8173
8274 EXPORT QtUI aud_plugin_instance;
2929 #include <libaudcore/i18n.h>
3030 #include <libaudqt/libaudqt.h>
3131
32 static QPushButton * makeButton (const char * icon, QWidget * parent)
32 static QPushButton * makeButton(const char * icon, QWidget * parent)
3333 {
34 auto button = new QPushButton (audqt::get_icon (icon), QString (), parent);
35 button->setFlat (true);
36 button->setFocusPolicy (Qt::NoFocus);
34 auto button = new QPushButton(audqt::get_icon(icon), QString(), parent);
35 button->setFlat(true);
36 button->setFocusPolicy(Qt::NoFocus);
3737 return button;
3838 }
3939
40 SearchBar::SearchBar (QWidget * parent, PlaylistWidget * playlistWidget) :
41 QWidget (parent),
42 m_playlistWidget (playlistWidget),
43 m_entry (new QLineEdit (this))
40 SearchBar::SearchBar(QWidget * parent, PlaylistWidget * playlistWidget)
41 : QWidget(parent), m_playlistWidget(playlistWidget),
42 m_entry(new QLineEdit(this))
4443 {
45 m_entry->setClearButtonEnabled (true);
46 m_entry->setPlaceholderText (_("Search playlist"));
44 m_entry->setClearButtonEnabled(true);
45 m_entry->setPlaceholderText(_("Search playlist"));
4746
48 auto upButton = makeButton ("go-up", this);
49 auto downButton = makeButton ("go-down", this);
50 auto closeButton = makeButton ("window-close", this);
47 auto upButton = makeButton("go-up", this);
48 auto downButton = makeButton("go-down", this);
49 auto closeButton = makeButton("window-close", this);
5150
52 auto layout = audqt::make_hbox (this);
53 layout->setContentsMargins (audqt::margins.TwoPt);
51 auto layout = audqt::make_hbox(this);
52 layout->setContentsMargins(audqt::margins.TwoPt);
5453
55 layout->addWidget (m_entry);
56 layout->addWidget (upButton);
57 layout->addWidget (downButton);
58 layout->addWidget (closeButton);
54 layout->addWidget(m_entry);
55 layout->addWidget(upButton);
56 layout->addWidget(downButton);
57 layout->addWidget(closeButton);
5958
60 setFocusProxy (m_entry);
59 setFocusProxy(m_entry);
6160
62 connect (m_entry, & QLineEdit::textChanged, [this] (const QString & text) {
63 m_playlistWidget->setFilter (text.toUtf8 ());
61 connect(m_entry, &QLineEdit::textChanged, [this](const QString & text) {
62 m_playlistWidget->setFilter(text.toUtf8());
6463 });
6564
66 connect (upButton, & QPushButton::clicked, [this] (bool) {
67 m_playlistWidget->moveFocus (-1);
68 });
65 connect(upButton, &QPushButton::clicked,
66 [this](bool) { m_playlistWidget->moveFocus(-1); });
6967
70 connect (downButton, & QPushButton::clicked, [this] (bool) {
71 m_playlistWidget->moveFocus (1);
72 });
68 connect(downButton, &QPushButton::clicked,
69 [this](bool) { m_playlistWidget->moveFocus(1); });
7370
74 connect (closeButton, & QPushButton::clicked, [this] (bool) {
75 m_entry->clear ();
76 m_playlistWidget->setFocus ();
77 hide ();
71 connect(closeButton, &QPushButton::clicked, [this](bool) {
72 m_entry->clear();
73 m_playlistWidget->setFocus();
74 hide();
7875 });
7976 }
8077
81 void SearchBar::keyPressEvent (QKeyEvent * event)
78 void SearchBar::keyPressEvent(QKeyEvent * event)
8279 {
83 auto CtrlShiftAlt = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
84 if (! (event->modifiers () & CtrlShiftAlt))
80 auto CtrlShiftAlt =
81 Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
82 if (!(event->modifiers() & CtrlShiftAlt))
8583 {
86 switch (event->key ())
84 switch (event->key())
8785 {
8886 case Qt::Key_Enter:
8987 case Qt::Key_Return:
9189 case Qt::Key_Down:
9290 case Qt::Key_PageUp:
9391 case Qt::Key_PageDown:
94 QApplication::sendEvent (m_playlistWidget, event);
92 QApplication::sendEvent(m_playlistWidget, event);
9593 return;
9694
9795 case Qt::Key_Escape:
98 m_entry->clear ();
99 m_playlistWidget->setFocus ();
100 hide ();
96 m_entry->clear();
97 m_playlistWidget->setFocus();
98 hide();
10199 return;
102100 }
103101 }
104102
105 QWidget::keyPressEvent (event);
103 QWidget::keyPressEvent(event);
106104 }
2727 class SearchBar : public QWidget
2828 {
2929 public:
30 SearchBar (QWidget * parent, PlaylistWidget * playlistWidget);
30 SearchBar(QWidget * parent, PlaylistWidget * playlistWidget);
3131
3232 private:
33 void keyPressEvent (QKeyEvent * event);
33 void keyPressEvent(QKeyEvent * event);
3434
3535 PlaylistWidget * m_playlistWidget;
3636 QLineEdit * m_entry;
2626 #include <QDesktopWidget>
2727
2828 const char * const qtui_defaults[] = {
29 // clang-format off
2930 "infoarea_show_vis", "TRUE",
3031 "infoarea_visible", "TRUE",
3132 "menu_visible", "TRUE",
32 "playlist_tabs_visible", "TRUE",
33 "playlist_tabs_visible", aud::numeric_string<PlaylistTabVisibility::AutoHide>::str,
3334 "statusbar_visible", "TRUE",
3435 "entry_count_visible", "FALSE",
3536 "close_button_visible", "TRUE",
3738 "autoscroll", "TRUE",
3839 "playlist_columns", DEFAULT_COLUMNS,
3940 "playlist_headers", "TRUE",
40 // "record", "FALSE",
4141 "show_remaining_time", "FALSE",
42 "step_size", "5",
42 // clang-format on
43 nullptr};
4344
44 nullptr
45 };
46
47 static void qtui_update_playlist_settings ()
45 static void qtui_update_playlist_settings()
4846 {
49 hook_call ("qtui update playlist settings", nullptr);
47 hook_call("qtui update playlist settings", nullptr);
5048 }
5149
50 static const ComboItem playlist_tabs_options[] = {
51 ComboItem(N_("Always"), PlaylistTabVisibility::Always),
52 ComboItem(N_("Auto-hide"), PlaylistTabVisibility::AutoHide),
53 ComboItem(N_("Never"), PlaylistTabVisibility::Never)};
54
5255 static const PreferencesWidget qtui_widgets[] = {
53 WidgetLabel (N_("<b>Playlist Tabs</b>")),
54 #if QT_VERSION >= 0x050400
55 WidgetCheck (N_("Always show tabs"),
56 WidgetBool ("qtui", "playlist_tabs_visible", qtui_update_playlist_settings)),
57 #endif
58 WidgetCheck (N_("Show entry counts"),
59 WidgetBool ("qtui", "entry_count_visible", qtui_update_playlist_settings)),
60 WidgetCheck (N_("Show close buttons"),
61 WidgetBool ("qtui", "close_button_visible", qtui_update_playlist_settings)),
62 WidgetLabel (N_("<b>Playlist Columns</b>")),
63 WidgetCheck (N_("Show column headers"),
64 WidgetBool ("qtui", "playlist_headers", qtui_update_playlist_settings)),
65 WidgetLabel (N_("<b>Miscellaneous</b>")),
66 WidgetSpin (N_("Arrow keys seek by:"),
67 WidgetFloat ("qtui", "step_size"),
68 {0.1, 60, 0.1, N_("seconds")}),
69 WidgetCheck (N_("Scroll on song change"),
70 WidgetBool ("qtui", "autoscroll"))
71 };
56 WidgetLabel(N_("<b>Playlist Tabs</b>")),
57 WidgetCombo(N_("Show playlist tabs:"),
58 WidgetInt("qtui", "playlist_tabs_visible",
59 qtui_update_playlist_settings),
60 {{playlist_tabs_options}}),
61 WidgetCheck(N_("Show entry counts"),
62 WidgetBool("qtui", "entry_count_visible",
63 qtui_update_playlist_settings)),
64 WidgetCheck(N_("Show close buttons"),
65 WidgetBool("qtui", "close_button_visible",
66 qtui_update_playlist_settings)),
67 WidgetLabel(N_("<b>Playlist Columns</b>")),
68 WidgetCheck(
69 N_("Show column headers"),
70 WidgetBool("qtui", "playlist_headers", qtui_update_playlist_settings)),
71 WidgetLabel(N_("<b>Miscellaneous</b>")),
72 WidgetCheck(N_("Scroll on song change"), WidgetBool("qtui", "autoscroll"))};
7273
7374 const PluginPreferences qtui_prefs = {{qtui_widgets}};
74
75 int getDPI ()
76 {
77 static int dpi = 0;
78
79 if (! dpi)
80 {
81 auto desktop = qApp->desktop ();
82 dpi = aud::max (96, (desktop->logicalDpiX () + desktop->logicalDpiY ()) / 2);
83 }
84
85 return dpi;
86 }
2323
2424 #define DEFAULT_COLUMNS "playing title artist album queued length"
2525
26 enum PlaylistTabVisibility
27 {
28 Always,
29 AutoHide,
30 Never
31 };
32
2633 struct PluginPreferences;
2734 extern const PluginPreferences qtui_prefs;
2835
2323 #include <libaudcore/i18n.h>
2424 #include <libaudcore/mainloop.h>
2525 #include <libaudcore/playlist.h>
26 #include <libaudcore/tinylock.h>
26 #include <libaudcore/threads.h>
2727
2828 #include <QLabel>
2929
3030 #define TIMEOUT_MS 5000
3131
32 static const char * normal_css =
33 "QStatusBar { background: transparent; }\n"
34 "QStatusBar::item { border: none; }";
32 static const char * normal_css = "QStatusBar { background: transparent; }\n"
33 "QStatusBar::item { border: none; }";
3534 static const char * warning_css =
36 "QStatusBar { background: rgba(255,255,0,64); }\n"
37 "QStatusBar::item { border: none; }";
38 static const char * error_css =
39 "QStatusBar { background: rgba(255,0,0,64); }\n"
40 "QStatusBar::item { border: none; }";
35 "QStatusBar { background: rgba(255,255,0,64); }\n"
36 "QStatusBar::item { border: none; }";
37 static const char * error_css = "QStatusBar { background: rgba(255,0,0,64); }\n"
38 "QStatusBar::item { border: none; }";
4139
42 StatusBar::StatusBar (QWidget * parent) :
43 QStatusBar (parent),
44 codec_label (new QLabel (this)),
45 length_label (new QLabel (this))
40 StatusBar::StatusBar(QWidget * parent)
41 : QStatusBar(parent), codec_label(new QLabel(this)),
42 length_label(new QLabel(this))
4643 {
47 addWidget (codec_label);
48 addPermanentWidget (length_label);
44 addWidget(codec_label);
45 addPermanentWidget(length_label);
4946
50 update_codec ();
51 update_length ();
47 update_codec();
48 update_length();
5249
53 setStyleSheet (normal_css);
50 setStyleSheet(normal_css);
5451
55 audlog::subscribe (log_handler, audlog::Warning);
52 audlog::subscribe(log_handler, audlog::Warning);
5653
5754 /* redisplay codec info when message is cleared */
58 connect (this, & QStatusBar::messageChanged, [this] (const QString & text) {
59 if (text.isEmpty ()) {
60 setStyleSheet (normal_css);
61 update_codec ();
55 connect(this, &QStatusBar::messageChanged, [this](const QString & text) {
56 if (text.isEmpty())
57 {
58 setStyleSheet(normal_css);
59 update_codec();
6260 }
6361 });
6462 }
6563
66 StatusBar::~StatusBar ()
64 StatusBar::~StatusBar()
6765 {
68 audlog::unsubscribe (log_handler);
69 event_queue_cancel ("qtui log message");
66 audlog::unsubscribe(log_handler);
67 event_queue_cancel("qtui log message");
7068 }
7169
7270 /* rate-limiting data */
7371 static QueuedFunc message_func;
74 static TinyLock message_lock;
72 static aud::spinlock message_lock;
7573 static int current_message_level = -1;
7674 static unsigned current_message_serial = 0;
7775
78 static void one_second_cb (void * serial)
76 static void one_second_cb(void * serial)
7977 {
80 tiny_lock (& message_lock);
78 auto lh = message_lock.take();
8179
8280 /* allow new messages after one second */
83 if (aud::from_ptr<unsigned> (serial) == current_message_serial)
81 if (aud::from_ptr<unsigned>(serial) == current_message_serial)
8482 current_message_level = -1;
85
86 tiny_unlock (& message_lock);
8783 }
8884
89 void StatusBar::log_handler (audlog::Level level, const char * file, int line,
90 const char * func, const char * text)
85 static bool set_message_level(audlog::Level level)
9186 {
92 tiny_lock (& message_lock);
87 auto lh = message_lock.take();
9388
9489 /* do not replace a message of same or higher priority */
9590 if (level <= current_message_level)
91 return false;
92
93 current_message_level = level;
94 current_message_serial++;
95
96 message_func.queue(1000, one_second_cb,
97 aud::to_ptr(current_message_serial));
98 return true;
99 }
100
101 void StatusBar::log_handler(audlog::Level level, const char * file, int line,
102 const char * func, const char * text)
103 {
104 if (!set_message_level(level))
105 return;
106
107 QString s = text;
108 if (s.contains('\n'))
109 s = s.split('\n', QString::SkipEmptyParts).last();
110
111 event_queue("qtui log message", new Message{level, s},
112 aud::delete_obj<Message>);
113 }
114
115 void StatusBar::log_message(const Message * message)
116 {
117 codec_label->hide();
118 setStyleSheet((message->level == audlog::Error) ? error_css : warning_css);
119 showMessage(message->text, TIMEOUT_MS);
120 }
121
122 void StatusBar::update_codec()
123 {
124 /* codec info is hidden when a message is displayed */
125 if (!currentMessage().isEmpty())
126 return;
127
128 if (!aud_drct_get_ready())
96129 {
97 tiny_unlock (& message_lock);
130 codec_label->hide();
98131 return;
99132 }
100133
101 current_message_level = level;
102 current_message_serial ++;
103
104 message_func.queue (1000, one_second_cb, aud::to_ptr (current_message_serial));
105
106 tiny_unlock (& message_lock);
107
108 QString s = text;
109 if (s.contains ('\n'))
110 s = s.split ('\n', QString::SkipEmptyParts).last ();
111
112 event_queue ("qtui log message", new Message {level, s}, aud::delete_obj<Message>);
113 }
114
115 void StatusBar::log_message (const Message * message)
116 {
117 codec_label->hide ();
118 setStyleSheet ((message->level == audlog::Error) ? error_css : warning_css);
119 showMessage (message->text, TIMEOUT_MS);
120 }
121
122 void StatusBar::update_codec ()
123 {
124 /* codec info is hidden when a message is displayed */
125 if (! currentMessage ().isEmpty ())
126 return;
127
128 if (! aud_drct_get_ready ())
129 {
130 codec_label->hide ();
131 return;
132 }
133
134 Tuple tuple = aud_drct_get_tuple ();
135 String codec = tuple.get_str (Tuple::Codec);
134 Tuple tuple = aud_drct_get_tuple();
135 String codec = tuple.get_str(Tuple::Codec);
136136
137137 int bitrate, samplerate, channels;
138 aud_drct_get_info (bitrate, samplerate, channels);
138 aud_drct_get_info(bitrate, samplerate, channels);
139139
140 StringBuf buf (0);
140 StringBuf buf(0);
141141
142142 if (codec)
143143 {
144 buf.insert (-1, codec);
144 buf.insert(-1, codec);
145145 if (channels > 0 || samplerate > 0 || bitrate > 0)
146 buf.insert (-1, ", ");
146 buf.insert(-1, ", ");
147147 }
148148
149149 if (channels > 0)
150150 {
151151 if (channels == 1)
152 buf.insert (-1, _("mono"));
152 buf.insert(-1, _("mono"));
153153 else if (channels == 2)
154 buf.insert (-1, _("stereo"));
154 buf.insert(-1, _("stereo"));
155155 else
156 str_append_printf (buf, ngettext ("%d channel", "%d channels", channels), channels);
156 str_append_printf(
157 buf, ngettext("%d channel", "%d channels", channels), channels);
157158
158159 if (samplerate > 0 || bitrate > 0)
159 buf.insert (-1, ", ");
160 buf.insert(-1, ", ");
160161 }
161162
162163 if (samplerate > 0)
163164 {
164 str_append_printf (buf, _("%d kHz"), samplerate / 1000);
165 str_append_printf(buf, _("%d kHz"), samplerate / 1000);
165166 if (bitrate > 0)
166 buf.insert (-1, ", ");
167 buf.insert(-1, ", ");
167168 }
168169
169170 if (bitrate > 0)
170 str_append_printf (buf, _("%d kbps"), bitrate / 1000);
171 str_append_printf(buf, _("%d kbps"), bitrate / 1000);
171172
172 codec_label->setText ((const char *) buf);
173 codec_label->show ();
173 codec_label->setText((const char *)buf);
174 codec_label->show();
174175 }
175176
176 void StatusBar::update_length ()
177 void StatusBar::update_length()
177178 {
178 auto playlist = Playlist::active_playlist ();
179 auto playlist = Playlist::active_playlist();
179180
180 StringBuf s1 = str_format_time (playlist.selected_length_ms ());
181 StringBuf s2 = str_format_time (playlist.total_length_ms ());
181 StringBuf s1 = str_format_time(playlist.selected_length_ms());
182 StringBuf s2 = str_format_time(playlist.total_length_ms());
182183
183 length_label->setText ((const char *) str_concat ({s1, " / ", s2}));
184 length_label->setText((const char *)str_concat({s1, " / ", s2}));
184185 }
2929 class StatusBar : public QStatusBar
3030 {
3131 public:
32 StatusBar (QWidget * parent);
33 ~StatusBar ();
32 StatusBar(QWidget * parent);
33 ~StatusBar();
3434
3535 private:
36 struct Message {
36 struct Message
37 {
3738 audlog::Level level;
3839 QString text;
3940 };
4142 QLabel * codec_label;
4243 QLabel * length_label;
4344
44 static void log_handler (audlog::Level level, const char * file, int line,
45 const char * func, const char * text);
45 static void log_handler(audlog::Level level, const char * file, int line,
46 const char * func, const char * text);
4647
47 void log_message (const Message * message);
48 void log_message(const Message * message);
4849
49 void update_codec ();
50 void update_length ();
50 void update_codec();
51 void update_length();
5152
52 const HookReceiver<StatusBar, const Message *>
53 log_hook {"qtui log message", this, & StatusBar::log_message};
53 const HookReceiver<StatusBar, const Message *> log_hook{
54 "qtui log message", this, &StatusBar::log_message};
5455
55 const HookReceiver<StatusBar>
56 hook1 {"playlist activate", this, & StatusBar::update_length},
57 hook2 {"playlist update", this, & StatusBar::update_length},
58 hook3 {"playback ready", this, & StatusBar::update_codec},
59 hook4 {"playback stop", this, & StatusBar::update_codec},
60 hook5 {"info change", this, & StatusBar::update_codec},
61 hook6 {"tuple change", this, & StatusBar::update_codec};
56 const HookReceiver<StatusBar> hook1{"playlist activate", this,
57 &StatusBar::update_length},
58 hook2{"playlist update", this, &StatusBar::update_length},
59 hook3{"playback ready", this, &StatusBar::update_codec},
60 hook4{"playback stop", this, &StatusBar::update_codec},
61 hook5{"info change", this, &StatusBar::update_codec},
62 hook6{"tuple change", this, &StatusBar::update_codec};
6263 };
6364
6465 #endif
2121 #include <libaudcore/audstrings.h>
2222 #include <libaudcore/drct.h>
2323 #include <libaudcore/runtime.h>
24 #include <libaudqt/libaudqt.h>
2425
2526 #include <QMouseEvent>
27 #include <QProxyStyle>
2628 #include <QStyle>
2729
28 MyLabel::MyLabel (QWidget * parent) : QLabel (parent) {}
29 MyLabel::~MyLabel () {}
30 TimeSliderLabel::TimeSliderLabel(QWidget * parent) : QLabel(parent)
31 {
32 setStyleSheet("font-weight: bold");
33 }
34 TimeSliderLabel::~TimeSliderLabel() {}
3035
31 void MyLabel::mouseDoubleClickEvent (QMouseEvent * event)
36 void TimeSliderLabel::mouseDoubleClickEvent(QMouseEvent * event)
3237 {
33 aud_toggle_bool ("qtui", "show_remaining_time");
34 hook_call ("qtui toggle remaining time", nullptr);
38 if (event->button() == Qt::LeftButton)
39 {
40 aud_toggle_bool("qtui", "show_remaining_time");
41 hook_call("qtui toggle remaining time", nullptr);
42 event->accept();
43 }
3544
36 event->accept ();
37
38 QLabel::mouseDoubleClickEvent (event);
45 QLabel::mouseDoubleClickEvent(event);
3946 }
4047
41 TimeSlider::TimeSlider (QWidget * parent) :
42 QSlider (Qt::Horizontal, parent),
43 m_label (new MyLabel (parent))
48 class TimeSliderStyle : public QProxyStyle
4449 {
45 setFocusPolicy (Qt::NoFocus);
46 setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed);
50 public:
51 int styleHint(QStyle::StyleHint hint, const QStyleOption * option = nullptr,
52 const QWidget * widget = nullptr,
53 QStyleHintReturn * returnData = nullptr) const
54 {
55 int styleHint =
56 QProxyStyle::styleHint(hint, option, widget, returnData);
4757
48 m_label->setContentsMargins (4, 0, 4, 0);
49 m_label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
58 if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
59 styleHint |= Qt::LeftButton;
5060
51 connect (this, & QSlider::sliderMoved, this, & TimeSlider::moved);
52 connect (this, & QSlider::sliderReleased, this, & TimeSlider::released);
61 return styleHint;
62 }
63 };
5364
54 start_stop ();
65 TimeSlider::TimeSlider(QWidget * parent)
66 : QSlider(Qt::Horizontal, parent), m_label(new TimeSliderLabel(parent))
67 {
68 setFocusPolicy(Qt::NoFocus);
69 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
70 setStyle(new TimeSliderStyle());
71
72 m_label->setContentsMargins(audqt::sizes.FourPt, 0, 0, 0);
73 m_label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
74
75 connect(this, &QSlider::sliderMoved, this, &TimeSlider::moved);
76 connect(this, &QSlider::sliderPressed, this, &TimeSlider::pressed);
77 connect(this, &QSlider::sliderReleased, this, &TimeSlider::released);
78
79 start_stop();
5580 }
5681
57 TimeSlider::~TimeSlider () {}
82 TimeSlider::~TimeSlider() {}
5883
59 void TimeSlider::set_label (int time, int length)
84 void TimeSlider::set_label(int time, int length)
6085 {
6186 QString text;
6287
6388 if (length >= 0)
64 if (aud_get_bool ("qtui", "show_remaining_time"))
65 text = str_concat ({str_format_time (time - length), " / ", str_format_time (length)});
89 if (aud_get_bool("qtui", "show_remaining_time"))
90 text = str_concat({str_format_time(time - length), " / ",
91 str_format_time(length)});
6692 else
67 text = str_concat ({str_format_time (time), " / ", str_format_time (length)});
93 text = str_concat(
94 {str_format_time(time), " / ", str_format_time(length)});
6895 else
69 text = str_format_time (time);
96 text = str_format_time(time);
7097
71 m_label->setText (text);
98 m_label->setText(text);
7299 }
73100
74 void TimeSlider::start_stop ()
101 void TimeSlider::start_stop()
75102 {
76 bool ready = aud_drct_get_ready ();
77 bool paused = aud_drct_get_paused ();
103 bool ready = aud_drct_get_ready();
104 bool paused = aud_drct_get_paused();
78105
79 setEnabled (ready);
80 m_label->setEnabled (ready);
106 setEnabled(ready);
107 m_label->setEnabled(ready);
81108
82 update ();
109 update();
83110
84 if (ready && ! paused)
85 m_timer.start ();
111 if (ready && !paused)
112 m_timer.start();
86113 else
87 m_timer.stop ();
114 m_timer.stop();
88115 }
89116
90 void TimeSlider::update ()
117 void TimeSlider::update()
91118 {
92 if (aud_drct_get_ready ())
119 if (aud_drct_get_ready())
93120 {
94 if (! isSliderDown ())
121 if (!isSliderDown())
95122 {
96 int time = aud_drct_get_time ();
97 int length = aud_drct_get_length ();
123 int time = aud_drct_get_time();
124 int length = aud_drct_get_length();
98125
99 setRange (0, length);
100 setValue (time);
126 setRange(0, length);
127 setValue(time);
101128
102 set_label (time, length);
129 set_label(time, length);
103130 }
104131 }
105132 else
106133 {
107 setRange (0, 0);
108 set_label (0, 0);
134 setRange(0, 0);
135 set_label(0, 0);
109136 }
110137 }
111138
112 void TimeSlider::moved (int value)
113 {
114 set_label (value, aud_drct_get_length ());
115 }
139 void TimeSlider::moved(int value) { set_label(value, aud_drct_get_length()); }
116140
117 void TimeSlider::released ()
118 {
119 aud_drct_seek (value ());
120 }
141 void TimeSlider::pressed() { set_label(value(), aud_drct_get_length()); }
121142
122 void TimeSlider::mousePressEvent (QMouseEvent * event)
123 {
124 if (event->button () == Qt::LeftButton)
125 {
126 setValue (QStyle::sliderValueFromPosition (minimum (), maximum (), event->x (), width ()));
127 event->accept ();
128 }
129
130 QSlider::mousePressEvent (event);
131 }
143 void TimeSlider::released() { aud_drct_seek(value()); }
2626
2727 class QMouseEvent;
2828
29 class MyLabel : public QLabel
29 class TimeSliderLabel : public QLabel
3030 {
3131 public:
32 MyLabel (QWidget * parent);
33 ~MyLabel ();
32 TimeSliderLabel(QWidget * parent);
33 ~TimeSliderLabel();
3434
3535 protected:
36 void mouseDoubleClickEvent (QMouseEvent * event);
36 void mouseDoubleClickEvent(QMouseEvent * event);
3737 };
3838
3939 class TimeSlider : public QSlider
4040 {
4141 public:
42 TimeSlider (QWidget * parent);
43 ~TimeSlider ();
42 TimeSlider(QWidget * parent);
43 ~TimeSlider();
4444
45 MyLabel * label ()
46 { return m_label; }
45 TimeSliderLabel * label() { return m_label; }
4746
4847 private:
49 void set_label (int time, int length);
48 void set_label(int time, int length);
5049
51 void start_stop ();
52 void update ();
53 void moved (int value);
54 void pressed ();
55 void released ();
50 void start_stop();
51 void update();
52 void moved(int value);
53 void pressed();
54 void released();
5655
57 void mousePressEvent (QMouseEvent * event);
56 TimeSliderLabel * m_label;
5857
59 MyLabel * m_label;
58 const Timer<TimeSlider> m_timer{TimerRate::Hz4, this, &TimeSlider::update};
6059
61 const Timer<TimeSlider>
62 m_timer {TimerRate::Hz4, this, & TimeSlider::update};
63
64 const HookReceiver<TimeSlider>
65 hook1 {"playback ready", this, & TimeSlider::start_stop},
66 hook2 {"playback pause", this, & TimeSlider::start_stop},
67 hook3 {"playback unpause", this, & TimeSlider::start_stop},
68 hook4 {"playback seek", this, & TimeSlider::update},
69 hook5 {"playback stop", this, & TimeSlider::start_stop},
70 hook6 {"qtui toggle remaining time", this, & TimeSlider::start_stop};
60 const HookReceiver<TimeSlider> hook1{"playback ready", this,
61 &TimeSlider::start_stop},
62 hook2{"playback pause", this, &TimeSlider::start_stop},
63 hook3{"playback unpause", this, &TimeSlider::start_stop},
64 hook4{"playback seek", this, &TimeSlider::update},
65 hook5{"playback stop", this, &TimeSlider::start_stop},
66 hook6{"qtui toggle remaining time", this, &TimeSlider::start_stop};
7167 };
7268
7369 #endif
2424 #include <libaudcore/runtime.h>
2525 #include <libaudqt/libaudqt.h>
2626
27 ToolBar::ToolBar (QWidget * parent, ArrayRef<ToolBarItem> items)
28 : QToolBar (parent)
27 ToolBar::ToolBar(QWidget * parent, ArrayRef<ToolBarItem> items)
28 : QToolBar(parent)
2929 {
30 setContextMenuPolicy (Qt::PreventContextMenu);
31 setMovable (false);
32 setObjectName ("MainToolBar");
30 setContextMenuPolicy(Qt::PreventContextMenu);
31 setMovable(false);
32 setObjectName("MainToolBar");
3333
3434 for (const ToolBarItem & item : items)
3535 {
3636 if (item.widget)
37 addWidget (item.widget);
37 addWidget(item.widget);
3838 else if (item.sep)
39 addSeparator ();
39 addSeparator();
4040 else if (item.icon_name)
4141 {
42 QAction * a = new QAction (audqt::get_icon (item.icon_name),
43 audqt::translate_str (item.name), this);
42 QAction * a = new QAction(audqt::get_icon(item.icon_name),
43 audqt::translate_str(item.name), this);
4444
4545 if (item.tooltip_text)
46 a->setToolTip (audqt::translate_str (item.tooltip_text));
46 a->setToolTip(audqt::translate_str(item.tooltip_text));
4747
4848 if (item.callback)
49 connect (a, & QAction::triggered, item.callback);
49 connect(a, &QAction::triggered, item.callback);
5050
5151 if (item.toggled)
5252 {
53 a->setCheckable (true);
54 connect (a, & QAction::toggled, item.toggled);
53 a->setCheckable(true);
54 connect(a, &QAction::toggled, item.toggled);
5555 }
5656
57 addAction (a);
57 addAction(a);
5858
5959 if (item.action_ptr)
60 * item.action_ptr = a;
60 *item.action_ptr = a;
6161 }
6262 }
6363 }
2323
2424 #include <libaudcore/objects.h>
2525
26 struct ToolBarItem {
26 struct ToolBarItem
27 {
2728 const char * icon_name;
2829 const char * name;
2930 const char * tooltip_text;
3031
31 void (* callback) ();
32 void (* toggled) (bool on);
32 void (*callback)();
33 void (*toggled)(bool on);
3334
3435 QWidget * widget;
3536
3637 bool sep;
3738
38 QAction * * action_ptr;
39 QAction ** action_ptr;
3940 };
4041
4142 class ToolBar : public QToolBar
4243 {
4344 public:
44 ToolBar (QWidget * parent, ArrayRef<ToolBarItem> items);
45 ToolBar(QWidget * parent, ArrayRef<ToolBarItem> items);
4546 };
4647
47 constexpr ToolBarItem ToolBarAction (const char * icon_name, const char * name,
48 const char * tooltip_text, void (* callback) (), QAction * * action_ptr = nullptr)
49 { return { icon_name, name, tooltip_text, callback, nullptr, nullptr, false, action_ptr }; }
48 constexpr ToolBarItem ToolBarAction(const char * icon_name, const char * name,
49 const char * tooltip_text,
50 void (*callback)(),
51 QAction ** action_ptr = nullptr)
52 {
53 return {icon_name, name, tooltip_text, callback,
54 nullptr, nullptr, false, action_ptr};
55 }
5056
51 constexpr ToolBarItem ToolBarAction (const char * icon_name, const char * name,
52 const char * tooltip_text, void (* toggled) (bool), QAction * * action_ptr = nullptr)
53 { return { icon_name, name, tooltip_text, nullptr, toggled, nullptr, false, action_ptr }; }
57 constexpr ToolBarItem ToolBarAction(const char * icon_name, const char * name,
58 const char * tooltip_text,
59 void (*toggled)(bool),
60 QAction ** action_ptr = nullptr)
61 {
62 return {icon_name, name, tooltip_text, nullptr,
63 toggled, nullptr, false, action_ptr};
64 }
5465
55 constexpr ToolBarItem ToolBarCustom (QWidget * item)
56 { return { nullptr, nullptr, nullptr, nullptr, nullptr, item }; }
66 constexpr ToolBarItem ToolBarCustom(QWidget * item)
67 {
68 return {nullptr, nullptr, nullptr, nullptr, nullptr, item};
69 }
5770
58 constexpr ToolBarItem ToolBarSeparator ()
59 { return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, true }; }
71 constexpr ToolBarItem ToolBarSeparator()
72 {
73 return {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, true};
74 }
6075
6176 #endif
0 shared_module('resample',
1 'resample.cc',
2 include_directories: [src_inc],
3 dependencies: [audacious_dep, samplerate_dep],
4 install: true,
5 install_dir: effect_plugin_dir
6 )
0 curl_dep = dependency('libcurl', version: '>= 7.9.7', required: false)
1
2
3 if curl_dep.found()
4 shared_module('scrobbler',
5 'scrobbler.cc',
6 'scrobbler_communication.cc',
7 'scrobbler_xml_parsing.cc',
8 'config_window.cc',
9 dependencies: [audacious_dep, glib_dep, curl_dep, xml_dep],
10 install: true,
11 install_dir: general_plugin_dir
12 )
13 endif
284284 //line[0] line[1] line[2] line[3] line[4] line[5] line[6] line[7]
285285 //artist album title number length "L" timestamp nullptr
286286
287 char **splitted_line = g_strsplit(*line, "\t", 0);
288 g_free(splitted_line[6]);
289 splitted_line[6] = g_strdup_printf("%" G_GINT64_FORMAT, g_get_real_time() / G_USEC_PER_SEC);
290 AUDDBG("splitted line's timestamp is now: %s.\n", splitted_line[6]);
287 char **split_line = g_strsplit(*line, "\t", 0);
288 g_free(split_line[6]);
289 split_line[6] = g_strdup_printf("%" G_GINT64_FORMAT, g_get_real_time() / G_USEC_PER_SEC);
290 AUDDBG("split line's timestamp is now: %s.\n", split_line[6]);
291291 g_free(*line);
292 (*line) = g_strjoinv("\t", splitted_line);
293 g_strfreev(splitted_line);
292 (*line) = g_strjoinv("\t", split_line);
293 g_strfreev(split_line);
294294 }
295295
296296 static void delete_lines_from_scrobble_log (GSList **lines_to_remove_ptr, GSList **lines_to_retry_ptr, char *queuepath) {
198198 sdlout_chan = chan;
199199 sdlout_rate = rate;
200200
201 int buffer_ms = aud_get_int (nullptr, "output_buffer_size");
201 int buffer_ms = aud_get_int ("output_buffer_size");
202202 buffer.alloc (2 * chan * aud::rescale (buffer_ms, 1000, rate));
203203
204204 prebuffer_flag = true;
00 PLUGIN = search-tool${PLUGIN_SUFFIX}
11
2 SRCS = search-tool.cc
2 SRCS = library.cc search-model.cc search-tool.cc
33
44 include ../../buildsys.mk
55 include ../../extra.mk
0 /*
1 * library.cc
2 * Copyright 2011-2019 John Lindgren
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #include "library.h"
20
21 #include <string.h>
22 #include <libaudcore/i18n.h>
23
24 aud::spinlock Library::s_adding_lock;
25 Library * Library::s_adding_library = nullptr;
26
27 void Library::find_playlist ()
28 {
29 m_playlist = Playlist ();
30
31 for (int p = 0; p < Playlist::n_playlists (); p ++)
32 {
33 auto playlist = Playlist::by_index (p);
34 if (! strcmp (playlist.get_title (), _("Library")))
35 {
36 m_playlist = playlist;
37 break;
38 }
39 }
40 }
41
42 void Library::create_playlist ()
43 {
44 m_playlist = Playlist::blank_playlist ();
45 m_playlist.set_title (_("Library"));
46 m_playlist.active_playlist ();
47 }
48
49 bool Library::check_playlist (bool require_added, bool require_scanned)
50 {
51 if (! m_playlist.exists ())
52 {
53 m_playlist = Playlist ();
54 return false;
55 }
56
57 if (require_added && m_playlist.add_in_progress ())
58 return false;
59 if (require_scanned && m_playlist.scan_in_progress ())
60 return false;
61
62 return true;
63 }
64
65 void Library::set_adding (bool adding)
66 {
67 auto lh = s_adding_lock.take ();
68 s_adding_library = adding ? this : nullptr;
69 }
70
71 bool Library::filter_cb (const char * filename, void *)
72 {
73 bool add = false;
74 auto lh = s_adding_lock.take ();
75
76 if (s_adding_library)
77 {
78 bool * added = s_adding_library->m_added_table.lookup (String (filename));
79
80 if ((add = ! added))
81 s_adding_library->m_added_table.add (String (filename), true);
82 else
83 (* added) = true;
84 }
85
86 return add;
87 }
88
89 void Library::begin_add (const char * uri)
90 {
91 if (s_adding_library)
92 return;
93
94 if (! check_playlist (false, false))
95 create_playlist ();
96
97 m_added_table.clear ();
98
99 int entries = m_playlist.n_entries ();
100
101 for (int entry = 0; entry < entries; entry ++)
102 {
103 String filename = m_playlist.entry_filename (entry);
104
105 if (! m_added_table.lookup (filename))
106 {
107 m_playlist.select_entry (entry, false);
108 m_added_table.add (filename, false);
109 }
110 else
111 m_playlist.select_entry (entry, true);
112 }
113
114 m_playlist.remove_selected ();
115
116 set_adding (true);
117
118 Index<PlaylistAddItem> add;
119 add.append (String (uri));
120 m_playlist.insert_filtered (-1, std::move (add), filter_cb, nullptr, false);
121 }
122
123 void Library::check_ready_and_update (bool force)
124 {
125 bool now_ready = check_playlist (true, true);
126 if (now_ready != m_is_ready || force)
127 {
128 m_is_ready = now_ready;
129 signal_update ();
130 }
131 }
132
133 void Library::add_complete ()
134 {
135 if (! check_playlist (true, false))
136 return;
137
138 if (s_adding_library)
139 {
140 set_adding (false);
141
142 int entries = m_playlist.n_entries ();
143
144 for (int entry = 0; entry < entries; entry ++)
145 {
146 String filename = m_playlist.entry_filename (entry);
147 bool * added = m_added_table.lookup (filename);
148
149 m_playlist.select_entry (entry, ! added || ! (* added));
150 }
151
152 m_added_table.clear ();
153
154 /* don't clear the playlist if nothing was added */
155 if (m_playlist.n_selected () < entries)
156 m_playlist.remove_selected ();
157 else
158 m_playlist.select_all (false);
159
160 m_playlist.sort_entries (Playlist::Path);
161 }
162
163 if (! m_playlist.update_pending ())
164 check_ready_and_update (false);
165 }
166
167 void Library::scan_complete ()
168 {
169 if (! m_playlist.update_pending ())
170 check_ready_and_update (false);
171 }
172
173 void Library::playlist_update ()
174 {
175 check_ready_and_update (m_playlist.update_detail ().level >= Playlist::Metadata);
176 }
0 /*
1 * library.h
2 * Copyright 2011-2019 John Lindgren
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #ifndef LIBRARY_H
20 #define LIBRARY_H
21
22 #include <libaudcore/hook.h>
23 #include <libaudcore/multihash.h>
24 #include <libaudcore/playlist.h>
25
26 class Library
27 {
28 public:
29 Library () { find_playlist (); }
30 ~Library () { set_adding (false); }
31
32 Playlist playlist () const { return m_playlist; }
33 bool is_ready () const { return m_is_ready; }
34
35 void begin_add (const char * uri);
36 void check_ready_and_update (bool force);
37
38 private:
39 void find_playlist ();
40 void create_playlist ();
41 bool check_playlist (bool require_added, bool require_scanned);
42 void set_adding (bool adding);
43
44 static bool filter_cb (const char * filename, void *);
45
46 void add_complete (void);
47 void scan_complete (void);
48 void playlist_update (void);
49
50 static void signal_update (); /* implemented externally */
51
52 Playlist m_playlist;
53 bool m_is_ready = false;
54 SimpleHash<String, bool> m_added_table;
55
56 /* to allow safe callback access from playlist add thread */
57 static aud::spinlock s_adding_lock;
58 static Library * s_adding_library;
59
60 HookReceiver<Library>
61 hook1 {"playlist add complete", this, & Library::add_complete},
62 hook2 {"playlist scan complete", this, & Library::scan_complete},
63 hook3 {"playlist update", this, & Library::playlist_update};
64 };
65
66 #endif // LIBRARY_H
0 /*
1 * search-model.cc
2 * Copyright 2011-2019 John Lindgren and René J.V. Bertin
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #include "search-model.h"
20 #include <string.h>
21
22 void SearchModel::destroy_database ()
23 {
24 m_playlist = Playlist ();
25 m_items.clear ();
26 m_hidden_items = 0;
27 m_database.clear ();
28 }
29
30 void SearchModel::create_database (Playlist playlist)
31 {
32 destroy_database ();
33
34 int entries = playlist.n_entries ();
35
36 for (int e = 0; e < entries; e ++)
37 {
38 Tuple tuple = playlist.entry_tuple (e, Playlist::NoWait);
39
40 aud::array<SearchField, String> fields;
41 fields[SearchField::Genre] = tuple.get_str (Tuple::Genre);
42 fields[SearchField::Artist] = tuple.get_str (Tuple::Artist);
43 fields[SearchField::Album] = tuple.get_str (Tuple::Album);
44 fields[SearchField::Title] = tuple.get_str (Tuple::Title);
45
46 Item * parent = nullptr;
47 SimpleHash<Key, Item> * hash = & m_database;
48
49 for (auto f : aud::range<SearchField> ())
50 {
51 if (fields[f])
52 {
53 Key key = {f, fields[f]};
54 Item * item = hash->lookup (key);
55
56 if (! item)
57 item = hash->add (key, Item (f, fields[f], parent));
58
59 item->matches.append (e);
60
61 /* genre is outside the normal hierarchy */
62 if (f != SearchField::Genre)
63 {
64 parent = item;
65 hash = & item->children;
66 }
67 }
68 }
69 }
70
71 m_playlist = playlist;
72 }
73
74 static void search_recurse (SimpleHash<Key, Item> & domain,
75 const Index<String> & terms, int mask, Index<const Item *> & results)
76 {
77 domain.iterate ([&] (const Key & key, Item & item)
78 {
79 int count = terms.len ();
80 int new_mask = mask;
81
82 for (int t = 0, bit = 1; t < count; t ++, bit <<= 1)
83 {
84 if (! (new_mask & bit))
85 continue; /* skip term if it is already found */
86
87 if (strstr (item.folded, terms[t]))
88 new_mask &= ~bit; /* we found it */
89 else if (! item.children.n_items ())
90 break; /* quit early if there are no children to search */
91 }
92
93 /* adding an item with exactly one child is redundant, so avoid it */
94 if (! new_mask && item.children.n_items () != 1)
95 results.append (& item);
96
97 search_recurse (item.children, terms, new_mask, results);
98 });
99 }
100
101 static int item_compare (const Item * const & a, const Item * const & b)
102 {
103 if (a->field < b->field)
104 return -1;
105 if (a->field > b->field)
106 return 1;
107
108 int val = str_compare (a->name, b->name);
109 if (val)
110 return val;
111
112 if (a->parent)
113 return b->parent ? item_compare (a->parent, b->parent) : 1;
114 else
115 return b->parent ? -1 : 0;
116 }
117
118 static int item_compare_pass1 (const Item * const & a, const Item * const & b)
119 {
120 if (a->matches.len () > b->matches.len ())
121 return -1;
122 if (a->matches.len () < b->matches.len ())
123 return 1;
124
125 return item_compare (a, b);
126 }
127
128 void SearchModel::do_search (const Index<String> & terms, int max_results)
129 {
130 m_items.clear ();
131 m_hidden_items = 0;
132
133 /* effectively limits number of search terms to 32 */
134 search_recurse (m_database, terms, (1 << terms.len ()) - 1, m_items);
135
136 /* first sort by number of songs per item */
137 m_items.sort (item_compare_pass1);
138
139 /* limit to items with most songs */
140 if (m_items.len () > max_results)
141 {
142 m_hidden_items = m_items.len () - max_results;
143 m_items.remove (max_results, -1);
144 }
145
146 /* sort by item type, then item name */
147 m_items.sort (item_compare);
148 }
0 /*
1 * search-model.h
2 * Copyright 2011-2019 John Lindgren and René J.V. Bertin
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #ifndef SEARCHMODEL_H
20 #define SEARCHMODEL_H
21
22 #include <libaudcore/audstrings.h>
23 #include <libaudcore/multihash.h>
24 #include <libaudcore/playlist.h>
25
26 enum class SearchField {
27 Genre,
28 Artist,
29 Album,
30 Title,
31 count
32 };
33
34 struct Key
35 {
36 SearchField field;
37 String name;
38
39 bool operator== (const Key & b) const
40 { return field == b.field && name == b.name; }
41 unsigned hash () const
42 { return (unsigned) field + name.hash (); }
43 };
44
45 struct Item
46 {
47 SearchField field;
48 String name, folded;
49 Item * parent;
50 SimpleHash<Key, Item> children;
51 Index<int> matches;
52
53 Item (SearchField field, const String & name, Item * parent) :
54 field (field),
55 name (name),
56 folded (str_tolower_utf8 (name)),
57 parent (parent) {}
58
59 Item (Item &&) = default;
60 Item & operator= (Item &&) = default;
61 };
62
63 class SearchModel
64 {
65 public:
66 int num_items () const { return m_items.len (); }
67 const Item & item_at (int idx) const { return * m_items[idx]; }
68 int num_hidden_items () const { return m_hidden_items; }
69
70 void destroy_database ();
71 void create_database (Playlist playlist);
72 void do_search (const Index<String> & terms, int max_results);
73
74 private:
75 Playlist m_playlist;
76 SimpleHash<Key, Item> m_database;
77 Index<const Item *> m_items;
78 int m_hidden_items = 0;
79 int m_rows = 0;
80 };
81
82 #endif // SEARCHMODEL_H
2121 #include <gdk/gdk.h>
2222
2323 #define AUD_GLIB_INTEGRATION
24 #include <libaudcore/audstrings.h>
25 #include <libaudcore/hook.h>
2624 #include <libaudcore/i18n.h>
27 #include <libaudcore/playlist.h>
2825 #include <libaudcore/plugin.h>
26 #include <libaudcore/preferences.h>
2927 #include <libaudcore/mainloop.h>
30 #include <libaudcore/multihash.h>
3128 #include <libaudcore/runtime.h>
32 #include <libaudcore/preferences.h>
3329 #include <libaudgui/libaudgui-gtk.h>
3430 #include <libaudgui/list.h>
3531 #include <libaudgui/menu.h>
32
33 #include "library.h"
34 #include "search-model.h"
3635
3736 #define CFG_ID "search-tool"
3837 #define SEARCH_DELAY 300
7978
8079 const PluginPreferences SearchTool::prefs = {{widgets}};
8180
82 enum class SearchField {
83 Genre,
84 Artist,
85 Album,
86 Title,
87 count
88 };
89
90 struct Key
91 {
92 SearchField field;
93 String name;
94
95 bool operator== (const Key & b) const
96 { return field == b.field && name == b.name; }
97 unsigned hash () const
98 { return (unsigned) field + name.hash (); }
99 };
100
101 struct Item
102 {
103 SearchField field;
104 String name, folded;
105 Item * parent;
106 SimpleHash<Key, Item> children;
107 Index<int> matches;
108
109 Item (SearchField field, const String & name, Item * parent) :
110 field (field),
111 name (name),
112 folded (str_tolower_utf8 (name)),
113 parent (parent) {}
114
115 Item (Item &&) = default;
116 Item & operator= (Item &&) = default;
117 };
118
119 static Playlist s_playlist;
120 static Index<String> s_search_terms;
121
122 /* Note: added_table is accessed by multiple threads.
123 * When adding = true, it may only be accessed by the playlist add thread.
124 * When adding = false, it may only be accessed by the UI thread.
125 * adding may only be set by the UI thread while holding adding_lock. */
126 static TinyLock s_adding_lock;
127 static bool s_adding = false;
128 static SimpleHash<String, bool> s_added_table;
129
130 static SimpleHash<Key, Item> s_database;
131 static bool s_database_valid;
132 static Index<const Item *> s_items;
133 static int s_hidden_items;
81 static Library * s_library = nullptr;
82 static SearchModel s_model;
13483 static Index<bool> s_selection;
13584
13685 static QueuedFunc s_search_timer;
13887
13988 static GtkWidget * entry, * help_label, * wait_label, * scrolled, * results_list, * stats_label;
14089
141 static void find_playlist ()
142 {
143 s_playlist = Playlist ();
144
145 for (int p = 0; p < Playlist::n_playlists (); p ++)
146 {
147 auto playlist = Playlist::by_index (p);
148 if (! strcmp (playlist.get_title (), _("Library")))
149 {
150 s_playlist = playlist;
151 break;
152 }
153 }
154 }
155
156 static void create_playlist ()
157 {
158 s_playlist = Playlist::blank_playlist ();
159 s_playlist.set_title (_("Library"));
160 s_playlist.active_playlist ();
161 }
162
163 static bool check_playlist (bool require_added, bool require_scanned)
164 {
165 if (! s_playlist.exists ())
166 {
167 s_playlist = Playlist ();
168 return false;
169 }
170
171 if (require_added && s_playlist.add_in_progress ())
172 return false;
173 if (require_scanned && s_playlist.scan_in_progress ())
174 return false;
175
176 return true;
177 }
178
17990 static String get_uri ()
18091 {
18192 auto to_uri = [] (const char * path)
18293 { return String (filename_to_uri (path)); };
18394
184 String path1 = aud_get_str ("search-tool", "path");
95 String path1 = aud_get_str (CFG_ID, "path");
18596 if (path1[0])
18697 return strstr (path1, "://") ? path1 : to_uri (path1);
18798
192103 return to_uri (g_get_home_dir ());
193104 }
194105
195 static void destroy_database ()
196 {
197 s_items.clear ();
198 s_hidden_items = 0;
199 s_database.clear ();
200 s_database_valid = false;
201 }
202
203 static void create_database ()
204 {
205 destroy_database ();
206
207 int entries = s_playlist.n_entries ();
208
209 for (int e = 0; e < entries; e ++)
210 {
211 Tuple tuple = s_playlist.entry_tuple (e, Playlist::NoWait);
212
213 aud::array<SearchField, String> fields;
214 fields[SearchField::Genre] = tuple.get_str (Tuple::Genre);
215 fields[SearchField::Artist] = tuple.get_str (Tuple::Artist);
216 fields[SearchField::Album] = tuple.get_str (Tuple::Album);
217 fields[SearchField::Title] = tuple.get_str (Tuple::Title);
218
219 Item * parent = nullptr;
220 SimpleHash<Key, Item> * hash = & s_database;
221
222 for (auto f : aud::range<SearchField> ())
223 {
224 if (fields[f])
225 {
226 Key key = {f, fields[f]};
227 Item * item = hash->lookup (key);
228
229 if (! item)
230 item = hash->add (key, Item (f, fields[f], parent));
231
232 item->matches.append (e);
233
234 /* genre is outside the normal hierarchy */
235 if (f != SearchField::Genre)
236 {
237 parent = item;
238 hash = & item->children;
239 }
240 }
241 }
242 }
243
244 s_database_valid = true;
245 }
246
247 static void search_recurse (SimpleHash<Key, Item> & domain, int mask, Index<const Item *> & results)
248 {
249 domain.iterate ([mask, & results] (const Key & key, Item & item)
250 {
251 int count = s_search_terms.len ();
252 int new_mask = mask;
253
254 for (int t = 0, bit = 1; t < count; t ++, bit <<= 1)
255 {
256 if (! (new_mask & bit))
257 continue; /* skip term if it is already found */
258
259 if (strstr (item.folded, s_search_terms[t]))
260 new_mask &= ~bit; /* we found it */
261 else if (! item.children.n_items ())
262 break; /* quit early if there are no children to search */
263 }
264
265 /* adding an item with exactly one child is redundant, so avoid it */
266 if (! new_mask && item.children.n_items () != 1)
267 results.append (& item);
268
269 search_recurse (item.children, new_mask, results);
270 });
271 }
272
273 static int item_compare (const Item * const & a, const Item * const & b)
274 {
275 if (a->field < b->field)
276 return -1;
277 if (a->field > b->field)
278 return 1;
279
280 int val = str_compare (a->name, b->name);
281 if (val)
282 return val;
283
284 if (a->parent)
285 return b->parent ? item_compare (a->parent, b->parent) : 1;
286 else
287 return b->parent ? -1 : 0;
288 }
289
290 static int item_compare_pass1 (const Item * const & a, const Item * const & b)
291 {
292 if (a->matches.len () > b->matches.len ())
293 return -1;
294 if (a->matches.len () < b->matches.len ())
295 return 1;
296
297 return item_compare (a, b);
298 }
299
300 static void do_search ()
301 {
302 s_items.clear ();
303 s_hidden_items = 0;
304
305 if (! s_database_valid)
306 return;
307
308 /* effectively limits number of search terms to 32 */
309 search_recurse (s_database, (1 << s_search_terms.len ()) - 1, s_items);
310
311 /* first sort by number of songs per item */
312 s_items.sort (item_compare_pass1);
313
314 int max_results = aud_get_int (CFG_ID, "max_results");
315 /* limit to items with most songs */
316 if (s_items.len () > max_results)
317 {
318 s_hidden_items = s_items.len () - max_results;
319 s_items.remove (max_results, -1);
320 }
321
322 /* sort by item type, then item name */
323 s_items.sort (item_compare);
324
325 s_selection.remove (0, -1);
326 s_selection.insert (0, s_items.len ());
327 if (s_items.len ())
328 s_selection[0] = true;
329 }
330
331 static bool filter_cb (const char * filename, void * unused)
332 {
333 bool add = false;
334 tiny_lock (& s_adding_lock);
335
336 if (s_adding)
337 {
338 bool * added = s_added_table.lookup (String (filename));
339
340 if ((add = ! added))
341 s_added_table.add (String (filename), true);
342 else
343 (* added) = true;
344 }
345
346 tiny_unlock (& s_adding_lock);
347 return add;
348 }
349
350 static void begin_add (const char * uri)
351 {
352 if (s_adding)
353 return;
354
355 if (! check_playlist (false, false))
356 create_playlist ();
357
358 /* if possible, store local path for compatibility with older versions */
359 StringBuf path = uri_to_filename (uri);
360 aud_set_str ("search-tool", "path", path ? path : uri);
361
362 s_added_table.clear ();
363
364 int entries = s_playlist.n_entries ();
365
366 for (int entry = 0; entry < entries; entry ++)
367 {
368 String filename = s_playlist.entry_filename (entry);
369
370 if (! s_added_table.lookup (filename))
371 {
372 s_playlist.select_entry (entry, false);
373 s_added_table.add (filename, false);
374 }
375 else
376 s_playlist.select_entry (entry, true);
377 }
378
379 s_playlist.remove_selected ();
380
381 tiny_lock (& s_adding_lock);
382 s_adding = true;
383 tiny_unlock (& s_adding_lock);
384
385 Index<PlaylistAddItem> add;
386 add.append (String (uri));
387 s_playlist.insert_filtered (-1, std::move (add), filter_cb, nullptr, false);
388 }
389
390106 static void show_hide_widgets ()
391107 {
392 if (s_playlist == Playlist ())
108 if (s_library->playlist () == Playlist ())
393109 {
394110 gtk_widget_hide (wait_label);
395111 gtk_widget_hide (scrolled);
400116 {
401117 gtk_widget_hide (help_label);
402118
403 if (s_database_valid)
119 if (s_library->is_ready ())
404120 {
405121 gtk_widget_hide (wait_label);
406122 gtk_widget_show (scrolled);
417133
418134 static void search_timeout (void * = nullptr)
419135 {
420 do_search ();
136 const char * text = gtk_entry_get_text ((GtkEntry *) entry);
137 auto terms = str_list_to_index (str_tolower_utf8 (text), " ");
138 s_model.do_search (terms, aud_get_int (CFG_ID, "max_results"));
139
140 int shown = s_model.num_items ();
141 int hidden = s_model.num_hidden_items ();
142 int total = shown + hidden;
143
144 s_selection.clear ();
145 s_selection.insert (0, shown);
146 if (shown)
147 s_selection[0] = true;
421148
422149 audgui_list_delete_rows (results_list, 0, audgui_list_row_count (results_list));
423 audgui_list_insert_rows (results_list, 0, s_items.len ());
424
425 int total = s_items.len () + s_hidden_items;
426
427 if (s_hidden_items)
150 audgui_list_insert_rows (results_list, 0, shown);
151
152 if (hidden)
428153 gtk_label_set_text ((GtkLabel *) stats_label,
429154 str_printf (dngettext (PACKAGE, "%d of %d result shown",
430 "%d of %d results shown", total), s_items.len (), total));
155 "%d of %d results shown", total), shown, total));
431156 else
432157 gtk_label_set_text ((GtkLabel *) stats_label,
433158 str_printf (dngettext (PACKAGE, "%d result", "%d results", total), total));
442167 s_search_pending = true;
443168 }
444169
445 static void update_database ()
446 {
447 if (check_playlist (true, true))
448 {
449 create_database ();
170 void Library::signal_update ()
171 {
172 if (s_library->is_ready ())
173 {
174 s_model.create_database (s_library->playlist ());
450175 search_timeout ();
451176 }
452177 else
453178 {
454 destroy_database ();
179 s_model.destroy_database ();
180 s_selection.clear ();
455181 audgui_list_delete_rows (results_list, 0, audgui_list_row_count (results_list));
456182 gtk_label_set_text ((GtkLabel *) stats_label, "");
457183 }
459185 show_hide_widgets ();
460186 }
461187
462 static void add_complete_cb (void *, void *)
463 {
464 if (! check_playlist (true, false))
465 return;
466
467 if (s_adding)
468 {
469 tiny_lock (& s_adding_lock);
470 s_adding = false;
471 tiny_unlock (& s_adding_lock);
472
473 int entries = s_playlist.n_entries ();
474
475 for (int entry = 0; entry < entries; entry ++)
476 {
477 String filename = s_playlist.entry_filename (entry);
478 bool * added = s_added_table.lookup (filename);
479
480 s_playlist.select_entry (entry, ! added || ! (* added));
481 }
482
483 s_added_table.clear ();
484
485 /* don't clear the playlist if nothing was added */
486 if (s_playlist.n_selected () < entries)
487 s_playlist.remove_selected ();
488 else
489 s_playlist.select_all (false);
490
491 s_playlist.sort_entries (Playlist::Path);
492 }
493
494 if (! s_database_valid && ! s_playlist.update_pending ())
495 update_database ();
496 }
497
498 static void scan_complete_cb (void *, void *)
499 {
500 if (! check_playlist (true, true))
501 return;
502
503 if (! s_database_valid && ! s_playlist.update_pending ())
504 update_database ();
505 }
506
507 static void playlist_update_cb (void *, void *)
508 {
509 if (! s_database_valid || ! check_playlist (true, true) ||
510 s_playlist.update_detail ().level >= Playlist::Metadata)
511 {
512 update_database ();
513 }
514 }
515
516188 static void search_init ()
517189 {
518 find_playlist ();
190 s_library = new Library;
519191
520192 if (aud_get_bool (CFG_ID, "rescan_on_startup"))
521 begin_add (get_uri ());
522
523 update_database ();
524
525 hook_associate ("playlist add complete", add_complete_cb, nullptr);
526 hook_associate ("playlist scan complete", scan_complete_cb, nullptr);
527 hook_associate ("playlist update", playlist_update_cb, nullptr);
193 s_library->begin_add (get_uri ());
194
195 s_library->check_ready_and_update (true);
528196 }
529197
530198 static void search_cleanup ()
531199 {
532 hook_dissociate ("playlist add complete", add_complete_cb);
533 hook_dissociate ("playlist scan complete", scan_complete_cb);
534 hook_dissociate ("playlist update", playlist_update_cb);
535
536200 s_search_timer.stop ();
537201 s_search_pending = false;
538202
539 s_search_terms.clear ();
540 s_items.clear ();
203 delete s_library;
204 s_library = nullptr;
205
206 s_model.destroy_database ();
541207 s_selection.clear ();
542
543 tiny_lock (& s_adding_lock);
544 s_adding = false;
545 tiny_unlock (& s_adding_lock);
546
547 s_added_table.clear ();
548 destroy_database ();
549208 }
550209
551210 static void do_add (bool play, bool set_title)
553212 if (s_search_pending)
554213 search_timeout ();
555214
556 int n_items = s_items.len ();
215 auto list = s_library->playlist ();
216 int n_items = s_model.num_items ();
557217 int n_selected = 0;
558218
559219 Index<PlaylistAddItem> add;
564224 if (! s_selection[i])
565225 continue;
566226
567 const Item * item = s_items[i];
568
569 for (int entry : item->matches)
227 auto & item = s_model.item_at (i);
228
229 for (int entry : item.matches)
570230 {
571231 add.append (
572 s_playlist.entry_filename (entry),
573 s_playlist.entry_tuple (entry, Playlist::NoWait),
574 s_playlist.entry_decoder (entry, Playlist::NoWait)
232 list.entry_filename (entry),
233 list.entry_tuple (entry, Playlist::NoWait),
234 list.entry_decoder (entry, Playlist::NoWait)
575235 );
576236 }
577237
578238 n_selected ++;
579239 if (n_selected == 1)
580 title = item->name;
240 title = item.name;
581241 }
582242
583243 auto list2 = Playlist::active_playlist ();
601261
602262 static void action_add_to_playlist ()
603263 {
604 if (s_playlist != Playlist::active_playlist ())
264 if (s_library->playlist () != Playlist::active_playlist ())
605265 do_add (false, false);
606266 }
607267
615275 auto escape = [] (const char * s)
616276 { return CharPtr (g_markup_escape_text (s, -1)); };
617277
618 g_return_if_fail (row >= 0 && row < s_items.len ());
619
620 const Item * item = s_items[row];
621
622 CharPtr name = escape ((item->field == SearchField::Genre) ?
623 str_toupper_utf8 (item->name) : item->name);
278 g_return_if_fail (row >= 0 && row < s_model.num_items ());
279
280 auto & item = s_model.item_at (row);
281
282 CharPtr name = escape ((item.field == SearchField::Genre) ?
283 str_toupper_utf8 (item.name) : item.name);
624284
625285 StringBuf desc (0);
626286
627 if (item->field != SearchField::Title)
287 if (item.field != SearchField::Title)
628288 {
629289 desc.insert (-1, " ");
630290 str_append_printf (desc, dngettext (PACKAGE, "%d song", "%d songs",
631 item->matches.len ()), item->matches.len ());
632 }
633
634 if (item->field == SearchField::Genre)
291 item.matches.len ()), item.matches.len ());
292 }
293
294 if (item.field == SearchField::Genre)
635295 {
636296 desc.insert (-1, " ");
637297 desc.insert (-1, _("of this genre"));
638298 }
639 else if (item->parent)
640 {
641 auto parent = (item->parent->parent ? item->parent->parent : item->parent);
299 else if (item.parent)
300 {
301 auto parent = (item.parent->parent ? item.parent->parent : item.parent);
642302
643303 desc.insert (-1, " ");
644304 desc.insert (-1, (parent->field == SearchField::Album) ? _("on") : _("by"));
649309 }
650310
651311 g_value_take_string (value, g_strdup_printf
652 ("%s%s%s\n<small>%s</small>", start_tags[item->field], (const char *) name,
653 end_tags[item->field], (const char *) desc));
312 ("%s%s%s\n<small>%s</small>", start_tags[item.field], (const char *) name,
313 end_tags[item.field], (const char *) desc));
654314 }
655315
656316 static bool list_get_selected (void * user, int row)
697357 if (s_search_pending)
698358 search_timeout ();
699359
700 int n_items = s_items.len ();
360 auto list = s_library->playlist ();
361 int n_items = s_model.num_items ();
701362 Index<char> buf;
702363
703 s_playlist.select_all (false);
364 list.select_all (false);
704365
705366 for (int i = 0; i < n_items; i ++)
706367 {
707368 if (! s_selection[i])
708369 continue;
709370
710 const Item * item = s_items[i];
711
712 for (int entry : item->matches)
371 auto & item = s_model.item_at (i);
372
373 for (int entry : item.matches)
713374 {
714375 if (buf.len ())
715376 buf.append ('\n');
716377
717 String filename = s_playlist.entry_filename (entry);
378 String filename = list.entry_filename (entry);
718379 buf.insert (filename, -1, strlen (filename));
719380
720 s_playlist.select_entry (entry, true);
381 list.select_entry (entry, true);
721382 }
722383 }
723384
724 s_playlist.cache_selected ();
385 list.cache_selected ();
725386
726387 return buf;
727388 }
741402
742403 static void entry_cb (GtkEntry * entry, void * unused)
743404 {
744 const char * text = gtk_entry_get_text ((GtkEntry *) entry);
745 s_search_terms = str_list_to_index (str_tolower_utf8 (text), " ");
746405 s_search_timer.queue (SEARCH_DELAY, search_timeout, nullptr);
747406 s_search_pending = true;
748407 }
759418 if (uri)
760419 {
761420 audgui_file_entry_set_uri (file_entry, uri); // normalize path
762 begin_add (uri);
763 update_database ();
421 /* if possible, store local path for compatibility with older versions */
422 StringBuf path = uri_to_filename (uri);
423 aud_set_str (CFG_ID, "path", path ? path : uri);
424
425 s_library->begin_add (uri);
426 s_library->check_ready_and_update (true);
764427 }
765428 }
766429
776439
777440 entry = gtk_entry_new ();
778441 gtk_entry_set_icon_from_icon_name ((GtkEntry *) entry, GTK_ENTRY_ICON_PRIMARY, "edit-find");
779 (void) _("Search library"); // translated string is used in GTK3 branch
780442 g_signal_connect (entry, "destroy", (GCallback) gtk_widget_destroyed, & entry);
781443 gtk_box_pack_start ((GtkBox *) vbox, entry, false, false, 0);
782444
802464 gtk_widget_set_no_show_all (scrolled, true);
803465 gtk_box_pack_start ((GtkBox *) vbox, scrolled, true, true, 0);
804466
805 results_list = audgui_list_new (& list_callbacks, nullptr, s_items.len ());
467 results_list = audgui_list_new (& list_callbacks, nullptr, 0);
806468 g_signal_connect (results_list, "destroy", (GCallback) gtk_widget_destroyed, & results_list);
807469 gtk_tree_view_set_headers_visible ((GtkTreeView *) results_list, false);
808470 audgui_list_add_column (results_list, nullptr, 0, G_TYPE_STRING, -1, true);
00 PLUGIN = search-tool-qt${PLUGIN_SUFFIX}
11
2 SRCS = search-tool-qt.cc
2 SRCS = html-delegate.cc library.cc search-model.cc search-tool-qt.cc
33
44 include ../../buildsys.mk
55 include ../../extra.mk
0 /*
1 * html-delegate.cc
2 * Copyright 2018 John Lindgren and René J.V. Bertin
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #include "html-delegate.h"
20
21 #include <QAbstractTextDocumentLayout>
22 #include <QApplication>
23 #include <QPainter>
24
25 #include <libaudqt/libaudqt.h>
26
27 static void init_text_document (QTextDocument & doc, const QStyleOptionViewItem & option)
28 {
29 doc.setHtml (option.text);
30 doc.setDocumentMargin (audqt::sizes.TwoPt);
31 doc.setDefaultFont (option.font);
32 }
33
34 void HtmlDelegate::paint (QPainter * painter, const QStyleOptionViewItem & option_,
35 const QModelIndex & index) const
36 {
37 QStyleOptionViewItem option = option_;
38 initStyleOption (& option, index);
39
40 QTextDocument doc;
41 init_text_document (doc, option);
42
43 QStyle * style = option.widget ? option.widget->style () : qApp->style ();
44 QAbstractTextDocumentLayout::PaintContext ctx;
45
46 // Painting item without text
47 option.text = QString ();
48 style->drawControl (QStyle::CE_ItemViewItem, & option, painter);
49
50 // Color group logic imitating qcommonstyle.cpp
51 QPalette::ColorGroup cg =
52 ! (option.state & QStyle::State_Enabled) ? QPalette::Disabled :
53 ! (option.state & QStyle::State_Active) ? QPalette::Inactive : QPalette::Normal;
54
55 // Highlighting text if item is selected
56 if (option.state & QStyle::State_Selected)
57 ctx.palette.setColor (QPalette::Text, option.palette.color (cg, QPalette::HighlightedText));
58 else
59 ctx.palette.setColor (QPalette::Text, option.palette.color (cg, QPalette::Text));
60
61 QRect textRect = style->subElementRect (QStyle::SE_ItemViewItemText, & option);
62 painter->save ();
63 painter->translate (textRect.topLeft ());
64 painter->setClipRect (textRect.translated (-textRect.topLeft ()));
65 doc.documentLayout ()->draw (painter, ctx);
66 painter->restore ();
67 }
68
69 QSize HtmlDelegate::sizeHint (const QStyleOptionViewItem & option_,
70 const QModelIndex & index) const
71 {
72 QStyleOptionViewItem option = option_;
73 initStyleOption (& option, index);
74
75 QTextDocument doc;
76 init_text_document (doc, option);
77
78 return QSize (audqt::sizes.OneInch, doc.size ().height ());
79 }
80
0 /*
1 * html-delegate.h
2 * Copyright 2018 John Lindgren and René J.V. Bertin
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #ifndef HTMLDELEGATE_H
20 #define HTMLDELEGATE_H
21
22 #include <QStyledItemDelegate>
23
24 // Allow rich text in QTreeView entries
25 class HtmlDelegate : public QStyledItemDelegate
26 {
27 protected:
28 void paint (QPainter * painter, const QStyleOptionViewItem & option,
29 const QModelIndex & index) const override;
30 QSize sizeHint (const QStyleOptionViewItem & option,
31 const QModelIndex & index) const override;
32 };
33
34 #endif // HTMLDELEGATE_H
0 /*
1 * library.cc
2 * Copyright 2011-2019 John Lindgren
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #include "library.h"
20
21 #include <string.h>
22 #include <libaudcore/i18n.h>
23
24 aud::spinlock Library::s_adding_lock;
25 Library * Library::s_adding_library = nullptr;
26
27 void Library::find_playlist ()
28 {
29 m_playlist = Playlist ();
30
31 for (int p = 0; p < Playlist::n_playlists (); p ++)
32 {
33 auto playlist = Playlist::by_index (p);
34 if (! strcmp (playlist.get_title (), _("Library")))
35 {
36 m_playlist = playlist;
37 break;
38 }
39 }
40 }
41
42 void Library::create_playlist ()
43 {
44 m_playlist = Playlist::blank_playlist ();
45 m_playlist.set_title (_("Library"));
46 m_playlist.active_playlist ();
47 }
48
49 bool Library::check_playlist (bool require_added, bool require_scanned)
50 {
51 if (! m_playlist.exists ())
52 {
53 m_playlist = Playlist ();
54 return false;
55 }
56
57 if (require_added && m_playlist.add_in_progress ())
58 return false;
59 if (require_scanned && m_playlist.scan_in_progress ())
60 return false;
61
62 return true;
63 }
64
65 void Library::set_adding (bool adding)
66 {
67 auto lh = s_adding_lock.take ();
68 s_adding_library = adding ? this : nullptr;
69 }
70
71 bool Library::filter_cb (const char * filename, void *)
72 {
73 bool add = false;
74 auto lh = s_adding_lock.take ();
75
76 if (s_adding_library)
77 {
78 bool * added = s_adding_library->m_added_table.lookup (String (filename));
79
80 if ((add = ! added))
81 s_adding_library->m_added_table.add (String (filename), true);
82 else
83 (* added) = true;
84 }
85
86 return add;
87 }
88
89 void Library::begin_add (const char * uri)
90 {
91 if (s_adding_library)
92 return;
93
94 if (! check_playlist (false, false))
95 create_playlist ();
96
97 m_added_table.clear ();
98
99 int entries = m_playlist.n_entries ();
100
101 for (int entry = 0; entry < entries; entry ++)
102 {
103 String filename = m_playlist.entry_filename (entry);
104
105 if (! m_added_table.lookup (filename))
106 {
107 m_playlist.select_entry (entry, false);
108 m_added_table.add (filename, false);
109 }
110 else
111 m_playlist.select_entry (entry, true);
112 }
113
114 m_playlist.remove_selected ();
115
116 set_adding (true);
117
118 Index<PlaylistAddItem> add;
119 add.append (String (uri));
120 m_playlist.insert_filtered (-1, std::move (add), filter_cb, nullptr, false);
121 }
122
123 void Library::check_ready_and_update (bool force)
124 {
125 bool now_ready = check_playlist (true, true);
126 if (now_ready != m_is_ready || force)
127 {
128 m_is_ready = now_ready;
129 if (update_func)
130 update_func (update_data);
131 }
132 }
133
134 void Library::add_complete ()
135 {
136 if (! check_playlist (true, false))
137 return;
138
139 if (s_adding_library)
140 {
141 set_adding (false);
142
143 int entries = m_playlist.n_entries ();
144
145 for (int entry = 0; entry < entries; entry ++)
146 {
147 String filename = m_playlist.entry_filename (entry);
148 bool * added = m_added_table.lookup (filename);
149
150 m_playlist.select_entry (entry, ! added || ! (* added));
151 }
152
153 m_added_table.clear ();
154
155 /* don't clear the playlist if nothing was added */
156 if (m_playlist.n_selected () < entries)
157 m_playlist.remove_selected ();
158 else
159 m_playlist.select_all (false);
160
161 m_playlist.sort_entries (Playlist::Path);
162 }
163
164 if (! m_playlist.update_pending ())
165 check_ready_and_update (false);
166 }
167
168 void Library::scan_complete ()
169 {
170 if (! m_playlist.update_pending ())
171 check_ready_and_update (false);
172 }
173
174 void Library::playlist_update ()
175 {
176 check_ready_and_update (m_playlist.update_detail ().level >= Playlist::Metadata);
177 }
0 /*
1 * library.h
2 * Copyright 2011-2019 John Lindgren
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #ifndef LIBRARY_H
20 #define LIBRARY_H
21
22 #include <libaudcore/hook.h>
23 #include <libaudcore/multihash.h>
24 #include <libaudcore/playlist.h>
25
26 class Library
27 {
28 public:
29 Library () { find_playlist (); }
30 ~Library () { set_adding (false); }
31
32 Playlist playlist () const { return m_playlist; }
33 bool is_ready () const { return m_is_ready; }
34
35 void begin_add (const char * uri);
36 void check_ready_and_update (bool force);
37
38 void connect_update (void (* func) (void *), void * data) {
39 update_func = func;
40 update_data = data;
41 };
42
43 private:
44 void find_playlist ();
45 void create_playlist ();
46 bool check_playlist (bool require_added, bool require_scanned);
47 void set_adding (bool adding);
48
49 static bool filter_cb (const char * filename, void *);
50
51 void add_complete (void);
52 void scan_complete (void);
53 void playlist_update (void);
54
55 Playlist m_playlist;
56 bool m_is_ready = false;
57 SimpleHash<String, bool> m_added_table;
58
59 /* to allow safe callback access from playlist add thread */
60 static aud::spinlock s_adding_lock;
61 static Library * s_adding_library;
62
63 void (* update_func) (void *) = nullptr;
64 void * update_data = nullptr;
65
66 HookReceiver<Library>
67 hook1 {"playlist add complete", this, & Library::add_complete},
68 hook2 {"playlist scan complete", this, & Library::scan_complete},
69 hook3 {"playlist update", this, & Library::playlist_update};
70 };
71
72 #endif // LIBRARY_H
0 shared_module('search-tool-qt',
1 'html-delegate.cc',
2 'library.cc',
3 'search-model.cc',
4 'search-tool-qt.cc',
5 dependencies: [audacious_dep, qt_dep, glib_dep, audqt_dep],
6 install: true,
7 install_dir: general_plugin_dir
8 )
9
0 /*
1 * search-model.cc
2 * Copyright 2011-2019 John Lindgren and René J.V. Bertin
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #include "search-model.h"
20
21 #include <QMimeData>
22 #include <QUrl>
23
24 #include <libaudcore/i18n.h>
25
26 static QString create_item_label (const Item & item)
27 {
28 static constexpr aud::array<SearchField, const char *> start_tags =
29 {"", "<b>", "<i>", ""};
30 static constexpr aud::array<SearchField, const char *> end_tags =
31 {"", "</b>", "</i>", ""};
32
33 QString string = start_tags[item.field];
34
35 string += QString ((item.field == SearchField::Genre) ?
36 str_toupper_utf8 (item.name) : item.name).toHtmlEscaped ();
37
38 string += end_tags[item.field];
39
40 #ifdef Q_OS_MAC // Mac-specific font tweaks
41 string += "<br>&nbsp;";
42 #else
43 string += "<br><small>&nbsp;";
44 #endif
45
46 if (item.field != SearchField::Title)
47 {
48 string += str_printf (dngettext (PACKAGE, "%d song", "%d songs",
49 item.matches.len ()), item.matches.len ());
50
51 if (item.field == SearchField::Genre || item.parent)
52 string += ' ';
53 }
54
55 if (item.field == SearchField::Genre)
56 {
57 string += _("of this genre");
58 }
59 else if (item.parent)
60 {
61 auto parent = (item.parent->parent ? item.parent->parent : item.parent);
62
63 string += (parent->field == SearchField::Album) ? _("on") : _("by");
64 string += ' ';
65 string += start_tags[parent->field];
66 string += QString (parent->name).toHtmlEscaped ();
67 string += end_tags[parent->field];
68 }
69
70 #ifndef Q_OS_MAC // Mac-specific font tweaks
71 string += "</small>";
72 #endif
73
74 return string;
75 }
76
77 QVariant SearchModel::data (const QModelIndex & index, int role) const
78 {
79 if (role == Qt::DisplayRole)
80 {
81 int row = index.row ();
82 if (row < 0 || row >= m_items.len ())
83 return QVariant ();
84
85 return create_item_label (* m_items[row]);
86 }
87
88 return QVariant ();
89 }
90
91 QMimeData * SearchModel::mimeData (const QModelIndexList & indexes) const
92 {
93 m_playlist.select_all (false);
94
95 QList<QUrl> urls;
96 for (auto & index : indexes)
97 {
98 int row = index.row ();
99 if (row < 0 || row >= m_items.len ())
100 continue;
101
102 for (int entry : m_items[row]->matches)
103 {
104 urls.append (QString (m_playlist.entry_filename (entry)));
105 m_playlist.select_entry (entry, true);
106 }
107 }
108
109 m_playlist.cache_selected ();
110
111 auto data = new QMimeData;
112 data->setUrls (urls);
113 return data;
114 }
115
116 void SearchModel::update ()
117 {
118 int rows = m_items.len ();
119 int keep = aud::min (rows, m_rows);
120
121 if (rows < m_rows)
122 {
123 beginRemoveRows (QModelIndex (), rows, m_rows - 1);
124 m_rows = rows;
125 endRemoveRows ();
126 }
127 else if (rows > m_rows)
128 {
129 beginInsertRows (QModelIndex (), m_rows, rows - 1);
130 m_rows = rows;
131 endInsertRows ();
132 }
133
134 if (keep > 0)
135 {
136 auto topLeft = createIndex (0, 0);
137 auto bottomRight = createIndex (keep - 1, 0);
138 emit dataChanged (topLeft, bottomRight);
139 }
140 }
141
142 void SearchModel::destroy_database ()
143 {
144 m_playlist = Playlist ();
145 m_items.clear ();
146 m_hidden_items = 0;
147 m_database.clear ();
148 }
149
150 void SearchModel::create_database (Playlist playlist)
151 {
152 destroy_database ();
153
154 int entries = playlist.n_entries ();
155
156 for (int e = 0; e < entries; e ++)
157 {
158 Tuple tuple = playlist.entry_tuple (e, Playlist::NoWait);
159
160 aud::array<SearchField, String> fields;
161 fields[SearchField::Genre] = tuple.get_str (Tuple::Genre);
162 fields[SearchField::Artist] = tuple.get_str (Tuple::Artist);
163 fields[SearchField::Album] = tuple.get_str (Tuple::Album);
164 fields[SearchField::Title] = tuple.get_str (Tuple::Title);
165
166 Item * parent = nullptr;
167 SimpleHash<Key, Item> * hash = & m_database;
168
169 for (auto f : aud::range<SearchField> ())
170 {
171 if (fields[f])
172 {
173 Key key = {f, fields[f]};
174 Item * item = hash->lookup (key);
175
176 if (! item)
177 item = hash->add (key, Item (f, fields[f], parent));
178
179 item->matches.append (e);
180
181 /* genre is outside the normal hierarchy */
182 if (f != SearchField::Genre)
183 {
184 parent = item;
185 hash = & item->children;
186 }
187 }
188 }
189 }
190
191 m_playlist = playlist;
192 }
193
194 static void search_recurse (SimpleHash<Key, Item> & domain,
195 const Index<String> & terms, int mask, Index<const Item *> & results)
196 {
197 domain.iterate ([&] (const Key & key, Item & item)
198 {
199 int count = terms.len ();
200 int new_mask = mask;
201
202 for (int t = 0, bit = 1; t < count; t ++, bit <<= 1)
203 {
204 if (! (new_mask & bit))
205 continue; /* skip term if it is already found */
206
207 if (strstr (item.folded, terms[t]))
208 new_mask &= ~bit; /* we found it */
209 else if (! item.children.n_items ())
210 break; /* quit early if there are no children to search */
211 }
212
213 /* adding an item with exactly one child is redundant, so avoid it */
214 if (! new_mask && item.children.n_items () != 1)
215 results.append (& item);
216
217 search_recurse (item.children, terms, new_mask, results);
218 });
219 }
220
221 static int item_compare (const Item * const & a, const Item * const & b)
222 {
223 if (a->field < b->field)
224 return -1;
225 if (a->field > b->field)
226 return 1;
227
228 int val = str_compare (a->name, b->name);
229 if (val)
230 return val;
231
232 if (a->parent)
233 return b->parent ? item_compare (a->parent, b->parent) : 1;
234 else
235 return b->parent ? -1 : 0;
236 }
237
238 static int item_compare_pass1 (const Item * const & a, const Item * const & b)
239 {
240 if (a->matches.len () > b->matches.len ())
241 return -1;
242 if (a->matches.len () < b->matches.len ())
243 return 1;
244
245 return item_compare (a, b);
246 }
247
248 void SearchModel::do_search (const Index<String> & terms, int max_results)
249 {
250 m_items.clear ();
251 m_hidden_items = 0;
252
253 /* effectively limits number of search terms to 32 */
254 search_recurse (m_database, terms, (1 << terms.len ()) - 1, m_items);
255
256 /* first sort by number of songs per item */
257 m_items.sort (item_compare_pass1);
258
259 /* limit to items with most songs */
260 if (m_items.len () > max_results)
261 {
262 m_hidden_items = m_items.len () - max_results;
263 m_items.remove (max_results, -1);
264 }
265
266 /* sort by item type, then item name */
267 m_items.sort (item_compare);
268 }
0 /*
1 * search-model.h
2 * Copyright 2011-2019 John Lindgren and René J.V. Bertin
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions, and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions, and the following disclaimer in the documentation
12 * provided with the distribution.
13 *
14 * This software is provided "as is" and without any warranty, express or
15 * implied. In no event shall the authors be liable for any damages arising from
16 * the use of this software.
17 */
18
19 #ifndef SEARCHMODEL_H
20 #define SEARCHMODEL_H
21
22 #include <QAbstractListModel>
23
24 #include <libaudcore/audstrings.h>
25 #include <libaudcore/multihash.h>
26 #include <libaudcore/playlist.h>
27
28 enum class SearchField {
29 Genre,
30 Artist,
31 Album,
32 Title,
33 count
34 };
35
36 struct Key
37 {
38 SearchField field;
39 String name;
40
41 bool operator== (const Key & b) const
42 { return field == b.field && name == b.name; }
43 unsigned hash () const
44 { return (unsigned) field + name.hash (); }
45 };
46
47 struct Item
48 {
49 SearchField field;
50 String name, folded;
51 Item * parent;
52 SimpleHash<Key, Item> children;
53 Index<int> matches;
54
55 Item (SearchField field, const String & name, Item * parent) :
56 field (field),
57 name (name),
58 folded (str_tolower_utf8 (name)),
59 parent (parent) {}
60
61 Item (Item &&) = default;
62 Item & operator= (Item &&) = default;
63 };
64
65 class SearchModel : public QAbstractListModel
66 {
67 public:
68 int num_items () const { return m_items.len (); }
69 const Item & item_at (int idx) const { return * m_items[idx]; }
70 int num_hidden_items () const { return m_hidden_items; }
71
72 void update ();
73 void destroy_database ();
74 void create_database (Playlist playlist);
75 void do_search (const Index<String> & terms, int max_results);
76
77 protected:
78 int rowCount (const QModelIndex & parent) const { return m_rows; }
79 int columnCount (const QModelIndex & parent) const { return 1; }
80 QVariant data (const QModelIndex & index, int role) const;
81
82 Qt::ItemFlags flags (const QModelIndex & index) const
83 {
84 if (index.isValid ())
85 return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
86 else
87 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
88 }
89
90 QStringList mimeTypes () const
91 {
92 return QStringList ("text/uri-list");
93 }
94
95 QMimeData * mimeData (const QModelIndexList & indexes) const;
96
97 private:
98 Playlist m_playlist;
99 SimpleHash<Key, Item> m_database;
100 Index<const Item *> m_items;
101 int m_hidden_items = 0;
102 int m_rows = 0;
103 };
104
105 #endif // SEARCHMODEL_H
00 /*
11 * search-tool-qt.cc
2 * Copyright 2011-2017 John Lindgren and René J.V. Bertin
2 * Copyright 2011-2019 John Lindgren, Ariadne Conill, and René J.V. Bertin
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions are met:
1616 * the use of this software.
1717 */
1818
19 #include <string.h>
2019 #include <glib.h>
2120
22 #include <QAbstractListModel>
23 #include <QAbstractTextDocumentLayout>
2421 #include <QApplication>
2522 #include <QBoxLayout>
2623 #include <QContextMenuEvent>
24 #include <QDirIterator>
25 #include <QFileSystemWatcher>
2726 #include <QIcon>
2827 #include <QLabel>
2928 #include <QLineEdit>
3029 #include <QMenu>
31 #include <QMimeData>
32 #include <QPainter>
30 #include <QPointer>
3331 #include <QPushButton>
34 #include <QStyledItemDelegate>
3532 #include <QTreeView>
36 #include <QUrl>
37
38 #include <libaudcore/audstrings.h>
39 #include <libaudcore/hook.h>
33
4034 #include <libaudcore/i18n.h>
41 #include <libaudcore/playlist.h>
4235 #include <libaudcore/plugin.h>
4336 #include <libaudcore/preferences.h>
4437 #include <libaudcore/mainloop.h>
45 #include <libaudcore/multihash.h>
4638 #include <libaudcore/runtime.h>
4739 #include <libaudqt/libaudqt.h>
48 #include <libaudqt/menu.h>
40
41 #include "html-delegate.h"
42 #include "library.h"
43 #include "search-model.h"
4944
5045 #define CFG_ID "search-tool"
5146 #define SEARCH_DELAY 300
7469
7570 EXPORT SearchToolQt aud_plugin_instance;
7671
77 static void trigger_search ();
72 class SearchEntry : public QLineEdit
73 {
74 public:
75 QTreeView * list = nullptr;
76
77 protected:
78 void keyPressEvent (QKeyEvent * event)
79 {
80 auto CtrlShiftAlt = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
81 if (list && ! (event->modifiers () & CtrlShiftAlt) && event->key () == Qt::Key_Down)
82 {
83 list->setCurrentIndex (list->model ()->index (0, 0));
84 list->setFocus (Qt::OtherFocusReason);
85 return;
86 }
87 QLineEdit::keyPressEvent (event);
88 }
89 };
90
91 class ResultsList : public QTreeView
92 {
93 public:
94 QWidget * entry = nullptr;
95
96 protected:
97 void keyPressEvent (QKeyEvent * event)
98 {
99 auto CtrlShiftAlt = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier;
100 if (entry && ! (event->modifiers () & CtrlShiftAlt) &&
101 event->key () == Qt::Key_Up && currentIndex ().row () == 0)
102 {
103 entry->setFocus (Qt::OtherFocusReason);
104 return;
105 }
106 QTreeView::keyPressEvent (event);
107 }
108 };
109
110 class SearchWidget : public QWidget
111 {
112 public:
113 SearchWidget ();
114
115 void grab_focus () { m_search_entry.setFocus (Qt::OtherFocusReason); }
116
117 void trigger_search ();
118 void reset_monitor ();
119
120 private:
121 void init_library ();
122 void show_hide_widgets ();
123 void search_timeout ();
124 void library_updated ();
125 void location_changed ();
126 void walk_library_paths ();
127 void setup_monitor ();
128
129 void do_add (bool play, bool set_title);
130 void action_play ();
131 void action_create_playlist ();
132 void action_add_to_playlist ();
133 void show_context_menu (const QPoint & global_pos);
134
135 Library m_library;
136 SearchModel m_model;
137 HtmlDelegate m_delegate;
138
139 SmartPtr<QFileSystemWatcher> m_watcher;
140 QStringList m_watcher_paths;
141
142 QueuedFunc m_search_timer;
143 bool m_search_pending = false;
144
145 QLabel m_help_label, m_wait_label, m_stats_label;
146 SearchEntry m_search_entry;
147 ResultsList m_results_list;
148 QPushButton m_refresh_btn;
149
150 QLineEdit * m_file_entry;
151 };
152
153 static QPointer<SearchWidget> s_widget;
78154
79155 const char * const SearchToolQt::defaults[] = {
80156 "max_results", "20",
81157 "rescan_on_startup", "FALSE",
158 "monitor", "FALSE",
82159 nullptr
83160 };
84161
85162 const PreferencesWidget SearchToolQt::widgets[] = {
86163 WidgetSpin (N_("Number of results to show:"),
87 WidgetInt (CFG_ID, "max_results", trigger_search),
164 WidgetInt (CFG_ID, "max_results", [] () { s_widget->trigger_search (); }),
88165 {10, 10000, 10}),
89166 WidgetCheck (N_("Rescan library at startup"),
90 WidgetBool (CFG_ID, "rescan_on_startup"))
167 WidgetBool (CFG_ID, "rescan_on_startup")),
168 WidgetCheck (N_("Monitor library for changes"),
169 WidgetBool (CFG_ID, "monitor", [] () { s_widget->reset_monitor (); }))
91170 };
92171
93172 const PluginPreferences SearchToolQt::prefs = {{widgets}};
94
95 enum class SearchField {
96 Genre,
97 Artist,
98 Album,
99 Title,
100 count
101 };
102
103 struct Key
104 {
105 SearchField field;
106 String name;
107
108 bool operator== (const Key & b) const
109 { return field == b.field && name == b.name; }
110 unsigned hash () const
111 { return (unsigned) field + name.hash (); }
112 };
113
114 struct Item
115 {
116 SearchField field;
117 String name, folded;
118 Item * parent;
119 SimpleHash<Key, Item> children;
120 Index<int> matches;
121
122 Item (SearchField field, const String & name, Item * parent) :
123 field (field),
124 name (name),
125 folded (str_tolower_utf8 (name)),
126 parent (parent) {}
127
128 Item (Item &&) = default;
129 Item & operator= (Item &&) = default;
130 };
131
132 class ResultsModel : public QAbstractListModel
133 {
134 public:
135 void update ();
136
137 protected:
138 int rowCount (const QModelIndex & parent) const { return m_rows; }
139 int columnCount (const QModelIndex & parent) const { return 1; }
140 QVariant data (const QModelIndex & index, int role) const;
141
142 Qt::ItemFlags flags (const QModelIndex & index) const
143 {
144 if (index.isValid ())
145 return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
146 else
147 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
148 }
149
150 QStringList mimeTypes () const
151 {
152 return QStringList ("text/uri-list");
153 }
154
155 QMimeData * mimeData (const QModelIndexList & indexes) const;
156
157 private:
158 int m_rows = 0;
159 };
160
161 // Allow rich text in QTreeView entries
162 // https://stackoverflow.com/questions/1956542/how-to-make-item-view-render-rich-html-text-in-qt
163 class HtmlDelegate : public QStyledItemDelegate
164 {
165 protected:
166 void paint (QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
167 QSize sizeHint (const QStyleOptionViewItem & option, const QModelIndex & index) const;
168 };
169
170 static void init_text_document (QTextDocument & doc, const QStyleOptionViewItem & option)
171 {
172 doc.setHtml (option.text);
173 doc.setDocumentMargin (audqt::sizes.TwoPt);
174 doc.setDefaultFont (option.font);
175 }
176
177 void HtmlDelegate::paint (QPainter * painter, const QStyleOptionViewItem & option_, const QModelIndex & index) const
178 {
179 QStyleOptionViewItem option = option_;
180 initStyleOption (& option, index);
181
182 QStyle * style = option.widget ? option.widget->style () : qApp->style ();
183
184 QTextDocument doc;
185 init_text_document (doc, option);
186
187 /// Painting item without text
188 option.text = QString ();
189 style->drawControl (QStyle::CE_ItemViewItem, & option, painter);
190
191 QAbstractTextDocumentLayout::PaintContext ctx;
192
193 // Color group logic imitating qcommonstyle.cpp
194 QPalette::ColorGroup cg =
195 ! (option.state & QStyle::State_Enabled) ? QPalette::Disabled :
196 ! (option.state & QStyle::State_Active) ? QPalette::Inactive : QPalette::Normal;
197
198 // Highlighting text if item is selected
199 if (option.state & QStyle::State_Selected)
200 ctx.palette.setColor (QPalette::Text, option.palette.color (cg, QPalette::HighlightedText));
201 else
202 ctx.palette.setColor (QPalette::Text, option.palette.color (cg, QPalette::Text));
203
204 QRect textRect = style->subElementRect (QStyle::SE_ItemViewItemText, & option);
205 painter->save ();
206 painter->translate (textRect.topLeft ());
207 painter->setClipRect (textRect.translated (-textRect.topLeft ()));
208 doc.documentLayout ()->draw (painter, ctx);
209 painter->restore ();
210 }
211
212 QSize HtmlDelegate::sizeHint (const QStyleOptionViewItem & option_, const QModelIndex & index) const
213 {
214 QStyleOptionViewItem option = option_;
215 initStyleOption (& option, index);
216
217 QTextDocument doc;
218 init_text_document (doc, option);
219
220 return QSize (audqt::sizes.OneInch, doc.size ().height ());
221 }
222
223 class ResultsView : public QTreeView
224 {
225 public:
226 ResultsView ()
227 { setItemDelegate (& m_delegate); }
228
229 protected:
230 void contextMenuEvent (QContextMenuEvent * event);
231
232 private:
233 HtmlDelegate m_delegate;
234 };
235
236 static QString create_item_label (int row);
237
238 static Playlist s_playlist;
239 static Index<String> s_search_terms;
240
241 /* Note: added_table is accessed by multiple threads.
242 * When adding = true, it may only be accessed by the playlist add thread.
243 * When adding = false, it may only be accessed by the UI thread.
244 * adding may only be set by the UI thread while holding adding_lock. */
245 static TinyLock s_adding_lock;
246 static bool s_adding = false;
247 static SimpleHash<String, bool> s_added_table;
248
249 static SimpleHash<Key, Item> s_database;
250 static bool s_database_valid;
251 static Index<const Item *> s_items;
252 static int s_hidden_items;
253
254 static QueuedFunc s_search_timer;
255 static bool s_search_pending;
256
257 static ResultsModel s_model;
258 static QLabel * s_help_label, * s_wait_label, * s_stats_label;
259 static QLineEdit * s_search_entry;
260 static QTreeView * s_results_list;
261 static QMenu * s_menu;
262
263 void ResultsModel::update ()
264 {
265 int rows = s_items.len ();
266 int keep = aud::min (rows, m_rows);
267
268 if (rows < m_rows)
269 {
270 beginRemoveRows (QModelIndex (), rows, m_rows - 1);
271 m_rows = rows;
272 endRemoveRows ();
273 }
274 else if (rows > m_rows)
275 {
276 beginInsertRows (QModelIndex (), m_rows, rows - 1);
277 m_rows = rows;
278 endInsertRows ();
279 }
280
281 if (keep > 0)
282 {
283 auto topLeft = createIndex (0, 0);
284 auto bottomRight = createIndex (keep - 1, 0);
285 emit dataChanged (topLeft, bottomRight);
286 }
287 }
288
289 QVariant ResultsModel::data (const QModelIndex & index, int role) const
290 {
291 if (role == Qt::DisplayRole)
292 return create_item_label (index.row ());
293 else
294 return QVariant ();
295 }
296
297 static void find_playlist ()
298 {
299 s_playlist = Playlist ();
300
301 for (int p = 0; p < Playlist::n_playlists (); p ++)
302 {
303 auto playlist = Playlist::by_index (p);
304 if (! strcmp (playlist.get_title (), _("Library")))
305 {
306 s_playlist = playlist;
307 break;
308 }
309 }
310 }
311
312 static void create_playlist ()
313 {
314 s_playlist = Playlist::blank_playlist ();
315 s_playlist.set_title (_("Library"));
316 s_playlist.active_playlist ();
317 }
318
319 static bool check_playlist (bool require_added, bool require_scanned)
320 {
321 if (! s_playlist.exists ())
322 {
323 s_playlist = Playlist ();
324 return false;
325 }
326
327 if (require_added && s_playlist.add_in_progress ())
328 return false;
329 if (require_scanned && s_playlist.scan_in_progress ())
330 return false;
331
332 return true;
333 }
334173
335174 static String get_uri ()
336175 {
337176 auto to_uri = [] (const char * path)
338177 { return String (filename_to_uri (path)); };
339178
340 String path1 = aud_get_str ("search-tool", "path");
179 String path1 = aud_get_str (CFG_ID, "path");
341180 if (path1[0])
342181 return strstr (path1, "://") ? path1 : to_uri (path1);
343182
348187 return to_uri (g_get_home_dir ());
349188 }
350189
351 static void destroy_database ()
352 {
353 s_items.clear ();
354 s_hidden_items = 0;
355 s_database.clear ();
356 s_database_valid = false;
357 }
358
359 static void create_database ()
360 {
361 destroy_database ();
362
363 int entries = s_playlist.n_entries ();
364
365 for (int e = 0; e < entries; e ++)
366 {
367 Tuple tuple = s_playlist.entry_tuple (e, Playlist::NoWait);
368
369 aud::array<SearchField, String> fields;
370 fields[SearchField::Genre] = tuple.get_str (Tuple::Genre);
371 fields[SearchField::Artist] = tuple.get_str (Tuple::Artist);
372 fields[SearchField::Album] = tuple.get_str (Tuple::Album);
373 fields[SearchField::Title] = tuple.get_str (Tuple::Title);
374
375 Item * parent = nullptr;
376 SimpleHash<Key, Item> * hash = & s_database;
377
378 for (auto f : aud::range<SearchField> ())
190 SearchWidget::SearchWidget () :
191 m_help_label (_("To import your music library into Audacious, "
192 "choose a folder and then click the \"refresh\" icon.")),
193 m_wait_label (_("Please wait ...")),
194 m_refresh_btn (audqt::get_icon ("view-refresh"), QString ()),
195 m_file_entry (audqt::file_entry_new (this, _("Choose Folder"),
196 QFileDialog::Directory, QFileDialog::AcceptOpen))
197 {
198 m_search_entry.setClearButtonEnabled (true);
199 m_search_entry.setPlaceholderText (_("Search library"));
200
201 m_help_label.setAlignment (Qt::AlignCenter);
202 m_help_label.setContentsMargins (audqt::margins.EightPt);
203 m_help_label.setWordWrap (true);
204
205 m_wait_label.setAlignment (Qt::AlignCenter);
206 m_wait_label.setContentsMargins (audqt::margins.EightPt);
207
208 m_results_list.setFrameStyle (QFrame::NoFrame);
209 m_results_list.setHeaderHidden (true);
210 m_results_list.setIndentation (0);
211 m_results_list.setModel (& m_model);
212 m_results_list.setItemDelegate (& m_delegate);
213 m_results_list.setSelectionMode (QTreeView::ExtendedSelection);
214 m_results_list.setDragDropMode (QTreeView::DragOnly);
215 m_results_list.setContextMenuPolicy (Qt::CustomContextMenu);
216
217 m_stats_label.setAlignment (Qt::AlignCenter);
218 m_stats_label.setContentsMargins (audqt::margins.TwoPt);
219
220 #ifdef Q_OS_MAC // Mac-specific font tweaks
221 m_search_entry.setFont (QApplication::font ("QTreeView"));
222 m_stats_label.setFont (QApplication::font ("QSmallFont"));
223 #endif
224
225 m_refresh_btn.setFlat (true);
226 m_refresh_btn.setFocusPolicy (Qt::NoFocus);
227
228 m_search_entry.list = & m_results_list;
229 m_results_list.entry = & m_search_entry;
230
231 auto hbox1 = audqt::make_hbox (nullptr);
232 hbox1->setContentsMargins (audqt::margins.TwoPt);
233 hbox1->addWidget (& m_search_entry);
234
235 auto hbox2 = audqt::make_hbox (nullptr);
236 hbox2->setContentsMargins (audqt::margins.TwoPt);
237 hbox2->addWidget (m_file_entry);
238 hbox2->addWidget (& m_refresh_btn);
239
240 auto vbox = audqt::make_vbox (this, 0);
241 vbox->addLayout (hbox1);
242 vbox->addWidget (& m_help_label);
243 vbox->addWidget (& m_wait_label);
244 vbox->addWidget (& m_results_list);
245 vbox->addWidget (& m_stats_label);
246 vbox->addLayout (hbox2);
247
248 audqt::file_entry_set_uri (m_file_entry, get_uri ());
249
250 init_library ();
251 reset_monitor ();
252
253 QObject::connect (& m_search_entry, & QLineEdit::textEdited, this, & SearchWidget::trigger_search);
254 QObject::connect (& m_search_entry, & QLineEdit::returnPressed, this, & SearchWidget::action_play);
255 QObject::connect (& m_results_list, & QTreeView::activated, this, & SearchWidget::action_play);
256
257 QObject::connect (& m_results_list, & QWidget::customContextMenuRequested,
258 [this] (const QPoint & pos) { show_context_menu (m_results_list.mapToGlobal (pos)); });
259
260 QObject::connect (m_file_entry, & QLineEdit::textChanged, [this] (const QString & text)
261 { m_refresh_btn.setDisabled (text.isEmpty ()); });
262
263 QObject::connect (m_file_entry, & QLineEdit::returnPressed, this, & SearchWidget::location_changed);
264 QObject::connect (& m_refresh_btn, & QPushButton::clicked, this, & SearchWidget::location_changed);
265 }
266
267 void SearchWidget::init_library ()
268 {
269 m_library.connect_update
270 (aud::obj_member<SearchWidget, & SearchWidget::library_updated>, this);
271
272 if (aud_get_bool (CFG_ID, "rescan_on_startup"))
273 m_library.begin_add (get_uri ());
274
275 m_library.check_ready_and_update (true);
276 }
277
278 void SearchWidget::show_hide_widgets ()
279 {
280 if (m_library.playlist () == Playlist ())
281 {
282 m_wait_label.hide ();
283 m_results_list.hide ();
284 m_stats_label.hide ();
285 m_help_label.show ();
286 }
287 else
288 {
289 m_help_label.hide ();
290
291 if (m_library.is_ready ())
379292 {
380 if (fields[f])
381 {
382 Key key = {f, fields[f]};
383 Item * item = hash->lookup (key);
384
385 if (! item)
386 item = hash->add (key, Item (f, fields[f], parent));
387
388 item->matches.append (e);
389
390 /* genre is outside the normal hierarchy */
391 if (f != SearchField::Genre)
392 {
393 parent = item;
394 hash = & item->children;
395 }
396 }
397 }
398 }
399
400 s_database_valid = true;
401 }
402
403 static void search_recurse (SimpleHash<Key, Item> & domain, int mask, Index<const Item *> & results)
404 {
405 domain.iterate ([mask, & results] (const Key & key, Item & item)
406 {
407 int count = s_search_terms.len ();
408 int new_mask = mask;
409
410 for (int t = 0, bit = 1; t < count; t ++, bit <<= 1)
411 {
412 if (! (new_mask & bit))
413 continue; /* skip term if it is already found */
414
415 if (strstr (item.folded, s_search_terms[t]))
416 new_mask &= ~bit; /* we found it */
417 else if (! item.children.n_items ())
418 break; /* quit early if there are no children to search */
419 }
420
421 /* adding an item with exactly one child is redundant, so avoid it */
422 if (! new_mask && item.children.n_items () != 1)
423 results.append (& item);
424
425 search_recurse (item.children, new_mask, results);
426 });
427 }
428
429 static int item_compare (const Item * const & a, const Item * const & b)
430 {
431 if (a->field < b->field)
432 return -1;
433 if (a->field > b->field)
434 return 1;
435
436 int val = str_compare (a->name, b->name);
437 if (val)
438 return val;
439
440 if (a->parent)
441 return b->parent ? item_compare (a->parent, b->parent) : 1;
442 else
443 return b->parent ? -1 : 0;
444 }
445
446 static int item_compare_pass1 (const Item * const & a, const Item * const & b)
447 {
448 if (a->matches.len () > b->matches.len ())
449 return -1;
450 if (a->matches.len () < b->matches.len ())
451 return 1;
452
453 return item_compare (a, b);
454 }
455
456 static void do_search ()
457 {
458 s_items.clear ();
459 s_hidden_items = 0;
460
461 if (! s_database_valid)
462 return;
463
464 /* effectively limits number of search terms to 32 */
465 search_recurse (s_database, (1 << s_search_terms.len ()) - 1, s_items);
466
467 /* first sort by number of songs per item */
468 s_items.sort (item_compare_pass1);
469
470 int max_results = aud_get_int (CFG_ID, "max_results");
471 /* limit to items with most songs */
472 if (s_items.len () > max_results)
473 {
474 s_hidden_items = s_items.len () - max_results;
475 s_items.remove (max_results, -1);
476 }
477
478 /* sort by item type, then item name */
479 s_items.sort (item_compare);
480 }
481
482 static bool filter_cb (const char * filename, void * unused)
483 {
484 bool add = false;
485 tiny_lock (& s_adding_lock);
486
487 if (s_adding)
488 {
489 bool * added = s_added_table.lookup (String (filename));
490
491 if ((add = ! added))
492 s_added_table.add (String (filename), true);
493 else
494 (* added) = true;
495 }
496
497 tiny_unlock (& s_adding_lock);
498 return add;
499 }
500
501 static void begin_add (const char * uri)
502 {
503 if (s_adding)
504 return;
505
506 if (! check_playlist (false, false))
507 create_playlist ();
508
509 /* if possible, store local path for compatibility with older versions */
510 StringBuf path = uri_to_filename (uri);
511 aud_set_str ("search-tool", "path", path ? path : uri);
512
513 s_added_table.clear ();
514
515 int entries = s_playlist.n_entries ();
516
517 for (int entry = 0; entry < entries; entry ++)
518 {
519 String filename = s_playlist.entry_filename (entry);
520
521 if (! s_added_table.lookup (filename))
522 {
523 s_playlist.select_entry (entry, false);
524 s_added_table.add (filename, false);
525 }
526 else
527 s_playlist.select_entry (entry, true);
528 }
529
530 s_playlist.remove_selected ();
531
532 tiny_lock (& s_adding_lock);
533 s_adding = true;
534 tiny_unlock (& s_adding_lock);
535
536 Index<PlaylistAddItem> add;
537 add.append (String (uri));
538 s_playlist.insert_filtered (-1, std::move (add), filter_cb, nullptr, false);
539 }
540
541 static void show_hide_widgets ()
542 {
543 if (s_playlist == Playlist ())
544 {
545 s_wait_label->hide ();
546 s_results_list->hide ();
547 s_stats_label->hide ();
548 s_help_label->show ();
549 }
550 else
551 {
552 s_help_label->hide ();
553
554 if (s_database_valid)
555 {
556 s_wait_label->hide ();
557 s_results_list->show ();
558 s_stats_label->show ();
293 m_wait_label.hide ();
294 m_results_list.show ();
295 m_stats_label.show ();
559296 }
560297 else
561298 {
562 s_results_list->hide ();
563 s_stats_label->hide ();
564 s_wait_label->show ();
299 m_results_list.hide ();
300 m_stats_label.hide ();
301 m_wait_label.show ();
565302 }
566303 }
567304 }
568305
569 static void search_timeout (void * = nullptr)
570 {
571 do_search ();
572
573 s_model.update ();
574
575 if (s_items.len ())
576 {
577 auto sel = s_results_list->selectionModel ();
578 sel->select (s_model.index (0, 0), sel->Clear | sel->SelectCurrent);
579 }
580
581 int total = s_items.len () + s_hidden_items;
582
583 if (s_hidden_items)
584 s_stats_label->setText ((const char *)
306 void SearchWidget::search_timeout ()
307 {
308 auto text = m_search_entry.text ().toUtf8 ();
309 auto terms = str_list_to_index (str_tolower_utf8 (text), " ");
310 m_model.do_search (terms, aud_get_int (CFG_ID, "max_results"));
311 m_model.update ();
312
313 int shown = m_model.num_items ();
314 int hidden = m_model.num_hidden_items ();
315 int total = shown + hidden;
316
317 if (shown)
318 {
319 auto sel = m_results_list.selectionModel ();
320 sel->select (m_model.index (0, 0), sel->Clear | sel->SelectCurrent);
321 }
322
323 if (hidden)
324 m_stats_label.setText ((const char *)
585325 str_printf (dngettext (PACKAGE, "%d of %d result shown",
586 "%d of %d results shown", total), s_items.len (), total));
326 "%d of %d results shown", total), shown, total));
587327 else
588 s_stats_label->setText ((const char *)
328 m_stats_label.setText ((const char *)
589329 str_printf (dngettext (PACKAGE, "%d result", "%d results", total), total));
590330
591 s_search_timer.stop ();
592 s_search_pending = false;
593 }
594
595 static void trigger_search ()
596 {
597 s_search_timer.queue (SEARCH_DELAY, search_timeout, nullptr);
598 s_search_pending = true;
599 }
600
601 static void update_database ()
602 {
603 if (check_playlist (true, true))
604 {
605 create_database ();
331 m_search_timer.stop ();
332 m_search_pending = false;
333 }
334
335 void SearchWidget::trigger_search ()
336 {
337 m_search_timer.queue (SEARCH_DELAY,
338 aud::obj_member<SearchWidget, & SearchWidget::search_timeout>, this);
339 m_search_pending = true;
340 }
341
342 void SearchWidget::library_updated ()
343 {
344 if (m_library.is_ready ())
345 {
346 m_model.create_database (m_library.playlist ());
606347 search_timeout ();
607348 }
608349 else
609350 {
610 destroy_database ();
611 s_model.update ();
612 s_stats_label->clear ();
351 m_model.destroy_database ();
352 m_model.update ();
353 m_stats_label.clear ();
613354 }
614355
615356 show_hide_widgets ();
616357 }
617358
618 static void add_complete_cb (void *, void *)
619 {
620 if (! check_playlist (true, false))
359 void SearchWidget::location_changed ()
360 {
361 auto uri = audqt::file_entry_get_uri (m_file_entry);
362 if (! uri)
621363 return;
622364
623 if (s_adding)
624 {
625 tiny_lock (& s_adding_lock);
626 s_adding = false;
627 tiny_unlock (& s_adding_lock);
628
629 int entries = s_playlist.n_entries ();
630
631 for (int entry = 0; entry < entries; entry ++)
632 {
633 String filename = s_playlist.entry_filename (entry);
634 bool * added = s_added_table.lookup (filename);
635
636 s_playlist.select_entry (entry, ! added || ! (* added));
637 }
638
639 s_added_table.clear ();
640
641 /* don't clear the playlist if nothing was added */
642 if (s_playlist.n_selected () < entries)
643 s_playlist.remove_selected ();
644 else
645 s_playlist.select_all (false);
646
647 s_playlist.sort_entries (Playlist::Path);
648 }
649
650 if (! s_database_valid && ! s_playlist.update_pending ())
651 update_database ();
652 }
653
654 static void scan_complete_cb (void *, void *)
655 {
656 if (! check_playlist (true, true))
365 audqt::file_entry_set_uri (m_file_entry, uri); // normalize path
366
367 // if possible, store local path for compatibility with older versions
368 StringBuf path = uri_to_filename (uri);
369 aud_set_str (CFG_ID, "path", path ? path : uri);
370
371 m_library.begin_add (uri);
372 m_library.check_ready_and_update (true);
373 reset_monitor ();
374 }
375
376 // QFileSystemWatcher doesn't support recursion, so we must do it ourselves.
377 // TODO: Since MacOS has an abysmally low default per-process FD limit, this
378 // means it probably won't work on MacOS with a huge media library.
379 // In the case of MacOS, we should use the FSEvents API instead.
380 void SearchWidget::walk_library_paths ()
381 {
382 if (! m_watcher_paths.isEmpty ())
383 m_watcher->removePaths (m_watcher_paths);
384
385 m_watcher_paths.clear ();
386
387 auto root = (QString) uri_to_filename (get_uri ());
388 if (root.isEmpty ())
657389 return;
658390
659 if (! s_database_valid && ! s_playlist.update_pending ())
660 update_database ();
661 }
662
663 static void playlist_update_cb (void *, void *)
664 {
665 if (! s_database_valid || ! check_playlist (true, true) ||
666 s_playlist.update_detail ().level >= Playlist::Metadata)
667 {
668 update_database ();
669 }
670 }
671
672 static void search_init ()
673 {
674 find_playlist ();
675
676 if (aud_get_bool (CFG_ID, "rescan_on_startup"))
677 begin_add (get_uri ());
678
679 update_database ();
680
681 hook_associate ("playlist add complete", add_complete_cb, nullptr);
682 hook_associate ("playlist scan complete", scan_complete_cb, nullptr);
683 hook_associate ("playlist update", playlist_update_cb, nullptr);
684 }
685
686 static void search_cleanup ()
687 {
688 hook_dissociate ("playlist add complete", add_complete_cb);
689 hook_dissociate ("playlist scan complete", scan_complete_cb);
690 hook_dissociate ("playlist update", playlist_update_cb);
691
692 s_search_timer.stop ();
693 s_search_pending = false;
694
695 s_search_terms.clear ();
696 s_items.clear ();
697
698 tiny_lock (& s_adding_lock);
699 s_adding = false;
700 tiny_unlock (& s_adding_lock);
701
702 s_added_table.clear ();
703 destroy_database ();
704
705 s_help_label = s_wait_label = s_stats_label = nullptr;
706 s_search_entry = nullptr;
707 s_results_list = nullptr;
708
709 delete s_menu;
710 s_menu = nullptr;
711 }
712
713 static void do_add (bool play, bool set_title)
714 {
715 if (s_search_pending)
391 m_watcher_paths.append (root);
392
393 QDirIterator it (root, QDir::Dirs | QDir::NoDot | QDir::NoDotDot, QDirIterator::Subdirectories);
394 while (it.hasNext ())
395 m_watcher_paths.append (it.next ());
396
397 m_watcher->addPaths (m_watcher_paths);
398 }
399
400 void SearchWidget::setup_monitor ()
401 {
402 AUDINFO ("Starting monitoring.\n");
403 m_watcher.capture (new QFileSystemWatcher);
404 m_watcher_paths.clear ();
405
406 QObject::connect (m_watcher.get (), & QFileSystemWatcher::directoryChanged,
407 [this] (const QString &)
408 {
409 AUDINFO ("Library directory changed, refreshing library.\n");
410
411 m_library.begin_add (get_uri ());
412 m_library.check_ready_and_update (true);
413
414 walk_library_paths ();
415 });
416
417 walk_library_paths ();
418 }
419
420 void SearchWidget::reset_monitor ()
421 {
422 if (aud_get_bool (CFG_ID, "monitor"))
423 {
424 setup_monitor ();
425 }
426 else if (m_watcher)
427 {
428 AUDINFO ("Stopping monitoring.\n");
429 m_watcher.clear ();
430 m_watcher_paths.clear ();
431 }
432 }
433
434 void SearchWidget::do_add (bool play, bool set_title)
435 {
436 if (m_search_pending)
716437 search_timeout ();
717438
718 int n_items = s_items.len ();
439 int n_items = m_model.num_items ();
719440 int n_selected = 0;
720441
442 auto list = m_library.playlist ();
721443 Index<PlaylistAddItem> add;
722444 String title;
723445
724 for (auto & idx : s_results_list->selectionModel ()->selectedRows ())
446 for (auto & idx : m_results_list.selectionModel ()->selectedRows ())
725447 {
726448 int i = idx.row ();
727449 if (i < 0 || i >= n_items)
728450 continue;
729451
730 const Item * item = s_items[i];
731
732 for (int entry : item->matches)
452 auto & item = m_model.item_at (i);
453
454 for (int entry : item.matches)
733455 {
734456 add.append (
735 s_playlist.entry_filename (entry),
736 s_playlist.entry_tuple (entry, Playlist::NoWait),
737 s_playlist.entry_decoder (entry, Playlist::NoWait)
457 list.entry_filename (entry),
458 list.entry_tuple (entry, Playlist::NoWait),
459 list.entry_decoder (entry, Playlist::NoWait)
738460 );
739461 }
740462
741463 n_selected ++;
742464 if (n_selected == 1)
743 title = item->name;
465 title = item.name;
744466 }
745467
746468 auto list2 = Playlist::active_playlist ();
750472 list2.set_title (title);
751473 }
752474
753 static void action_play ()
475 void SearchWidget::action_play ()
754476 {
755477 Playlist::temporary_playlist ().activate ();
756478 do_add (true, false);
757479 }
758480
759 static void action_create_playlist ()
481 void SearchWidget::action_create_playlist ()
760482 {
761483 Playlist::new_playlist ();
762484 do_add (false, true);
763485 }
764486
765 static void action_add_to_playlist ()
766 {
767 if (s_playlist != Playlist::active_playlist ())
487 void SearchWidget::action_add_to_playlist ()
488 {
489 if (m_library.playlist () != Playlist::active_playlist ())
768490 do_add (false, false);
769491 }
770492
771 static QString create_item_label (int row)
772 {
773 static constexpr aud::array<SearchField, const char *> start_tags =
774 {"", "<b>", "<i>", ""};
775 static constexpr aud::array<SearchField, const char *> end_tags =
776 {"", "</b>", "</i>", ""};
777
778 if (row < 0 || row >= s_items.len ())
779 return QString ();
780
781 const Item * item = s_items[row];
782
783 QString string = start_tags[item->field];
784
785 string += QString ((item->field == SearchField::Genre) ?
786 str_toupper_utf8 (item->name) : item->name).toHtmlEscaped ();
787
788 string += end_tags[item->field];
789
790 #ifdef Q_OS_MAC // Mac-specific font tweaks
791 string += "<br>&nbsp;";
792 #else
793 string += "<br><small>&nbsp;";
794 #endif
795
796 if (item->field != SearchField::Title)
797 {
798 string += str_printf (dngettext (PACKAGE, "%d song", "%d songs",
799 item->matches.len ()), item->matches.len ());
800
801 if (item->field == SearchField::Genre || item->parent)
802 string += ' ';
803 }
804
805 if (item->field == SearchField::Genre)
806 {
807 string += _("of this genre");
808 }
809 else if (item->parent)
810 {
811 auto parent = (item->parent->parent ? item->parent->parent : item->parent);
812
813 string += (parent->field == SearchField::Album) ? _("on") : _("by");
814 string += ' ';
815 string += start_tags[parent->field];
816 string += QString (parent->name).toHtmlEscaped ();
817 string += end_tags[parent->field];
818 }
819
820 #ifndef Q_OS_MAC // Mac-specific font tweaks
821 string += "</small>";
822 #endif
823
824 return string;
825 }
826
827 void ResultsView::contextMenuEvent (QContextMenuEvent * event)
828 {
829 static const audqt::MenuItem items[] = {
830 audqt::MenuCommand ({N_("_Play"), "media-playback-start"}, action_play),
831 audqt::MenuCommand ({N_("_Create Playlist"), "document-new"}, action_create_playlist),
832 audqt::MenuCommand ({N_("_Add to Playlist"), "list-add"}, action_add_to_playlist)
833 };
834
835 if (! s_menu)
836 s_menu = audqt::menu_build ({items});
837
838 s_menu->popup (event->globalPos ());
839 }
840
841 QMimeData * ResultsModel::mimeData (const QModelIndexList & indexes) const
842 {
843 if (s_search_pending)
844 search_timeout ();
845
846 s_playlist.select_all (false);
847
848 QList<QUrl> urls;
849 for (auto & index : indexes)
850 {
851 int row = index.row ();
852 if (row < 0 || row >= s_items.len ())
853 continue;
854
855 for (int entry : s_items[row]->matches)
856 {
857 urls.append (QString (s_playlist.entry_filename (entry)));
858 s_playlist.select_entry (entry, true);
859 }
860 }
861
862 s_playlist.cache_selected ();
863
864 auto data = new QMimeData;
865 data->setUrls (urls);
866 return data;
493 void SearchWidget::show_context_menu (const QPoint & global_pos)
494 {
495 auto menu = new QMenu (this);
496
497 auto play_act = new QAction (audqt::get_icon ("media-playback-start"),
498 audqt::translate_str (N_("_Play")), menu);
499 auto create_act = new QAction (audqt::get_icon ("document-new"),
500 audqt::translate_str (N_("_Create Playlist")), menu);
501 auto add_act = new QAction (audqt::get_icon ("list-add"),
502 audqt::translate_str (N_("_Add to Playlist")), menu);
503
504 QObject::connect (play_act, & QAction::triggered, this, & SearchWidget::action_play);
505 QObject::connect (create_act, & QAction::triggered, this, & SearchWidget::action_create_playlist);
506 QObject::connect (add_act, & QAction::triggered, this, & SearchWidget::action_add_to_playlist);
507
508 menu->addAction (play_act);
509 menu->addAction (create_act);
510 menu->addAction (add_act);
511
512 menu->setAttribute (Qt::WA_DeleteOnClose);
513 menu->popup (global_pos);
867514 }
868515
869516 bool SearchToolQt::init ()
874521
875522 void * SearchToolQt::get_qt_widget ()
876523 {
877 s_search_entry = new QLineEdit;
878 s_search_entry->setContentsMargins (audqt::margins.TwoPt);
879 s_search_entry->setClearButtonEnabled (true);
880 s_search_entry->setPlaceholderText (_("Search library"));
881
882 s_help_label = new QLabel (_("To import your music library into Audacious, "
883 "choose a folder and then click the \"refresh\" icon."));
884 s_help_label->setAlignment (Qt::AlignCenter);
885 s_help_label->setContentsMargins (audqt::margins.EightPt);
886 s_help_label->setWordWrap (true);
887
888 s_wait_label = new QLabel (_("Please wait ..."));
889 s_wait_label->setAlignment (Qt::AlignCenter);
890 s_wait_label->setContentsMargins (audqt::margins.EightPt);
891
892 s_results_list = new ResultsView;
893 s_results_list->setFrameStyle (QFrame::NoFrame);
894 s_results_list->setHeaderHidden (true);
895 s_results_list->setIndentation (0);
896 s_results_list->setModel (& s_model);
897 s_results_list->setSelectionMode (QTreeView::ExtendedSelection);
898 s_results_list->setDragDropMode (QTreeView::DragOnly);
899
900 s_stats_label = new QLabel;
901 s_stats_label->setAlignment (Qt::AlignCenter);
902 s_stats_label->setContentsMargins (audqt::margins.TwoPt);
903
904 #ifdef Q_OS_MAC // Mac-specific font tweaks
905 s_search_entry->setFont (QApplication::font ("QTreeView"));
906 s_stats_label->setFont (QApplication::font ("QSmallFont"));
907 #endif
908
909 auto chooser = new QLineEdit;
910
911 auto button = new QPushButton (audqt::get_icon ("view-refresh"), QString ());
912 button->setFlat (true);
913 button->setFocusPolicy (Qt::NoFocus);
914
915 auto hbox = audqt::make_hbox (nullptr);
916 hbox->setContentsMargins (audqt::margins.TwoPt);
917
918 hbox->addWidget (chooser);
919 hbox->addWidget (button);
920
921 auto widget = new QWidget;
922 auto vbox = audqt::make_vbox (widget, 0);
923
924 vbox->addWidget (s_search_entry);
925 vbox->addWidget (s_help_label);
926 vbox->addWidget (s_wait_label);
927 vbox->addWidget (s_results_list);
928 vbox->addWidget (s_stats_label);
929 vbox->addLayout (hbox);
930
931 String uri = get_uri ();
932 StringBuf path = uri_to_filename (uri, false);
933 chooser->setText (path ? path : uri);
934
935 search_init ();
936
937 QObject::connect (widget, & QObject::destroyed, search_cleanup);
938 QObject::connect (s_search_entry, & QLineEdit::returnPressed, action_play);
939 QObject::connect (s_results_list, & QTreeView::doubleClicked, action_play);
940
941 QObject::connect (s_search_entry, & QLineEdit::textEdited, [] (const QString & text)
942 {
943 s_search_terms = str_list_to_index (str_tolower_utf8 (text.toUtf8 ()), " ");
944 trigger_search ();
945 });
946
947 QObject::connect (chooser, & QLineEdit::textEdited, [button] (const QString & text)
948 { button->setDisabled (text.isEmpty ()); });
949
950 auto refresh = [chooser] () {
951 QByteArray path = chooser->text ().toUtf8 ();
952 if (! path.isEmpty ())
953 {
954 begin_add (strstr (path, "://") ? path : filename_to_uri (path));
955 update_database ();
956 }
957 };
958
959 QObject::connect (chooser, & QLineEdit::returnPressed, refresh);
960 QObject::connect (button, & QPushButton::clicked, refresh);
961
962 return widget;
524 if (! s_widget)
525 s_widget = new SearchWidget;
526
527 return s_widget;
963528 }
964529
965530 int SearchToolQt::take_message (const char * code, const void *, int)
966531 {
967 if (! strcmp (code, "grab focus") && s_search_entry)
968 {
969 s_search_entry->setFocus (Qt::OtherFocusReason);
532 if (! strcmp (code, "grab focus") && s_widget)
533 {
534 s_widget->grab_focus ();
970535 return 0;
971536 }
972537
0 sidplayfp_dep = dependency('libsidplayfp', version: '>= 2.0', required: false)
1
2
3 if sidplayfp_dep.found()
4 siddatadir = join_paths(get_option('prefix'), get_option('datadir'))
5
6 shared_module('sid',
7 'xmms-sid.cc',
8 'xs_config.cc',
9 'xs_sidplay2.cc',
10 cpp_args: ['-DSIDDATADIR="@0@"'.format(siddatadir)],
11 dependencies: [audacious_dep, sidplayfp_dep],
12 install: true,
13 install_dir: input_plugin_dir
14 )
15 endif
0 shared_module('silence-removal',
1 'silence-removal.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
5454 m_value = (float) (25 - m_pos) * AUD_EQ_MAX_GAIN / 25;
5555
5656 if (m_band < 0)
57 aud_set_double (nullptr, "equalizer_preamp", m_value);
57 aud_set_double ("equalizer_preamp", m_value);
5858 else
5959 aud_eq_set_band (m_band, m_value);
6060
7676
7777 static void eq_on_cb (Button * button, GdkEventButton * event)
7878 {
79 aud_set_bool (nullptr, "equalizer_active", button->get_active ());
79 aud_set_bool ("equalizer_active", button->get_active ());
8080 }
8181
8282 static void update_from_config (void *, void *)
8383 {
84 equalizerwin_on->set_active (aud_get_bool (nullptr, "equalizer_active"));
85 equalizerwin_preamp->set_value (aud_get_double (nullptr, "equalizer_preamp"));
84 equalizerwin_on->set_active (aud_get_bool ("equalizer_active"));
85 equalizerwin_preamp->set_value (aud_get_double ("equalizer_preamp"));
8686
8787 double bands[AUD_EQ_NBANDS];
8888 aud_eq_get_bands (bands);
190190 {
191191 equalizerwin_on = new Button (25, 12, 10, 119, 128, 119, 69, 119, 187, 119, SKIN_EQMAIN, SKIN_EQMAIN);
192192 equalizerwin->put_widget (false, equalizerwin_on, 14, 18);
193 equalizerwin_on->set_active (aud_get_bool (nullptr, "equalizer_active"));
193 equalizerwin_on->set_active (aud_get_bool ("equalizer_active"));
194194 equalizerwin_on->on_release (eq_on_cb);
195195
196196 // AUTO button currently does nothing
222222
223223 equalizerwin_preamp = new EqSlider (_("Preamp"), -1);
224224 equalizerwin->put_widget (false, equalizerwin_preamp, 21, 38);
225 equalizerwin_preamp->set_value (aud_get_double (nullptr, "equalizer_preamp"));
225 equalizerwin_preamp->set_value (aud_get_double ("equalizer_preamp"));
226226
227227 const char * const bandnames[AUD_EQ_NBANDS] = {N_("31 Hz"),
228228 N_("63 Hz"), N_("125 Hz"), N_("250 Hz"), N_("500 Hz"), N_("1 kHz"),
7979 void draw (cairo_t * cr);
8080 bool button_press (GdkEventButton * event);
8181 bool scroll (GdkEventScroll * event);
82 bool motion (GdkEventMotion * event);
83 bool leave ();
84
85 QueuedFunc m_popup_timer;
86 bool m_popup_shown = false;
8287 };
8388
8489 Window * mainwin;
128133 /* always returns a 6-character string */
129134 static StringBuf format_time (int time, int length)
130135 {
131 bool zero = aud_get_bool (nullptr, "leading_zero");
136 bool zero = aud_get_bool ("leading_zero");
132137 bool remaining = aud_get_bool ("skins", "show_remaining_time");
133138
134139 if (remaining && length > 0)
442447 {
443448 if (aud_drct_get_record_enabled ())
444449 {
445 if (aud_get_bool (nullptr, "record"))
450 if (aud_get_bool ("record"))
446451 mainwin_show_status_message (_("Recording on"));
447452 else
448453 mainwin_show_status_message (_("Recording off"));
451456
452457 static void repeat_toggled ()
453458 {
454 mainwin_repeat->set_active (aud_get_bool (nullptr, "repeat"));
459 mainwin_repeat->set_active (aud_get_bool ("repeat"));
455460 }
456461
457462 static void shuffle_toggled ()
458463 {
459 mainwin_shuffle->set_active (aud_get_bool (nullptr, "shuffle"));
464 mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
460465 }
461466
462467 static void no_advance_toggled ()
463468 {
464 if (aud_get_bool (nullptr, "no_playlist_advance"))
469 if (aud_get_bool ("no_playlist_advance"))
465470 mainwin_show_status_message (_("Single mode."));
466471 else
467472 mainwin_show_status_message (_("Playlist mode."));
469474
470475 static void stop_after_song_toggled ()
471476 {
472 if (aud_get_bool (nullptr, "stop_after_current_song"))
477 if (aud_get_bool ("stop_after_current_song"))
473478 mainwin_show_status_message (_("Stopping after song."));
474479 }
475480
478483 switch (event->direction)
479484 {
480485 case GDK_SCROLL_UP:
481 mainwin_set_volume_diff (5);
486 mainwin_set_volume_diff (aud_get_int ("volume_delta"));
482487 break;
483488 case GDK_SCROLL_DOWN:
484 mainwin_set_volume_diff (-5);
489 mainwin_set_volume_diff (-aud_get_int ("volume_delta"));
485490 break;
486491 case GDK_SCROLL_LEFT:
487 aud_drct_seek (aud_drct_get_time () - 5000);
492 aud_drct_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
488493 break;
489494 case GDK_SCROLL_RIGHT:
490 aud_drct_seek (aud_drct_get_time () + 5000);
495 aud_drct_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
491496 break;
492497 default:
493498 break;
516521 return Window::button_press (event);
517522 }
518523
524 bool MainWindow::motion (GdkEventMotion * event)
525 {
526 if (is_shaded () &&
527 event->x >= 79 * config.scale &&
528 event->x <= 157 * config.scale &&
529 aud_get_bool ("show_filepopup_for_tuple"))
530 {
531 if (! m_popup_shown)
532 {
533 m_popup_timer.queue (aud_get_int ("filepopup_delay") * 100,
534 [] (void *) { audgui_infopopup_show_current (); }, nullptr);
535 m_popup_shown = true;
536 }
537 }
538 else if (m_popup_shown)
539 {
540 audgui_infopopup_hide ();
541 m_popup_timer.stop ();
542 m_popup_shown = false;
543 }
544
545 return Window::motion (event);
546 }
547
548 bool MainWindow::leave ()
549 {
550 if (m_popup_shown)
551 {
552 audgui_infopopup_hide ();
553 m_popup_timer.stop ();
554 m_popup_shown = false;
555 }
556
557 return Window::leave ();
558 }
559
519560 static void mainwin_playback_rpress (Button * button, GdkEventButton * event)
520561 {
521562 menu_popup (UI_MENU_PLAYBACK, event->x_root, event->y_root, false, false,
532573 case GDK_KEY_Left:
533574 case GDK_KEY_KP_Left:
534575 case GDK_KEY_KP_7:
535 aud_drct_seek (aud_drct_get_time () - 5000);
576 aud_drct_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
536577 break;
537578 case GDK_KEY_Right:
538579 case GDK_KEY_KP_Right:
539580 case GDK_KEY_KP_9:
540 aud_drct_seek (aud_drct_get_time () + 5000);
581 aud_drct_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
541582 break;
542583 case GDK_KEY_KP_4:
543584 aud_drct_pl_prev ();
661702 { seek_release (event, false); }
662703
663704 static void mainwin_shuffle_cb (Button * button, GdkEventButton * event)
664 { aud_set_bool (nullptr, "shuffle", button->get_active ()); }
705 { aud_set_bool ("shuffle", button->get_active ()); }
665706 static void mainwin_repeat_cb (Button * button, GdkEventButton * event)
666 { aud_set_bool (nullptr, "repeat", button->get_active ()); }
707 { aud_set_bool ("repeat", button->get_active ()); }
667708 static void mainwin_eq_cb (Button * button, GdkEventButton * event)
668709 { view_set_show_equalizer (button->get_active ()); }
669710 static void mainwin_pl_cb (Button * button, GdkEventButton * event)
957998
958999 mainwin_shuffle = new Button (46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP, SKIN_SHUFREP);
9591000 mainwin->put_widget (false, mainwin_shuffle, 164, 89);
960 mainwin_shuffle->set_active (aud_get_bool (nullptr, "shuffle"));
1001 mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
9611002 mainwin_shuffle->on_release (mainwin_shuffle_cb);
9621003
9631004 mainwin_repeat = new Button (28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP, SKIN_SHUFREP);
9641005 mainwin->put_widget (false, mainwin_repeat, 210, 89);
965 mainwin_repeat->set_active (aud_get_bool (nullptr, "repeat"));
1006 mainwin_repeat->set_active (aud_get_bool ("repeat"));
9661007 mainwin_repeat->on_release (mainwin_repeat_cb);
9671008
9681009 mainwin_eq = new Button (23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP, SKIN_SHUFREP);
110110 MenuCommand (N_("Stop"), "media-playback-stop", 'v', NO_MOD, aud_drct_stop),
111111 MenuCommand (N_("Previous"), "media-skip-backward", 'z', NO_MOD, aud_drct_pl_prev),
112112 MenuCommand (N_("Next"), "media-skip-forward", 'b', NO_MOD, aud_drct_pl_next),
113 MenuCommand (N_("Previous Album"), nullptr, NO_KEY, aud_drct_pl_prev_album),
114 MenuCommand (N_("Next Album"), nullptr, NO_KEY, aud_drct_pl_next_album),
113115 MenuSep (),
114116 MenuCommand (N_("Set A-B Repeat"), nullptr, 'a', NO_MOD, action_ab_set),
115117 MenuCommand (N_("Clear A-B Repeat"), nullptr, 'a', SHIFT, action_ab_clear),
171171
172172 /* entry numbers */
173173
174 if (aud_get_bool (nullptr, "show_numbers_in_pl"))
174 if (aud_get_bool ("show_numbers_in_pl"))
175175 {
176176 width = 0;
177177
769769 {
770770 if (position == -1 || position == m_length)
771771 cancel_all ();
772 else if (aud_get_bool (nullptr, "show_filepopup_for_tuple") && m_popup_pos != position)
772 else if (aud_get_bool ("show_filepopup_for_tuple") && m_popup_pos != position)
773773 {
774774 cancel_all ();
775775 popup_trigger (position);
792792 audgui_infopopup_hide ();
793793
794794 m_popup_pos = pos;
795 m_popup_timer.queue (aud_get_int (nullptr, "filepopup_delay") * 100,
795 m_popup_timer.queue (aud_get_int ("filepopup_delay") * 100,
796796 aud::obj_member<PlaylistWidget, & PlaylistWidget::popup_show>, this);
797797 }
798798
117117 String title = tuple.get_str (Tuple::FormattedTitle);
118118 int length = tuple.get_int (Tuple::Length);
119119
120 if (aud_get_bool (nullptr, "show_numbers_in_pl"))
120 if (aud_get_bool ("show_numbers_in_pl"))
121121 APPEND (scratch, "%d. ", 1 + entry);
122122
123123 APPEND (scratch, "%s", (const char *) title);
123123 if (bands != last_bands)
124124 {
125125 xscale.resize (bands + 1);
126 for (int i = 0; i <= bands; i ++)
127 xscale[i] = powf (256, (float) i / bands) - 0.5f;
128
126 Visualizer::compute_log_xscale (& xscale[0], bands);
129127 last_bands = bands;
130128 }
131129
132130 for (int i = 0; i < bands; i ++)
133131 {
134 /* sum up values in freq array between xscale[i] and xscale[i + 1],
135 including fractional parts */
136 int a = ceilf (xscale[i]);
137 int b = floorf (xscale[i + 1]);
138 float sum = 0;
139
140 if (b < a)
141 sum += freq[b] * (xscale[i + 1] - xscale[i]);
142 else
143 {
144 if (a > 0)
145 sum += freq[a - 1] * (a - xscale[i]);
146 for (; a < b; a ++)
147 sum += freq[a];
148 if (b < 256)
149 sum += freq[b] * (xscale[i + 1] - b);
150 }
151
152 /* fudge factor to make the graph have the same overall height as a
153 12-band one no matter how many bands there are */
154 sum *= (float) bands / 12;
155
156 /* convert to dB */
157 float val = 20 * log10f (sum);
158
132 float val = Visualizer::compute_freq_band (freq, & xscale[0], i, bands);
159133 /* scale (-db_range, 0.0) to (0.0, int_range) */
160134 val = (1 + val / db_range) * int_range;
161
162135 graph[i] = aud::clamp ((int) val, 0, int_range);
163136 }
164137 }
0 skins_target_dir = join_paths(get_option('datadir'), 'audacious')
1
2
3 install_subdir('Skins', install_dir: skins_target_dir)
5454 m_value = (float) (25 - m_pos) * AUD_EQ_MAX_GAIN / 25;
5555
5656 if (m_band < 0)
57 aud_set_double (nullptr, "equalizer_preamp", m_value);
57 aud_set_double ("equalizer_preamp", m_value);
5858 else
5959 aud_eq_set_band (m_band, m_value);
6060
7373
7474 static void eq_on_cb (Button * button, QMouseEvent * event)
7575 {
76 aud_set_bool (nullptr, "equalizer_active", button->get_active ());
76 aud_set_bool ("equalizer_active", button->get_active ());
7777 }
7878
7979 static void update_from_config (void *, void *)
8080 {
81 equalizerwin_on->set_active (aud_get_bool (nullptr, "equalizer_active"));
82 equalizerwin_preamp->set_value (aud_get_double (nullptr, "equalizer_preamp"));
81 equalizerwin_on->set_active (aud_get_bool ("equalizer_active"));
82 equalizerwin_preamp->set_value (aud_get_double ("equalizer_preamp"));
8383
8484 double bands[AUD_EQ_NBANDS];
8585 aud_eq_get_bands (bands);
186186 {
187187 equalizerwin_on = new Button (25, 12, 10, 119, 128, 119, 69, 119, 187, 119, SKIN_EQMAIN, SKIN_EQMAIN);
188188 equalizerwin->put_widget (false, equalizerwin_on, 14, 18);
189 equalizerwin_on->set_active (aud_get_bool (nullptr, "equalizer_active"));
189 equalizerwin_on->set_active (aud_get_bool ("equalizer_active"));
190190 equalizerwin_on->on_release (eq_on_cb);
191191
192192 // AUTO button currently does nothing
218218
219219 equalizerwin_preamp = new EqSlider (_("Preamp"), -1);
220220 equalizerwin->put_widget (false, equalizerwin_preamp, 21, 38);
221 equalizerwin_preamp->set_value (aud_get_double (nullptr, "equalizer_preamp"));
221 equalizerwin_preamp->set_value (aud_get_double ("equalizer_preamp"));
222222
223223 const char * const bandnames[AUD_EQ_NBANDS] = {N_("31 Hz"),
224224 N_("63 Hz"), N_("125 Hz"), N_("250 Hz"), N_("500 Hz"), N_("1 kHz"),
7575
7676 private:
7777 DialogWindows m_dialogs;
78 int m_scroll_delta_x = 0;
79 int m_scroll_delta_y = 0;
7880
7981 void draw (QPainter & cr);
8082 bool button_press (QMouseEvent * event);
8183 bool scroll (QWheelEvent * event);
84 void enterEvent (QEvent * event);
8285 };
8386
8487 Window * mainwin;
128131 /* always returns a 6-character string */
129132 static StringBuf format_time (int time, int length)
130133 {
131 bool zero = aud_get_bool (nullptr, "leading_zero");
134 bool zero = aud_get_bool ("leading_zero");
132135 bool remaining = aud_get_bool ("skins", "show_remaining_time");
133136
134137 if (remaining && length > 0)
428431 {
429432 if (aud_drct_get_record_enabled ())
430433 {
431 if (aud_get_bool (nullptr, "record"))
434 if (aud_get_bool ("record"))
432435 mainwin_show_status_message (_("Recording on"));
433436 else
434437 mainwin_show_status_message (_("Recording off"));
437440
438441 static void repeat_toggled ()
439442 {
440 mainwin_repeat->set_active (aud_get_bool (nullptr, "repeat"));
443 mainwin_repeat->set_active (aud_get_bool ("repeat"));
441444 }
442445
443446 static void shuffle_toggled ()
444447 {
445 mainwin_shuffle->set_active (aud_get_bool (nullptr, "shuffle"));
448 mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
446449 }
447450
448451 static void no_advance_toggled ()
449452 {
450 if (aud_get_bool (nullptr, "no_playlist_advance"))
453 if (aud_get_bool ("no_playlist_advance"))
451454 mainwin_show_status_message (_("Single mode."));
452455 else
453456 mainwin_show_status_message (_("Playlist mode."));
455458
456459 static void stop_after_song_toggled ()
457460 {
458 if (aud_get_bool (nullptr, "stop_after_current_song"))
461 if (aud_get_bool ("stop_after_current_song"))
459462 mainwin_show_status_message (_("Stopping after song."));
460463 }
461464
462465 bool MainWindow::scroll (QWheelEvent * event)
463466 {
464 int delta = event->angleDelta ().y () / 24;
465 if (delta)
466 mainwin_set_volume_diff (delta);
467
468 #if 0
469 case GDK_SCROLL_LEFT:
470 aud_drct_seek (aud_drct_get_time () - 5000);
471 break;
472 case GDK_SCROLL_RIGHT:
473 aud_drct_seek (aud_drct_get_time () + 5000);
474 break;
475 #endif
467 m_scroll_delta_x += event->angleDelta ().x ();
468 m_scroll_delta_y += event->angleDelta ().y ();
469
470 /* we want discrete steps here */
471 int steps_x = m_scroll_delta_x / 120;
472 int steps_y = m_scroll_delta_y / 120;
473
474 if (steps_x != 0)
475 {
476 m_scroll_delta_x -= 120 * steps_x;
477 int step_size = aud_get_int ("step_size");
478 aud_drct_seek (aud_drct_get_time () - steps_x * step_size * 1000);
479 }
480
481 if (steps_y != 0)
482 {
483 m_scroll_delta_y -= 120 * steps_y;
484 int volume_delta = aud_get_int ("volume_delta");
485 aud_drct_set_volume_main (aud_drct_get_volume_main () + steps_y * volume_delta);
486 }
476487
477488 return true;
478489 }
496507 return Window::button_press (event);
497508 }
498509
510 void MainWindow::enterEvent (QEvent * event)
511 {
512 if (! is_shaded() || ! aud_get_bool (nullptr, "show_filepopup_for_tuple"))
513 return;
514
515 auto enterEvent = static_cast<QEnterEvent *> (event);
516 if (enterEvent->x () >= 79 * config.scale &&
517 enterEvent->x () <= 157 * config.scale)
518 {
519 audqt::infopopup_show_current ();
520 }
521 }
522
499523 static void mainwin_playback_rpress (Button * button, QMouseEvent * event)
500524 {
501525 menu_popup (UI_MENU_PLAYBACK, event->globalX (), event->globalY (), false, false);
509533 switch (event->key ())
510534 {
511535 case Qt::Key_Left:
512 aud_drct_seek (aud_drct_get_time () - 5000);
536 aud_drct_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
513537 break;
514538 case Qt::Key_Right:
515 aud_drct_seek (aud_drct_get_time () + 5000);
539 aud_drct_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
516540 break;
517541 case Qt::Key_Space:
518542 aud_drct_pause ();
619643 { seek_release (event, false); }
620644
621645 static void mainwin_shuffle_cb (Button * button, QMouseEvent * event)
622 { aud_set_bool (nullptr, "shuffle", button->get_active ()); }
646 { aud_set_bool ("shuffle", button->get_active ()); }
623647 static void mainwin_repeat_cb (Button * button, QMouseEvent * event)
624 { aud_set_bool (nullptr, "repeat", button->get_active ()); }
648 { aud_set_bool ("repeat", button->get_active ()); }
625649 static void mainwin_eq_cb (Button * button, QMouseEvent * event)
626650 { view_set_show_equalizer (button->get_active ()); }
627651 static void mainwin_pl_cb (Button * button, QMouseEvent * event)
914938
915939 mainwin_shuffle = new Button (46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP, SKIN_SHUFREP);
916940 mainwin->put_widget (false, mainwin_shuffle, 164, 89);
917 mainwin_shuffle->set_active (aud_get_bool (nullptr, "shuffle"));
941 mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
918942 mainwin_shuffle->on_release (mainwin_shuffle_cb);
919943
920944 mainwin_repeat = new Button (28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP, SKIN_SHUFREP);
921945 mainwin->put_widget (false, mainwin_repeat, 210, 89);
922 mainwin_repeat->set_active (aud_get_bool (nullptr, "repeat"));
946 mainwin_repeat->set_active (aud_get_bool ("repeat"));
923947 mainwin_repeat->on_release (mainwin_repeat_cb);
924948
925949 mainwin_eq = new Button (23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP, SKIN_SHUFREP);
101101 audqt::MenuCommand ({N_("Stop"), "media-playback-stop", "V"}, aud_drct_stop),
102102 audqt::MenuCommand ({N_("Previous"), "media-skip-backward", "Z"}, aud_drct_pl_prev),
103103 audqt::MenuCommand ({N_("Next"), "media-skip-forward", "B"}, aud_drct_pl_next),
104 audqt::MenuCommand ({N_("Previous Album")}, aud_drct_pl_prev_album),
105 audqt::MenuCommand ({N_("Next Album")}, aud_drct_pl_next_album),
104106 audqt::MenuSep (),
105107 audqt::MenuCommand ({N_("Set A-B Repeat"), nullptr, "A"}, action_ab_set),
106108 audqt::MenuCommand ({N_("Clear A-B Repeat"), nullptr, "Shift+A"}, action_ab_clear),
0 skins_qt_sources = [
1 'actions.cc',
2 'button.cc',
3 'dialogs-qt.cc',
4 'dock.cc',
5 'drag-handle.cc',
6 'eq-graph.cc',
7 'eq-slider.cc',
8 'equalizer.cc',
9 'hslider.cc',
10 'main.cc',
11 'menurow.cc',
12 'menu-ops.cc',
13 'menus.cc',
14 'monostereo.cc',
15 'number.cc',
16 'playlistwin.cc',
17 'playlist-slider.cc',
18 'playlist-widget.cc',
19 'playstatus.cc',
20 'plugin.cc',
21 'plugin-window.cc',
22 'skin.cc',
23 'skin-ini.cc',
24 'skins_cfg.cc',
25 'skins_util.cc',
26 'skinselector.cc',
27 'svis.cc',
28 'textbox.cc',
29 'view.cc',
30 'vis-callbacks.cc',
31 'vis.cc',
32 'widget.cc',
33 'window.cc'
34 ]
35
36
37 shared_module('skins-qt',
38 skins_qt_sources,
39 dependencies: [audacious_dep, qt_dep, glib_dep, audqt_dep],
40 install: true,
41 install_dir: general_plugin_dir
42 )
43
160160
161161 /* entry numbers */
162162
163 if (aud_get_bool (nullptr, "show_numbers_in_pl"))
163 if (aud_get_bool ("show_numbers_in_pl"))
164164 {
165165 width = 0;
166166
291291
292292 void PlaylistWidget::set_font (const char * font)
293293 {
294 m_font.capture (qfont_from_string (font));
294 m_font.capture (new QFont (audqt::qfont_from_string (font)));
295295 m_metrics.capture (new QFontMetrics (* m_font, this));
296296 m_row_height = m_metrics->height ();
297297 refresh ();
727727 {
728728 if (position == -1 || position == m_length)
729729 cancel_all ();
730 else if (aud_get_bool (nullptr, "show_filepopup_for_tuple") && m_popup_pos != position)
730 else if (aud_get_bool ("show_filepopup_for_tuple") && m_popup_pos != position)
731731 {
732732 cancel_all ();
733733 popup_trigger (position);
750750 audqt::infopopup_hide ();
751751
752752 m_popup_pos = pos;
753 m_popup_timer.queue (aud_get_int (nullptr, "filepopup_delay") * 100,
753 m_popup_timer.queue (aud_get_int ("filepopup_delay") * 100,
754754 aud::obj_member<PlaylistWidget, & PlaylistWidget::popup_show>, this);
755755 }
756756
113113 String title = tuple.get_str (Tuple::FormattedTitle);
114114 int length = tuple.get_int (Tuple::Length);
115115
116 if (aud_get_bool (nullptr, "show_numbers_in_pl"))
116 if (aud_get_bool ("show_numbers_in_pl"))
117117 APPEND (scratch, "%d. ", 1 + entry);
118118
119119 APPEND (scratch, "%s", (const char *) title);
462462 skin_draw_pixbuf (cr, SKIN_TITLEBAR, 27, y_offset, 0, 0,
463463 skin.hints.mainwin_width, 14);
464464 }
465
466 /* parse a subset of Pango font descriptions */
467 QFont * qfont_from_string (const char * name)
468 {
469 auto family = str_copy (name);
470 int size = 0;
471 QFont::Weight weight = QFont::Normal;
472 QFont::Style style = QFont::StyleNormal;
473 QFont::Stretch stretch = QFont::Unstretched;
474
475 while (1)
476 {
477 /* check for attributes */
478 bool attr_found = false;
479 const char * space = strrchr (family, ' ');
480
481 if (space)
482 {
483 const char * attr = space + 1;
484 int num = str_to_int (attr);
485
486 attr_found = true;
487
488 if (num > 0)
489 size = num;
490 else if (! strcmp (attr, "Light"))
491 weight = QFont::Light;
492 else if (! strcmp (attr, "Bold"))
493 weight = QFont::Bold;
494 else if (! strcmp (attr, "Oblique"))
495 style = QFont::StyleOblique;
496 else if (! strcmp (attr, "Italic"))
497 style = QFont::StyleItalic;
498 else if (! strcmp (attr, "Condensed"))
499 stretch = QFont::Condensed;
500 else if (! strcmp (attr, "Expanded"))
501 stretch = QFont::Expanded;
502 else
503 attr_found = false;
504 }
505
506 if (! attr_found)
507 {
508 auto font = new QFont ((const char *) family);
509
510 /* check for a recognized font family */
511 if (! space || font->exactMatch ())
512 {
513 if (size > 0)
514 font->setPointSize (size);
515 if (weight != QFont::Normal)
516 font->setWeight (weight);
517 if (style != QFont::StyleNormal)
518 font->setStyle (style);
519 if (stretch != QFont::Unstretched)
520 font->setStretch (stretch);
521
522 return font;
523 }
524
525 delete font;
526 }
527
528 family.resize (space - family);
529 }
530 }
187187 void skin_draw_playlistwin_frame (QPainter & cr, int width, int height, bool focus);
188188 void skin_draw_mainwin_titlebar (QPainter & cr, bool shaded, bool focus);
189189
190 QFont * qfont_from_string (const char * name);
191
192190 /* ui_skin_load_ini.c */
193191 void skin_load_hints (const char * path);
194192 void skin_load_pl_colors (const char * path);
2929 #include <libaudcore/audstrings.h>
3030 #include <libaudcore/hook.h>
3131 #include <libaudcore/objects.h>
32 #include <libaudqt/libaudqt.h>
3233
3334 #include "skins_cfg.h"
3435 #include "skin.h"
8384 void TextBox::render_vector (const char * text)
8485 {
8586 QRect ink = m_metrics->tightBoundingRect (text);
87
88 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
89 int logical_width = m_metrics->horizontalAdvance (text);
90 #else
8691 int logical_width = m_metrics->width (text);
92 #endif
8793
8894 /* use logical width so as not to trim off the trailing space of the " --- " */
8995 /* use ink height since vertical space is quite limited */
245251 {
246252 if (font)
247253 {
248 m_font.capture (qfont_from_string (font));
254 m_font.capture (new QFont (audqt::qfont_from_string (font)));
249255 m_metrics.capture (new QFontMetrics (* m_font, this));
250256 }
251257 else
123123 if (bands != last_bands)
124124 {
125125 xscale.resize (bands + 1);
126 for (int i = 0; i <= bands; i ++)
127 xscale[i] = powf (256, (float) i / bands) - 0.5f;
128
126 Visualizer::compute_log_xscale (& xscale[0], bands);
129127 last_bands = bands;
130128 }
131129
132130 for (int i = 0; i < bands; i ++)
133131 {
134 /* sum up values in freq array between xscale[i] and xscale[i + 1],
135 including fractional parts */
136 int a = ceilf (xscale[i]);
137 int b = floorf (xscale[i + 1]);
138 float sum = 0;
139
140 if (b < a)
141 sum += freq[b] * (xscale[i + 1] - xscale[i]);
142 else
143 {
144 if (a > 0)
145 sum += freq[a - 1] * (a - xscale[i]);
146 for (; a < b; a ++)
147 sum += freq[a];
148 if (b < 256)
149 sum += freq[b] * (xscale[i + 1] - b);
150 }
151
152 /* fudge factor to make the graph have the same overall height as a
153 12-band one no matter how many bands there are */
154 sum *= (float) bands / 12;
155
156 /* convert to dB */
157 float val = 20 * log10f (sum);
158
132 float val = Visualizer::compute_freq_band (freq, & xscale[0], i, bands);
159133 /* scale (-db_range, 0.0) to (0.0, int_range) */
160134 val = (1 + val / db_range) * int_range;
161
162135 graph[i] = aud::clamp ((int) val, 0, int_range);
163136 }
164137 }
0 sndfile_dep = dependency('sndfile', version: '>= 0.19', required: false)
1
2
3 if sndfile_dep.found()
4 shared_module('sndfile',
5 'plugin.cc',
6 dependencies: [audacious_dep, sndfile_dep],
7 include_directories: [src_inc],
8 install: true,
9 install_dir: input_plugin_dir,
10 )
11 endif
3131 public:
3232 static const char about[];
3333 static const char * const exts[];
34 static const char * const mimes[];
3435
3536 static constexpr PluginInfo info = {
3637 N_("Sndfile Plugin"),
4041
4142 constexpr SndfilePlugin () : InputPlugin (info, InputInfo ()
4243 .with_priority (9) /* low priority fallback (but before ffaudio) */
43 .with_exts (exts)) {}
44 .with_exts (exts)
45 .with_mimes (mimes)) {}
4446
4547 bool is_our_file (const char * filename, VFSFile & file);
4648 bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
373375 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.");
374376
375377 const char * const SndfilePlugin::exts[] = { "aiff", "au", "raw", "wav", nullptr };
378 const char * const SndfilePlugin::mimes[] = { "audio/wav", "audio/x-wav", nullptr };
200200 m_last_write_time = timeval ();
201201 m_flush_count = 0;
202202
203 int buffer_ms = aud_get_int (nullptr, "output_buffer_size");
203 int buffer_ms = aud_get_int ("output_buffer_size");
204204
205205 sio_par par;
206206 sio_initpar (& par);
0 shared_module('song-info-qt',
1 'song-info.cc',
2 dependencies: [audacious_dep, qt_dep, audqt_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
6
99 LD = ${CXX}
1010
1111 CFLAGS += ${PLUGIN_CFLAGS}
12 CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../..
12 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GLIB_CFLAGS} -I../..
13 LIBS += ${GLIB_LIBS}
0 shared_module('songchange',
1 'song_change.cc',
2 'formatter.cc',
3 dependencies: [audacious_dep, glib_dep],
4 install: true,
5 install_dir: general_plugin_dir
6 )
33 */
44
55 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 #include <signal.h>
9 #include <unistd.h>
6 #include "songchange_crossplatform.h"
107
118 #include <assert.h>
9
1210 #include <string.h>
13
1411 #include <libaudcore/runtime.h>
1512 #include <libaudcore/drct.h>
1613 #include <libaudcore/i18n.h>
8178 assert (out == escaped + escaped.len ());
8279
8380 return escaped;
84 }
85
86 static void bury_child (int signal)
87 {
88 waitpid (-1, nullptr, WNOHANG);
89 }
90
91 static void execute_command (const char * cmd)
92 {
93 const char * argv[4] = {"/bin/sh", "-c", nullptr, nullptr};
94 argv[2] = cmd;
95 signal (SIGCHLD, bury_child);
96
97 if (fork () == 0)
98 {
99 /* We don't want this process to hog the audio device etc */
100 for (int i = 3; i < 255; i ++)
101 close (i);
102 execv (argv[0], (char * *) argv);
103 }
10481 }
10582
10683 /* Format codes:
251228 cmd_line_end = String ();
252229 cmd_line_ttc = String ();
253230
254 signal (SIGCHLD, SIG_DFL);
231 signal_child();
255232 }
256233
257234 typedef struct {
0 /*
1 * songchange_crossplatform.h
2 * Audacious
3 *
4 * Copyright (C) 2005-2018 Audacious team
5 *
6 * XMMS - Cross-platform multimedia player
7 * Copyright (C) 1998-2003 Peter Alm, Mikael Alm, Olle Hallnas,
8 * Thomas Nilsson and 4Front Technologies
9 * Copyright (C) 1999-2003 Haavard Kvaalen
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; under version 3 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses>.
22 *
23 * The Audacious team does not consider modular code linking to
24 * Audacious or using our public API to be a derived work.
25 */
26
27 #ifndef AUDACIOUS1_SONGCHANGE_CROSSPLATFORM_H
28 #define AUDACIOUS1_SONGCHANGE_CROSSPLATFORM_H
29
30 #include <libaudcore/runtime.h>
31
32 #ifdef _WIN32
33
34 #include <windows.h>
35 #include <glib.h>
36
37
38 static void signal_child() {
39 // signal (SIGCHLD, SIG_DFL);
40 }
41
42 static void execute_command(const char *cmd) {
43 auto *windows_cmd = reinterpret_cast<wchar_t *>(g_utf8_to_utf16(cmd, -1, nullptr, nullptr, nullptr));
44 g_return_if_fail (windows_cmd);
45
46 STARTUPINFOW si;
47 _PROCESS_INFORMATION pi;
48 ZeroMemory(&si, sizeof(si));
49 si.cb = sizeof(si);
50 ZeroMemory(&pi, sizeof(pi));
51
52 unsigned long flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
53 BOOL executed = ::CreateProcessW(NULL, windows_cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
54
55 if (!executed) {
56 AUDINFO("SongChange cannot run the command: %s\n", cmd);
57 }
58 g_free(windows_cmd);
59 }
60
61
62 #else
63 #include <signal.h>
64 #include <unistd.h>
65 #include <sys/wait.h>
66
67 static void signal_child() {
68 signal (SIGCHLD, SIG_DFL);
69 }
70
71 static void bury_child (int signal)
72 {
73 waitpid (-1, nullptr, WNOHANG);
74 }
75
76 static void execute_command (const char * cmd)
77 {
78 const char * argv[4] = {"/bin/sh", "-c", nullptr, nullptr};
79 argv[2] = cmd;
80 signal (SIGCHLD, bury_child);
81
82 if (fork () == 0)
83 {
84 /* We don't want this process to hog the audio device etc */
85 for (int i = 3; i < 255; i ++)
86 close (i);
87 execv (argv[0], (char * *) argv);
88 }
89 }
90 #endif
91
92 #endif //AUDACIOUS1_SONGCHANGE_CROSSPLATFORM_H
0 shared_module('speed-pitch',
1 'speed-pitch.cc',
2 include_directories: [src_inc],
3 dependencies: [audacious_dep, samplerate_dep],
4 install: true,
5 install_dir: effect_plugin_dir
6 )
7
7373
7474 const char * const StatusIcon::defaults[] = {
7575 "scroll_action", aud::numeric_string<SI_CFG_SCROLL_ACTION_VOLUME>::str,
76 "volume_delta", "5",
7776 "disable_popup", "FALSE",
7877 "close_to_tray", "FALSE",
7978 "reverse_scroll", "FALSE",
141140 switch (aud_get_int ("statusicon", "scroll_action"))
142141 {
143142 case SI_CFG_SCROLL_ACTION_VOLUME:
144 si_volume_change (aud_get_int ("statusicon", "volume_delta"));
143 si_volume_change (aud_get_int ("volume_delta"));
145144 break;
146145 case SI_CFG_SCROLL_ACTION_SKIP:
147146 if (aud_get_bool ("statusicon", "reverse_scroll"))
158157 switch (aud_get_int ("statusicon", "scroll_action"))
159158 {
160159 case SI_CFG_SCROLL_ACTION_VOLUME:
161 si_volume_change (-aud_get_int ("statusicon", "volume_delta"));
160 si_volume_change (-aud_get_int ("volume_delta"));
162161 break;
163162 case SI_CFG_SCROLL_ACTION_SKIP:
164163 if (aud_get_bool ("statusicon", "reverse_scroll"))
0 shared_module('statusicon-qt',
1 'statusicon.cc',
2 dependencies: [audacious_dep, qt_dep, audqt_dep],
3 install: true,
4 install_dir: general_plugin_dir
5 )
6
7575
7676 const char * const StatusIcon::defaults[] = {
7777 "scroll_action", aud::numeric_string<SI_CFG_SCROLL_ACTION_VOLUME>::str,
78 "volume_delta", "5",
7978 "disable_popup", "FALSE",
8079 "close_to_tray", "FALSE",
8180 "reverse_scroll", "FALSE",
143142 {
144143 case SI_CFG_SCROLL_ACTION_VOLUME:
145144 aud_drct_set_volume_main (aud_drct_get_volume_main () +
146 aud_get_int ("statusicon", "volume_delta") * steps);
145 aud_get_int ("volume_delta") * steps);
147146 break;
148147
149148 case SI_CFG_SCROLL_ACTION_SKIP:
0 shared_module('stereo',
1 'stereo.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
0 PLUGIN = streamtuner${PLUGIN_SUFFIX}
1
2 SRCS = \
3 streamtuner.cc \
4 shoutcast-widget.cc \
5 shoutcast-model.cc \
6 icecast-widget.cc \
7 icecast-model.cc \
8 ihr-widget.cc \
9 ihr-model.cc
10
11 include ../../buildsys.mk
12 include ../../extra.mk
13
14 plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR}
15
16 LD = ${CXX}
17
18 CFLAGS += ${PLUGIN_CFLAGS}
19 CPPFLAGS += ${PLUGIN_CPPFLAGS} ${QT_CFLAGS} ${QTNETWORK_CFLAGS} -I../..
20 LIBS += ${QT_LIBS} ${QTNETWORK_LIBS} -laudqt
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include <QXmlStreamReader>
11
12 #include "icecast-model.h"
13
14 static const char *ICECAST_YP = "http://dir.xiph.org/yp.xml";
15
16 IcecastTunerModel::IcecastTunerModel (QObject * parent) :
17 QAbstractListModel (parent)
18 {
19 fetch_stations ();
20 }
21
22 IcecastTunerModel::~IcecastTunerModel ()
23 {
24 m_results.clear ();
25 }
26
27 void IcecastTunerModel::fetch_stations ()
28 {
29 vfs_async_file_get_contents(ICECAST_YP, [&] (const char *, const Index<char> & buf) {
30 if (! buf.len ())
31 return;
32
33 beginResetModel ();
34
35 AUDINFO("icecast: got results from YP server\n");
36
37 // oh, this is going to be fun... parse the XML as fast as possible
38 QXmlStreamReader reader (QByteArray (buf.begin (), buf.len ()));
39 IcecastEntry entry;
40
41 // lets prefab some atoms for fast comparisons
42 QString entry_atom = QString ("entry");
43 QString server_name_atom = QString ("server_name");
44 QString listen_url_atom = QString ("listen_url");
45 QString server_type_atom = QString ("server_type");
46 QString bitrate_atom = QString ("bitrate");
47 QString genre_atom = QString ("genre");
48 QString current_song_atom = QString ("current_song");
49 QString mp3_atom = QString ("audio/mpeg");
50 QString aac_atom = QString ("audio/aacp");
51 QString vorbis_atom = QString ("application/ogg");
52
53 while (! reader.atEnd ()) {
54 auto token_type = reader.readNext ();
55
56 switch (token_type) {
57 case QXmlStreamReader::StartElement:
58 if (! reader.name ().compare (server_name_atom))
59 entry.title = reader.readElementText ();
60 else if (! reader.name ().compare (listen_url_atom))
61 entry.stream_uri = reader.readElementText ();
62 else if (! reader.name ().compare (current_song_atom))
63 entry.current_song = reader.readElementText ();
64 else if (! reader.name ().compare (genre_atom))
65 entry.genre = reader.readElementText ();
66 else if (! reader.name ().compare (server_type_atom))
67 {
68 auto server_type = reader.readElementText ();
69
70 if (! server_type.compare (mp3_atom))
71 entry.type = IcecastEntry::MP3;
72 else if (! server_type.compare (aac_atom))
73 entry.type = IcecastEntry::AAC;
74 else if (! server_type.compare (vorbis_atom))
75 entry.type = IcecastEntry::Vorbis;
76 else
77 entry.type = IcecastEntry::Other;
78 }
79 else if (! reader.name ().compare (bitrate_atom))
80 entry.bitrate = reader.readElementText ().toInt ();
81
82 break;
83 case QXmlStreamReader::EndElement:
84 if (! reader.name ().compare (entry_atom))
85 m_results.append (entry);
86
87 break;
88 default:
89 break;
90 }
91 }
92
93 endResetModel ();
94 });
95 }
96
97 const IcecastEntry & IcecastTunerModel::entry (int idx) const
98 {
99 return m_results[idx];
100 }
101
102 int IcecastTunerModel::columnCount (const QModelIndex &) const
103 {
104 return NColumns;
105 }
106
107 int IcecastTunerModel::rowCount (const QModelIndex &) const
108 {
109 return m_results.len ();
110 }
111
112 QVariant IcecastTunerModel::headerData (int section, Qt::Orientation orientation, int role) const
113 {
114 if (role != Qt::DisplayRole)
115 return QVariant ();
116
117 switch (section) {
118 case Title:
119 return QString (_("Title"));
120
121 case Genre:
122 return QString (_("Genre"));
123
124 case Type:
125 return QString (_("Type"));
126
127 case Bitrate:
128 return QString (_("Bitrate"));
129
130 case CurrentSong:
131 return QString (_("Current Song"));
132 }
133
134 return QVariant ();
135 }
136
137 QVariant IcecastTunerModel::data (const QModelIndex &index, int role) const
138 {
139 if (role != Qt::DisplayRole)
140 return QVariant ();
141
142 int row = index.row ();
143 auto station = entry (row);
144
145 switch (index.column ())
146 {
147 case Title:
148 return QString (station.title);
149
150 case Genre:
151 return QString (station.genre);
152
153 case Type:
154 switch (station.type)
155 {
156 case IcecastEntry::MP3:
157 return QString ("MP3");
158 case IcecastEntry::AAC:
159 return QString ("AAC");
160 case IcecastEntry::Vorbis:
161 return QString ("OGG");
162 default:
163 return QString (_("Other"));
164 }
165 break;
166
167 case Bitrate:
168 return QString::number (station.bitrate);
169
170 case CurrentSong:
171 return QString (station.current_song);
172 }
173
174 return QVariant ();
175 }
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #ifndef STREAMTUNER_ICECAST_MODEL_H
11 #define STREAMTUNER_ICECAST_MODEL_H
12
13 #include <libaudcore/drct.h>
14 #include <libaudcore/i18n.h>
15 #include <libaudcore/plugin.h>
16 #include <libaudcore/plugins.h>
17 #include <libaudcore/preferences.h>
18 #include <libaudcore/audstrings.h>
19 #include <libaudcore/hook.h>
20 #include <libaudcore/runtime.h>
21 #include <libaudcore/index.h>
22 #include <libaudcore/playlist.h>
23 #include <libaudcore/vfs_async.h>
24
25 #include <libaudqt/treeview.h>
26
27 #include <QWidget>
28 #include <QTabWidget>
29 #include <QVBoxLayout>
30 #include <QSplitter>
31 #include <QAbstractListModel>
32
33 struct IcecastEntry {
34 QString title;
35 QString genre;
36 QString current_song;
37 QString stream_uri;
38
39 enum {
40 MP3,
41 AAC,
42 Vorbis,
43 Other
44 } type;
45
46 int bitrate;
47 };
48
49 class IcecastTunerModel : public QAbstractListModel {
50 public:
51 enum {
52 Title,
53 Genre,
54 Type,
55 Bitrate,
56 CurrentSong,
57 NColumns
58 };
59
60 IcecastTunerModel (QObject * parent = nullptr);
61 ~IcecastTunerModel ();
62
63 int columnCount (const QModelIndex &parent = QModelIndex()) const;
64 int rowCount (const QModelIndex &parent = QModelIndex()) const;
65 QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
66 QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const;
67
68 void fetch_stations ();
69
70 const IcecastEntry & entry (int idx) const;
71
72 private:
73 Index<IcecastEntry> m_results;
74 };
75
76 #endif
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include "icecast-widget.h"
11
12 IcecastListingWidget::IcecastListingWidget (QWidget * parent) :
13 audqt::TreeView (parent)
14 {
15 m_model = new IcecastTunerModel (this);
16
17 setModel (m_model);
18 setRootIsDecorated (false);
19 }
20
21 void IcecastListingWidget::activate (const QModelIndex & index)
22 {
23 if (index.row () < 0)
24 return;
25
26 Playlist::temporary_playlist ().activate ();
27 auto entry = m_model->entry (index.row ());
28
29 AUDINFO ("Play radio entry %s [%s].\n", (const char *) entry.title.toLocal8Bit (), (const char *) entry.stream_uri.toLocal8Bit ());
30
31 Playlist::temporary_playlist ().insert_entry (-1, entry.stream_uri.toUtf8 (), Tuple (), true);
32 }
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #ifndef STREAMTUNER_ICECAST_WIDGET_H
11 #define STREAMTUNER_ICECAST_WIDGET_H
12
13 #include <libaudqt/treeview.h>
14
15 #include <QWidget>
16 #include <QTabWidget>
17 #include <QVBoxLayout>
18 #include <QSplitter>
19 #include <QAbstractListModel>
20 #include <QNetworkAccessManager>
21 #include <QNetworkRequest>
22 #include <QNetworkReply>
23 #include <QJsonDocument>
24 #include <QJsonArray>
25 #include <QJsonObject>
26
27 #include "icecast-model.h"
28
29 class IcecastListingWidget : public audqt::TreeView {
30 public:
31 IcecastListingWidget(QWidget * parent = nullptr);
32
33 void activate (const QModelIndex & index);
34
35 private:
36 IcecastTunerModel *m_model;
37 };
38
39 #endif
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include <libaudcore/drct.h>
11 #include <libaudcore/i18n.h>
12 #include <libaudcore/plugin.h>
13 #include <libaudcore/plugins.h>
14 #include <libaudcore/preferences.h>
15 #include <libaudcore/audstrings.h>
16 #include <libaudcore/hook.h>
17 #include <libaudcore/runtime.h>
18 #include <libaudcore/index.h>
19 #include <libaudcore/playlist.h>
20 #include <libaudcore/vfs_async.h>
21
22 #include <libaudqt/treeview.h>
23
24 #include <QWidget>
25 #include <QTabWidget>
26 #include <QAbstractListModel>
27 #include <QNetworkAccessManager>
28 #include <QNetworkRequest>
29 #include <QNetworkReply>
30 #include <QJsonDocument>
31 #include <QJsonArray>
32 #include <QJsonObject>
33
34 #include "ihr-model.h"
35
36 IHRMarketModel::IHRMarketModel (QObject * parent) :
37 QAbstractListModel (parent)
38 {
39 fetch_markets ();
40 }
41
42 IHRMarketModel::~IHRMarketModel ()
43 {
44 m_results.clear ();
45 }
46
47 int IHRMarketModel::columnCount (const QModelIndex &) const
48 {
49 return 1;
50 }
51
52 int IHRMarketModel::rowCount (const QModelIndex &) const
53 {
54 return m_results.len ();
55 }
56
57 QVariant IHRMarketModel::headerData (int section, Qt::Orientation orientation, int role) const
58 {
59 if (role != Qt::DisplayRole)
60 return QVariant ();
61
62 return QString (_("Market"));
63 }
64
65 QVariant IHRMarketModel::data (const QModelIndex &index, int role) const
66 {
67 if (role != Qt::DisplayRole)
68 return QVariant ();
69
70 int row = index.row ();
71 auto entry = m_results[row];
72
73 return QString ("%1, %2, %3 (%4)")
74 .arg (entry.city)
75 .arg (entry.state)
76 .arg (entry.country_code)
77 .arg (entry.station_count);
78 }
79
80 static const char *URI_GET_MARKETS = "https://api.iheart.com/api/v2/content/markets?limit=10000&cache=true";
81
82 void IHRMarketModel::fetch_markets ()
83 {
84 vfs_async_file_get_contents (URI_GET_MARKETS, [&] (const char *, const Index<char> & buf) {
85 if (! buf.len ())
86 return;
87
88 auto doc = QJsonDocument::fromJson(QByteArray (buf.begin (), buf.len ()));
89 if (! doc.isObject ())
90 return;
91
92 auto root = doc.object ();
93 auto market_count = root["total"].toInt ();
94
95 AUDINFO ("Fetched %d markets.\n", market_count);
96
97 beginResetModel ();
98
99 auto markets = root["hits"].toArray ();
100
101 for (auto market_ref : markets)
102 {
103 auto market = market_ref.toObject ();
104 IHRMarketEntry entry;
105
106 entry.market_id = market["marketId"].toInt ();
107 entry.station_count = market["stationCount"].toInt ();
108 entry.city = market["city"].toString ();
109 entry.state = market["stateAbbreviation"].toString ();
110 entry.country_code = market["countryAbbreviation"].toString ();
111
112 m_results.append (entry);
113 }
114
115 endResetModel ();
116 });
117 }
118
119 int IHRMarketModel::id_for_idx (const QModelIndex &index) const
120 {
121 if (index.row () < 0)
122 return -1;
123
124 auto entry = m_results[index.row ()];
125 return entry.market_id;
126 }
127
128 IHRTunerModel::IHRTunerModel (QObject * parent) :
129 QAbstractListModel (parent)
130 {
131 }
132
133 IHRTunerModel::~IHRTunerModel ()
134 {
135 m_results.clear ();
136 }
137
138 int IHRTunerModel::columnCount (const QModelIndex &) const
139 {
140 return NColumns;
141 }
142
143 int IHRTunerModel::rowCount (const QModelIndex &) const
144 {
145 return m_results.len ();
146 }
147
148 QVariant IHRTunerModel::headerData (int section, Qt::Orientation orientation, int role) const
149 {
150 if (role != Qt::DisplayRole)
151 return QVariant ();
152
153 switch (section) {
154 case CallLetters:
155 return QString (_("Call Letters"));
156
157 case Title:
158 return QString (_("Title"));
159
160 case Description:
161 return QString (_("Description"));
162 }
163
164 return QVariant ();
165 }
166
167 QVariant IHRTunerModel::data (const QModelIndex &index, int role) const
168 {
169 if (role != Qt::DisplayRole)
170 return QVariant ();
171
172 int row = index.row ();
173 int col = index.column ();
174 auto entry = m_results[row];
175
176 switch (col) {
177 case CallLetters:
178 return QString (entry.call_letters);
179
180 case Title:
181 return QString (entry.title);
182
183 case Description:
184 return QString (entry.description);
185 }
186
187 return QVariant ();
188 }
189
190 void IHRTunerModel::fetch_stations (int market_id)
191 {
192 StringBuf uri = str_printf("https://api.iheart.com/api/v2/content/liveStations?limit=100&marketId=%d", market_id);
193
194 vfs_async_file_get_contents(uri, [&] (const char *, const Index<char> & buf) {
195 if (! buf.len ())
196 return;
197
198 auto doc = QJsonDocument::fromJson(QByteArray (buf.begin (), buf.len ()));
199 if (! doc.isObject ())
200 return;
201
202 auto root = doc.object ();
203 auto station_count = root["total"].toInt ();
204
205 AUDINFO ("Fetched %d stations for market %d.\n", station_count, market_id);
206
207 beginResetModel ();
208
209 m_results.clear ();
210
211 auto stations = root["hits"].toArray ();
212
213 for (auto station_ref : stations)
214 {
215 auto station = station_ref.toObject ();
216 IHRStationEntry entry;
217
218 entry.title = station["name"].toString ();
219 entry.description = station["description"].toString ();
220 entry.call_letters = station["callLetters"].toString ();
221
222 auto streams = station["streams"].toObject ();
223 entry.stream_uri = streams["shoutcast_stream"].toString ();
224
225 m_results.append (entry);
226 }
227
228 endResetModel ();
229 });
230 }
231
232 const IHRStationEntry & IHRTunerModel::station_for_idx (const QModelIndex &index) const
233 {
234 return m_results[index.row ()];
235 }
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #ifndef STREAMTUNER_IHR_MODEL_H
11 #define STREAMTUNER_IHR_MODEL_H
12
13 #include <libaudcore/drct.h>
14 #include <libaudcore/i18n.h>
15 #include <libaudcore/plugin.h>
16 #include <libaudcore/plugins.h>
17 #include <libaudcore/preferences.h>
18 #include <libaudcore/audstrings.h>
19 #include <libaudcore/hook.h>
20 #include <libaudcore/runtime.h>
21 #include <libaudcore/index.h>
22 #include <libaudcore/playlist.h>
23
24 #include <libaudqt/treeview.h>
25
26 #include <QWidget>
27 #include <QTabWidget>
28 #include <QAbstractListModel>
29 #include <QNetworkAccessManager>
30 #include <QNetworkRequest>
31 #include <QNetworkReply>
32 #include <QJsonDocument>
33 #include <QJsonArray>
34 #include <QJsonObject>
35
36 struct IHRMarketEntry {
37 QString city;
38 QString state;
39 QString country_code;
40 int station_count;
41 int market_id;
42 };
43
44 struct IHRStationEntry {
45 QString title;
46 QString description;
47 QString call_letters;
48 QString stream_uri;
49 };
50
51 class IHRMarketModel : public QAbstractListModel {
52 public:
53 IHRMarketModel (QObject * parent = nullptr);
54 ~IHRMarketModel ();
55
56 int columnCount (const QModelIndex &parent = QModelIndex()) const;
57 int rowCount (const QModelIndex &parent = QModelIndex()) const;
58 QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
59 QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const;
60
61 void fetch_markets ();
62
63 int id_for_idx (const QModelIndex &index) const;
64
65 private:
66 Index<IHRMarketEntry> m_results;
67 };
68
69 class IHRTunerModel : public QAbstractListModel {
70 public:
71 IHRTunerModel (QObject * parent = nullptr);
72 ~IHRTunerModel ();
73
74 enum {
75 CallLetters,
76 Title,
77 Description,
78 NColumns
79 };
80
81 int columnCount (const QModelIndex &parent = QModelIndex()) const;
82 int rowCount (const QModelIndex &parent = QModelIndex()) const;
83 QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
84 QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const;
85
86 void fetch_stations (int market_id);
87
88 const IHRStationEntry & station_for_idx (const QModelIndex &index) const;
89
90 private:
91 Index<IHRStationEntry> m_results;
92 };
93
94 #endif
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include <libaudcore/drct.h>
11 #include <libaudcore/i18n.h>
12 #include <libaudcore/plugin.h>
13 #include <libaudcore/plugins.h>
14 #include <libaudcore/preferences.h>
15 #include <libaudcore/audstrings.h>
16 #include <libaudcore/hook.h>
17 #include <libaudcore/runtime.h>
18 #include <libaudcore/index.h>
19 #include <libaudcore/playlist.h>
20
21 #include "ihr-model.h"
22 #include "ihr-widget.h"
23
24 IHRListingWidget::IHRListingWidget (QWidget * parent) :
25 audqt::TreeView (parent)
26 {
27 m_model = new IHRTunerModel (this);
28
29 setModel (m_model);
30 setRootIsDecorated (false);
31 }
32
33 void IHRListingWidget::activate (const QModelIndex & index)
34 {
35 if (index.row () < 0)
36 return;
37
38 Playlist::temporary_playlist ().activate ();
39 auto entry = m_model->station_for_idx (index);
40
41 AUDINFO ("Play radio entry %s [%s].\n", (const char *) entry.title.toLocal8Bit (), (const char *) entry.stream_uri.toLocal8Bit ());
42
43 Playlist::temporary_playlist ().insert_entry (-1, entry.stream_uri.toUtf8 (), Tuple (), true);
44 }
45
46 IHRMarketWidget::IHRMarketWidget (QWidget * parent) :
47 QTreeView (parent)
48 {
49 m_model = new IHRMarketModel (this);
50
51 setModel (m_model);
52 setRootIsDecorated (false);
53 }
54
55 IHRTunerWidget::IHRTunerWidget (QWidget * parent) :
56 QWidget (parent)
57 {
58 m_layout = new QVBoxLayout (this);
59
60 m_splitter = new QSplitter ();
61
62 m_markets = new IHRMarketWidget ();
63 m_splitter->addWidget (m_markets);
64
65 m_tuner = new IHRListingWidget ();
66 m_splitter->addWidget (m_tuner);
67 m_splitter->setStretchFactor (1, 2);
68
69 m_layout->addWidget (m_splitter);
70
71 auto market_selection_model = m_markets->selectionModel ();
72 connect(market_selection_model, &QItemSelectionModel::selectionChanged, [&] (const QItemSelection &selected, const QItemSelection &) {
73 // this should never happen, but just to be sure...
74 if (! selected.indexes ().length ())
75 return;
76
77 auto idx = selected.indexes ().first ();
78 IHRMarketModel *market = (IHRMarketModel *) m_markets->model ();
79
80 IHRTunerModel *model = (IHRTunerModel *) m_tuner->model ();
81 model->fetch_stations (market->id_for_idx (idx));
82 });
83 }
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #ifndef STREAMTUNER_IHR_WIDGET_H
11 #define STREAMTUNER_IHR_WIDGET_H
12
13 #include <libaudqt/treeview.h>
14
15 #include <QWidget>
16 #include <QTabWidget>
17 #include <QVBoxLayout>
18 #include <QSplitter>
19 #include <QAbstractListModel>
20 #include <QNetworkAccessManager>
21 #include <QNetworkRequest>
22 #include <QNetworkReply>
23 #include <QJsonDocument>
24 #include <QJsonArray>
25 #include <QJsonObject>
26
27 #include "ihr-model.h"
28
29 class IHRListingWidget : public audqt::TreeView {
30 public:
31 IHRListingWidget(QWidget * parent = nullptr);
32
33 void activate (const QModelIndex & index);
34
35 private:
36 IHRTunerModel *m_model;
37 };
38
39 class IHRMarketWidget : public QTreeView {
40 public:
41 IHRMarketWidget(QWidget * parent = nullptr);
42
43 private:
44 IHRMarketModel *m_model;
45 };
46
47 class IHRTunerWidget : public QWidget {
48 public:
49 IHRTunerWidget(QWidget * parent = nullptr);
50
51 private:
52 IHRListingWidget *m_tuner;
53 IHRMarketWidget *m_markets;
54 QSplitter *m_splitter;
55 QVBoxLayout *m_layout;
56 };
57
58 #endif
0 qtnetwork_dep = dependency('qt5', version: qt_req, required: true, modules: ['Network'])
1
2
3 if qtnetwork_dep.found()
4 shared_module('streamtuner',
5 'streamtuner.cc',
6 'shoutcast-model.cc',
7 'shoutcast-widget.cc',
8 'icecast-widget.cc',
9 'icecast-model.cc',
10 'ihr-widget.cc',
11 'ihr-model.cc',
12 dependencies: [qt_dep, qtnetwork_dep, audacious_dep, audqt_dep],
13 install: true,
14 install_dir: general_plugin_dir
15 )
16 endif
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include <libaudcore/drct.h>
11 #include <libaudcore/i18n.h>
12 #include <libaudcore/plugin.h>
13 #include <libaudcore/plugins.h>
14 #include <libaudcore/preferences.h>
15 #include <libaudcore/audstrings.h>
16 #include <libaudcore/hook.h>
17 #include <libaudcore/runtime.h>
18 #include <libaudcore/index.h>
19 #include <libaudcore/playlist.h>
20
21 #include <QAbstractListModel>
22 #include <QNetworkAccessManager>
23 #include <QNetworkRequest>
24 #include <QNetworkReply>
25 #include <QJsonDocument>
26 #include <QJsonArray>
27 #include <QJsonObject>
28
29 #include "shoutcast-model.h"
30
31 ShoutcastTunerModel::ShoutcastTunerModel (QObject * parent) :
32 QAbstractListModel (parent)
33 {
34 m_qnam = new QNetworkAccessManager (this);
35
36 fetch_stations ();
37 }
38
39 ShoutcastTunerModel::~ShoutcastTunerModel ()
40 {
41 m_results.clear ();
42 }
43
44 void ShoutcastTunerModel::fetch_stations (String genre)
45 {
46 auto base = "https://directory.shoutcast.com";
47 StringBuf uri;
48 StringBuf post_data;
49
50 // undefined genre: fetch top 500
51 if (! genre || ! strcmp (genre, "Top 500 Stations"))
52 uri = str_concat ({base, "/Home/Top"});
53 else
54 {
55 uri = str_concat ({base, "/Home/BrowseByGenre"});
56 post_data = str_concat ({"genrename=", genre});
57 }
58
59 // build the request for the fetch
60 QUrl url = QUrl (QString (uri));
61 QNetworkRequest request = QNetworkRequest (url);
62 request.setHeader (QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
63
64 QNetworkReply * reply = m_qnam->post (request, (const char *) post_data);
65 QObject::connect (reply, &QNetworkReply::finished, [reply, this] () {
66 if (200 != reply->attribute (QNetworkRequest::HttpStatusCodeAttribute))
67 return;
68
69 auto data = reply->readAll();
70 auto doc = QJsonDocument::fromJson(data);
71
72 if (! doc.isArray ())
73 return;
74
75 auto stations = doc.array ();
76 process_stations (stations);
77 });
78 }
79
80 void ShoutcastTunerModel::process_station (QJsonObject object)
81 {
82 ShoutcastEntry entry;
83
84 entry.listeners = object["Listeners"].toInt ();
85 entry.bitrate = object["Bitrate"].toInt ();
86 entry.station_id = object["ID"].toInt ();
87 entry.genre = object["Genre"].toString ();
88 entry.title = object["Name"].toString ();
89 entry.type = object["Format"].toString () == QString ("audio/mpeg") ? ShoutcastEntry::MP3 : ShoutcastEntry::AAC;
90
91 m_results.append (entry);
92 }
93
94 void ShoutcastTunerModel::process_stations (QJsonArray & stations)
95 {
96 AUDINFO ("Retrieved %d stations.\n", stations.size ());
97
98 beginResetModel ();
99
100 m_results.clear ();
101
102 for (auto st : stations)
103 {
104 if (! st.isObject ())
105 continue;
106
107 process_station (st.toObject ());
108 }
109
110 endResetModel ();
111 }
112
113 QVariant ShoutcastTunerModel::headerData (int section, Qt::Orientation, int role) const
114 {
115 if (role != Qt::DisplayRole)
116 return QVariant ();
117
118 switch (section)
119 {
120 case Title:
121 return QString (_("Title"));
122
123 case Genre:
124 return QString (_("Genre"));
125
126 case Listeners:
127 return QString (_("Listeners"));
128
129 case Type:
130 return QString (_("Type"));
131
132 case Bitrate:
133 return QString (_("Bitrate"));
134 }
135
136 return QVariant ();
137 }
138
139 QVariant ShoutcastTunerModel::data (const QModelIndex &index, int role) const
140 {
141 if (role != Qt::DisplayRole)
142 return QVariant ();
143
144 int row = index.row ();
145 if (row > m_results.len ())
146 return QVariant ();
147
148 auto entry = m_results[row];
149
150 switch (index.column ())
151 {
152 case Title:
153 return QString (entry.title);
154
155 case Genre:
156 return QString (entry.genre);
157
158 case Listeners:
159 return QString::number (entry.listeners);
160
161 case Type:
162 return entry.type == ShoutcastEntry::MP3 ? QString ("MP3") : QString ("AAC");
163
164 case Bitrate:
165 return QString::number (entry.bitrate);
166 }
167
168 return QVariant ();
169 }
170
171 int ShoutcastTunerModel::columnCount (const QModelIndex &) const
172 {
173 return NColumns;
174 }
175
176 int ShoutcastTunerModel::rowCount (const QModelIndex &) const
177 {
178 return m_results.len ();
179 }
180
181 const ShoutcastEntry & ShoutcastTunerModel::entry (int idx) const
182 {
183 return m_results[idx];
184 }
185
186 const char *ShoutcastTunerModel::genres[] = {
187 N_("Top 500 Stations"),
188 N_("Alternative"),
189 N_("Blues"),
190 N_("Classical"),
191 N_("Country"),
192 N_("Decades"),
193 N_("Easy Listening"),
194 N_("Electronic"),
195 N_("Folk"),
196 N_("Inspirational"),
197 N_("International"),
198 N_("Jazz"),
199 N_("Latin"),
200 N_("Metal"),
201 N_("Misc"),
202 N_("New Age"),
203 N_("Pop"),
204 N_("Public Radio"),
205 N_("R&B and Urban"),
206 N_("Rap"),
207 N_("Reggae"),
208 N_("Rock"),
209 N_("Seasonal and Holiday"),
210 N_("Soundtracks"),
211 N_("Talk"),
212 N_("Themes")
213 };
214
215 ShoutcastGenreModel::ShoutcastGenreModel (QObject * parent) :
216 QAbstractListModel (parent)
217 {
218 }
219
220 int ShoutcastGenreModel::columnCount (const QModelIndex &) const
221 {
222 return 1;
223 }
224
225 int ShoutcastGenreModel::rowCount (const QModelIndex &) const
226 {
227 return sizeof (ShoutcastTunerModel::genres) / sizeof (ShoutcastTunerModel::genres[0]);
228 }
229
230 QVariant ShoutcastGenreModel::headerData (int, Qt::Orientation, int role) const
231 {
232 if (role != Qt::DisplayRole)
233 return QVariant ();
234
235 return QString (_("Genre"));
236 }
237
238 QVariant ShoutcastGenreModel::data (const QModelIndex &index, int role) const
239 {
240 if (role != Qt::DisplayRole)
241 return QVariant ();
242
243 return QString (_(ShoutcastTunerModel::genres[index.row ()]));
244 }
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #ifndef STREAMTUNER_SHOUTCAST_MODEL_H
11 #define STREAMTUNER_SHOUTCAST_MODEL_H
12
13 #include <libaudcore/drct.h>
14 #include <libaudcore/i18n.h>
15 #include <libaudcore/plugin.h>
16 #include <libaudcore/plugins.h>
17 #include <libaudcore/preferences.h>
18 #include <libaudcore/audstrings.h>
19 #include <libaudcore/hook.h>
20 #include <libaudcore/runtime.h>
21 #include <libaudcore/index.h>
22 #include <libaudcore/playlist.h>
23
24 #include <libaudqt/treeview.h>
25
26 #include <QWidget>
27 #include <QTabWidget>
28 #include <QAbstractListModel>
29 #include <QNetworkAccessManager>
30 #include <QNetworkRequest>
31 #include <QNetworkReply>
32 #include <QJsonDocument>
33 #include <QJsonArray>
34 #include <QJsonObject>
35
36 struct ShoutcastEntry {
37 QString title;
38 QString genre;
39 int listeners;
40
41 enum {
42 MP3,
43 AAC
44 } type;
45
46 int bitrate;
47 int station_id;
48 };
49
50 class ShoutcastTunerModel : public QAbstractListModel {
51 public:
52 static const char *genres[];
53
54 enum {
55 Title,
56 Genre,
57 Listeners,
58 Type,
59 Bitrate,
60 NColumns
61 };
62
63 ShoutcastTunerModel (QObject * parent = nullptr);
64 ~ShoutcastTunerModel ();
65
66 int columnCount (const QModelIndex &parent = QModelIndex()) const;
67 int rowCount (const QModelIndex &parent = QModelIndex()) const;
68 QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
69 QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const;
70
71 void fetch_stations (String genre = String ());
72
73 void process_station (QJsonObject object);
74 void process_stations (QJsonArray & stations);
75
76 const ShoutcastEntry & entry (int idx) const;
77
78 private:
79 Index<ShoutcastEntry> m_results;
80 QNetworkAccessManager *m_qnam;
81 };
82
83 class ShoutcastGenreModel : public QAbstractListModel {
84 public:
85 ShoutcastGenreModel (QObject * parent = nullptr);
86
87 int columnCount (const QModelIndex &parent = QModelIndex()) const;
88 int rowCount (const QModelIndex &parent = QModelIndex()) const;
89 QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
90 QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const;
91 };
92
93 #endif
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include <libaudcore/drct.h>
11 #include <libaudcore/i18n.h>
12 #include <libaudcore/plugin.h>
13 #include <libaudcore/plugins.h>
14 #include <libaudcore/preferences.h>
15 #include <libaudcore/audstrings.h>
16 #include <libaudcore/hook.h>
17 #include <libaudcore/runtime.h>
18 #include <libaudcore/index.h>
19 #include <libaudcore/playlist.h>
20
21 #include "shoutcast-model.h"
22 #include "shoutcast-widget.h"
23
24 ShoutcastListingWidget::ShoutcastListingWidget (QWidget * parent) :
25 audqt::TreeView (parent)
26 {
27 m_model = new ShoutcastTunerModel (this);
28
29 setModel (m_model);
30 setRootIsDecorated (false);
31 }
32
33 void ShoutcastListingWidget::activate (const QModelIndex & index)
34 {
35 if (index.row () < 0)
36 return;
37
38 Playlist::temporary_playlist ().activate ();
39 auto entry = m_model->entry (index.row ());
40
41 AUDINFO ("Play radio entry %s [%d].\n", (const char *) entry.title.toLocal8Bit (), entry.station_id);
42
43 StringBuf playlist_uri = str_printf ("https://yp.shoutcast.com/sbin/tunein-station.m3u?id=%d", entry.station_id);
44
45 Playlist::temporary_playlist ().insert_entry (-1, playlist_uri, Tuple (), true);
46 }
47
48 ShoutcastGenreWidget::ShoutcastGenreWidget (QWidget * parent) :
49 QTreeView (parent)
50 {
51 m_model = new ShoutcastGenreModel ();
52
53 setModel (m_model);
54 setRootIsDecorated (false);
55
56 auto idx = m_model->index (0);
57 auto selection = selectionModel ();
58 selection->select (idx, QItemSelectionModel::Select);
59 }
60
61 ShoutcastTunerWidget::ShoutcastTunerWidget (QWidget * parent) :
62 QWidget (parent)
63 {
64 m_layout = new QVBoxLayout (this);
65
66 m_splitter = new QSplitter ();
67
68 m_genre = new ShoutcastGenreWidget ();
69 m_splitter->addWidget (m_genre);
70
71 m_tuner = new ShoutcastListingWidget ();
72 m_splitter->addWidget (m_tuner);
73 m_splitter->setStretchFactor (1, 2);
74
75 m_layout->addWidget (m_splitter);
76
77 auto genre_selection_model = m_genre->selectionModel ();
78 connect(genre_selection_model, &QItemSelectionModel::selectionChanged, [&] (const QItemSelection &selected, const QItemSelection &) {
79 // this should never happen, but just to be sure...
80 if (! selected.indexes ().length ())
81 return;
82
83 auto idx = selected.indexes ().first ();
84
85 ShoutcastTunerModel *model = (ShoutcastTunerModel *) m_tuner->model ();
86 model->fetch_stations (String (ShoutcastTunerModel::genres [idx.row ()]));
87 });
88 }
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #ifndef STREAMTUNER_SHOUTCAST_WIDGET_H
11 #define STREAMTUNER_SHOUTCAST_WIDGET_H
12
13 #include <libaudqt/treeview.h>
14
15 #include <QWidget>
16 #include <QTabWidget>
17 #include <QVBoxLayout>
18 #include <QSplitter>
19 #include <QAbstractListModel>
20 #include <QNetworkAccessManager>
21 #include <QNetworkRequest>
22 #include <QNetworkReply>
23 #include <QJsonDocument>
24 #include <QJsonArray>
25 #include <QJsonObject>
26
27 #include "shoutcast-model.h"
28
29 class ShoutcastListingWidget : public audqt::TreeView {
30 public:
31 ShoutcastListingWidget(QWidget * parent = nullptr);
32
33 void activate (const QModelIndex & index);
34
35 private:
36 ShoutcastTunerModel *m_model;
37 };
38
39 class ShoutcastGenreWidget : public QTreeView {
40 public:
41 ShoutcastGenreWidget(QWidget * parent = nullptr);
42
43 private:
44 ShoutcastGenreModel *m_model;
45 };
46
47 class ShoutcastTunerWidget : public QWidget {
48 public:
49 ShoutcastTunerWidget(QWidget * parent = nullptr);
50
51 private:
52 ShoutcastListingWidget *m_tuner;
53 ShoutcastGenreWidget *m_genre;
54 QSplitter *m_splitter;
55 QVBoxLayout *m_layout;
56 };
57
58 #endif
0 // Copyright (c) 2019 Ariadne Conill <ariadne@dereferenced.org>
1 //
2 // Permission to use, copy, modify, and/or distribute this software for any
3 // purpose with or without fee is hereby granted, provided that the above
4 // copyright notice and this permission notice appear in all copies.
5 //
6 // This software is provided 'as is' and without any warranty, express or
7 // implied. In no event shall the authors be liable for any damages arising
8 // from the use of this software.
9
10 #include <libaudcore/drct.h>
11 #include <libaudcore/i18n.h>
12 #include <libaudcore/plugin.h>
13 #include <libaudcore/plugins.h>
14 #include <libaudcore/preferences.h>
15 #include <libaudcore/audstrings.h>
16 #include <libaudcore/hook.h>
17 #include <libaudcore/runtime.h>
18 #include <libaudcore/index.h>
19 #include <libaudcore/playlist.h>
20
21 #include <libaudqt/treeview.h>
22
23 #include <QWidget>
24 #include <QTabWidget>
25 #include <QAbstractListModel>
26 #include <QNetworkAccessManager>
27 #include <QNetworkRequest>
28 #include <QNetworkReply>
29 #include <QJsonDocument>
30 #include <QJsonArray>
31 #include <QJsonObject>
32
33 #include "shoutcast-model.h"
34 #include "shoutcast-widget.h"
35 #include "icecast-widget.h"
36 #include "ihr-widget.h"
37
38 class StreamTunerWidget : public QTabWidget {
39 public:
40 StreamTunerWidget(QWidget * parent = nullptr);
41
42 private:
43 ShoutcastTunerWidget *m_shoutcast_tuner;
44 IcecastListingWidget *m_icecast_tuner;
45 IHRTunerWidget *m_ihr_tuner;
46 };
47
48 StreamTunerWidget::StreamTunerWidget(QWidget *parent) :
49 QTabWidget(parent)
50 {
51 setDocumentMode (true);
52 setTabPosition (QTabWidget::TabPosition::South);
53
54 m_shoutcast_tuner = new ShoutcastTunerWidget (this);
55 m_icecast_tuner = new IcecastListingWidget (this);
56 m_ihr_tuner = new IHRTunerWidget (this);
57
58 addTab (m_shoutcast_tuner, _("Shoutcast"));
59 addTab (m_icecast_tuner, _("Icecast"));
60 addTab (m_ihr_tuner, "iHeartRadio");
61
62 tabBar ()->setAutoHide (false);
63 }
64
65 // plugin glue
66
67 class StreamTunerPlugin : public GeneralPlugin {
68 public:
69 static constexpr PluginInfo info = {
70 N_("Stream Tuner"),
71 PACKAGE,
72 nullptr,
73 nullptr,
74 PluginQtOnly
75 };
76
77 constexpr StreamTunerPlugin () : GeneralPlugin (info, false) { }
78
79 void * get_qt_widget ();
80 };
81
82 EXPORT StreamTunerPlugin aud_plugin_instance;
83
84 void * StreamTunerPlugin::get_qt_widget ()
85 {
86 return new StreamTunerWidget ();
87 }
0 shared_module('tonegen',
1 'tonegen.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: input_plugin_dir
5 )
6
8282
8383 void pl_song_info ()
8484 {
85 auto list = Playlist::active_playlist ();
86 int focus = list.get_focus ();
87 if (focus >= 0)
88 audqt::infowin_show (list, focus);
85 audqt::infowin_show_selected (Playlist::active_playlist ());
8986 }
9087
9188 void pl_open_folder ()
1818
1919 #include <libaudcore/drct.h>
2020 #include <libaudcore/playlist.h>
21 #include <libaudcore/runtime.h>
2122
2223 #define ACTIVE Playlist::active_playlist ()
2324
116117 pl_select_all ();
117118 }
118119
119 void volume_up () { aud_drct_set_volume_main (aud_drct_get_volume_main () + 5); }
120 void volume_down () { aud_drct_set_volume_main (aud_drct_get_volume_main () - 5); }
120 void volume_up ()
121 { aud_drct_set_volume_main (aud_drct_get_volume_main () + aud_get_int ("volume_delta")); }
122 void volume_down ()
123 { aud_drct_set_volume_main (aud_drct_get_volume_main () - aud_get_int ("volume_delta")); }
0 shared_module('voice_removal',
1 'voice_removal.cc',
2 dependencies: [audacious_dep],
3 install: true,
4 install_dir: effect_plugin_dir
5 )
6
0 ogg_dep = dependency('ogg', version: '>= 1.0')
1 vorbis_dep = dependency('vorbis', version: '>= 1.0')
2 vorbisenc_dep = dependency('vorbisenc', version: '>= 1.0')
3 vorbisfile_dep = dependency('vorbisfile', version: '>= 1.0')
4
5
6 if ogg_dep.found()
7 shared_module('vorbis',
8 'vcupdate.cc',
9 'vcedit.cc',
10 'vorbis.cc',
11 dependencies: [audacious_dep, ogg_dep, vorbis_dep, vorbisenc_dep, vorbisfile_dep, glib_dep],
12 include_directories: [src_inc],
13 install: true,
14 install_dir: input_plugin_dir,
15 )
16 endif
17
18
9898 insert_str_tuple_field_to_dictionary (tuple, Tuple::AlbumArtist, dict, "ALBUMARTIST");
9999 insert_str_tuple_field_to_dictionary (tuple, Tuple::Comment, dict, "COMMENT");
100100 insert_str_tuple_field_to_dictionary (tuple, Tuple::Genre, dict, "GENRE");
101 insert_str_tuple_field_to_dictionary (tuple, Tuple::Description, dict, "DESCRIPTION");
102 insert_str_tuple_field_to_dictionary (tuple, Tuple::MusicBrainzID, dict, "musicbrainz_trackid");
101103
102104 insert_int_tuple_field_to_dictionary (tuple, Tuple::Year, dict, "DATE");
103105 insert_int_tuple_field_to_dictionary (tuple, Tuple::Track, dict, "TRACKNUMBER");
141141 set_tuple_str (tuple, Tuple::AlbumArtist, comment, "ALBUMARTIST");
142142 set_tuple_str (tuple, Tuple::Genre, comment, "GENRE");
143143 set_tuple_str (tuple, Tuple::Comment, comment, "COMMENT");
144 set_tuple_str (tuple, Tuple::Description, comment, "DESCRIPTION");
145 set_tuple_str (tuple, Tuple::MusicBrainzID, comment, "musicbrainz_trackid");
144146
145147 if ((tmps = vorbis_comment_query (comment, "TRACKNUMBER", 0)))
146148 tuple.set_int (Tuple::Track, atoi (tmps));
439441 "Eugene Zagidullin <e.asphyx@gmail.com>");
440442
441443 const char * const VorbisPlugin::exts[] = {"ogg", "ogm", "oga", nullptr};
442 const char * const VorbisPlugin::mimes[] = {"application/ogg", nullptr};
444 const char * const VorbisPlugin::mimes[] = {
445 "application/ogg",
446 "application/x-ogg",
447 "audio/ogg",
448 "audio/x-vorbis+ogg",
449 nullptr
450 };
2020 };
2121
2222 constexpr VorbisPlugin () : InputPlugin (info, InputInfo (FlagWritesTag)
23 .with_priority (2) /* medium-high priority (a little slow) */
23 .with_priority (_AUD_PLUGIN_DEFAULT_PRIO + 2) /* medium-high priority (a little slow) */
2424 .with_exts (exts)
2525 .with_mimes (mimes)) {}
2626
0 vtx_sources = [
1 'ay8912.cc',
2 'info.cc',
3 'lh5dec.cc',
4 'vtx.cc',
5 'vtxfile.cc'
6 ]
7
8
9 shared_module('vtx',
10 vtx_sources,
11 dependencies: [audacious_dep],
12 install: true,
13 install_dir: input_plugin_dir
14 )
0 PLUGIN = vumeter-qt${PLUGIN_SUFFIX}
1
2 SRCS = vumeter_qt.cc vumeter_qt_widget.cc
3
4 include ../../buildsys.mk
5 include ../../extra.mk
6
7 plugindir := ${plugindir}/${VISUALIZATION_PLUGIN_DIR}
8
9 LD = ${CXX}
10 CFLAGS += ${PLUGIN_CFLAGS}
11 CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../.. ${QT_CFLAGS}
12 LIBS += -lm ${QT_LIBS}
0 shared_module('vumeter-qt',
1 'vumeter_qt.cc',
2 'vumeter_qt_widget.cc',
3 dependencies: [audacious_dep, qt_dep],
4 install: true,
5 install_dir: visualization_plugin_dir
6 )
7
0 /*
1 * Copyright (c) 2017-2019 Marc Sanchez Fauste.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
11 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
15 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
16 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17 * POSSIBILITY OF SUCH DAMAGE.
18 */
19
20 #include "vumeter_qt.h"
21 #include "vumeter_qt_widget.h"
22
23 #include <QPointer>
24 #include <libaudcore/interface.h>
25 #include <libaudcore/runtime.h>
26
27 EXPORT VUMeterQt aud_plugin_instance;
28
29 const char VUMeterQt::about[] =
30 N_("VU Meter Plugin for Audacious\n"
31 "Copyright 2017-2019 Marc Sánchez Fauste");
32
33 const PreferencesWidget VUMeterQt::widgets[] = {
34 WidgetLabel (N_("<b>VU Meter Settings</b>")),
35 WidgetSpin (
36 N_("Peak hold time:"),
37 WidgetFloat ("vumeter", "peak_hold_time"),
38 {0.1, 30, 0.1, N_("seconds")}
39 ),
40 WidgetSpin (
41 N_("Fall-off time:"),
42 WidgetFloat ("vumeter", "falloff"),
43 {0.1, 96, 0.1, N_("dB/second")}
44 ),
45 WidgetCheck (N_("Display legend"),
46 WidgetBool ("vumeter", "display_legend", toggle_display_legend)
47 ),
48 };
49
50 const PluginPreferences VUMeterQt::prefs = {{widgets}};
51
52 const char * const VUMeterQt::prefs_defaults[] = {
53 "peak_hold_time", "1.6",
54 "falloff", "13.3",
55 "display_legend", "TRUE",
56 nullptr
57 };
58
59 static QPointer<VUMeterQtWidget> spect_widget;
60
61 bool VUMeterQt::init()
62 {
63 aud_config_set_defaults ("vumeter", prefs_defaults);
64 return true;
65 }
66
67 void VUMeterQt::render_multi_pcm(const float * pcm, int channels)
68 {
69 if (spect_widget)
70 {
71 spect_widget->render_multi_pcm(pcm, channels);
72 }
73 }
74
75 void VUMeterQt::clear()
76 {
77 if (spect_widget)
78 {
79 spect_widget->reset();
80 spect_widget->update();
81 }
82 }
83
84 void * VUMeterQt::get_qt_widget()
85 {
86 if (spect_widget)
87 {
88 return spect_widget;
89 }
90
91 spect_widget = new VUMeterQtWidget;
92 return spect_widget;
93 }
94
95 void VUMeterQt::toggle_display_legend()
96 {
97 if (spect_widget)
98 {
99 spect_widget->toggle_display_legend();
100 }
101 }
0 /*
1 * Copyright (c) 2017-2019 Marc Sanchez Fauste.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
11 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
15 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
16 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17 * POSSIBILITY OF SUCH DAMAGE.
18 */
19
20 #ifndef __VUMETER_QT_H
21 #define __VUMETER_QT_H
22
23 #include <libaudcore/i18n.h>
24 #include <libaudcore/plugin.h>
25 #include <libaudcore/preferences.h>
26
27 class VUMeterQt : public VisPlugin
28 {
29 public:
30 static const char about[];
31 static const PreferencesWidget widgets[];
32 static const PluginPreferences prefs;
33 static const char * const prefs_defaults[];
34
35 static constexpr PluginInfo info = {
36 N_("VU Meter"),
37 PACKAGE,
38 about,
39 & prefs,
40 PluginQtOnly
41 };
42
43 constexpr VUMeterQt () : VisPlugin (info, Visualizer::MultiPCM) {}
44
45 bool init ();
46 void * get_qt_widget ();
47
48 void clear ();
49 void render_multi_pcm (const float * pcm, int channels);
50
51 static void toggle_display_legend();
52 };
53
54 #endif
0 /*
1 * Copyright (c) 2017-2019 Marc Sanchez Fauste.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
11 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
15 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
16 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17 * POSSIBILITY OF SUCH DAMAGE.
18 */
19
20 #include "vumeter_qt_widget.h"
21
22 #include <math.h>
23 #include <libaudcore/runtime.h>
24
25 const QColor VUMeterQtWidget::backgroundColor = QColor(16, 16, 16, 255);
26 const QColor VUMeterQtWidget::text_color = QColor(255, 255, 255);
27 const QColor VUMeterQtWidget::db_line_color = QColor(120, 120, 120);
28 const float VUMeterQtWidget::legend_line_width = 1.0f;
29 const int VUMeterQtWidget::redraw_interval = 25; // ms
30
31 float VUMeterQtWidget::get_db_on_range(float db)
32 {
33 return aud::clamp<float>(db, -db_range, 0);
34 }
35
36 float VUMeterQtWidget::get_db_factor(float db)
37 {
38 float factor = 0.0f;
39
40 if (db < -db_range)
41 {
42 factor = 0.0f;
43 }
44 else if (db < -60.0f)
45 {
46 factor = (db + db_range) * 2.5f/(db_range-60);
47 }
48 else if (db < -50.0f)
49 {
50 factor = (db + 60.0f) * 0.5f + 2.5f;
51 }
52 else if (db < -40.0f)
53 {
54 factor = (db + 50.0f) * 0.75f + 7.5f;
55 }
56 else if (db < -30.0f)
57 {
58 factor = (db + 40.0f) * 1.5f + 15.0f;
59 }
60 else if (db < -20.0f)
61 {
62 factor = (db + 30.0f) * 2.0f + 30.0f;
63 }
64 else if (db < 0.0f)
65 {
66 factor = (db + 20.0f) * 2.5f + 50.0f;
67 }
68 else
69 {
70 factor = 100.0f;
71 }
72
73 return factor / 100.0f;
74 }
75
76 float VUMeterQtWidget::get_height_from_db(float db)
77 {
78 return get_db_factor(db) * vumeter_height;
79 }
80
81 float VUMeterQtWidget::get_y_from_db(float db)
82 {
83 return vumeter_top_padding + vumeter_height - get_height_from_db(db);
84 }
85
86 void VUMeterQtWidget::render_multi_pcm (const float * pcm, int channels)
87 {
88 nchannels = aud::clamp(channels, 0, max_channels);
89
90 float peaks[channels];
91 for (int channel = 0; channel < channels; channel++)
92 {
93 peaks[channel] = fabsf(pcm[channel]);
94 }
95
96 for (int i = 0; i < 512 * channels;)
97 {
98 for (int channel = 0; channel < channels; channel++)
99 {
100 peaks[channel] = fmaxf(peaks[channel], fabsf(pcm[i++]));
101 }
102 }
103
104 for (int i = 0; i < nchannels; i++)
105 {
106 float n = peaks[i];
107
108 float db = 20 * log10f(n);
109 db = get_db_on_range(db);
110
111 if (db > channels_db_level[i])
112 {
113 channels_db_level[i] = db;
114 }
115
116 if (db > channels_peaks[i])
117 {
118 channels_peaks[i] = db;
119 last_peak_times[i].start();
120 }
121 }
122 }
123
124 void VUMeterQtWidget::redraw_timer_expired()
125 {
126 qint64 elapsed_render_time = redraw_elapsed_timer.restart();
127 float falloff = aud_get_double ("vumeter", "falloff") / 1000.0;
128 qint64 peak_hold_time = aud_get_double ("vumeter", "peak_hold_time") * 1000;
129
130 for (int i = 0; i < nchannels; i++)
131 {
132 float decay_amount = elapsed_render_time * falloff;
133 channels_db_level[i] = get_db_on_range(channels_db_level[i] - decay_amount);
134
135 qint64 elapsed_peak_time = last_peak_times[i].elapsed();
136 if (channels_db_level[i] > channels_peaks[i] || elapsed_peak_time > peak_hold_time)
137 {
138 channels_peaks[i] = channels_db_level[i];
139 last_peak_times[i].start();
140 }
141 }
142
143 update();
144 }
145
146 void VUMeterQtWidget::reset()
147 {
148 for (int i = 0; i < max_channels; i++)
149 {
150 last_peak_times[i].start();
151 channels_db_level[i] = -db_range;
152 channels_peaks[i] = -db_range;
153 }
154 }
155
156 void VUMeterQtWidget::draw_background(QPainter & p)
157 {
158 p.fillRect(0, 0, width(), height(), backgroundColor);
159 }
160
161 void VUMeterQtWidget::draw_vu_legend(QPainter & p)
162 {
163 float font_size_width = legend_width / 4.0f;
164 float font_size_height = vumeter_height * 0.015f;
165
166 QFont font = p.font();
167 font.setPointSizeF(fminf(font_size_width, font_size_height));
168 p.setFont(font);
169
170 QPen pen = p.pen();
171 pen.setWidth(legend_line_width);
172 pen.setColor(text_color);
173 p.setPen(pen);
174
175 draw_vu_legend_db(p, 0, "0");
176 draw_vu_legend_db(p, -3, "-3");
177 draw_vu_legend_db(p, -6, "-6");
178 draw_vu_legend_db(p, -9, "-9");
179 draw_vu_legend_db(p, -12, "-12");
180 draw_vu_legend_db(p, -15, "-15");
181 draw_vu_legend_db(p, -18, "-18");
182 draw_vu_legend_db(p, -20, "-20");
183 draw_vu_legend_db(p, -25, "-25");
184 draw_vu_legend_db(p, -30, "-30");
185 draw_vu_legend_db(p, -35, "-35");
186 draw_vu_legend_db(p, -40, "-40");
187 draw_vu_legend_db(p, -50, "-50");
188 draw_vu_legend_db(p, -60, "-60");
189 draw_vu_legend_db(p, -db_range, "-inf");
190
191 pen.setColor(db_line_color);
192 p.setPen(pen);
193 for (int i = 0; i >= -60; i--)
194 {
195 if (i > -30)
196 {
197 draw_vu_legend_line(p, i);
198 draw_vu_legend_line(p, i - 0.5, 0.5);
199 }
200 else if (i > -40)
201 {
202 draw_vu_legend_line(p, i);
203 }
204 else if (i >= -60)
205 {
206 draw_vu_legend_line(p, i);
207 i -= 1;
208 }
209 }
210 draw_vu_legend_line(p, -db_range);
211 }
212
213 void VUMeterQtWidget::draw_vu_legend_line(QPainter &p, float db, float line_width_factor)
214 {
215 float y = get_y_from_db(db);
216 if (db > -db_range)
217 {
218 y += (legend_line_width / 2.0f);
219 }
220 else
221 {
222 y -= (legend_line_width / 2.0f);
223 }
224 float line_width = aud::clamp<float>(legend_width * 0.25f, 1, 8);
225 p.drawLine(
226 QPointF(legend_width - line_width * line_width_factor - (legend_line_width / 2.0f), y),
227 QPointF(legend_width - (legend_line_width / 2.0f), y)
228 );
229 p.drawLine(
230 QPointF(width() - legend_width + (legend_line_width / 2.0f), y),
231 QPointF(width() - legend_width + (legend_line_width / 2.0f) + line_width * line_width_factor, y)
232 );
233 }
234
235 void VUMeterQtWidget::draw_vu_legend_db(QPainter &p, float db, const char *text)
236 {
237 QFontMetricsF fm(p.font());
238 QSizeF text_size = fm.size(0, text);
239 float y = get_y_from_db(db);
240 float padding = aud::clamp<float>(legend_width * 0.25f, 1, 8) * 1.5f;
241 p.drawText(QPointF(legend_width - text_size.width() - padding, y + (text_size.height()/4.0f)), text);
242 p.drawText(QPointF(width() - legend_width + padding, y + (text_size.height()/4.0f)), text);
243 }
244
245 void VUMeterQtWidget::draw_visualizer_peaks(QPainter &p)
246 {
247 float bar_width = get_bar_width(nchannels);
248 float font_size_width = bar_width / 3.0f;
249 float font_size_height = vumeter_top_padding * 0.50f;
250
251 QFont font = p.font();
252 font.setPointSizeF(fminf(font_size_width, font_size_height));
253 p.setFont(font);
254
255 QPen pen = p.pen();
256 pen.setColor(text_color);
257 p.setPen(pen);
258
259 QFontMetricsF fm(p.font());
260 for (int i = 0; i < nchannels; i++)
261 {
262 QString text = format_db(channels_peaks[i]);
263 QSizeF text_size = fm.size(0, text);
264 p.drawText(
265 QPointF(
266 legend_width + bar_width*(i+0.5f) - text_size.width()/2.0f,
267 vumeter_top_padding/2.0f + (text_size.height()/4.0f)
268 ),
269 text
270 );
271 }
272 }
273
274 void VUMeterQtWidget::draw_visualizer(QPainter & p)
275 {
276 for (int i = 0; i < nchannels; i++)
277 {
278 float bar_width = get_bar_width(nchannels);
279 float x = legend_width + (bar_width * i);
280 if (i > 0)
281 {
282 x += 1;
283 bar_width -= 1;
284 }
285
286 p.fillRect (
287 QRectF(x, vumeter_top_padding, bar_width, vumeter_height),
288 background_vumeter_pattern
289 );
290
291 p.fillRect (
292 QRectF(x, get_y_from_db(channels_db_level[i]),
293 bar_width, (get_height_from_db(channels_db_level[i]))),
294 vumeter_pattern
295 );
296
297 if (channels_peaks[i] > -db_range)
298 {
299 p.fillRect (
300 QRectF(x, get_y_from_db(channels_peaks[i]), bar_width, 1),
301 vumeter_pattern
302 );
303 }
304 }
305 }
306
307 QString VUMeterQtWidget::format_db(const float val)
308 {
309 if (val > -10)
310 {
311 return QString::number(val, 'f', 1);
312 }
313 else if (val > -db_range)
314 {
315 return QString::number(val, 'f', 0);
316 }
317 else
318 {
319 return QString("-inf");
320 }
321 }
322
323 float VUMeterQtWidget::get_bar_width(int channels)
324 {
325 return vumeter_width / channels;
326 }
327
328 void VUMeterQtWidget::update_sizes()
329 {
330 if (height() > 200 && width() > 60 && aud_get_bool("vumeter", "display_legend"))
331 {
332 must_draw_vu_legend = true;
333 vumeter_top_padding = height() * 0.03f;
334 vumeter_bottom_padding = height() * 0.015f;
335 vumeter_height = height() - vumeter_top_padding - vumeter_bottom_padding;
336 legend_width = width() * 0.3f;
337 vumeter_width = width() - (legend_width * 2);
338 }
339 else
340 {
341 must_draw_vu_legend = false;
342 vumeter_top_padding = 0;
343 vumeter_bottom_padding = 0;
344 vumeter_height = height();
345 legend_width = 0;
346 vumeter_width = width();
347 }
348 vumeter_pattern = get_vumeter_pattern();
349 background_vumeter_pattern = get_vumeter_pattern(30);
350 }
351
352 VUMeterQtWidget::VUMeterQtWidget (QWidget * parent)
353 : QWidget (parent),
354 redraw_timer(new QTimer(this))
355 {
356 reset();
357 connect(redraw_timer, &QTimer::timeout, this, &VUMeterQtWidget::redraw_timer_expired);
358 redraw_timer->start(redraw_interval);
359 redraw_elapsed_timer.start();
360 update_sizes();
361 }
362
363 QLinearGradient VUMeterQtWidget::get_vumeter_pattern(int alpha)
364 {
365 QLinearGradient vumeter_pattern = QLinearGradient(
366 0, vumeter_top_padding + vumeter_height, 0, vumeter_top_padding
367 );
368 vumeter_pattern.setColorAt(get_db_factor(0), QColor(190, 40, 10, alpha));
369 vumeter_pattern.setColorAt(get_db_factor(-2), QColor(190, 40, 10, alpha));
370 vumeter_pattern.setColorAt(get_db_factor(-9), QColor(210, 210, 15, alpha));
371 vumeter_pattern.setColorAt(get_db_factor(-50), QColor(0, 190, 20, alpha));
372 return vumeter_pattern;
373 }
374
375 void VUMeterQtWidget::resizeEvent (QResizeEvent *)
376 {
377 update_sizes();
378 }
379
380 void VUMeterQtWidget::paintEvent (QPaintEvent *)
381 {
382 QPainter p(this);
383
384 draw_background(p);
385 if (must_draw_vu_legend)
386 {
387 draw_vu_legend(p);
388 draw_visualizer_peaks(p);
389 }
390 draw_visualizer(p);
391 }
392
393 void VUMeterQtWidget::toggle_display_legend()
394 {
395 update_sizes();
396 update();
397 }
0 /*
1 * Copyright (c) 2017-2019 Marc Sanchez Fauste.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
11 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
15 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
16 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17 * POSSIBILITY OF SUCH DAMAGE.
18 */
19
20 #ifndef __VUMETER_QT_WIDGET_H
21 #define __VUMETER_QT_WIDGET_H
22
23 #include <QWidget>
24 #include <QPainter>
25 #include <QLinearGradient>
26 #include <QColor>
27 #include <QString>
28 #include <QTimer>
29 #include <QElapsedTimer>
30
31 class VUMeterQtWidget : public QWidget
32 {
33 private:
34 static constexpr int max_channels = 20;
35 static constexpr int db_range = 96;
36
37 static const QColor backgroundColor;
38 static const QColor text_color;
39 static const QColor db_line_color;
40 static const float legend_line_width;
41 static const int redraw_interval;
42
43 int nchannels = 2;
44 float channels_db_level[max_channels];
45 float channels_peaks[max_channels];
46 QElapsedTimer last_peak_times[max_channels]; // Time elapsed since peak was set
47 QLinearGradient vumeter_pattern;
48 QLinearGradient background_vumeter_pattern;
49 float legend_width;
50 float vumeter_height;
51 float vumeter_width;
52 float vumeter_top_padding;
53 float vumeter_bottom_padding;
54 bool must_draw_vu_legend;
55 QTimer *redraw_timer;
56 QElapsedTimer redraw_elapsed_timer;
57
58 void draw_background (QPainter &p);
59 void draw_visualizer (QPainter &p);
60 void draw_vu_legend(QPainter &p);
61 float get_height_from_db(float db);
62 float get_y_from_db(float db);
63 QLinearGradient get_vumeter_pattern(int alpha = 255);
64 float get_bar_width(int channels);
65 void draw_vu_legend_db(QPainter &p, float db, const char *text);
66 void draw_vu_legend_line(QPainter &p, float db, float line_width_factor = 1.0f);
67 void draw_visualizer_peaks(QPainter &p);
68 void update_sizes();
69
70 static QString format_db(const float val);
71 static float get_db_on_range(float db);
72 static float get_db_factor(float db);
73
74 public slots:
75 void redraw_timer_expired();
76
77 public:
78 VUMeterQtWidget (QWidget * parent = nullptr);
79
80 void reset ();
81 void render_multi_pcm (const float * pcm, int channels);
82 void toggle_display_legend();
83
84 protected:
85 void resizeEvent (QResizeEvent *);
86 void paintEvent (QPaintEvent *);
87 };
88
89 #endif
151151 return false;
152152 }
153153
154 int block_ms = aud_get_int (nullptr, "output_buffer_size") / NUM_BLOCKS;
154 int block_ms = aud_get_int ("output_buffer_size") / NUM_BLOCKS;
155155 block_size = FMT_SIZEOF (format) * chan * aud::rescale (block_ms, 1000, rate);
156156
157157 headers.insert (0, NUM_BLOCKS);
0 wavpack_dep = dependency('wavpack', version: '>= 4.31', required: false)
1
2
3 if wavpack_dep.found()
4 shared_module('wavpack',
5 'wavpack.cc',
6 dependencies: [audacious_dep, wavpack_dep, audtag_dep],
7 include_directories: [src_inc],
8 install: true,
9 install_dir: input_plugin_dir,
10 )
11 endif
1818 public:
1919 static const char about[];
2020 static const char * const exts[];
21 static const char * const mimes[];
2122
2223 static constexpr PluginInfo info = {
2324 N_("WavPack Decoder"),
2627 };
2728
2829 constexpr WavpackPlugin() : InputPlugin (info, InputInfo (FlagWritesTag)
29 .with_exts (exts)) {}
30 .with_exts (exts)
31 .with_mimes (mimes)) {}
3032
3133 bool is_our_file (const char * filename, VFSFile & file)
3234 { return false; }
255257 "Some of the plugin code was by Miles Egan.");
256258
257259 const char * const WavpackPlugin::exts[] = { "wv", nullptr };
260 const char * const WavpackPlugin::mimes[] = { "audio/x-wavpack", nullptr };
28082808 return;
28092809 case REG_GCROMCTRL :
28102810 {
2811 int i;
2811 u32 i;
28122812
28132813 if(MEM_8(MMU.MMU_MEM[proc], REG_GCCMDOUT) == 0xB7)
28142814 {
265265 void NDS_Reset( void)
266266 {
267267 BOOL oldexecute=execute;
268 int i;
268 u32 i;
269269 u32 src;
270270 u32 dst;
271271 NDS_header * header = NDS_getROMHeader();
0 plugin_sources = [
1 'corlett.cc',
2 'plugin.cc',
3 'vio2sf.cc'
4 ]
5
6
7 desmume_sources = [
8 'desmume/armcpu.cc',
9 'desmume/arm_instructions.cc',
10 'desmume/bios.cc',
11 'desmume/cp15.cc',
12 'desmume/FIFO.cc',
13 'desmume/GPU.cc',
14 'desmume/matrix.cc',
15 'desmume/mc.cc',
16 'desmume/MMU.cc',
17 'desmume/NDSSystem.cc',
18 'desmume/SPU.cc',
19 'desmume/thumb_instructions.cc'
20 ]
21
22
23 shared_module('xsf',
24 plugin_sources,
25 desmume_sources,
26 dependencies: [audacious_dep, zlib_dep],
27 install: true,
28 install_dir: input_plugin_dir
29 )
0 shared_module('xspf',
1 'xspf.cc',
2 dependencies: [audacious_dep, xml_dep, glib_dep],
3 install: true,
4 install_dir: container_plugin_dir
5 )
6
3737
3838 #define XSPF_ROOT_NODE_NAME "playlist"
3939 #define XSPF_XMLNS "http://xspf.org/ns/0/"
40 #define MB_RECORDING_IRI "https://musicbrainz.org/recording"
4041
4142 typedef struct {
4243 Tuple::Field tupleField;
8081 {Tuple::TrackPeak, "gain-track-peak", true},
8182 {Tuple::GainDivisor, "gain-gain-unit", true},
8283 {Tuple::PeakDivisor, "gain-peak-unit", true},
84
85 {Tuple::Description, "description", true},
86 {Tuple::MusicBrainzID, MB_RECORDING_IRI, true},
8387 };
8488
8589 static const char * const xspf_exts[] = {"xspf"};