diff --git a/.github/workflows/linux_and_macos.yml b/.github/workflows/linux_and_macos.yml index 48c791d43..86dc5d7e9 100644 --- a/.github/workflows/linux_and_macos.yml +++ b/.github/workflows/linux_and_macos.yml @@ -75,7 +75,8 @@ jobs: libasound2-dev \ libsdl1.2-dev \ libgl1-mesa-dev \ - pkg-config + pkg-config \ + portaudio19-dev - name: Install build dependency Clang ${{ matrix.clang_major_version }} (Linux) if: "${{ runner.os == 'Linux' && contains(matrix.cxx, 'clang') }}" @@ -102,6 +103,7 @@ jobs: mesa-glu \ orc \ pkg-config \ + portaudio \ sdl12-compat - name: Setting dynamic environment variables diff --git a/libvisual-plugins/configure.ac b/libvisual-plugins/configure.ac index 2d7b97de9..88ac7621c 100644 --- a/libvisual-plugins/configure.ac +++ b/libvisual-plugins/configure.ac @@ -111,6 +111,21 @@ else fi fi +dnl PortAudio +AC_ARG_ENABLE([portaudio], AS_HELP_STRING([--disable-portaudio], + [Do not build PortAudio input plugin @<:@default=enabled@:>@]), + [ENABLE_INPUT_PORTAUDIO=$enableval], + [ENABLE_INPUT_PORTAUDIO=yes]) +AS_IF([test "$ENABLE_INPUT_PORTAUDIO" = yes], [ + PKG_CHECK_MODULES([PORTAUDIO], [portaudio-2.0], [HAVE_PORTAUDIO="yes"], [HAVE_PORTAUDIO="no"]) + AS_IF([test "$HAVE_PORTAUDIO" = yes], [ + build_input_plugins="$build_input_plugins portaudio" + ], [ + AC_MSG_WARN([*** Could not find PortAudio. + The PortAudio input plugin won't be built.]) + ]) +]) + dnl GdkPixbuf AC_ARG_ENABLE([gdkpixbuf-plugin], AS_HELP_STRING([--disable-gdkpixbuf-plugin], @@ -556,6 +571,7 @@ AC_CONFIG_FILES([ plugins/input/mplayer/Makefile plugins/input/jack/Makefile plugins/input/debug/Makefile + plugins/input/portaudio/Makefile plugins/morph/Makefile plugins/morph/alphablend/Makefile plugins/morph/tentacle/Makefile diff --git a/libvisual-plugins/plugins/input/Makefile.am b/libvisual-plugins/plugins/input/Makefile.am index 1b4da3ba1..a9f349bfe 100644 --- a/libvisual-plugins/plugins/input/Makefile.am +++ b/libvisual-plugins/plugins/input/Makefile.am @@ -1,4 +1,4 @@ SUBDIRS = $(build_input_plugins) -DIST_SUBDIRS = mplayer jack alsa debug +DIST_SUBDIRS = mplayer jack alsa debug portaudio diff --git a/libvisual-plugins/plugins/input/portaudio/Makefile.am b/libvisual-plugins/plugins/input/portaudio/Makefile.am new file mode 100644 index 000000000..42d664c5b --- /dev/null +++ b/libvisual-plugins/plugins/input/portaudio/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to generate a Makefile.in + +input_plugin_LTLIBRARIES = input_portaudio.la + +input_portaudio_la_SOURCES = input_portaudio.c +input_portaudio_la_CPPFLAGS = -I$(top_srcdir) +input_portaudio_la_CFLAGS = $(LIBVISUAL_CFLAGS) $(PORTAUDIO_CFLAGS) +input_portaudio_la_LIBADD = $(LIBVISUAL_LIBS) $(PORTAUDIO_LIBS) +input_portaudio_la_LDFLAGS = -module -avoid-version diff --git a/libvisual-plugins/plugins/input/portaudio/input_portaudio.c b/libvisual-plugins/plugins/input/portaudio/input_portaudio.c new file mode 100644 index 000000000..ffa634fec --- /dev/null +++ b/libvisual-plugins/plugins/input/portaudio/input_portaudio.c @@ -0,0 +1,173 @@ +/* Libvisual-plugins - Standard plugins for libvisual + * + * Copyright (C) 2023 Sebastian Pipping + * + * Authors: Sebastian Pipping + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include // malloc + +#include +#include "gettext.h" +#include + +VISUAL_PLUGIN_API_VERSION_VALIDATOR + +#define SAMPLE_RATE 44100 +#define SAMPLE_RATE_TYPE_LV VISUAL_AUDIO_SAMPLE_RATE_44100 +#define CHANNELS 2 +#define CHANNELS_TYPE VISUAL_AUDIO_SAMPLE_CHANNEL_STEREO +#define SAMPLE_FORMAT_BITS 16 +#define SAMPLE_FORMAT_PA paInt16 +#define SAMPLE_FORMAT_LV VISUAL_AUDIO_SAMPLE_FORMAT_S16 + +#define FRAMES 1024 + +typedef struct { + PaStream *stream; + void * buffer; +} PortAudioPrivate; + +static int inp_portaudio_init (VisPluginData *plugin); +static int inp_portaudio_cleanup (VisPluginData *plugin); +static int inp_portaudio_upload (VisPluginData *plugin, VisAudio *audio); + +const VisPluginInfo *get_plugin_info (int *count) +{ + static VisInputPlugin input[] = {{ + .upload = inp_portaudio_upload + }}; + + static VisPluginInfo info[] = {{ + .type = VISUAL_PLUGIN_TYPE_INPUT, + + .plugname = "portaudio", + .name = "portaudio", + .author = "Sebastian Pipping ", + .version = "1.0", + .about = N_("PortAudio capture plugin"), + .help = N_("Use this plugin to capture PCM data from the PortAudio record device"), + .license = VISUAL_PLUGIN_LICENSE_LGPL, + + .init = inp_portaudio_init, + .cleanup = inp_portaudio_cleanup, + + .plugin = VISUAL_OBJECT (&input[0]) + }}; + + *count = sizeof (info) / sizeof (*info); + + return info; +} + +int inp_portaudio_init (VisPluginData *plugin) +{ +#if ENABLE_NLS + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); +#endif + + PortAudioPrivate * const priv = visual_mem_new0 (PortAudioPrivate, 1); + visual_log_return_val_if_fail(priv != NULL, -1); + visual_object_set_private (VISUAL_OBJECT (plugin), priv); + + // Init PortAudio + const PaError init_error = Pa_Initialize(); + visual_log_return_val_if_fail (init_error == paNoError, -2); + + // Select input device + const PaDeviceIndex input_device = Pa_GetDefaultInputDevice (); + visual_log_return_val_if_fail (input_device != paNoDevice, -3); + + // Open stream + const double latency_seconds = 1.0 / SAMPLE_RATE * FRAMES; + const PaStreamParameters input_parameters = { + .device = input_device, + .channelCount = CHANNELS, + .sampleFormat = SAMPLE_FORMAT_PA, + .suggestedLatency = latency_seconds, + .hostApiSpecificStreamInfo = NULL}; + const PaError open_error = + Pa_OpenStream (&priv->stream, &input_parameters, NULL, + SAMPLE_RATE, FRAMES, paClipOff, NULL, NULL); + + // Allocate buffer + const visual_size_t buffer_size_bytes = FRAMES * CHANNELS * (SAMPLE_FORMAT_BITS / 8); + priv->buffer = malloc (buffer_size_bytes); + visual_log_return_val_if_fail (priv->buffer != NULL, -4); + + // Start stream + const PaError input_start_error = Pa_StartStream (priv->stream); + visual_log_return_val_if_fail (input_start_error == paNoError, -4); + + return 0; +} + +int inp_portaudio_cleanup (VisPluginData *plugin) +{ + visual_log_return_val_if_fail (plugin != NULL, -1); + + PortAudioPrivate * const priv = visual_object_get_private (VISUAL_OBJECT (plugin)); + visual_log_return_val_if_fail (priv != NULL, -2); + + free (priv->buffer); + priv->buffer = NULL; + + Pa_StopStream (priv->stream); + Pa_CloseStream (priv->stream); + priv->stream = NULL; + + Pa_Terminate (); + + visual_mem_free (priv); + + return 0; +} + +int inp_portaudio_upload (VisPluginData *plugin, VisAudio *audio) +{ + visual_log_return_val_if_fail (plugin != NULL, -1); + visual_log_return_val_if_fail (audio != NULL, -2); + + PortAudioPrivate * const priv = visual_object_get_private (VISUAL_OBJECT (plugin)); + visual_log_return_val_if_fail (priv != NULL, -3); + visual_log_return_val_if_fail (priv->stream != NULL, -4); + + for (;;) { + long frames_to_read = Pa_GetStreamReadAvailable (priv->stream); + if (frames_to_read < 1) { + return 0; + } + if (frames_to_read > FRAMES) { + frames_to_read = FRAMES; // because that's all that priv->buffer has space for + } + + const PaError read_error = Pa_ReadStream(priv->stream, priv->buffer, frames_to_read); + if (read_error != paNoError) { + return 0; + } + + const visual_size_t bytes_to_write = frames_to_read * CHANNELS * (SAMPLE_FORMAT_BITS / 8); + + VisBuffer buffer; + visual_buffer_init(&buffer, priv->buffer, bytes_to_write, NULL); + + visual_audio_samplepool_input(audio->samplepool, &buffer, SAMPLE_RATE_TYPE_LV, + SAMPLE_FORMAT_LV, CHANNELS_TYPE); + } + + // we never get here +} diff --git a/libvisual-plugins/po/POTFILES.in b/libvisual-plugins/po/POTFILES.in index 7279f2cc9..9b7de902b 100644 --- a/libvisual-plugins/po/POTFILES.in +++ b/libvisual-plugins/po/POTFILES.in @@ -20,3 +20,4 @@ plugins/input/alsa/input_alsa.c plugins/input/debug/input_debug.c plugins/input/jack/input_jack.c plugins/input/mplayer/input_mplayer.c +plugins/input/portaudio/input_portaudio.c diff --git a/libvisual-plugins/po/de.po b/libvisual-plugins/po/de.po index ca4cb1703..f40199df8 100644 --- a/libvisual-plugins/po/de.po +++ b/libvisual-plugins/po/de.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: libvisual-plugins 0.4.0\n" "Report-Msgid-Bugs-To: https://github.com/Libvisual/libvisual/issues/\n" -"POT-Creation-Date: 2023-01-14 20:48+0100\n" +"POT-Creation-Date: 2023-01-21 03:37+0100\n" "PO-Revision-Date: 2017-11-23 18:08:07+0200\n" "Last-Translator: Chris Leick \n" "Language-Team: German \n" @@ -519,3 +519,13 @@ msgstr "falscher Dateideskriptor %d" #, c-format msgid "Could not munmap() area %p+%d. %s" msgstr "munmap() von Bereich %p+%d nicht möglich. %s" + +#: plugins/input/portaudio/input_portaudio.c:62 +msgid "PortAudio capture plugin" +msgstr "PortAudio-Erfassungserweiterung" + +#: plugins/input/portaudio/input_portaudio.c:63 +msgid "Use this plugin to capture PCM data from the PortAudio record device" +msgstr "" +"Benutzen Sie diese Erweiterung, um PCM-Daten vom PortAudio-Aufzeichungsgerät " +"zu erfassen." diff --git a/libvisual-plugins/po/es_AR.po b/libvisual-plugins/po/es_AR.po index dc49d0cb7..67dd72d13 100644 --- a/libvisual-plugins/po/es_AR.po +++ b/libvisual-plugins/po/es_AR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Libvisual plugins 0.3.0\n" "Report-Msgid-Bugs-To: https://github.com/Libvisual/libvisual/issues/\n" -"POT-Creation-Date: 2023-01-14 20:48+0100\n" +"POT-Creation-Date: 2023-01-21 03:37+0100\n" "PO-Revision-Date: 2005-03-16 00:11-0300\n" "Last-Translator: Duilio Javier Protti \n" "Language-Team: Spanish \n" @@ -504,6 +504,16 @@ msgstr "%d es un descriptor de archivo erróneo" msgid "Could not munmap() area %p+%d. %s" msgstr "No se puede munmap()-ear área %p+%d: %s" +#: plugins/input/portaudio/input_portaudio.c:62 +msgid "PortAudio capture plugin" +msgstr "Plugin de captura de audio PortAudio" + +#: plugins/input/portaudio/input_portaudio.c:63 +msgid "Use this plugin to capture PCM data from the PortAudio record device" +msgstr "" +"Use este plugin para capturar datos PCM del dispositivo de grabación " +"PortAudio" + #~ msgid "This plugin shows multiple visual effect using openGL" #~ msgstr "Éste plugin muestra múltiples efectos visuales utilizando OpenGL" diff --git a/libvisual-plugins/po/es_ES.po b/libvisual-plugins/po/es_ES.po index bc2fdf726..2f195e35c 100644 --- a/libvisual-plugins/po/es_ES.po +++ b/libvisual-plugins/po/es_ES.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Libvisual plugins 0.3.0\n" "Report-Msgid-Bugs-To: https://github.com/Libvisual/libvisual/issues/\n" -"POT-Creation-Date: 2023-01-14 20:48+0100\n" +"POT-Creation-Date: 2023-01-21 03:37+0100\n" "PO-Revision-Date: 2005-03-16 00:11-0300\n" "Last-Translator: Duilio Javier Protti \n" "Language-Team: Spanish \n" @@ -504,6 +504,16 @@ msgstr "%d es un descriptor de archivo erróneo" msgid "Could not munmap() area %p+%d. %s" msgstr "No se puede munmap()-ear área %p+%d: %s" +#: plugins/input/portaudio/input_portaudio.c:62 +msgid "PortAudio capture plugin" +msgstr "Plugin de captura de audio PortAudio" + +#: plugins/input/portaudio/input_portaudio.c:63 +msgid "Use this plugin to capture PCM data from the PortAudio record device" +msgstr "" +"Use este plugin para capturar datos PCM del dispositivo de grabación " +"PortAudio" + #~ msgid "This plugin shows multiple visual effect using openGL" #~ msgstr "Éste plugin muestra múltiples efectos visuales utilizando OpenGL" diff --git a/libvisual-plugins/po/libvisual-plugins-0.4.pot b/libvisual-plugins/po/libvisual-plugins-0.4.pot index c5d9a1839..e796cdf90 100644 --- a/libvisual-plugins/po/libvisual-plugins-0.4.pot +++ b/libvisual-plugins/po/libvisual-plugins-0.4.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: libvisual-plugins 0.4.1\n" "Report-Msgid-Bugs-To: https://github.com/Libvisual/libvisual/issues/\n" -"POT-Creation-Date: 2023-01-14 20:48+0100\n" +"POT-Creation-Date: 2023-01-21 03:37+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -477,3 +477,11 @@ msgstr "" #, c-format msgid "Could not munmap() area %p+%d. %s" msgstr "" + +#: plugins/input/portaudio/input_portaudio.c:62 +msgid "PortAudio capture plugin" +msgstr "" + +#: plugins/input/portaudio/input_portaudio.c:63 +msgid "Use this plugin to capture PCM data from the PortAudio record device" +msgstr ""