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);
