Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package audaspace for openSUSE:Factory 
checked in at 2026-07-17 18:49:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/audaspace (Old)
 and      /work/SRC/openSUSE:Factory/.audaspace.new.24530 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "audaspace"

Fri Jul 17 18:49:37 2026 rev:26 rq:1366361 version:1.10.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/audaspace/audaspace.changes      2026-03-23 
17:11:45.457653857 +0100
+++ /work/SRC/openSUSE:Factory/.audaspace.new.24530/audaspace.changes   
2026-07-17 18:51:01.328384070 +0200
@@ -1,0 +2,13 @@
+Thu Jul 16 21:08:38 UTC 2026 - Marcus Rueckert <[email protected]>
+
+- Update to release 1.10.0
+  - Improved audio capture support with OpenAL adding the
+    possibility to choose a device (thanks Yogeshgouda Patil)
+  - More build fixes for Mac and SDL3 support (thanks Jonas
+    Holzman)
+  - Fixed cancellation of mixdown (thanks Kévin Dietrich)
+  - Several more build and bug fixes (thanks Aras Pranckevicius and
+    Ted Rodgers)
+- replace sdl2 module with the sdl3 module
+
+-------------------------------------------------------------------

Old:
----
  audaspace-1.9.0.tar.gz

New:
----
  audaspace-1.10.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ audaspace.spec ++++++
--- /var/tmp/diff_new_pack.Cpi6Kr/_old  2026-07-17 18:51:03.060442622 +0200
+++ /var/tmp/diff_new_pack.Cpi6Kr/_new  2026-07-17 18:51:03.072443028 +0200
@@ -18,8 +18,8 @@
 
 # See also http://en.opensuse.org/openSUSE:Shared_library_packaging_policy
 # NOTE: sover follows version.
-%define sover 1_9
-%define soversion 1.9
+%define sover 1_10
+%define soversion 1.10
 
 %if %{pkg_vcmp pipewire-devel >= 1.4.0}
 %bcond_without pipewire
@@ -28,7 +28,7 @@
 %endif
 
 Name:           audaspace
-Version:        1.9.0
+Version:        1.10.0
 Release:        0
 Summary:        A High-Level Audio Library
 License:        Apache-2.0
@@ -52,7 +52,8 @@
 BuildRequires:  pkgconfig(libpipewire-0.3)
 BuildRequires:  pkgconfig(libpulse)
 BuildRequires:  pkgconfig(openal)
-BuildRequires:  pkgconfig(sdl2)
+BuildRequires:  pkgconfig(rubberband)
+BuildRequires:  pkgconfig(sdl3)
 BuildRequires:  pkgconfig(sndfile)
 
 %description
@@ -111,14 +112,14 @@
 This package contains the Pipewire plugin
 %endif
 
-%package        plugin-sdl2
-Summary:        SDL2 plugin for %{name}
+%package        plugin-sdl3
+Summary:        sdl3 plugin for %{name}
 Group:          System/Libraries
 Provides:       audaspace-deviceplugin
 
-%description    plugin-sdl2
+%description    plugin-sdl3
 Audaspace (pronounced "outer space") is a high-level audio library.
-This package contains the SDL2 plugin
+This package contains the sdl3 plugin
 
 %package        plugin-sndfile
 Summary:        Sndfile plugin for %{name}
@@ -234,7 +235,7 @@
 %{_libdir}/%{name}-%{soversion}/libaudpipewire.so
 %endif
 
-%files plugin-sdl2
+%files plugin-sdl3
 %{_libdir}/%{name}-%{soversion}/libaudsdl.so
 
 %files plugin-sndfile

++++++ audaspace-1.9.0.tar.gz -> audaspace-1.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/AUTHORS new/audaspace-1.10.0/AUTHORS
--- old/audaspace-1.9.0/AUTHORS 2026-03-20 18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/AUTHORS        2026-07-16 22:24:57.000000000 +0200
@@ -19,7 +19,7 @@
 
 - Marcos Perez
 
-Some performance improvements, especially to the JOSResampler have been made by
+Some fixes and performance improvements, especially to the JOSResampler have 
been made by
 
 - Aras Pranckevičius
 
@@ -35,6 +35,10 @@
 
 - AGoldenDragon
 
+Capture device functionality of OpenAL has been improved by
+
+- Yogeshgouda Patil
+
 Several people provided fixes:
 
 - Aaron Carlisle
@@ -48,3 +52,5 @@
 - Andrej Zhilenkov
 - Jacques Lucke
 - Ray Molenkamp
+- Kévin Dietrich
+- Ted Rodgers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/CHANGES new/audaspace-1.10.0/CHANGES
--- old/audaspace-1.9.0/CHANGES 2026-03-20 18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/CHANGES        2026-07-16 22:24:57.000000000 +0200
@@ -1,3 +1,23 @@
+Audaspace 1.10
+
+- Improved audio capture support with OpenAL adding the possibility to choose 
a device (thanks Yogeshgouda Patil)
+- More build fixes for Mac and SDL3 support (thanks Jonas Holzman)
+- Fixed cancellation of mixdown (thanks Kévin Dietrich)
+- Several more build and bug fixes (thanks Aras Pranckevicius and Ted Rodgers)
+
+Detailed list of changes:
+
+a69e6e0 Porting changes from Blender upstream.
+096cb28 Remove DefaultSampleRate and make values into constexpr.
+d6fbaa8 add 3 missing includes for gcc-17
+1eb0a9d Fix sound.data() crash on non-existing file
+21afb9a Fix AnimateableProperty::writeConstantRange resulting in garbage 
values when resampling
+437349a Bugfix: wrongly spaced animation updates.
+206f7a5 Upgrade SDL backend plugin from SDL2 to SDL3
+546b749 Mixdown, FileWriter: allow cancelation via callback
+f946ead Build: macOS: Fix deprecated enum float comparison warning in Audaspace
+b433cd9 Audaspace: Add OpenAL capture support (#68)
+
 Audaspace 1.9
 
 - New Echo effect (thanks AGoldenDragon)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/CMakeLists.txt 
new/audaspace-1.10.0/CMakeLists.txt
--- old/audaspace-1.9.0/CMakeLists.txt  2026-03-20 18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/CMakeLists.txt 2026-07-16 22:24:57.000000000 +0200
@@ -14,16 +14,12 @@
 # limitations under the License.
 
################################################################################
 
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.21)
 include(CMakeDependentOption)
 
-if(POLICY CMP0054)
-       cmake_policy(SET CMP0054 NEW)
-endif()
-
 project(audaspace)
 
-set(AUDASPACE_VERSION 1.9)
+set(AUDASPACE_VERSION 1.10)
 set(AUDASPACE_LONG_VERSION ${AUDASPACE_VERSION}.0)
 
 if(DEFINED AUDASPACE_CMAKE_CFG)
@@ -146,6 +142,7 @@
        include/devices/DeviceManager.h
        include/devices/I3DDevice.h
        include/devices/I3DHandle.h
+       include/devices/ICaptureDeviceFactory.h
        include/devices/IDeviceFactory.h
        include/devices/IDevice.h
        include/devices/IHandle.h
