# HG changeset patch # User Bram Moolenaar # Date 1560080706 -7200 # Node ID 353ed7ef78dfb570f618504eac8a5f7147bc93af # Parent 0363f6e9eac335a679269942928e91cb0be99188 patch 8.1.1502: cannot play any sound commit https://github.com/vim/vim/commit/427f5b66ce0abe19daed9291b1693f6e8aae6552 Author: Bram Moolenaar Date: Sun Jun 9 13:43:51 2019 +0200 patch 8.1.1502: cannot play any sound Problem: Cannot play any sound. Solution: Use libcanberra if available. Add sound functions. diff --git a/.travis.yml b/.travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -77,6 +77,7 @@ addons: - clang - lcov - gettext + - libcanberra-dev - libperl-dev - python-dev - python3-dev diff --git a/Filelist b/Filelist --- a/Filelist +++ b/Filelist @@ -88,6 +88,7 @@ SRC_ALL = \ src/search.c \ src/sha256.c \ src/sign.c \ + src/sound.c \ src/spell.c \ src/spell.h \ src/spellfile.c \ @@ -150,6 +151,7 @@ SRC_ALL = \ src/testdir/samples/test000 \ src/testdir/if_ver*.vim \ src/testdir/color_ramp.vim \ + src/testdir/silent.wav \ src/proto.h \ src/protodef.h \ src/proto/arabic.pro \ @@ -209,6 +211,7 @@ SRC_ALL = \ src/proto/search.pro \ src/proto/sha256.pro \ src/proto/sign.pro \ + src/proto/sound.pro \ src/proto/spell.pro \ src/proto/spellfile.pro \ src/proto/syntax.pro \ diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2622,6 +2622,12 @@ sin({expr}) Float sine of {expr} sinh({expr}) Float hyperbolic sine of {expr} sort({list} [, {func} [, {dict}]]) List sort {list}, using {func} to compare +sound_playevent({name} [, {callback}]) + Number play an event sound +sound_playfile({name} [, {callback}]) + Number play a sound file +sound_stop({id}) none stop playing sound {id} +sound_stopall() none stop playing all sounds soundfold({word}) String sound-fold {word} spellbadword() String badly spelled word at cursor spellsuggest({word} [, {max} [, {capital}]]) @@ -8837,6 +8843,49 @@ sort({list} [, {func} [, {dict}]]) *so return a:i1 - a:i2 endfunc < + *sound_playevent()* +sound_playevent({name} [, {callback}]) + Play a sound identified by {name}. Which event names are + supported depends on the system. Often the XDG sound names + are used. On Ubuntu they may be found in + /usr/share/sounds/freedesktop/stereo. Example: > + call sound_playevent('bell') + +< When {callback} is specified it is invoked when the sound is + finished. The first argument is the sound ID, the second + argument is the status: + 0 sound was played to the end + 1 sound was interruped + 2 error occured after sound started + Example: > + func Callback(id, status) + echomsg "sound " .. a:id .. " finished with " .. a:status + endfunc + call sound_playevent('bell', 'Callback') + +< Returns the sound ID, which can be passed to `sound_stop()`. + Returns zero if the sound could not be played. + {only available when compiled with the +sound feature} + + *sound_playfile()* +sound_playfile({name} [, {callback}]) + Like `sound_playevent()` but play sound file {name}. {name} + must be a full path. On Ubuntu you may find files to play + with this command: > + :!find /usr/share/sounds -type f | grep -v index.theme + +< {only available when compiled with the +sound feature} + + +sound_stop({id}) *sound_stop()* + Stop playing sound {id}. {id} must be previously returned by + `sound_playevent()` or `sound_playfile()`. + {only available when compiled with the +sound feature} + +sound_stopall() *sound_stopall()* + Stop playing all sounds. + {only available when compiled with the +sound feature} + *soundfold()* soundfold({word}) Return the sound-folded equivalent of {word}. Uses the first @@ -10756,6 +10805,7 @@ scrollbind Compiled with 'scrollbind' s showcmd Compiled with 'showcmd' support. signs Compiled with |:sign| support. smartindent Compiled with 'smartindent' support. +sound Compiled with sound support, e.g. `sound_playevent()` spell Compiled with spell checking support |spell|. startuptime Compiled with |--startuptime| support. statusline Compiled with support for 'statusline', 'rulerformat' diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -1628,6 +1628,7 @@ BASIC_SRC = \ search.c \ sha256.c \ sign.c \ + sound.c \ spell.c \ spellfile.c \ syntax.c \ @@ -1743,6 +1744,7 @@ OBJ_COMMON = \ objects/search.o \ objects/sha256.o \ objects/sign.o \ + objects/sound.o \ objects/spell.o \ objects/spellfile.o \ objects/syntax.o \ @@ -1883,6 +1885,7 @@ PRO_AUTO = \ search.pro \ sha256.pro \ sign.pro \ + sound.pro \ spell.pro \ spellfile.pro \ syntax.pro \ @@ -3235,6 +3238,9 @@ objects/sha256.o: sha256.c objects/sign.o: sign.c $(CCC) -o $@ sign.c +objects/sound.o: sound.c + $(CCC) -o $@ sound.c + objects/spell.o: spell.c $(CCC) -o $@ spell.c @@ -3650,6 +3656,10 @@ objects/sign.o: sign.c vim.h protodef.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ proto.h globals.h +objects/sound.o: spell.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h objects/spell.o: spell.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ diff --git a/src/auto/configure b/src/auto/configure --- a/src/auto/configure +++ b/src/auto/configure @@ -9303,28 +9303,8 @@ fi - -if test -z "$SKIP_GTK2"; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5 -$as_echo_n "checking --disable-gtktest argument... " >&6; } - # Check whether --enable-gtktest was given. -if test "${enable_gtktest+set}" = set; then : - enableval=$enable_gtktest; -else - enable_gtktest=yes -fi - - if test "x$enable_gtktest" = "xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5 -$as_echo "gtk test enabled" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5 -$as_echo "gtk test disabled" >&6; } - fi - - if test "X$PKG_CONFIG" = "X"; then - if test -n "$ac_tool_prefix"; then +if test "X$PKG_CONFIG" = "X"; then + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -9422,6 +9402,26 @@ else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi +fi + + +if test -z "$SKIP_GTK2"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5 +$as_echo_n "checking --disable-gtktest argument... " >&6; } + # Check whether --enable-gtktest was given. +if test "${enable_gtktest+set}" = set; then : + enableval=$enable_gtktest; +else + enable_gtktest=yes +fi + + if test "x$enable_gtktest" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5 +$as_echo "gtk test enabled" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5 +$as_echo "gtk test disabled" >&6; } fi if test "x$PKG_CONFIG" != "xno"; then @@ -9677,107 +9677,6 @@ fi $as_echo "gtk test disabled" >&6; } fi - if test "X$PKG_CONFIG" = "X"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -PKG_CONFIG=$ac_cv_path_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -$as_echo "$PKG_CONFIG" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_PKG_CONFIG"; then - ac_pt_PKG_CONFIG=$PKG_CONFIG - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -if test -n "$ac_pt_PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -$as_echo "$ac_pt_PKG_CONFIG" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_pt_PKG_CONFIG" = x; then - PKG_CONFIG="no" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PKG_CONFIG=$ac_pt_PKG_CONFIG - fi -else - PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -fi - - fi - if test "x$PKG_CONFIG" != "xno"; then if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then @@ -13026,6 +12925,56 @@ rm -rf conftest* fi + +if test "x$PKG_CONFIG" != "xno"; then + canberra_lib=`$PKG_CONFIG --libs libcanberrax 2>/dev/null` + canberra_cflags=`$PKG_CONFIG --cflags libcanberrax 2>/dev/null` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_lib: $canberra_lib" >&5 +$as_echo "canberra_lib: $canberra_lib" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_cflags: $canberra_cflags" >&5 +$as_echo "canberra_cflags: $canberra_cflags" >&6; } +fi +if test "x$canberra_lib" = "x"; then + canberra_lib=-lcanberra + canberra_cflags=-D_REENTRANT +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_lib: $canberra_lib" >&5 +$as_echo "canberra_lib: $canberra_lib" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: canberra_cflags: $canberra_cflags" >&5 +$as_echo "canberra_cflags: $canberra_cflags" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcanberra" >&5 +$as_echo_n "checking for libcanberra... " >&6; } +ac_save_CFLAGS="$CFLAGS" +ac_save_LIBS="$LIBS" +CFLAGS="$CFLAGS $canberra_cflags" +LIBS="$LIBS $canberra_lib" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# include + +int +main () +{ + + ca_context *hello; + ca_context_create(&hello); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_CANBERRA 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_blksize" >&5 $as_echo_n "checking for st_blksize... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext diff --git a/src/config.h.in b/src/config.h.in --- a/src/config.h.in +++ b/src/config.h.in @@ -207,6 +207,7 @@ #undef HAVE_STRNICMP #undef HAVE_STRPBRK #undef HAVE_STRTOL +#undef HAVE_CANBERRA #undef HAVE_ST_BLKSIZE #undef HAVE_SYSCONF #undef HAVE_SYSCTL diff --git a/src/configure.ac b/src/configure.ac --- a/src/configure.ac +++ b/src/configure.ac @@ -2702,6 +2702,10 @@ AC_DEFUN([GNOME_INIT],[ GNOME_INIT_HOOK([],fail) ]) +if test "X$PKG_CONFIG" = "X"; then + AC_PATH_TOOL(PKG_CONFIG, pkg-config, no) +fi + dnl --------------------------------------------------------------------------- dnl Check for GTK2. If it fails, then continue on for Motif as before... @@ -2717,10 +2721,6 @@ if test -z "$SKIP_GTK2"; then AC_MSG_RESULT(gtk test disabled) fi - if test "X$PKG_CONFIG" = "X"; then - AC_PATH_TOOL(PKG_CONFIG, pkg-config, no) - fi - if test "x$PKG_CONFIG" != "xno"; then dnl First try finding version 2.2.0 or later. The 2.0.x series has dnl problems (bold fonts, --remote doesn't work). @@ -2769,10 +2769,6 @@ if test -z "$SKIP_GTK3"; then AC_MSG_RESULT(gtk test disabled) fi - if test "X$PKG_CONFIG" = "X"; then - AC_PATH_TOOL(PKG_CONFIG, pkg-config, no) - fi - if test "x$PKG_CONFIG" != "xno"; then AM_PATH_GTK(3.0.0, [GUI_LIB_LOC="$GTK_LIBDIR" @@ -3755,6 +3751,29 @@ dnl define _LARGE_FILES, _FILE_OFFSET_BI dnl appropriate, so that off_t is 64 bits when needed. AC_SYS_LARGEFILE + +if test "x$PKG_CONFIG" != "xno"; then + canberra_lib=`$PKG_CONFIG --libs libcanberra 2>/dev/null` + canberra_cflags=`$PKG_CONFIG --cflags libcanberra 2>/dev/null` +fi +if test "x$canberra_lib" = "x"; then + canberra_lib=-lcanberra + canberra_cflags=-D_REENTRANT +fi +AC_MSG_CHECKING(for libcanberra) +ac_save_CFLAGS="$CFLAGS" +ac_save_LIBS="$LIBS" +CFLAGS="$CFLAGS $canberra_cflags" +LIBS="$LIBS $canberra_lib" +AC_TRY_LINK([ +# include + ], [ + ca_context *hello; + ca_context_create(&hello);], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_CANBERRA), + AC_MSG_RESULT(no); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS") + + dnl fstatfs() can take 2 to 4 arguments, try to use st_blksize if possible AC_MSG_CHECKING(for st_blksize) AC_TRY_COMPILE( diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -925,6 +925,12 @@ static struct fst {"sinh", 1, 1, f_sinh}, #endif {"sort", 1, 3, f_sort}, +#ifdef FEAT_SOUND + {"sound_playevent", 1, 2, f_sound_playevent}, + {"sound_playfile", 1, 2, f_sound_playfile}, + {"sound_stop", 1, 1, f_sound_stop}, + {"sound_stopall", 0, 0, f_sound_stopall}, +#endif {"soundfold", 1, 1, f_soundfold}, {"spellbadword", 0, 1, f_spellbadword}, {"spellsuggest", 1, 3, f_spellsuggest}, @@ -6782,6 +6788,9 @@ f_has(typval_T *argvars, typval_T *rettv #ifdef FEAT_NETBEANS_INTG "netbeans_intg", #endif +#ifdef FEAT_SOUND + "sound", +#endif #ifdef FEAT_SPELL "spell", #endif diff --git a/src/feature.h b/src/feature.h --- a/src/feature.h +++ b/src/feature.h @@ -660,6 +660,13 @@ # define FEAT_TERM_POPUP_MENU #endif +/* + * sound - currently only with libcanberra + */ +#if !defined(FEAT_SOUND) && defined(FEAT_BIG) && defined(HAVE_CANBERRA) +# define FEAT_SOUND +#endif + /* There are two ways to use XPM. */ #if (defined(HAVE_XM_XPMP_H) && defined(FEAT_GUI_MOTIF)) \ || defined(HAVE_X11_XPM_H) diff --git a/src/proto.h b/src/proto.h --- a/src/proto.h +++ b/src/proto.h @@ -183,6 +183,7 @@ void qsort(void *base, size_t elm_count, # ifdef FEAT_SIGNS # include "sign.pro" # endif +# include "sound.pro" # include "spell.pro" # include "spellfile.pro" # include "syntax.pro" diff --git a/src/proto/sound.pro b/src/proto/sound.pro new file mode 100644 --- /dev/null +++ b/src/proto/sound.pro @@ -0,0 +1,7 @@ +/* sound.c */ +void f_sound_playevent(typval_T *argvars, typval_T *rettv); +void f_sound_playfile(typval_T *argvars, typval_T *rettv); +void f_sound_stop(typval_T *argvars, typval_T *rettv); +void f_sound_stopall(typval_T *argvars, typval_T *rettv); +void sound_free(void); +/* vim: set ft=c : */ diff --git a/src/sound.c b/src/sound.c new file mode 100644 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,193 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * sound.c: functions related making noise + */ + +#include "vim.h" + +#if (defined(FEAT_SOUND) && defined(HAVE_CANBERRA)) || defined(PROTO) + +#include + +static long sound_id = 0; +static ca_context *context = NULL; + +typedef struct soundcb_S soundcb_T; + +struct soundcb_S { + callback_T snd_callback; + soundcb_T *snd_next; +}; + +static soundcb_T *first_callback = NULL; + + static soundcb_T * +get_sound_callback(typval_T *arg) +{ + callback_T callback; + soundcb_T *soundcb; + + if (arg->v_type == VAR_UNKNOWN) + return NULL; + callback = get_callback(arg); + if (callback.cb_name == NULL) + return NULL; + + soundcb = ALLOC_ONE(soundcb_T); + if (soundcb == NULL) + free_callback(&callback); + else + { + soundcb->snd_next = first_callback; + first_callback = soundcb; + set_callback(&soundcb->snd_callback, &callback); + } + return soundcb; +} + +/* + * Delete "soundcb" from the list of pending callbacks. + */ + static void +delete_sound_callback(soundcb_T *soundcb) +{ + soundcb_T *p; + soundcb_T *prev = NULL; + + for (p = first_callback; p != NULL; prev = p, p = p->snd_next) + if (p == soundcb) + { + if (prev == NULL) + first_callback = p->snd_next; + else + prev->snd_next = p->snd_next; + free_callback(&p->snd_callback); + vim_free(p); + break; + } +} + + static void +sound_callback( + ca_context *c UNUSED, + uint32_t id, + int error_code, + void *userdata) +{ + soundcb_T *soundcb = (soundcb_T *)userdata; + typval_T argv[3]; + typval_T rettv; + int dummy; + + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = id; + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = error_code == CA_SUCCESS ? 0 + : error_code == CA_ERROR_CANCELED + || error_code == CA_ERROR_DESTROYED + ? 1 : 2; + argv[2].v_type = VAR_UNKNOWN; + + call_callback(&soundcb->snd_callback, -1, + &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL); + clear_tv(&rettv); + + delete_sound_callback(soundcb); + redraw_after_callback(TRUE); +} + + static void +sound_play_common(typval_T *argvars, typval_T *rettv, int playfile) +{ + if (context == NULL) + ca_context_create(&context); + if (context != NULL) + { + soundcb_T *soundcb = get_sound_callback(&argvars[1]); + int res = CA_ERROR_INVALID; + + ++sound_id; + if (soundcb == NULL) + { + res = ca_context_play(context, sound_id, + playfile ? CA_PROP_MEDIA_FILENAME : CA_PROP_EVENT_ID, + tv_get_string(&argvars[0]), + CA_PROP_CANBERRA_CACHE_CONTROL, "volatile", + NULL); + } + else + { + static ca_proplist *proplist = NULL; + + ca_proplist_create(&proplist); + if (proplist != NULL) + { + if (playfile) + ca_proplist_sets(proplist, CA_PROP_MEDIA_FILENAME, + (char *)tv_get_string(&argvars[0])); + else + ca_proplist_sets(proplist, CA_PROP_EVENT_ID, + (char *)tv_get_string(&argvars[0])); + ca_proplist_sets(proplist, CA_PROP_CANBERRA_CACHE_CONTROL, + "volatile"); + res = ca_context_play_full(context, sound_id, proplist, + sound_callback, soundcb); + if (res != CA_SUCCESS) + delete_sound_callback(soundcb); + + ca_proplist_destroy(proplist); + } + } + rettv->vval.v_number = res == CA_SUCCESS ? sound_id : 0; + } +} + + void +f_sound_playevent(typval_T *argvars, typval_T *rettv) +{ + sound_play_common(argvars, rettv, FALSE); +} + + void +f_sound_playfile(typval_T *argvars, typval_T *rettv) +{ + sound_play_common(argvars, rettv, TRUE); +} + + void +f_sound_stop(typval_T *argvars, typval_T *rettv UNUSED) +{ + if (context != NULL) + ca_context_cancel(context, tv_get_number(&argvars[0])); +} + + void +f_sound_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ + if (context != NULL) + { + ca_context_destroy(context); + context = NULL; + } +} + +#if defined(EXITFREE) || defined(PROTO) + void +sound_free(void) +{ + if (context != NULL) + ca_context_destroy(context); + while (first_callback != NULL) + delete_sound_callback(first_callback); +} +#endif + +#endif // FEAT_SOUND && HAVE_CANBERRA diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -228,6 +228,7 @@ NEW_TESTS = \ test_signs \ test_smartindent \ test_sort \ + test_sound \ test_source \ test_source_utf8 \ test_spell \ @@ -399,6 +400,7 @@ NEW_TESTS_RES = \ test_signals.res \ test_signs.res \ test_smartindent.res \ + test_sound.res \ test_source.res \ test_spell.res \ test_startup.res \ diff --git a/src/testdir/silent.wav b/src/testdir/silent.wav new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4631a7e8ed007b62af0a63111b9e4adc60a9eebe GIT binary patch literal 65580 zc$|%$JCZEPl3YC^tGd~@1Q6H=M1T<)76d?#2m~CsSr!;9ulrVpqq5vJ^r*S#eN!Xz zvTuIk<8EIyHH-iLumAEd|G6FQfBu*M@!$UU|M~a-^pDoQ|8=(i`hQ#d$NxLqNBc+n zU;p;+|Mq(K_5ZzJ{m~xntABmJezdDU`|JDd`;*r<*s>+}1ywejn#_wV1F z-|xL%$7kpG_~+Nh_cz-2v9IrAe|-P?tN&Wg(SQEy`o4ppUA#x9NXA3sMu=YBorT8v|j)#=|yeEs|RBNOAu$6WK{=Ss$}&mXyY{@lmd z`*GfJ4`1JB`TSY&@qORJxT|A+yU#m)-m9q{w{$$`stjowXZ-cEf|9ypUfp9JX{?ok7fZ)>JKdrnPzt?(b;uYZ4k>vLMh18ZUFIH&ff zRcLdCPROWi+xVj;)q4KUdUxpGHKqTWHuC&g=a=LU%PLzctvTl2oN=YLYOUD6<422S zB_8vA$wUnfmA3xIi$Fv!bvL@1+$1Rh?XMEnfGPI-LpIQp+8)Q}K zi|i-Pxn9TZd(NqCw#L@LWA18NOUbA_OTVq+SYz$xkjyqUbX>33EbVW<^+>wm9eB?B z88SGo>6~6~Lz`qJB;B^|&yZKyz5^CPapF1G@-eSmD<(a)1(2us_?DCB)NsdRk7+^2@B7@jmqh*X zqpfY;sXY=S7RO{AuT=}FjWv$Dph1smH|;^jH+8-f$CSTjv~d;f$?KIJw#W53tG#oq z^Ktum#Vp=y?}@cV{^XecCfCGvPEpPU%YTFia4ge%#zwRn-tXZRp3~b}mTbRtCDJDD zkUq_wVq~Lufl>N}PaQ+(TQ!4_b);?P@y2f?(?=Xf(aYn0@3`aS2iCa$9nBHW1&i65 zBi5AO-K+j2JJexCi>-Wr_usU=w$}1Fi~>`N#(hZRuNi0Nk+q|YC)Y^VD?GBy=bgo6 zMDEy#F?EgP(xu$OMUFVu!31?glT29{~spG$$!`36EwWxXBaj&7{GRFTy z170@s?-}zy=RGUZ?d2M1nJ71ur?ErIDTb99`|)VbO}(0u7)2WwvOdKe1wiv<>h(jOdQC8`KVY66xb}ku+Pg zj$_**IpNDoy$G6A#?l8xvU*~rf zo!pljD%1e6Hxg*(hyT=K0QzD`G)S{%DMrYs68{uN9+p zb@a>gRf&2R~fBQR;cxg60{lv*Hdov6&9?nJae|{yVmb{ZECb?9Y}1hL%wL~ zm0t@9Ozb)>fbzC?66y2$+IhAMKBq<#+6&_g#*QpGUSa1J*YrQHJFq>gxPr5T7SdC_ z%%iQ@j3fB5_K8LaAxzA{H3!CCnY(hY(?X2TiP|x5qkM9QcBn$dl!(U;%PR}L;%>wW zS5$}Z8AU&^Bl6nRLn3lqhYs0wJfpQ`CTWlE>$43c&Zy{U?6Q4JjjEkt>AHk~(AF5e zQ3OJJf86(>IPT+q9rkSXUpp-RyuEm>BYBMzFKc%^G_G7LqSb9n{OL&KD%R9U0OJft zHL1g1WnN2S)3Ot-rEMhcB#BkFe>7)J6_4;YhypyO%#Ettu(w9ajrQm$S)Vh4Kn${4 zPGc&jh_#&e~uMgt}$2!EQRy2^>Zfim5uDPcxYR&>y zeEM46BTA6bPk!Dv5~9^ME_~ck&4pdDwWyfz9wV0BSG6xOM*F(!&hnqPceAA?zCBRC zV^%<3naxo!`iv7EGy2ILBkJoleZo4d7-33po8NOqLK#+vY}PE>Iy+W%98)#ZulxGn z$0g$%RcEX<-YH`vjJ&Vgc0K}2?cMg%w!o1sbLw$-6>&W7{bDVS*_Z6Ku+zt#g&)l} z$bOWbci1np4#t)5a6rq~8q=N4aX@N&4|^p`L)_C|vT_$F`^0#-C*1wiUR5;CpL_e5 zF|yth{$;#{XR5jETGOIkW|kzxk?{@hY_0EAbTIL|)@sb4{XMNVBPv>T)(g(qfnC-@Z&h(Z-6fGz zS4vyUT*&caE5~z8dg42*vT(hxVi#o}n1d*{ZH<{iM{HYdoL1{>nH`MyY^@1orGdE- z5y%&c^!dFbfAv4wpWim)*Uyz}51CIYQaf8KYg4QEtHl&{eBQ@qL`03*dAqZjaY3HX zfg@4hl)sK&Wd%qpPj6t|Fe350KUWmakWsRB*4W7Y!hR#UI~6<48rC@adE0r`1m9H} z^1XiR)$h?1>H9#vYaKB08AVjXryVo*HEwZ0ACx1wGPKLBbj6uN9CJ-RCT4qvM9aoH zqpC;Ty{GpRE3)MCc;tu){dBHpR#iqyz8A($_2`y#=9bov6_2%t$e5VFuK0VuuS}nR zb>j46U!TDa9N$$|sQ94PiPq}+*W4-jT`|+l6<8~ylC4ApoC8tIo;SkqLe&Nz@|xF7 z{D1X~maGxMeod^;(J`|a>w=gQt~%PbXHAKCg=@?;%d9oKRR>vpyNcwbm#j!CQ5Z9! zvRdzN9&z=~AX7tpW^&*d$JJVo;-kU$dHi6BMr?W)+sAd-T`ewo278QH^ zK4rD)W8!7ZmlNNyXU;gQqRr_^YA&obJ|J0HV`}qwMqOPAJa7iqZFFUoS3`Ws`(Zmn zZtRI)nlDKiwp~-SH{?mkx6rcI#Ke4TqQqKl_`RRa9Oc?v8FTzB3->uhL^0q^6EdoU;pZ^9J*$>`eW%|W_~MbkT#PD+1IpJk`&4+ zqtRzik4zu&DDNwdJ#QIx6yi^atq2`|7CYlATgLv3_1D;BV8&&C2rq8RMjlu3ZWlQ;n-g>yXSiYS=q8ZpX2#^*PoD z73VVgtkOUmWmcd)pmBwr<)e)fn|bAR@#=UqS_$%9*4ntd_EC<+*reaON_%?6?)lXS z%AW1&7*%J7cx@Ug_*ReQ{O zzp>w4WMF$y zTb714RwmZbtp9x?x|JPl1jDkM2>vnIYFVr3olJ$aU1^VM+<%nyCr7ttS1Z%0vM$rs zG7@$LKpM{~(26zl+^K){J?Vk2+&KezVCLkJm7rLksH{B5$Ulk3Wh7iP--??N6B0wg zT5pSMZzUY|Z1f~qrAvLz?jP zic`JK`o1b7*PW#dy*Pg2pU-C0KI2Kg8eiGPLe62cKdEw!GK;cAW(_T|vl|}ZR7p4 z?k`^G-`{8ZoPO+V^hC}!ygI30vj4tsYnHA;K7DkSK4xdhuoXl_rH^}TWVLF(`}H^U zF!GE~+`S}Iu@W%`*FgDic9Ah#vByqsdgX7Ki>Zu))tTfflk>vpS~{*A$-ZRZoF7w{ zY*EPy&e-FG89L+Eqza_b8#sw>cVfcGbhk07z+~<&s93J5#?i{GlT~9m{#J zqllX2(bBIxr|hX<5B&O@L{#Z5G9q_J^IE$+8#TPvB3IluYYF|{x%#d2q_qlnG+P_4 zwz;s5JIF&lir1kexd*1AE_>8*MJ<`tUFGxa-!P}=aqH>dMPDldW3Tt@>ibaMXe;4( z+I-U1%q}qtphoD7bap66a#6>sv;O3KIkSkh+m2OtTFvYsO$@xoA8SpEx@S*B#@+Mg z7FE2&7#uSh$<41=Z&m|V&f$u+B)a5mgIFq$maM9*Q6$%wk(uk~oT-p&pS&}zz^+og zLtlNGZIJHiOL z_;dNDrEaZ}c{ivl)yAGbmS|+QnQ>+Hgz9+w8xSHN?u9OWz>>pL~jn zNUqg;t*1Q^F+{Ce=JS~u<@}Yl+ydOs-lB@kRYhM_Sa8%;>b*=>~IOmLBUUXw;$$@F5xbj{d;vwFP%RJWEDKWR~l%PlFeYq~gx?F1D&Pq61sc~KMm)7YgkJ}$eBgApZ zEFrC)?^n^t*YfSX->cO-*KCB_J?742P5d1W%gV%xQ>++_J#EgPa;CP*IGH9#s~zUz zrkh>E2#*<{S>MDP(*{&oN`5F=d9r7jdktIR-sN2kO^L~9j}cA!3q~8v9%Mgw-Pza8 zitt(sXDl^hlLJ_YGxX%Iv8qHq92t!{jn5fw?e})yxAv4g9OXSma1z6H#s1M~;ag;P z>LM|7{6CtvuU5_|4D0OPv5E~;497eRuD^O}e|1g0V?~QNI#HPpc}$;}@%fOFwS&1z za&~i*@s$;=T2oprX2W_LtH}3g70f%V-LvU|FIe_h)baO?)F!KO&6qMCuX>Q20$Z_T zu_|kQHtQ{k>hOE6Hjshqp5&S@_+Dsv*Y|c3_s{K?x#hza9awqd71efTY)l-e`kd@A z_O+kQS#zy|Xy@z~u89|GPUzRviQI*;R^~f+7K~(u^%KYCYrJ=CuBK+=Zo);n9j%^ z_5-vRJ2YUA0?S*Gw@56tR-hA6U0DP4LGFq13=_s=+LPC6zC6tz-`^WtGwobvyVctz z9YA`)vMl8FS-PuJV>UowmL&ymz?>K;-?817-%2P~qRFcdr%NdZb z{+xNFy9JL{IR$G(V_EV4I)iO@EvxqO7!^&sw8jBKDFzn(>T`IZcdzb2vBN6%Rk5je zRS~bvilbSsuAV$Q-63PPs<(Beva`T?=j%y~i|7>Nz={%^|8~Yvlh3 zRh_opT1Au6%5sKMR>D~|WIr?Od>1|w``P-G_@v+S>@uR|6|Gt8lu9^g(wyB z{F$BB8Y!#bPq5pw2X0qAPEBQIkVqBTOMWWE%J^8dy4q4}&ASdlMNZyJTi+hCX|#|v zg0{%2x%QmAQeyx<(P4*v)jVF&|KN*U$j*)WX}yNzxQbq}6;(d|XsvlZ3=#LN(ok;P z>1C;`*m?E3>GPz2>R~vSJYM&n-I|mk9?!K9_uH9U0_^JHkdhopSD>xkaIc7 z1FR8gvf9(zq~6pDO5!(_hmt*goch4NChkBzvn7dsO&qS_RnEA3-XZ-lr-|xLbM^N1 zlU?rMyiNL_ch42rA-`?PgRPGCeVwXYWsBWAM%5YJ=dn~{NoKk3OmdKxPF`84i#T*c zmq#s!{*`%+W9^kWkx1(~eN9CR^_y`Oi6$y1V-22lEPg8yg1Xk{TNEIr?F3RPmg)nO zi&cSPhoKSQuUp37Ash9Nx`zQItDRoD41)LS3%B|kL?$}1mt@&)76CPsC zJ{3tT3*ftBE%dw)RwV5sotwFOOC*&!XfL~zNN7cM&wE1UqnWp*sA;WCR1C|Q!wJsa zp3V4P(lfqIyg)Ioy+~Gw8T)1S%4?*@ySnfMt~#d+U7ZYP@nqJV&#~spT+Esg|4o?~NRcZc>FJe0 zuKvJ&+?ZHC{Vr|Cuy;9qR~m9HHp{!~8Akb}#N9fWVWZ6S1FOS(v!z`TwY6$r`;@aj zo+#Z?kwVRCW_UK#H zCS%yF2Xn4LeSTGCbJPmr9%~{tpIEmdB}OlM*(Ewq(Y!TUqYYUn#i;fro$1q)a|c|j ztTm>}3(Ng?hsp48+=sD&L(m zVn-JFl-cBAusc%HsYzIM7Ws;hWZWZ(UFXLhb01a~LB%DLGhcgE_WJD=?mc4|Mv0@Y zFy_~Pbx)%4vs=xRe#g{4r^Iu1i6c+TFl`vUgd@TZnYH%P8a!g%S5}v;o>9`u{$G0m zTp_Acd$NY+ygVloT=zTqj7&)m(Np(Utk14mSBg;`^U@J1^vNR{b&{9fygcNundeoE zJJ;2?OnrV!?YCi8X>CX^pWFm`(tTG^?rT=gg&lU6AARpM&4X%{pN$@t>8EU|*;lk)2#d@IGJ> zvxd6Qda}wdk5W1Iy&qd`Q1rq2W$g`?U5-K>^< zZ6u=W+*$+meHW@UKt484o5r_QnN=iRqceO*KQ-IPDwAUs)|$AY ziT~skd;N{M>8Wlb2E97vDbFCwUVTGivqH*t)7rgeMGmy$Uf6WY;d;(gHH>>Z;m@ZN5 zd>VkTa{GK%TBWy~W^C5CkieW`n3+nA(sS;={I_cfD^Aa7&ikRvnN#2Ndubo#$9dlK zmLtt#@nq-^pgz4@YOTyw`>Cjyk-w8eSpVb7p%)rFMK3KJP?(`ZYc5nALaO zPZUaa`8!{!dhACN|CLCZq^M>Z)Y-&8KBvsA75GG!z1CHd8$6qGes#6+>2}_0`Spyl zjr!OURn87;aO?^<>cGkV=CRk|GhEqX>!zEjuKGiMUh@!TVJEfEn?4Iu6HzKW80oiovO`jVx%X0Mq+9m`&j@ua$@zG?O! za|Yd`yQ%9;h?<8Q>uPb#QI%QwhdNWu%af&aLeeN7$;dq#<8HL{gut(~&0P>}&sk--&9w}+~`^83yovxQiTy87zx z%q47LFIN=Tb~e|jy?Kw(YVA<9mudI<5WBZO6?U<5sCtph^e0@oT;ZCR)$A;Ja7202 zFTOjY|9ZFg$xK%q0nHB{*j7%UCUa-SSStF;oR#ro_ETkzh&k~Ng{XMCeXJ~bF2w#IeNT7WZBa)4~9Yc=jd>_cBjJeqw_tWVU~J#$sgKm5QNHQY1T z%i3OjzN2qhxXh@va*6(D<%VeeZZ4XzUit?61X~>EW$NP-KX%21ZQ+baCSLNpTH$*u zmsQ$2U4*FFT3e+?B<5nBNNm6vUiIPZBJB7D?e0}pAv=~5-$@)^Xk@aaG{f8X$qB)g z*R%dRt)bAJC&ic^0PZbq&B*9E3YlfBGmbJa-#KYPx z#|_6*zV&rm=486=P=LxmumvS%tamuKZ=FMw*h`J-$vj{clQR&rI#>JHGYiyoDNf)y zH*4xxzT@cBretNUK4`^DsWa9IKPlJK^D@p~{a)o)*2ti3{+qS!6^-@one|?+|LPU% z9dS;VS6k-R<4A;U)2?3nacQBi>ub7-bY5RS_7lZnzhYpWOhuY zZu6*XCY6j*=3cexOJsIbfBGFM%lG6{WgRhFKZ)V)Ili`uk}F=9W!9GPXpB&5jwPEQ ztIUo7Ke4JxUCwdJwH^F$&q_#sm)YC>?wWQS!%k(}(u@jaIT*z!tKZSSQ9#a+u@5uu znUez9necMc?4?S zkk+)!<1dk%yfRltS+}iGs{NI!_^jTn@kEu^tQVUJZU3F@C0gwoHSFwCMttqwnROE7 zQC2UHPi!JF+^c7ed&g$U9cEp>_H(|w%Zjk7j(glOj#h0Pu}|!Y&&eYnNE(%Ft6t9J z>opfC84kN%97W~o#PN)T6;q)E?)nnAc0{XffmjRf-C6YhY426jGICYKTAv0j39t=( zH-Vf!Y3*|0l%c%l_4(~}mR_xor#v0y9&;zjP^#P%S5!RhpRax{?HT7Au^{7SqIW!( zkdgGVYh1QxAgx`*YmZNM*AQ*yuC3i)M&A?jw3MVz9x`KAqBFfje`>D0M|bJfSA;b2 zsQO##4{;h=OtM<}q)$p|l?Gi+?|wR1MMo$#dnWq3EZKUu&oh}daiS#kJiVyy_`G+@ zbx7&(IM;|iU+nfjZp7m174=y=7%q5ZGuc?dI_8}_b5qWFA=2SYwrc&1oOq{uHzd%_H}>ntGjkgR?8VXM7DUX4q6XcLE_Z3^}g0Fko4cR zXZ~m_LU%3l!uo=>oE%usmVZpGxq9u_ue~N~ob0@sn6sr~*FVNuuRYm$um9i|Rj*>i zA+f~Pc70&3rmR(oTASYSYTt8VMJU+Xz&HdX=J*pLRR~E)Gdnbd%DAo>-rJv>*IG@MyQRShi*2E|{yTGk!^ii2{ z6A9y_)0fWv`TgEs-|zj=+$Cxq^4gvo+aL>nHuakBpQ@IAUwK=0+Wkk~W9IaZ8FOys zB|R{E$Wl)$9)nE_ZQ9L0+*}<%*RQ zBUOFa?z_lbmNh+Qx5Ti9@6O0`t^c{B=cDx4Nngkl%~_Gv(z5EcKL2(^%EWOfk&4NA zhOBbbPNVEvATFHP;HXR0T!fff{;jg)9Qj%9%=t6rydv7RO#CD(MwaD@)g^+KyfMp# zc$XEK-bqZw_-%VAK!vBKhI*FmYQ`7R?rj^sP}=A zY|f`x`p!PdjC2y{g%@={THu`icNr4$>Df*GW4_UegZA@oqTJ8FHR{-;AsGIlEU*(V^@onXfC( zNvtiWB)sote_HbGvGMaGwmXY9C3**Z5X@SfPXx)j1SL~C~Rz(w6yQzPj z<;rUO;bT>%E~{s|etTvcL?bJgLsduBg6NB!iISo6oJX&n%&MejM@!DGpxmXOX3b}< zu~093_vr)cOc33rqNbHk=!)&g-TX8^V}6=aR-bZ9pS+90Q^)Nkea(tlZ2xxbx7RNe zF;&j)I6CX1!lnmT(TLG&rAG$nDVXa1S?yA0H=G;An&G}uZZ=qUO>tLu_HA(CK7o#2 zvD?I&$?&cID0iDztga7rhJPUoQVe};uAMR@E0&fh?Yz9;j%neia7a@)?Me|a>!rdu zd(UYqS&QQI<>zWmXSSCHAm}5@l?ZC<#Q3U_UX*Y(bm;7hij1CT7m67ZDOuw z>K_r9BYX*S$K*lQnOupeiS;UU`nuy4qqrGUjyQ>vIou7C`%inrjHY%|WR1+Iq;a{m zD}(%pcb^+`$y#yNR$M7$ANJ66WBKf`psaA_iuS&tD)cqGfq(Vd&yw5+dA*tgYGv$C zj5Z|eTouPNES)3Fvl$`CxbQJ|be-a#H7HtL#?Q3&=Fil6Xfop7|2fuRZo4v>IVWOd zmVOr5b4o{@p^`0nm3U1 zfgV%G2WvNA#tCijRnOxsp^^N*(v|N>xI`5vA-3X|=fyWe!tEb1b)X_u8gR**5 zpJ3(61mpDKdyMg~T!K$%gw zT7BLqkE+zRjY2i9`Lye=pNV?U+h?wsQ{ojygwx}5UEN1cw3@bPjgsD1`*i#r6S!h& ziLlXMRYa4Kyeo9h`(EEPmU5Kb%!nnURaU%|7f>4+yRF_fr}pH867wp~Ti%&(tg(nK z#nnBpigmN|jv7CIe2C}mDkJ=8p5SJCq`cSJ1X22mvgdS!UEh6WhK)$zpR=9P&+OiF z%vW(q$Fa}Oj(>IL@d*XaCdRRu9jIH4{J`FykYMKPJ6s~~i9DCuv74DL(Hly4YO1FX zhzGwiKdV1zI9patoI_V;jn?NKR&5KC3>|hqjkuVSka>gZS*eidy&=6vM(U)}gj#Wr|6^|opXS)E0=<0LUgU>$+?&$y2fQZo5CDO#4j zm7R9QiTy^zw(Wh_N#yj2HJ+vStksmflcP~4ldG&F-?7W8uAUL|4v%^l zDf_=y4!1npm?b=NfIr(YyC%lDzh+)AW>vjo4`z&=mVZSsiK1{n+?%>iORG^-okryB zEiHSZ+g<~rCCY2-YNs?^o1IJqDKP+g8P|Ig75bWz+v3cLBGLx5Sd%_|viYd2tFLve z^bh&@;E}v+_#e&u(v>epE`>PzwI)-iWq5CDl-Qw{u8;`TRz-5`WlE3VGf#^%(solK z^PVf?(Uk$`CP(ZB^D91+#gj+Jv&El32-Qa;&t%V^%Lsm*p>@S|kx^BvgzWa<{1fkX z3)#w8RMsaWfb*7F+lf`aB|A^(X77B8lsRwiTBwyv;nWp9Hhykt77r7EOk+#*R98?}qPFHh&Dvz8@4s`@%rypk;WaLPTM&0m=N-JDRIBpXR`g&Iw&c@k}?CKJpyz?aF0gSAmPT!K%Q5>F~J;_sA zx$0bb;@Xxo*SaL*XRJhWw^ppp|Ls-rRjxT~^20L%sXU-+!*Vj+I=8u^(OI4GnJBM} zQ+XZN?MHu?g=-JK=AECYFg_=P!F8~e-?58oi65^Sj_M)RPcR}E23so*LSA=IoT#gp zj4gVmib>k5>~<`9l>f|%rd2Yw_SxLSu+{*w_VM2aB<&(ijnc4NQWyZzIk3EWILbJUdlO4?o$i!;1J0Q7S zzend3X{@oXWTKV#SL9wLtOlS9;ztz4-0xMD}qUkm=i%go1JY>c>xGbi_s zGcKz2qla6cV&Q1cD^g!qr~Sc z>)$rS^BMhoV#W~<>^zx0UblLruM)Suvq41i>9xr?taX^(ybtDK#?~?m5lXFytu-@g zz82P&7>@m(q%@u-np4@HMT#s7tZ}6eS?lYRSX;@QAa9>%e25)lI|kZOj<1zJZfR3i zqWKKFYK!;G-p(;)TGtvMRBq$Z2AVY{(tTkfozW#ueArc`EaB-%i3ruGfoMxUQ^AO| zuGse6UWOTK{V$@EoQBeGZ5vnTDKq9@Gb3T1!r8RxWs{*(>&f(%91 zI7Qp?wDaz+NhEIOe9u;|aFnw5>;vtwiI#BTbJ zbCG&A?CY<;5Q=0?tMzdrn$p@wqn|NOl5vTjtdwY|SxH8Q$1m!1g31x-h>??nwa!kV zw|b9W80n;SeZ(EP$B}#I-(*KZ+PbVO=4>tRB{9D|w{5Die`N|e5z3iw&W~WHMzS9* z)#hw5R#axF2@@X?LH};f*gyMk`4}Z|s$I*x2}Pzt`Cy zX*tI4h*5CbQDyDx7tFRRche{W*)e=Rlvc#~t8KS*Df@7S6gk08Z zqB8o^>ec?mV_wbRKa6Kdf87l9^Y(w7OYHnc)xj&Iw0G`+t$2-xhF8z3f{}qW{ZR&GQM5SwUv~Tm3S8 zZnW+9ihCzYO{A1n>pmlz*Smw8*5uOxD1(yd5qR&jT;G$c8U6j?*4 z*4Gp7G7EGzw@zwxtY}>z#+tY`>wJ{Pn!{xcik!Kl`Kr~Gki9;v-qLfjCyC6I)qlID zUitOA8vfZ<++^i}IFhfCw9yQCANql@E5m~(_gTGipUoW-UayQ&%_TH;Mz2B*@Kils zxj7QfSjBaFH20jXsAq#`NoIi7Fd0y_3w8LqBd&m6)>1h3z&=vl#f}yIJni0X{dO_o z%AiVrxN64HDvH)_nX)AyO1(a_Dtp$*>rYK$jFEYEUg?_izphEl0Qa-$$tz}xyngrp E0p>-wfB*mh diff --git a/src/testdir/test_sound.vim b/src/testdir/test_sound.vim new file mode 100644 --- /dev/null +++ b/src/testdir/test_sound.vim @@ -0,0 +1,45 @@ +" Tests for the sound feature + +if !has('sound') + throw 'Skipped: sound feature not available' +endif + +func PlayCallback(id, result) + let g:id = a:id + let g:result = a:result +endfunc + +func Test_play_event() + let id = sound_playevent('bell', 'PlayCallback') + if id == 0 + throw 'Skipped: bell event not available' + endif + " Stop it quickly, avoid annoying the user. + sleep 20m + call sound_stop(id) + sleep 20m + call assert_equal(id, g:id) + call assert_equal(1, g:result) " sound was aborted +endfunc + +func Test_play_silent() + let fname = fnamemodify('silent.wav', '%p') + + " play without callback + let id1 = sound_playfile(fname) + call assert_true(id1 > 0) + + " play until the end + let id2 = sound_playfile(fname, 'PlayCallback') + call assert_true(id2 > 0) + sleep 500m + call assert_equal(id2, g:id) + call assert_equal(0, g:result) + + let id2 = sound_playfile(fname, 'PlayCallback') + call assert_true(id2 > 0) + sleep 20m + call sound_stopall() + call assert_equal(id2, g:id) + call assert_equal(1, g:result) +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -580,6 +580,16 @@ static char *(features[]) = #else "-smartindent", #endif +#ifdef FEAT_SOUND + "+sound", +#else + "-sound", +#endif +#ifdef FEAT_SPELL + "+spell", +#else + "-spell", +#endif #ifdef STARTUPTIME "+startuptime", #else @@ -768,6 +778,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1502, +/**/ 1501, /**/ 1500,