@@ -329,7 +326,7 @@
        cmake_dependent_option(PLUGIN_SDL "Build SDL Plugin" TRUE 
"WITH_SDL;SHARED_LIBRARY" FALSE)
        cmake_dependent_option(PLUGIN_WASAPI "Build WASAPI Plugin" TRUE 
"WITH_WASAPI;SHARED_LIBRARY" FALSE)
        cmake_dependent_option(WITH_PYTHON_MODULE "Build Python Module" TRUE 
"WITH_PYTHON" FALSE)
-       cmake_dependent_option(USE_SDL2 "Use SDL2 instead of 1 if available" 
TRUE "WITH_SDL" FALSE)
+       cmake_dependent_option(USE_SDL3 "Use SDL3" TRUE "WITH_SDL" FALSE)
        cmake_dependent_option(DYNLOAD_JACK "Dynamically load JACK" FALSE 
"WITH_JACK" FALSE)
        cmake_dependent_option(DYNLOAD_PULSEAUDIO "Dynamically load PulseAudio" 
FALSE "WITH_PULSEAUDIO" FALSE)
        cmake_dependent_option(DYNLOAD_PIPEWIRE "Dynamically load PipeWire" 
FALSE "WITH_PIPEWIRE" FALSE)
@@ -837,11 +834,11 @@
 # SDL
 if(WITH_SDL)
        if(AUDASPACE_STANDALONE)
-               if(USE_SDL2)
-                       find_package(SDL2)
-                       if(SDL2_FOUND)
-                               set(SDL_INCLUDE_DIR ${SDL2_INCLUDE_DIR})
-                               set(SDL_LIBRARY ${SDL2_LIBRARY})
+               if(USE_SDL3)
+                       find_package(SDL3 CONFIG)
+                       if(SDL3_FOUND)
+                               get_target_property(SDL_INCLUDE_DIR 
SDL3::Headers INTERFACE_INCLUDE_DIRECTORIES)
+                               set(SDL_LIBRARY SDL3::SDL3)
                                set(SDL_FOUND TRUE)
                        else()
                                find_package(SDL ${PACKAGE_OPTION})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/README.md 
new/audaspace-1.10.0/README.md
--- old/audaspace-1.9.0/README.md       2026-03-20 18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/README.md      2026-07-16 22:24:57.000000000 +0200
@@ -32,7 +32,7 @@
 License
 -------
 
-> Copyright © 2009-2025 Jörg Müller. All rights reserved.
+> Copyright © 2009-2026 Jörg Müller. All rights reserved.
 >
 > Licensed under the Apache License, Version 2.0 (the "License");
 > you may not use this file except in compliance with the License.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/bindings/C/AUD_Device.cpp 
new/audaspace-1.10.0/bindings/C/AUD_Device.cpp
--- old/audaspace-1.9.0/bindings/C/AUD_Device.cpp       2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/bindings/C/AUD_Device.cpp      2026-07-16 
22:24:57.000000000 +0200
@@ -51,7 +51,7 @@
                dspecs.channels = CHANNELS_STEREO;
        if(dspecs.format == FORMAT_INVALID)
                dspecs.format = FORMAT_FLOAT32;
-       if(dspecs.rate == double(RATE_INVALID))
+       if(dspecs.rate == RATE_INVALID)
                dspecs.rate = RATE_48000;
        if(buffersize < 128)
                buffersize = AUD_DEFAULT_BUFFER_SIZE;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/bindings/C/AUD_Sound.cpp 
new/audaspace-1.10.0/bindings/C/AUD_Sound.cpp
--- old/audaspace-1.9.0/bindings/C/AUD_Sound.cpp        2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/bindings/C/AUD_Sound.cpp       2026-07-16 
22:24:57.000000000 +0200
@@ -174,7 +174,7 @@
                DeviceSpecs specs;
                specs.specs = reader->getSpecs();
 
-               if((rate != double(RATE_INVALID)) && (specs.rate != rate))
+               if((rate != RATE_INVALID) && (specs.rate != rate))
                {
                        specs.rate = rate;
                        reader = std::make_shared<JOSResampleReader>(reader, 
rate);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/bindings/C/AUD_Special.cpp 
new/audaspace-1.10.0/bindings/C/AUD_Special.cpp
--- old/audaspace-1.9.0/bindings/C/AUD_Special.cpp      2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/bindings/C/AUD_Special.cpp     2026-07-16 
22:24:57.000000000 +0200
@@ -270,7 +270,7 @@
        return length;
 }
 
-AUD_API int AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int 
length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, 
AUD_Container format, AUD_Codec codec, unsigned int bitrate, 
AUD_ResampleQuality quality, void(*callback)(float, void*), void* data, char* 
error, size_t errorsize)
+AUD_API int AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int 
length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, 
AUD_Container format, AUD_Codec codec, unsigned int bitrate, 
AUD_ResampleQuality quality, bool(*callback)(float, void*), void* data, char* 
error, size_t errorsize)
 {
        try
        {
@@ -295,7 +295,7 @@
        }
 }
 
-AUD_API int AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, 
unsigned int length, unsigned int buffersize, const char* filename, 
AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int 
bitrate, AUD_ResampleQuality quality, void(*callback)(float, void*), void* 
data, char* error, size_t errorsize)
+AUD_API int AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, 
unsigned int length, unsigned int buffersize, const char* filename, 
AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int 
bitrate, AUD_ResampleQuality quality, bool(*callback)(float, void*), void* 
data, char* error, size_t errorsize)
 {
        try
        {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/bindings/C/AUD_Special.h 
new/audaspace-1.10.0/bindings/C/AUD_Special.h
--- old/audaspace-1.9.0/bindings/C/AUD_Special.h        2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/bindings/C/AUD_Special.h       2026-07-16 
22:24:57.000000000 +0200
@@ -72,7 +72,7 @@
  * \param codec The codec used for encoding the audio data.
  * \param bitrate The bitrate for encoding.
  * \param quality The resampling quality.
- * \param callback A callback function that is called periodically during 
mixdown, reporting progress if length > 0. Can be NULL.
+ * \param callback A callback function that is called periodically during 
mixdown, reporting progress if length > 0. Mixdown is canceled if the callback 
returns false. Can be NULL.
  * \param data Pass through parameter that is passed to the callback.
  * \param error String buffer to copy the error message to in case of failure.
  * \param errorsize The size of the error buffer.
@@ -82,7 +82,7 @@
                                                           unsigned int 
buffersize, const char* filename,
                                                           AUD_DeviceSpecs 
specs, AUD_Container format,
                                                           AUD_Codec codec, 
unsigned int bitrate, AUD_ResampleQuality quality,
-                                                          
void(*callback)(float, void*), void* data, char* error, size_t errorsize);
+                                                          
bool(*callback)(float, void*), void* data, char* error, size_t errorsize);
 
 /**
  * Mixes a sound down into multiple files.
@@ -96,7 +96,7 @@
  * \param codec The codec used for encoding the audio data.
  * \param bitrate The bitrate for encoding.
  * \param quality The resampling quality.
- * \param callback A callback function that is called periodically during 
mixdown, reporting progress if length > 0. Can be NULL.
+ * \param callback A callback function that is called periodically during 
mixdown, reporting progress if length > 0. Mixdown is canceled if the callback 
returns false. Can be NULL.
  * \param data Pass through parameter that is passed to the callback.
  * \param error String buffer to copy the error message to in case of failure.
  * \param errorsize The size of the error buffer.
@@ -106,7 +106,7 @@
                                                                                
   unsigned int buffersize, const char* filename,
                                                                                
   AUD_DeviceSpecs specs, AUD_Container format,
                                                                                
   AUD_Codec codec, unsigned int bitrate, AUD_ResampleQuality quality,
-                                                                               
   void(*callback)(float, void*), void* data, char* error, size_t errorsize);
+                                                                               
   bool(*callback)(float, void*), void* data, char* error, size_t errorsize);
 
 /**
  * Opens a read device and prepares it for mixdown of the sound scene.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/bindings/python/PySound.cpp 
new/audaspace-1.10.0/bindings/python/PySound.cpp
--- old/audaspace-1.9.0/bindings/python/PySound.cpp     2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/bindings/python/PySound.cpp    2026-07-16 
22:24:57.000000000 +0200
@@ -133,25 +133,33 @@
 static PyObject *
 Sound_data(Sound* self)
 {
-       std::shared_ptr<ISound> sound = 
*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound);
-
-       auto stream_buffer = std::dynamic_pointer_cast<StreamBuffer>(sound);
-       if(!stream_buffer)
-               stream_buffer = std::make_shared<StreamBuffer>(sound);
-       Specs specs = stream_buffer->getSpecs();
-       auto buffer = stream_buffer->getBuffer();
-
-       npy_intp dimensions[2];
-       dimensions[0] = buffer->getSize() / AUD_SAMPLE_SIZE(specs);
-       dimensions[1] = specs.channels;
-
-       PyArrayObject* array = 
reinterpret_cast<PyArrayObject*>(PyArray_SimpleNew(2, dimensions, NPY_FLOAT));
-
-       sample_t* data = reinterpret_cast<sample_t*>(PyArray_DATA(array));
-
-       std::memcpy(data, buffer->getBuffer(), buffer->getSize());
-
-       return reinterpret_cast<PyObject*>(array);
+       try
+       {
+               std::shared_ptr<ISound> sound = 
*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound);
+
+               auto stream_buffer = 
std::dynamic_pointer_cast<StreamBuffer>(sound);
+               if(!stream_buffer)
+                       stream_buffer = std::make_shared<StreamBuffer>(sound);
+               Specs specs = stream_buffer->getSpecs();
+               auto buffer = stream_buffer->getBuffer();
+
+               npy_intp dimensions[2];
+               dimensions[0] = buffer->getSize() / AUD_SAMPLE_SIZE(specs);
+               dimensions[1] = specs.channels;
+
+               PyArrayObject* array = 
reinterpret_cast<PyArrayObject*>(PyArray_SimpleNew(2, dimensions, NPY_FLOAT));
+
+               sample_t* data = 
reinterpret_cast<sample_t*>(PyArray_DATA(array));
+
+               std::memcpy(data, buffer->getBuffer(), buffer->getSize());
+
+               return reinterpret_cast<PyObject*>(array);
+       }
+       catch(Exception& e)
+       {
+               PyErr_SetString(AUDError, e.what());
+               return nullptr;
+       }
 }
 
 PyDoc_STRVAR(M_aud_Sound_write_doc,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/cmake/FindSDL2.cmake 
new/audaspace-1.10.0/cmake/FindSDL2.cmake
--- old/audaspace-1.9.0/cmake/FindSDL2.cmake    2026-03-20 18:10:20.000000000 
+0100
+++ new/audaspace-1.10.0/cmake/FindSDL2.cmake   1970-01-01 01:00:00.000000000 
+0100
@@ -1,255 +0,0 @@
-# Locate SDL2 library
-# This module defines
-# SDL2_LIBRARY, the name of the library to link against
-# SDL2_FOUND, if false, do not try to link to SDL2
-# SDL2_INCLUDE_DIR, where to find SDL.h
-#
-# This module responds to the the flag:
-# SDL2_BUILDING_LIBRARY
-# If this is defined, then no SDL2_main will be linked in because
-# only applications need main().
-# Otherwise, it is assumed you are building an application and this
-# module will attempt to locate and set the the proper link flags
-# as part of the returned SDL2_LIBRARY variable.
-#
-# Don't forget to include SDL2main.h and SDL2main.m your project for the
-# OS X framework based version. (Other versions link to -lSDL2main which
-# this module will try to find on your behalf.) Also for OS X, this
-# module will automatically add the -framework Cocoa on your behalf.
-#
-#
-# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
-# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
-# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
-# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
-# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
-# as appropriate. These values are used to generate the final SDL2_LIBRARY
-# variable, but when these values are unset, SDL2_LIBRARY does not get created.
-#
-#
-# $SDL2 is an environment variable that would
-# correspond to the ./configure --prefix=$SDL2
-# used in building SDL2.
-# l.e.galup 9-20-02
-#
-# Modified by Eric Wing.
-# Added code to assist with automated building by using environmental variables
-# and providing a more controlled/consistent search behavior.
-# Added new modifications to recognize OS X frameworks and
-# additional Unix paths (FreeBSD, etc).
-# Also corrected the header search path to follow "proper" SDL2 guidelines.
-# Added a search for SDL2main which is needed by some platforms.
-# Added a search for threads which is needed by some platforms.
-# Added needed compile switches for MinGW.
-#
-# On OSX, this will prefer the Framework version (if found) over others.
-# People will have to manually change the cache values of
-# SDL2_LIBRARY to override this selection or set the CMake environment
-# CMAKE_INCLUDE_PATH to modify the search paths.
-#
-# Note that the header path has changed from SDL2/SDL.h to just SDL.h
-# This needed to change because "proper" SDL2 convention
-# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
-# reasons because not all systems place things in SDL2/ (see FreeBSD).
-#
-# Ported by Johnny Patterson. This is a literal port for SDL2 of the 
FindSDL.cmake
-# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
-# was not created for redistribution, and exists temporarily pending official
-# SDL2 CMake modules.
-#
-# Note that on windows this will only search for the 32bit libraries, to search
-# for 64bit change x86/i686-w64 to x64/x86_64-w64
-
-#=============================================================================
-# Copyright 2003-2009 Kitware, Inc.
-#
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2014 Kitware, Inc.
-# Copyright 2000-2011 Insight Software Consortium
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the names of Kitware, Inc., the Insight Software Consortium,
-# nor the names of their contributors may be used to endorse or promote
-# products derived from this software without specific prior written
-# permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-# License text for the above reference.)
-
-FIND_PATH(SDL2_INCLUDE_DIR SDL.h
-       HINTS
-       ${SDL2}
-       $ENV{SDL2}
-       PATH_SUFFIXES include/SDL2 include SDL2
-       i686-w64-mingw32/include/SDL2
-       x86_64-w64-mingw32/include/SDL2
-       PATHS
-       ~/Library/Frameworks
-       /Library/Frameworks
-       /usr/local/include/SDL2
-       /usr/include/SDL2
-       /sw # Fink
-       /opt/local # DarwinPorts
-       /opt/csw # Blastwave
-       /opt
-)
-
-# Lookup the 64 bit libs on x64
-IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
-       FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2
-               HINTS
-               ${SDL2}
-               $ENV{SDL2}
-               PATH_SUFFIXES lib64 lib
-               lib/x64
-               x86_64-w64-mingw32/lib
-               PATHS
-               /sw
-               /opt/local
-               /opt/csw
-               /opt
-       )
-# On 32bit build find the 32bit libs
-ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
-       FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2
-               HINTS
-               ${SDL2}
-               $ENV{SDL2}
-               PATH_SUFFIXES lib
-               lib/x86
-               i686-w64-mingw32/lib
-               PATHS
-               /sw
-               /opt/local
-               /opt/csw
-               /opt
-       )
-ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
-
-IF(NOT SDL2_BUILDING_LIBRARY)
-       IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
-               # Non-OS X framework versions expect you to also dynamically 
link to
-               # SDL2main. This is mainly for Windows and OS X. Other (Unix) 
platforms
-               # seem to provide SDL2main for compatibility even though they 
don't
-               # necessarily need it.
-               # Lookup the 64 bit libs on x64
-               IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
-                       FIND_LIBRARY(SDL2MAIN_LIBRARY
-                               NAMES SDL2main
-                               HINTS
-                               ${SDL2}
-                               $ENV{SDL2}
-                               PATH_SUFFIXES lib64 lib
-                               lib/x64
-                               x86_64-w64-mingw32/lib
-                               PATHS
-                               /sw
-                               /opt/local
-                               /opt/csw
-                               /opt
-                               )
-                       # On 32bit build find the 32bit libs
-               ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
-                       FIND_LIBRARY(SDL2MAIN_LIBRARY
-                               NAMES SDL2main
-                               HINTS
-                               ${SDL2}
-                               $ENV{SDL2}
-                               PATH_SUFFIXES lib
-                               lib/x86
-                               i686-w64-mingw32/lib
-                               PATHS
-                               /sw
-                               /opt/local
-                               /opt/csw
-                               /opt
-                               )
-               ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
-       ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
-ENDIF(NOT SDL2_BUILDING_LIBRARY)
-
-# SDL2 may require threads on your system.
-# The Apple build may not need an explicit flag because one of the
-# frameworks may already provide it.
-# But for non-OSX systems, I will use the CMake Threads package.
-IF(NOT APPLE)
-       FIND_PACKAGE(Threads)
-ENDIF(NOT APPLE)
-
-# MinGW needs an additional library, mwindows
-# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
-# (Actually on second look, I think it only needs one of the m* libraries.)
-IF(MINGW)
-       SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
-ENDIF(MINGW)
-
-SET(SDL2_FOUND "NO")
-       IF(SDL2_LIBRARY_TEMP)
-               # For SDL2main
-               IF(NOT SDL2_BUILDING_LIBRARY)
-                       IF(SDL2MAIN_LIBRARY)
-                               SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} 
${SDL2_LIBRARY_TEMP})
-                       ENDIF(SDL2MAIN_LIBRARY)
-               ENDIF(NOT SDL2_BUILDING_LIBRARY)
-
-               # For OS X, SDL2 uses Cocoa as a backend so it must link to 
Cocoa.
-               # CMake doesn't display the -framework Cocoa string in the UI 
even
-               # though it actually is there if I modify a pre-used variable.
-               # I think it has something to do with the CACHE STRING.
-               # So I use a temporary variable until the end so I can set the
-               # "real" variable in one-shot.
-               IF(APPLE)
-                       SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework 
Cocoa")
-               ENDIF(APPLE)
-
-               # For threads, as mentioned Apple doesn't need this.
-               # In fact, there seems to be a problem if I used the Threads 
package
-               # and try using this line, so I'm just skipping it entirely for 
OS X.
-               IF(NOT APPLE)
-                       SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} 
${CMAKE_THREAD_LIBS_INIT})
-               ENDIF(NOT APPLE)
-
-               # For MinGW library
-               IF(MINGW)
-                       SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} 
${SDL2_LIBRARY_TEMP})
-               ENDIF(MINGW)
-
-               # Set the final string here so the GUI reflects the final state.
-               SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the 
SDL2 Library can be found")
-               # Set the temp variable to INTERNAL so it is not seen in the 
CMake GUI
-               SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
-
-               SET(SDL2_FOUND "YES")
-ENDIF(SDL2_LIBRARY_TEMP)
-
-INCLUDE(FindPackageHandleStandardArgs)
-
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY 
SDL2_INCLUDE_DIR)
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/include/devices/DeviceManager.h 
new/audaspace-1.10.0/include/devices/DeviceManager.h
--- old/audaspace-1.9.0/include/devices/DeviceManager.h 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/include/devices/DeviceManager.h        2026-07-16 
22:24:57.000000000 +0200
@@ -23,6 +23,7 @@
  */
 
 #include "Audaspace.h"
+#include "respec/Specification.h"
 
 #include <memory>
 #include <vector>
@@ -33,7 +34,9 @@
 
 class IDevice;
 class IDeviceFactory;
+class ICaptureDeviceFactory;
 class I3DDevice;
+class IReader;
 
 /**
  * This class manages all device plugins and maintains a device if asked to do 
so.
@@ -47,6 +50,7 @@
        static std::unordered_map<std::string, std::shared_ptr<IDeviceFactory>> 
m_factories;
 
        static std::shared_ptr<IDevice> m_device;
+       static std::unordered_map<std::string, 
std::shared_ptr<ICaptureDeviceFactory>> m_capture_factories;
 
        // delete copy constructor and operator=
        DeviceManager(const DeviceManager&) = delete;
@@ -125,6 +129,37 @@
         * @return A list of strings with the names of available devices.
         */
        static std::vector<std::string> getAvailableDeviceNames();
+
+       /**
+        * Returns a list of available capture devices.
+        * @return A list of strings with the names of available capture 
devices.
+        */
+       static std::vector<std::string> getAvailableCaptureDeviceNames();
+
+       /**
+        * Returns the factory for a specific capture device.
+        * @param name The representative name of the capture device.
+        * @return The factory if it was found, or nullptr otherwise.
+        */
+       static std::shared_ptr<ICaptureDeviceFactory> 
getCaptureDeviceFactory(const std::string& name);
+
+       /**
+        * Registers a capture device factory.
+        * @param name A representative name for the capture device.
+        * @param factory The factory that creates the capture reader.
+        */
+       static void registerCaptureDevice(const std::string& name, 
std::shared_ptr<ICaptureDeviceFactory> factory);
+
+       /**
+        * Opens an input capture reader.
+        * @param name The capture device name.
+        * @param specs The desired specification.
+        * @param buffersize The capture buffer size in samples.
+        */
+       static std::shared_ptr<IReader> openCaptureDevice(const std::string& 
name,
+                                                        Specs specs,
+                                                        int buffersize = 
AUD_DEFAULT_BUFFER_SIZE);
+
 };
 
 AUD_NAMESPACE_END
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/audaspace-1.9.0/include/devices/ICaptureDeviceFactory.h 
new/audaspace-1.10.0/include/devices/ICaptureDeviceFactory.h
--- old/audaspace-1.9.0/include/devices/ICaptureDeviceFactory.h 1970-01-01 
01:00:00.000000000 +0100
+++ new/audaspace-1.10.0/include/devices/ICaptureDeviceFactory.h        
2026-07-16 22:24:57.000000000 +0200
@@ -0,0 +1,46 @@
+#pragma once
+
+/**
+ * @file ICaptureDeviceFactory.h
+ * @ingroup devices
+ * The ICaptureDeviceFactory interface.
+ */
+
+#include "Audaspace.h"
+#include "respec/Specification.h"
+
+#include <memory>
+#include <string>
+
+AUD_NAMESPACE_BEGIN
+
+class IReader;
+
+/**
+ * @interface ICaptureDeviceFactory
+ * The ICaptureDeviceFactory interface opens an input capture device.
+ */
+class AUD_API ICaptureDeviceFactory
+{
+public:
+       /**
+        * Destroys the capture device factory.
+        */
+       virtual ~ICaptureDeviceFactory() {}
+
+       /**
+        * Opens an audio capture device.
+        * \param specs The desired specification.
+        * \param buffersize The capture buffer size in samples.
+        * \exception Exception Thrown if the audio device cannot be opened.
+        */
+       virtual std::shared_ptr<IReader> openDevice(Specs specs, int 
buffersize)=0;
+
+       /**
+        * Sets a name for the capture device.
+        * \param name The internal name for the capture device.
+        */
+       virtual void setName(const std::string &name)=0;
+};
+
+AUD_NAMESPACE_END
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/include/file/FileWriter.h 
new/audaspace-1.10.0/include/file/FileWriter.h
--- old/audaspace-1.9.0/include/file/FileWriter.h       2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/include/file/FileWriter.h      2026-07-16 
22:24:57.000000000 +0200
@@ -63,7 +63,7 @@
         * \param length How many samples should be transferred.
         * \param buffersize How many samples should be transferred at once.
         */
-       static void writeReader(std::shared_ptr<IReader> reader, 
std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, 
void(*callback)(float, void*) = nullptr, void* data = nullptr);
+       static void writeReader(std::shared_ptr<IReader> reader, 
std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, 
bool(*callback)(float, void*) = nullptr, void* data = nullptr);
 
        /**
         * Writes a reader to several writers.
@@ -72,7 +72,7 @@
         * \param length How many samples should be transferred.
         * \param buffersize How many samples should be transferred at once.
         */
-       static void writeReader(std::shared_ptr<IReader> reader, 
std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned 
int buffersize, void(*callback)(float, void*) = nullptr, void* data = nullptr);
+       static void writeReader(std::shared_ptr<IReader> reader, 
std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned 
int buffersize, bool(*callback)(float, void*) = nullptr, void* data = nullptr);
 };
 
 AUD_NAMESPACE_END
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/include/respec/Specification.h 
new/audaspace-1.10.0/include/respec/Specification.h
--- old/audaspace-1.9.0/include/respec/Specification.h  2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/include/respec/Specification.h 2026-07-16 
22:24:57.000000000 +0200
@@ -92,27 +92,24 @@
        HIGH         /// JOS resample at high quality preset.
 };
 
+/// Sample rate type.
+typedef double SampleRate;
+
 /**
  * The sample rate tells how many samples are played back within one second.
  * Some exotic formats may use other sample rates than provided here.
  */
-enum DefaultSampleRate
-{
-       RATE_INVALID = 0,                       /// Invalid sample rate.
-       RATE_8000    = 8000,            /// 8000 Hz.
-       RATE_16000   = 16000,           /// 16000 Hz.
-       RATE_11025   = 11025,           /// 11025 Hz.
-       RATE_22050   = 22050,           /// 22050 Hz.
-       RATE_32000   = 32000,           /// 32000 Hz.
-       RATE_44100   = 44100,           /// 44100 Hz.
-       RATE_48000   = 48000,           /// 48000 Hz.
-       RATE_88200   = 88200,           /// 88200 Hz.
-       RATE_96000   = 96000,           /// 96000 Hz.
-       RATE_192000  = 192000           /// 192000 Hz.
-};
-
-/// Sample rate type.
-typedef double SampleRate;
+constexpr SampleRate RATE_INVALID = 0;                 /// Invalid sample rate.
+constexpr SampleRate RATE_8000    = 8000;              /// 8000 Hz.
+constexpr SampleRate RATE_16000   = 16000;             /// 16000 Hz.
+constexpr SampleRate RATE_11025   = 11025;             /// 11025 Hz.
+constexpr SampleRate RATE_22050   = 22050;             /// 22050 Hz.
+constexpr SampleRate RATE_32000   = 32000;             /// 32000 Hz.
+constexpr SampleRate RATE_44100   = 44100;             /// 44100 Hz.
+constexpr SampleRate RATE_48000   = 48000;             /// 48000 Hz.
+constexpr SampleRate RATE_88200   = 88200;             /// 88200 Hz.
+constexpr SampleRate RATE_96000   = 96000;             /// 96000 Hz.
+constexpr SampleRate RATE_192000  = 192000;            /// 192000 Hz.
 
 /// Specification of a sound source.
 struct Specs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/audaspace-1.9.0/include/sequence/AnimateableProperty.h 
new/audaspace-1.10.0/include/sequence/AnimateableProperty.h
--- old/audaspace-1.9.0/include/sequence/AnimateableProperty.h  2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/include/sequence/AnimateableProperty.h 2026-07-16 
22:24:57.000000000 +0200
@@ -73,6 +73,7 @@
        AnimateableProperty& operator=(const AnimateableProperty&) = delete;
 
        void AUD_LOCAL updateUnknownCache(int start, int end);
+       void AUD_LOCAL updateUnknownAfterWrite(int pos, int position, int 
count);
 
 public:
        /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/openal/OpenALDevice.cpp 
new/audaspace-1.10.0/plugins/openal/OpenALDevice.cpp
--- old/audaspace-1.9.0/plugins/openal/OpenALDevice.cpp 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/openal/OpenALDevice.cpp        2026-07-16 
22:24:57.000000000 +0200
@@ -15,6 +15,7 @@
  
******************************************************************************/
 
 #include "OpenALDevice.h"
+#include "OpenALReader.h"
 
 #include <chrono>
 #include <cstring>
@@ -24,6 +25,7 @@
 #include "ISound.h"
 
 #include "devices/DeviceManager.h"
+#include "devices/ICaptureDeviceFactory.h"
 #include "devices/IDeviceFactory.h"
 #include "generator/SilenceReader.h"
 #include "respec/ConverterReader.h"
@@ -931,7 +933,7 @@
 
                                        ALCint attribs[] = { ALC_FREQUENCY, 
(ALCint)specs.rate, 0 };
                                        ALCint* attributes = attribs;
-                                       if(specs.rate == double(RATE_INVALID))
+                                       if(specs.rate == RATE_INVALID)
                                                attributes = nullptr;
 
                                        m_context = alcCreateContext(m_device, 
attributes);
@@ -1152,7 +1154,7 @@
        // at least try to set the frequency
        ALCint attribs[] = { ALC_FREQUENCY, (ALCint)specs.rate, 0 };
        ALCint* attributes = attribs;
-       if(specs.rate == double(RATE_INVALID))
+       if(specs.rate == RATE_INVALID)
                attributes = nullptr;
 
        m_context = alcCreateContext(m_device, attributes);
@@ -1652,14 +1654,42 @@
        }
 };
 
+class OpenALCaptureDeviceFactory : public ICaptureDeviceFactory
+{
+private:
+       std::string m_name;
+
+public:
+       OpenALCaptureDeviceFactory(const std::string& name = "") :
+               m_name(name)
+       {
+       }
+
+       virtual std::shared_ptr<IReader> openDevice(Specs specs, int buffersize)
+       {
+               return std::shared_ptr<IReader>(new OpenALReader(specs, 
buffersize, m_name));
+       }
+
+       virtual void setName(const std::string& name)
+       {
+               m_name = name;
+       }
+};
+
 void OpenALDevice::registerPlugin()
 {
        auto names = OpenALDevice::getDeviceNames();
+       auto capture_names = OpenALReader::getDeviceNames();
        DeviceManager::registerDevice("OpenAL", 
std::shared_ptr<IDeviceFactory>(new OpenALDeviceFactory));
+       DeviceManager::registerCaptureDevice("OpenAL", 
std::shared_ptr<ICaptureDeviceFactory>(new OpenALCaptureDeviceFactory));
        for(const std::string &name : names)
        {
                DeviceManager::registerDevice("OpenAL - " + name, 
std::shared_ptr<IDeviceFactory>(new OpenALDeviceFactory(name)));
        }
+       for(const std::string& name : capture_names)
+       {
+               DeviceManager::registerCaptureDevice("OpenAL - " + name, 
std::shared_ptr<ICaptureDeviceFactory>(new OpenALCaptureDeviceFactory(name)));
+       }
 }
 
 #ifdef OPENAL_PLUGIN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/openal/OpenALReader.cpp 
new/audaspace-1.10.0/plugins/openal/OpenALReader.cpp
--- old/audaspace-1.9.0/plugins/openal/OpenALReader.cpp 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/openal/OpenALReader.cpp        2026-07-16 
22:24:57.000000000 +0200
@@ -20,18 +20,23 @@
 
 #include <algorithm>
 #include <al.h>
+#include <cstdint>
+#include <cstring>
+#include <vector>
 
 AUD_NAMESPACE_BEGIN
 
-OpenALReader::OpenALReader(Specs specs, int buffersize) :
+OpenALReader::OpenALReader(Specs specs, int buffersize, const std::string& 
name) :
        m_specs(specs),
        m_position(0),
        m_device(nullptr)
 {
        if((specs.channels != CHANNELS_MONO) && (specs.channels != 
CHANNELS_STEREO))
                specs.channels = CHANNELS_MONO;
+       m_specs.channels = specs.channels;
 
-       m_device = alcCaptureOpenDevice(nullptr, specs.rate,
+       const char* device_name = name.empty() ? nullptr : name.c_str();
+       m_device = alcCaptureOpenDevice(device_name, specs.rate,
                                                                        
specs.channels == CHANNELS_MONO ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
                                                                        
buffersize * specs.channels * 2);
 
@@ -45,11 +50,48 @@
 {
        if(m_device)
        {
-               //alcCaptureStop(m_device);
+               alcCaptureStop(m_device);
                alcCaptureCloseDevice(m_device);
        }
 }
 
+std::vector<std::string> OpenALReader::getDeviceNames()
+{
+       std::vector<std::string> names;
+
+       /* ALC_CAPTURE_DEVICE_SPECIFIER requires ALC_ENUMERATION_EXT.
+       * Without it alcGetString may return garbage on some drivers. */
+       if(!alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
+               return names;
+
+       const ALCchar* devices = alcGetString(nullptr, 
ALC_CAPTURE_DEVICE_SPECIFIER);
+       if(devices != nullptr)
+       {
+               const ALCchar* cursor = devices;
+               while(*cursor != '\0')
+               {
+                       names.push_back(cursor);
+                       cursor += std::strlen(cursor) + 1;
+               }
+       }
+
+       const ALCchar* default_device = alcGetString(nullptr, 
ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+       if(default_device != nullptr && default_device[0] != '\0')
+       {
+               const std::string default_name(default_device);
+               auto it = std::find(names.begin(), names.end(), default_name);
+               if(it == names.end())
+                       names.insert(names.begin(), default_name);
+               else if(it != names.begin())
+               {
+                       names.erase(it);
+                       names.insert(names.begin(), default_name);
+               }
+       }
+
+       return names;
+}
+
 bool OpenALReader::isSeekable() const
 {
        return false;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/openal/OpenALReader.h 
new/audaspace-1.10.0/plugins/openal/OpenALReader.h
--- old/audaspace-1.9.0/plugins/openal/OpenALReader.h   2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/openal/OpenALReader.h  2026-07-16 
22:24:57.000000000 +0200
@@ -29,6 +29,8 @@
 #include "IReader.h"
 
 #include <alc.h>
+#include <string>
+#include <vector>
 
 AUD_NAMESPACE_BEGIN
 
@@ -67,11 +69,18 @@
         * Creates a new reader.
         * \param specs The desired specification of the output samples.
         * \param buffersize The buffer size used to read from the device.
+        * \param name The name of the capture device.
         */
-       OpenALReader(Specs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
+       OpenALReader(Specs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE, 
const std::string& name = "");
 
        virtual ~OpenALReader();
 
+       /**
+        * Lists all available OpenAL capture devices.
+        * \return Device names.
+        */
+       static std::vector<std::string> getDeviceNames();
+
        virtual bool isSeekable() const;
        virtual void seek(int position);
        virtual int getLength() const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/pipewire/PipeWireDevice.h 
new/audaspace-1.10.0/plugins/pipewire/PipeWireDevice.h
--- old/audaspace-1.9.0/plugins/pipewire/PipeWireDevice.h       2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/pipewire/PipeWireDevice.h      2026-07-16 
22:24:57.000000000 +0200
@@ -26,6 +26,8 @@
  * The PipeWireDevice class.
  */
 
+#include <string>
+
 #include <pipewire/pipewire.h>
 
 #include "devices/MixingThreadDevice.h"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/audaspace-1.9.0/plugins/pulseaudio/PulseAudioDevice.cpp 
new/audaspace-1.10.0/plugins/pulseaudio/PulseAudioDevice.cpp
--- old/audaspace-1.9.0/plugins/pulseaudio/PulseAudioDevice.cpp 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/pulseaudio/PulseAudioDevice.cpp        
2026-07-16 22:24:57.000000000 +0200
@@ -22,6 +22,8 @@
 #include "devices/DeviceManager.h"
 #include "devices/IDeviceFactory.h"
 
+#include <string>
+
 AUD_NAMESPACE_BEGIN
 
 void PulseAudioDevice::preMixingWork(bool playing)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/audaspace-1.9.0/plugins/pulseaudio/PulseAudioDevice.h 
new/audaspace-1.10.0/plugins/pulseaudio/PulseAudioDevice.h
--- old/audaspace-1.9.0/plugins/pulseaudio/PulseAudioDevice.h   2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/pulseaudio/PulseAudioDevice.h  2026-07-16 
22:24:57.000000000 +0200
@@ -30,6 +30,8 @@
 
 #include "devices/MixingThreadDevice.h"
 
+#include <string>
+
 AUD_NAMESPACE_BEGIN
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/sdl/SDLDevice.cpp 
new/audaspace-1.10.0/plugins/sdl/SDLDevice.cpp
--- old/audaspace-1.9.0/plugins/sdl/SDLDevice.cpp       2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/sdl/SDLDevice.cpp      2026-07-16 
22:24:57.000000000 +0200
@@ -22,104 +22,91 @@
 
 AUD_NAMESPACE_BEGIN
 
-void SDLDevice::SDL_mix(void* data, Uint8* buffer, int length)
+void SDLDevice::SDL_mix(void* userdata, SDL_AudioStream* stream, int 
additional_amount, int /*total_amount*/)
 {
-       SDLDevice* device = (SDLDevice*)data;
+       SDLDevice* device = (SDLDevice*)userdata;
 
        if(!device->m_playback)
-       {
-               SDL_PauseAudio(1);
-
-               std::memset(buffer, 0, length);
-
                return;
-       }
 
-       device->mix((data_t*)buffer, length / 
AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
+       const int sample_size = AUD_DEVICE_SAMPLE_SIZE(device->m_specs);
+       const int num_samples = additional_amount / sample_size;
+       data_t* buffer = (data_t*)SDL_stack_alloc(Uint8, additional_amount);
+       device->mix(buffer, num_samples);
+       SDL_PutAudioStreamData(stream, buffer, additional_amount);
+       SDL_stack_free(buffer);
 }
 
 void SDLDevice::playing(bool playing)
 {
-       if(!m_playback)
-               SDL_PauseAudio(playing ? 0 : 1);
+       if(playing)
+               SDL_ResumeAudioStreamDevice(m_stream);
+       else
+               SDL_PauseAudioStreamDevice(m_stream);
 
        m_playback = playing;
 }
 
-SDLDevice::SDLDevice(DeviceSpecs specs, int buffersize) :
-       m_playback(false)
+SDL_AudioSpec SDLDevice::sdl_audiospec_from_device_specs(const DeviceSpecs 
&specs)
 {
-       if(specs.channels == CHANNELS_INVALID)
-               specs.channels = CHANNELS_STEREO;
-       if(specs.format == FORMAT_INVALID)
-               specs.format = FORMAT_FLOAT32;
-       if(specs.rate == RATE_INVALID)
-               specs.rate = RATE_48000;
-
-       m_specs = specs;
+       SDL_AudioSpec audiospec;
 
-       SDL_AudioSpec format, obtained;
-
-       format.freq = m_specs.rate;
-       switch(m_specs.format)
+       switch(specs.format)
        {
        case FORMAT_U8:
-               format.format = AUDIO_U8;
+               audiospec.format = SDL_AUDIO_U8;
                break;
        case FORMAT_S16:
-               format.format = AUDIO_S16SYS;
+               audiospec.format = SDL_AUDIO_S16;
                break;
        case FORMAT_S32:
-               format.format = AUDIO_S32SYS;
+               audiospec.format = SDL_AUDIO_S32;
                break;
        case FORMAT_FLOAT32:
-               format.format = AUDIO_F32SYS;
+               audiospec.format = SDL_AUDIO_F32;
                break;
        default:
-               format.format = AUDIO_F32SYS;
+               audiospec.format = SDL_AUDIO_F32;
                break;
        }
 
-       format.channels = m_specs.channels;
-       format.samples = buffersize;
-       format.callback = SDLDevice::SDL_mix;
-       format.userdata = this;
+       audiospec.channels = specs.channels;
+       audiospec.freq = specs.rate;
 
-       if(SDL_OpenAudio(&format, &obtained) != 0)
-               AUD_THROW(DeviceException, "The audio device couldn't be opened 
with SDL.");
+       return audiospec;
+}
 
-       m_specs.rate = (SampleRate)obtained.freq;
-       m_specs.channels = (Channels)obtained.channels;
+SDLDevice::SDLDevice(DeviceSpecs specs, int buffersize) :
+       m_playback(false),
+       m_stream(nullptr)
+{
+       if(specs.channels == CHANNELS_INVALID)
+               specs.channels = CHANNELS_STEREO;
+       if(specs.format == FORMAT_INVALID)
+               specs.format = FORMAT_FLOAT32;
+       if(specs.rate == RATE_INVALID)
+               specs.rate = RATE_48000;
 
-       switch(obtained.format)
-       {
-       case AUDIO_U8:
-               m_specs.format = FORMAT_U8;
-               break;
-       case AUDIO_S16SYS:
-               m_specs.format = FORMAT_S16;
-               break;
-       case AUDIO_S32SYS:
-               m_specs.format = FORMAT_S32;
-               break;
-       case AUDIO_F32SYS:
-               m_specs.format = FORMAT_FLOAT32;
-               break;
-       default:
-               SDL_CloseAudio();
-               AUD_THROW(DeviceException, "The sample format obtained from SDL 
is not supported.");
-               break;
-       }
+       m_specs = specs;
+
+       if(!SDL_InitSubSystem(SDL_INIT_AUDIO))
+               AUD_THROW(DeviceException, "Failed to initialize SDL Audio 
subsystem.");
+
+       const SDL_AudioSpec audiospec = sdl_audiospec_from_device_specs(specs);
+       m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, 
&audiospec, SDLDevice::SDL_mix, this);
+
+       if(!m_stream)
+               AUD_THROW(DeviceException, "The audio device couldn't be opened 
with SDL.");
 
        create();
 }
 
 SDLDevice::~SDLDevice()
 {
-       SDL_PauseAudio(1);
-       SDL_CloseAudio();
-
        destroy();
+
+       SDL_DestroyAudioStream(m_stream);
+       SDL_QuitSubSystem(SDL_INIT_AUDIO);
 }
 
 class SDLDeviceFactory : public IDeviceFactory
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/sdl/SDLDevice.h 
new/audaspace-1.10.0/plugins/sdl/SDLDevice.h
--- old/audaspace-1.9.0/plugins/sdl/SDLDevice.h 2026-03-20 18:10:20.000000000 
+0100
+++ new/audaspace-1.10.0/plugins/sdl/SDLDevice.h        2026-07-16 
22:24:57.000000000 +0200
@@ -28,7 +28,7 @@
 
 #include "devices/SoftwareDevice.h"
 
-#include <SDL.h>
+#include <SDL3/SDL.h>
 
 AUD_NAMESPACE_BEGIN
 
@@ -44,12 +44,24 @@
        bool m_playback;
 
        /**
-        * Mixes the next bytes into the buffer.
-        * \param data The SDL device.
-        * \param buffer The target buffer.
-        * \param length The length in bytes to be filled.
+        * The SDL audio stream.
         */
-       AUD_LOCAL static void SDL_mix(void* data, Uint8* buffer, int length);
+       SDL_AudioStream* m_stream;
+
+       /**
+        * SDL callback to mix the next bytes into the audio stream.
+        * Uses the SDL_AudioStreamCallback signature.
+        * \param userdata The SDL device.
+        * \param stream The target audio stream.
+        * \param additional_amount The number of bytes needed.
+        * \param total_amount The total amount of data buffered.
+        */
+       AUD_LOCAL static void SDL_mix(void* userdata, SDL_AudioStream* stream, 
int additional_amount, int total_amount);
+
+       /**
+        * Helper function to convert Audaspace DeviceSpecs structs to SDL 
SDL_AudioSpec structs.
+        */
+       AUD_LOCAL static SDL_AudioSpec sdl_audiospec_from_device_specs(const 
DeviceSpecs &specs);
 
        // delete copy constructor and operator=
        SDLDevice(const SDLDevice&) = delete;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/plugins/wasapi/WASAPIDevice.cpp 
new/audaspace-1.10.0/plugins/wasapi/WASAPIDevice.cpp
--- old/audaspace-1.9.0/plugins/wasapi/WASAPIDevice.cpp 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/plugins/wasapi/WASAPIDevice.cpp        2026-07-16 
22:24:57.000000000 +0200
@@ -373,7 +373,7 @@
                specs.channels = CHANNELS_STEREO;
        if(specs.format == FORMAT_INVALID)
                specs.format = FORMAT_FLOAT32;
-       if(int(specs.rate) == RATE_INVALID)
+       if(specs.rate == RATE_INVALID)
                specs.rate = RATE_48000;
 
        if(FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, 
CLSCTX_ALL, IID_IMMDeviceEnumerator, 
reinterpret_cast<void**>(m_imm_device_enumerator.GetAddressOf()))))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/src/devices/DeviceManager.cpp 
new/audaspace-1.10.0/src/devices/DeviceManager.cpp
--- old/audaspace-1.9.0/src/devices/DeviceManager.cpp   2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/src/devices/DeviceManager.cpp  2026-07-16 
22:24:57.000000000 +0200
@@ -15,9 +15,11 @@
  
******************************************************************************/
 
 #include "devices/DeviceManager.h"
+#include "devices/ICaptureDeviceFactory.h"
 #include "devices/IDeviceFactory.h"
 #include "devices/IDevice.h"
 #include "devices/I3DDevice.h"
+#include "Exception.h"
 
 #include <limits>
 #include <string>
@@ -27,6 +29,7 @@
 
 std::unordered_map<std::string, std::shared_ptr<IDeviceFactory>> 
DeviceManager::m_factories;
 std::shared_ptr<IDevice> DeviceManager::m_device;
+std::unordered_map<std::string, std::shared_ptr<ICaptureDeviceFactory>> 
DeviceManager::m_capture_factories;
 
 void DeviceManager::registerDevice(const std::string &name, 
std::shared_ptr<IDeviceFactory> factory)
 {
@@ -119,4 +122,37 @@
        return names;
 }
 
+std::vector<std::string> DeviceManager::getAvailableCaptureDeviceNames()
+{
+       std::vector<std::string> names;
+       names.reserve(m_capture_factories.size());
+
+       for(auto& entry : m_capture_factories)
+               names.push_back(entry.first);
+
+       return names;
+}
+
+std::shared_ptr<ICaptureDeviceFactory> 
DeviceManager::getCaptureDeviceFactory(const std::string& name)
+{
+       auto it = m_capture_factories.find(name);
+
+       if(it == m_capture_factories.end())
+               return nullptr;
+
+       return it->second;
+}
+
+void DeviceManager::registerCaptureDevice(const std::string& name, 
std::shared_ptr<ICaptureDeviceFactory> factory)
+{
+       m_capture_factories[name] = factory;
+}
+
+std::shared_ptr<IReader> DeviceManager::openCaptureDevice(const std::string& 
name,
+                                                          Specs specs,
+                                                          int buffersize)
+{
+       return getCaptureDeviceFactory(name)->openDevice(specs, buffersize);
+}
+
 AUD_NAMESPACE_END
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/src/file/FileWriter.cpp 
new/audaspace-1.10.0/src/file/FileWriter.cpp
--- old/audaspace-1.9.0/src/file/FileWriter.cpp 2026-03-20 18:10:20.000000000 
+0100
+++ new/audaspace-1.10.0/src/file/FileWriter.cpp        2026-07-16 
22:24:57.000000000 +0200
@@ -27,7 +27,7 @@
        return FileManager::createWriter(filename, specs, format, codec, 
bitrate);
 }
 
-void FileWriter::writeReader(std::shared_ptr<IReader> reader, 
std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, 
void(*callback)(float, void*), void* data)
+void FileWriter::writeReader(std::shared_ptr<IReader> reader, 
std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, 
bool(*callback)(float, void*), void* data)
 {
        Buffer buffer(buffersize * AUD_SAMPLE_SIZE(writer->getSpecs()));
        sample_t* buf = buffer.getBuffer();
@@ -59,12 +59,15 @@
                        float progress = -1;
                        if(length > 0)
                                progress = pos / float(length);
-                       callback(progress, data);
+                       if (!callback(progress, data))
+                       {
+                               break;
+                       }
                }
        }
 }
 
-void FileWriter::writeReader(std::shared_ptr<IReader> reader, 
std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned 
int buffersize, void(*callback)(float, void*), void* data)
+void FileWriter::writeReader(std::shared_ptr<IReader> reader, 
std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned 
int buffersize, bool(*callback)(float, void*), void* data)
 {
        Buffer buffer(buffersize * AUD_SAMPLE_SIZE(reader->getSpecs()));
        Buffer buffer2(buffersize * sizeof(sample_t));
@@ -103,7 +106,10 @@
                        float progress = -1;
                        if(length > 0)
                                progress = pos / float(length);
-                       callback(progress, data);
+                       if (!callback(progress, data))
+                       {
+                               break;
+                       }
                }
        }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/src/sequence/AnimateableProperty.cpp 
new/audaspace-1.10.0/src/sequence/AnimateableProperty.cpp
--- old/audaspace-1.9.0/src/sequence/AnimateableProperty.cpp    2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/src/sequence/AnimateableProperty.cpp   2026-07-16 
22:24:57.000000000 +0200
@@ -68,8 +68,18 @@
 
 void AnimateableProperty::writeConstantRange(const float* data, int 
position_start, int position_end)
 {
+       int pos = getSize() / (sizeof(float) * m_count);
+
        assureSize(position_end * m_count * sizeof(float), true);
        float* buffer = Buffer::getBuffer();
+       
+       // if we were not animated yet, use the new constant value as the
+       // first/default value to fill in the unknown parts
+       if (!m_isAnimated)
+       {
+               std::memcpy(buffer, data, m_count * sizeof(float));
+               pos = 0;
+       }
 
        for(int i = position_start; i < position_end; i++)
        {
@@ -77,6 +87,8 @@
        }
 
        m_isAnimated = true;
+       
+       updateUnknownAfterWrite(pos, position_start, position_end - 
position_start);
 }
 
 void AnimateableProperty::write(const float* data, int position, int count)
@@ -95,7 +107,12 @@
        float* buf = Buffer::getBuffer();
 
        std::memcpy(buf + position * m_count, data, count * m_count * 
sizeof(float));
+       
+       updateUnknownAfterWrite(pos, position, count);
+}
 
+void AnimateableProperty::updateUnknownAfterWrite(int pos, int position, int 
count)
+{
        // have to fill up space between?
        if(pos < position)
        {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/src/sequence/SequenceHandle.cpp 
new/audaspace-1.10.0/src/sequence/SequenceHandle.cpp
--- old/audaspace-1.9.0/src/sequence/SequenceHandle.cpp 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/src/sequence/SequenceHandle.cpp        2026-07-16 
22:24:57.000000000 +0200
@@ -22,7 +22,7 @@
 #include <mutex>
 
 #define KEEP_TIME 10
-#define POSITION_EPSILON (1.0 / static_cast<double>(RATE_48000))
+#define POSITION_EPSILON (1.0 / RATE_48000)
 
 AUD_NAMESPACE_BEGIN
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/audaspace-1.9.0/src/sequence/SequenceReader.cpp 
new/audaspace-1.10.0/src/sequence/SequenceReader.cpp
--- old/audaspace-1.9.0/src/sequence/SequenceReader.cpp 2026-03-20 
18:10:20.000000000 +0100
+++ new/audaspace-1.10.0/src/sequence/SequenceReader.cpp        2026-07-16 
22:24:57.000000000 +0200
@@ -161,7 +161,7 @@
                frame = time * m_sequence->m_fps;
                cfra = int(std::floor(frame));
 
-               len = int(std::ceil((cfra + 1) / m_sequence->m_fps * 
specs.rate)) - m_position;
+               len = int(std::ceil((cfra + 1) / m_sequence->m_fps * 
specs.rate)) - m_position - pos;
                len = std::min(length - pos, len);
                len = std::max(len, 1);
 

Reply via email to