Hello community, here is the log from the commit of package audaspace for openSUSE:Factory checked in at 2015-10-19 22:52:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/audaspace (Old) and /work/SRC/openSUSE:Factory/.audaspace.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "audaspace" Changes: -------- --- /work/SRC/openSUSE:Factory/audaspace/audaspace.changes 2015-10-08 08:24:14.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.audaspace.new/audaspace.changes 2015-10-20 00:06:19.000000000 +0200 @@ -1,0 +2,29 @@ +Sat Oct 17 07:08:39 UTC 2015 - [email protected] + +- Update to version 1.1 +- Remove audaspace-datetime.patch and audaspace-pkgcnflib.patch + issues fixed upstream. +- Upstream changes: + *Bug fixes: + pkgconfig uses cmake configured library directory + FFMPEG file writing crashed, also corrected pts for encoding + silenced Doxygen warnings about undefined defines + *C++ API: + ResampleReader uses specs instead of sample rate + *Bindings API: + writing sounds to files + reading sound data, specs and length + resampling sounds + *CMake/Building: + first steps towards building for Mac + windows builds copy dlls automatically + *Python module: + using distutils instead of setuptools + added numpy as dependency + *Documentation: + added windows building and plugin documentation + disabled html timestamps in doxygen + updated sphinx template + build binding documentation without installing the python module + +------------------------------------------------------------------- Old: ---- audaspace-1.0.tar.gz audaspace-datetime.patch audaspace-pkgcnflib.patch New: ---- audaspace-1.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ audaspace.spec ++++++ --- /var/tmp/diff_new_pack.1Gp8H8/_old 2015-10-20 00:06:20.000000000 +0200 +++ /var/tmp/diff_new_pack.1Gp8H8/_new 2015-10-20 00:06:20.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package audaspace # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,37 +17,35 @@ # See also http://en.opensuse.org/openSUSE:Shared_library_packaging_policy -%define soname 1_0 +# NOTE: soname foillows version. +%define soname 1_1 Name: audaspace -Version: 1.0 -Release: 11 +Version: 1.1 +Release: 0 Summary: A High Level Audio Library License: Apache-2.0 Group: System/Libraries -Url: https://github.com/audaspace +Url: https://github.com/audaspace/audaspace/releases/tag/v%{version} Source0: audaspace-%{version}.tar.gz -# Remove time stamp from html documentation. -Patch0: audaspace-datetime.patch -# pkgconfig file doesn't use lib64 on x86_64 builds. -Patch1: audaspace-pkgcnflib.patch %if 0%{?suse_version} > 1320 BuildRequires: ffmpeg-devel %endif BuildRequires: cmake > 3 BuildRequires: doxygen BuildRequires: fdupes -BuildRequires: graphviz BuildRequires: gcc-c++ -BuildRequires: pkg-config +BuildRequires: graphviz BuildRequires: jack-audio-connection-kit-devel +BuildRequires: pkg-config BuildRequires: pkgconfig(sndfile) -BuildRequires: python-devel -#BuildRequires: python-Sphinx -BuildRequires: python3-devel +#BuildRequires: python-devel +#BuildRequires: python3-Sphinx BuildRequires: python3 -BuildRequires: pkgconfig(sdl2) +BuildRequires: python3-devel +BuildRequires: python3-numpy-devel BuildRequires: pkgconfig(openal) +BuildRequires: pkgconfig(sdl2) #Requires: %description @@ -121,18 +119,16 @@ The %{name}-doc package contains documentation for developing applications that use %{name}. -#%%define __cmake ccmake - %prep %setup -n audaspace-%{version} -q -%patch0 -%patch1 %build - - %cmake -DWITH_FFMPEG:BOOL=FALSE \ +# NOTE: python3 numpy include flag (-isystem points to includes) reported upstream. +%cmake -DWITH_FFMPEG:BOOL=FALSE \ -DDEFAULT_PLUGIN_PATH:PATH=%{_libdir}/%{name}/plugins \ -DWITH_PYTHON_MODULE:BOOL=off \ + -DCMAKE_C_FLAGS:STRING="%{optflags} -isystem %{python3_sitearch}/numpy/core/include/" \ + -DCMAKE_CXX_FLAGS:STRING="%{optflags} -isystem %{python3_sitearch}/numpy/core/include/" \ -DDOCUMENTATION_INSTALL_PATH:PATH=%{_docdir}/%{name} %make_jobs ++++++ audaspace-1.0.tar.gz -> audaspace-1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/CHANGES new/audaspace-1.1/CHANGES --- old/audaspace-1.0/CHANGES 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/CHANGES 2015-10-13 21:55:59.000000000 +0200 @@ -1,3 +1,54 @@ +Audaspace 1.1 +============= + +- Bug fixes: + - pkgconfig uses cmake configured library directory + - FFMPEG file writing crashed, also corrected pts for encoding + - silenced Doxygen warnings about undefined defines +- C++ API: + - ResampleReader uses specs instead of sample rate +- Bindings API: + - writing sounds to files + - reading sound data, specs and length + - resampling sounds +- CMake/Building: + - first steps towards building for Mac + - windows builds copy dlls automatically +- Python module: + - using distutils instead of setuptools + - added numpy as dependency +- Documentation: + - added windows building and plugin documentation + - disabled html timestamps in doxygen + - updated sphinx template + - build binding documentation without installing the python module + +Detailed list of changes: + +326a300 Documentation: windows, dll copying now done automatically. +54cac4f Windows: install dlls. +65c2d78 Bindings: Sound length and specs properties. +c38da70 Bindings API: adding resampling. +374822f Documentation: Added windows and plugin documentation. +a9dc5b9 Python module: add numpy as dependency. +c933a02 C API: implement new API based on the python API. +ac54c52 Python API: silence numpy warnings. +c9491bb Python API: checking for a positive sample rate. +4eb1fa8 Python API: reorder functions. +ec7c00b Sphinx update and fixes. +e16d979 FFMPEG: correct pts during encoding. +7ab3935 Documentation: git path fix. +28d77bb Python: use distutils directly instead of setuptools. +1f43284 Silence doxygen warning about undefined defines. +0d52458 CMake: improvements and fixes for building on Mac. +37daedf FFMPEG: bugfixes for file writing. +780ca2a ResampleReader API change +4d9863d Python API: Optimization for cached sounds' data access. +ea04fee Python API: read sound data and create sound buffers as well as getting the specs of a sound. +335b293 Python sound writing API. +36a7252 Pkgconfig: use cmake configured library directory. +5503908 Doxygen: disable html timestamps. + Initial Release of Audaspace 1.0 ================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/CMakeLists.txt new/audaspace-1.1/CMakeLists.txt --- old/audaspace-1.0/CMakeLists.txt 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/CMakeLists.txt 2015-10-13 21:55:59.000000000 +0200 @@ -23,7 +23,7 @@ project(audaspace) -set(AUDASPACE_VERSION 1.0) +set(AUDASPACE_VERSION 1.1) set(AUDASPACE_LONG_VERSION ${AUDASPACE_VERSION}) # sources @@ -215,6 +215,7 @@ set(INCLUDE ${CMAKE_CURRENT_BINARY_DIR} include) if(WIN32) + set(DLLS) set(LIBRARIES) set(LIBRARY_PATH "../lib" CACHE PATH "Path which contains the libraries.") file(GLOB LIBRARY_DIRS ${LIBRARY_PATH}/*) @@ -236,7 +237,6 @@ option(WITH_C "Build C Module" TRUE) option(WITH_DOCS "Build C++ HTML Documentation with Doxygen" TRUE) -option(WITH_BINDING_DOCS "Build C/Python HTML Documentation with Sphinx" TRUE) option(WITH_FFMPEG "Build With FFMPEG" TRUE) option(WITH_JACK "Build With Plugin" TRUE) option(WITH_LIBSNDFILE "Build With LibSndFile" TRUE) @@ -249,15 +249,15 @@ set(PACKAGE_OPTION REQUIRED) endif() -if(WIN32 OR APPLE) - set(DEFAULT_PLUGIN_PATH "." CACHE PATH "Default plugin installation and loading path.") +if(WIN32) + set(DEFAULT_PLUGIN_PATH "." CACHE STRING "Default plugin installation and loading path.") set(DOCUMENTATION_INSTALL_PATH "doc" CACHE PATH "Path where the documentation is installed.") else() - set(DEFAULT_PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/share/audaspace/plugins" CACHE PATH "Default plugin installation and loading path.") + set(DEFAULT_PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/share/audaspace/plugins" CACHE STRING "Default plugin installation and loading path.") set(DOCUMENTATION_INSTALL_PATH "share/doc/audaspace" CACHE PATH "Path where the documentation is installed.") endif() -cmake_dependent_option(SEPARATE_C "Build C Binding as separate library" TRUE "WITH_C;SHARED_LIBRARY" FALSE) +cmake_dependent_option(SEPARATE_C "Build C Binding as separate library" TRUE "WITH_C" FALSE) cmake_dependent_option(PLUGIN_FFMPEG "Build FFMPEG Plugin" TRUE "WITH_FFMPEG;SHARED_LIBRARY" FALSE) cmake_dependent_option(PLUGIN_JACK "Build Jack Plugin" TRUE "WITH_JACK;SHARED_LIBRARY" FALSE) cmake_dependent_option(PLUGIN_LIBSNDFILE "Build LibSndFile Plugin" TRUE "WITH_LIBSNDFILE;SHARED_LIBRARY" FALSE) @@ -265,6 +265,7 @@ cmake_dependent_option(PLUGIN_SDL "Build SDL Plugin" TRUE "WITH_SDL;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(WITH_BINDING_DOCS "Build C/Python HTML Documentation with Sphinx" TRUE "WITH_PYTHON_MODULE" FALSE) # compiler options @@ -344,6 +345,11 @@ list(APPEND HDR ${FFMPEG_HDR}) list(APPEND STATIC_PLUGINS FFMPEG) endif() + + if(WIN32) + file(GLOB FFMPEG_DLLS ${LIBRARY_PATH}/ffmpeg/bin/*.dll) + list(APPEND DLLS ${FFMPEG_DLLS}) + endif() else() set(WITH_FFMPEG FALSE CACHE BOOL "Build With FFMPEG" FORCE) message(WARNING "FFMPEG not found, plugin will not be built.") @@ -371,6 +377,11 @@ list(APPEND HDR ${JACK_HDR}) list(APPEND STATIC_PLUGINS JackDevice) endif() + + if(WIN32) + file(GLOB JACK_DLLS ${LIBRARY_PATH}/jack/bin/*.dll) + list(APPEND DLLS ${JACK_DLLS}) + endif() else() set(WITH_JACK FALSE CACHE BOOL "Build With Plugin" FORCE) message(WARNING "Jack not found, plugin will not be built.") @@ -400,6 +411,11 @@ list(APPEND HDR ${LIBSNDFILE_HDR}) list(APPEND STATIC_PLUGINS SndFile) endif() + + if(WIN32) + file(GLOB LIBSNDFILE_DLLS ${LIBRARY_PATH}/libsndfile/bin/*.dll) + list(APPEND DLLS ${LIBSNDFILE_DLLS}) + endif() else() set(WITH_LIBSNDFILE FALSE CACHE BOOL "Build With LibSndFile" FORCE) message(WARNING "LibSndFile not found, plugin will not be built.") @@ -427,6 +443,11 @@ list(APPEND HDR ${OPENAL_HDR}) list(APPEND STATIC_PLUGINS OpenALDevice) endif() + + if(WIN32) + file(GLOB OPENAL_DLLS ${LIBRARY_PATH}/OpenAL/bin/*.dll) + list(APPEND DLLS ${OPENAL_DLLS}) + endif() else() set(WITH_OPENAL FALSE CACHE BOOL "Build With OpenAL" FORCE) message(WARNING "OpenAL not found, plugin will not be built.") @@ -450,6 +471,11 @@ endif() set(AUDASPACE_PY_LIBRARY -laudaspace-py) + + if(WIN32) + file(GLOB PYTHON_DLLS ${LIBRARY_PATH}/Python/bin/*.dll) + list(APPEND DLLS ${PYTHON_DLLS}) + endif() else() set(WITH_PYTHON FALSE CACHE BOOL "Build With Python Library" FORCE) message(WARNING "Python libraries not found, language binding will not be built.") @@ -486,6 +512,11 @@ list(APPEND HDR ${SDL_HDR}) list(APPEND STATIC_PLUGINS SDLDevice) endif() + + if(WIN32) + file(GLOB SDL_DLLS ${LIBRARY_PATH}/sdl/bin/*.dll) + list(APPEND DLLS ${SDL_DLLS}) + endif() else() set(WITH_SDL FALSE CACHE BOOL "Build With SDL" FORCE) message(WARNING "SDL not found, plugin will not be built.") @@ -610,6 +641,14 @@ install(TARGETS audsdl DESTINATION ${DEFAULT_PLUGIN_PATH}) endif() +# dlls + +if(WIN32) + if(DLLS) + install(FILES ${DLLS} DESTINATION ${BIN_DESTINATION}) + endif() +endif() + # demos if(BUILD_DEMOS) @@ -649,15 +688,17 @@ # bindings -if(WITH_C AND SEPARATE_C) - add_library(audaspace-c ${LIBRARY_TYPE} ${C_SRC} ${C_HDR}) - target_link_libraries(audaspace-c audaspace) - set_target_properties(audaspace-c PROPERTIES SOVERSION ${AUDASPACE_VERSION}) - install(TARGETS audaspace-c - RUNTIME DESTINATION ${BIN_DESTINATION} - LIBRARY DESTINATION ${LIB_DESTINATION} - ARCHIVE DESTINATION ${LIB_DESTINATION} - ) +if(WITH_C) + if(SEPARATE_C) + add_library(audaspace-c ${LIBRARY_TYPE} ${C_SRC} ${C_HDR}) + target_link_libraries(audaspace-c audaspace) + set_target_properties(audaspace-c PROPERTIES SOVERSION ${AUDASPACE_VERSION}) + install(TARGETS audaspace-c + RUNTIME DESTINATION ${BIN_DESTINATION} + LIBRARY DESTINATION ${LIB_DESTINATION} + ARCHIVE DESTINATION ${LIB_DESTINATION} + ) + endif() install(FILES ${C_HDR} DESTINATION include/audaspace) endif() @@ -697,7 +738,7 @@ configure_file(${PYTHON_SOURCE_DIRECTORY}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py ESCAPE_QUOTES @ONLY) if(APPLE) - add_custom_command(OUTPUT build COMMAND MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} ${PYTHON_EXECUTABLE} setup.py build DEPENDS ${PYTHON_SRC} ${PYTHON_HDR}) + add_custom_command(AUDPYTHON_MODULE OUTPUT build COMMAND MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} ${PYTHON_EXECUTABLE} setup.py build DEPENDS ${PYTHON_SRC} ${PYTHON_HDR}) elseif(WIN32) set(ENV{VS100COMNTOOLS} $ENV{VS120COMNTOOLS}) add_custom_command(OUTPUT build COMMAND ${PYTHON_EXECUTABLE} setup.py build DEPENDS ${PYTHON_SRC} ${PYTHON_HDR}) @@ -732,7 +773,7 @@ if(SPHINX_FOUND) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bindings/doc/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @ONLY) - add_custom_target(bindings_doc ALL ${SPHINX_EXECUTABLE} -q -b html -c "${CMAKE_CURRENT_BINARY_DIR}" -d "${CMAKE_CURRENT_BINARY_DIR}/_doctrees" "${CMAKE_CURRENT_SOURCE_DIR}/bindings/doc" "${CMAKE_CURRENT_BINARY_DIR}/doc/bindings" COMMENT "Building C/Python HTML documentation with Sphinx.") + add_custom_target(bindings_doc ALL COMMAND ${PYTHON_EXECUTABLE} setup.py --build-docs ${SPHINX_EXECUTABLE} -q -b html -c "${CMAKE_CURRENT_BINARY_DIR}" -d "${CMAKE_CURRENT_BINARY_DIR}/_doctrees" "${CMAKE_CURRENT_SOURCE_DIR}/bindings/doc" "${CMAKE_CURRENT_BINARY_DIR}/doc/bindings" DEPENDS pythonmodule COMMENT "Building C/Python HTML documentation with Sphinx.") else() set(WITH_BINDING_DOCS FALSE CACHE BOOL "Build C/Python HTML Documentation with Sphinx" FORCE) message(WARNING "Sphinx not found, binding documentation will not be built.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/INSTALL new/audaspace-1.1/INSTALL --- old/audaspace-1.0/INSTALL 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/INSTALL 2015-10-13 21:55:59.000000000 +0200 @@ -8,7 +8,7 @@ Build Dependencies ------------------ -Audaspace is written in C++ 11 so a fairly recent compiler (g++ 4.8.2, clang 3.3, MSVC 2013) is needed to build it. The following build dependencies are all optional, but without any it's neither possible to open sound files nor play back through the speakers. +Audaspace is written in C++ 11 so a fairly recent compiler (g++ 4.8.2, clang 3.3, MSVC 2013) is needed to build it. The build system used is CMake and you need at least version 3.0. The following build dependencies are all optional, but without any it's neither possible to open sound files nor play back through the speakers. For windows a library folder called build-dependencies can be downloaded from https://github.com/audaspace/audaspace/releases. - OpenAL (input/output device) - SDL (output device) @@ -24,10 +24,17 @@ For the most recent version you can use git to get the source code. - git clone https://github.com:audaspace/audaspace.git + git clone https://github.com/audaspace/audaspace.git -Configuration -------------- +Plugins +------- + +Before diving into the exact build steps for each platform, we will have a look at plugins. There are so far two types of plugins: input and output plugins. Input plugins are for reading audio files in many different formats and output plugins are for output devices on different platforms. During the configuration audaspace's standard plugins can be enabled with their repsective `WITH_*` and `PLUGIN_*` configuration option. Plugins are built as shared libraries. By default audaspace looks in the `DEFAULT_PLUGIN_PATH` for shared libraries it can load. Building with a dependency (`WITH_*`) but without enabling the respective `PLUGIN_*` option will compile the plugin directly into the library, so the plugin always gets loaded when the plugins are initialised. + +Building for Linux +------------------ + +### Configuration ### It is highly recommended to build audaspace outside of the actual source code in a specific build directory. @@ -56,23 +63,45 @@ This specific configuration is recommended for a system wide installation of audaspace where all build dependencies are required. -Building --------- +### Building ### After configuration the building is as easy as running make -Installation ------------- +### Installation ### Installation is then also simple using make install -Using the library ------------------ +### Using the library ### When audaspace is installed to the system, the required configuration for _pkgconfig_ is also installed and pkgconfig can then be used to compile projects with audaspace. It is also possible to build audaspace as a static library and use it directly in a project. For this the library has to be configured accordingly with ccmake and after building the resulting library file can be added to the project's build system. + +Building for Windows +-------------------- + +### Configuration ### + +Using cmake-gui select Visual Studio 2013 or 2015 for the architecture you want to build for and choose audaspace's source directory and a build directory. It is highly recommended to build audaspace outside of the source directory. During the first configuration cmake tries to find the dependencies. Dependencies that are not installed on the system are automatically disabled. To prevent this, enable `WITH_STRICT_DEPENDENCIES`. To use the build dependencies folder from the website, set the `LIBRARY_PATH` to point to the extracted directory. Also don't forget to set the `CMAKE_INSTALL_PREFIX` to a path where your user account can install to. Finally enable the dependencies that you want to use (`WITH_*`), configure and generate. + +### Building ### + +Open the project in Visual Studio and set the configuration to Release. Then you can simply hit the build button. + +### Installation ### + +To install audaspace to your target folder, build the INSTALL target. +Note that if you don't use the libraries folder provided on the website, the INSTALL target might fail and you need to copy the files manually, including the dlls of the dependencies. + +### Using the library ### + +To use audaspace in your project, configure the include path and the libraries that you need, which you can find in the include and lib directories in your installation path. + +### Notes for plugins on windows ### + +- FFMPEG: Due to a problem with FFMPEG's 32 bit libraries, it is necessary to disable SAFESEH for the audffmpeg build target inside Visual Studio (Properties, Linker, Advanced). This has to be done after each generate step of CMake. +- Jack: If no jack server is running on windows and your application or one of the demos tries to use the jack plugin, this adds a long delay to the device initialisation. In case you don't need jack, make sure to disable the plugin or for the prebuilt version of audaspace simply delete audjack.dll (and any files with jack in the name to clean up). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/bindings/C/AUD_Sound.cpp new/audaspace-1.1/bindings/C/AUD_Sound.cpp --- old/audaspace-1.0/bindings/C/AUD_Sound.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/bindings/C/AUD_Sound.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -20,6 +20,7 @@ #include "generator/Square.h" #include "generator/Triangle.h" #include "file/File.h" +#include "file/FileWriter.h" #include "util/StreamBuffer.h" #include "fx/Accumulator.h" #include "fx/ADSR.h" @@ -40,17 +41,203 @@ #include "sequence/Superpose.h" #include "sequence/PingPong.h" #include "respec/LinearResample.h" +#include "respec/JOSResample.h" +#include "respec/JOSResampleReader.h" #include "respec/ChannelMapper.h" +#include "respec/ChannelMapperReader.h" #include "util/Buffer.h" #include "Exception.h" #include <cassert> +#include <cstring> using namespace aud; #define AUD_CAPI_IMPLEMENTATION #include "AUD_Sound.h" +static inline AUD_Specs convSpecToC(aud::Specs specs) +{ + AUD_Specs s; + s.channels = static_cast<AUD_Channels>(specs.channels); + s.rate = static_cast<AUD_SampleRate>(specs.rate); + return s; +} + +static inline aud::Specs convCToSpec(AUD_Specs specs) +{ + aud::Specs s; + s.channels = static_cast<Channels>(specs.channels); + s.rate = static_cast<SampleRate>(specs.rate); + return s; +} + +AUD_API AUD_Specs AUD_Sound_getSpecs(AUD_Sound* sound) +{ + assert(sound); + + return convSpecToC((*sound)->createReader()->getSpecs()); +} + +AUD_API int AUD_Sound_getLength(AUD_Sound* sound) +{ + assert(sound); + + return (*sound)->createReader()->getLength(); +} + +AUD_API sample_t* AUD_Sound_data(AUD_Sound* sound, int* length, AUD_Specs* specs) +{ + assert(sound); + assert(length); + assert(specs); + + auto stream_buffer = std::dynamic_pointer_cast<StreamBuffer>(*sound); + if(!stream_buffer) + stream_buffer = std::make_shared<StreamBuffer>(*sound); + *specs = convSpecToC(stream_buffer->getSpecs()); + auto buffer = stream_buffer->getBuffer(); + + *length = buffer->getSize() / AUD_SAMPLE_SIZE((*specs)); + + sample_t* data = new sample_t[buffer->getSize()]; + + std::memcpy(data, buffer->getBuffer(), buffer->getSize()); + + return data; +} + +AUD_API void AUD_Sound_freeData(sample_t* data) +{ + delete[] data; +} + +AUD_API const char* AUD_Sound_write(AUD_Sound* sound, const char* filename, AUD_SampleRate rate, AUD_Channels channels, AUD_SampleFormat format, AUD_Container container, AUD_Codec codec, int bitrate, int buffersize) +{ + assert(sound); + assert(filename); + + try + { + std::shared_ptr<IReader> reader = (*sound)->createReader(); + + DeviceSpecs specs; + specs.specs = reader->getSpecs(); + + if((rate != RATE_INVALID) && (specs.rate != rate)) + { + specs.rate = rate; + reader = std::make_shared<JOSResampleReader>(reader, rate); + } + + if((channels != AUD_CHANNELS_INVALID) && (specs.channels != static_cast<Channels>(channels))) + { + specs.channels = static_cast<Channels>(channels); + reader = std::make_shared<ChannelMapperReader>(reader, specs.channels); + } + + if(format == AUD_FORMAT_INVALID) + format = AUD_FORMAT_S16; + specs.format = static_cast<SampleFormat>(format); + + const char* invalid_container_error = "Container could not be determined from filename."; + + if(container == AUD_CONTAINER_INVALID) + { + std::string path = filename; + + if(path.length() < 4) + return invalid_container_error; + + std::string extension = path.substr(path.length() - 4); + + if(extension == ".ac3") + container = AUD_CONTAINER_AC3; + else if(extension == "flac") + container = AUD_CONTAINER_FLAC; + else if(extension == ".mkv") + container = AUD_CONTAINER_MATROSKA; + else if(extension == ".mp2") + container = AUD_CONTAINER_MP2; + else if(extension == ".mp3") + container = AUD_CONTAINER_MP3; + else if(extension == ".ogg") + container = AUD_CONTAINER_OGG; + else if(extension == ".wav") + container = AUD_CONTAINER_WAV; + else + return invalid_container_error; + } + + if(codec == AUD_CODEC_INVALID) + { + switch(container) + { + case AUD_CONTAINER_AC3: + codec = AUD_CODEC_AC3; + break; + case AUD_CONTAINER_FLAC: + codec = AUD_CODEC_FLAC; + break; + case AUD_CONTAINER_MATROSKA: + codec = AUD_CODEC_OPUS; + break; + case AUD_CONTAINER_MP2: + codec = AUD_CODEC_MP2; + break; + case AUD_CONTAINER_MP3: + codec = AUD_CODEC_MP3; + break; + case AUD_CONTAINER_OGG: + codec = AUD_CODEC_VORBIS; + break; + case AUD_CONTAINER_WAV: + codec = AUD_CODEC_PCM; + break; + default: + return "Unknown container, cannot select default codec."; + } + } + + if(buffersize <= 0) + buffersize = AUD_DEFAULT_BUFFER_SIZE; + + std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, specs, static_cast<Container>(container), static_cast<Codec>(codec), bitrate); + FileWriter::writeReader(reader, writer, 0, buffersize); + } + catch(Exception& e) + { + return "An exception occured while writing."; + } + + return nullptr; +} + +AUD_API AUD_Sound* AUD_Sound_buffer(sample_t* data, int length, AUD_Specs specs) +{ + assert(data); + + if(length <= 0 || specs.rate <= 0 || specs.channels <= 0) + { + return nullptr; + } + + int size = length * AUD_SAMPLE_SIZE(specs); + + std::shared_ptr<Buffer> buffer = std::make_shared<Buffer>(size); + + std::memcpy(buffer->getBuffer(), data, size); + + try + { + return new AUD_Sound(new StreamBuffer(buffer, convCToSpec(specs))); + } + catch(Exception&) + { + return nullptr; + } +} + AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size) { assert(buffer); @@ -299,6 +486,27 @@ } catch(Exception&) { + return nullptr; + } +} + +AUD_API AUD_Sound* AUD_Sound_resample(AUD_Sound* sound, AUD_SampleRate rate, bool high_quality) +{ + assert(sound); + + try + { + DeviceSpecs specs; + specs.channels = CHANNELS_INVALID; + specs.rate = rate; + specs.format = FORMAT_INVALID; + if(high_quality) + return new AUD_Sound(new JOSResample(*sound, specs)); + else + return new AUD_Sound(new LinearResample(*sound, specs)); + } + catch(Exception&) + { return nullptr; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/bindings/C/AUD_Sound.h new/audaspace-1.1/bindings/C/AUD_Sound.h --- old/audaspace-1.0/bindings/C/AUD_Sound.h 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/bindings/C/AUD_Sound.h 2015-10-13 21:55:59.000000000 +0200 @@ -23,6 +23,65 @@ #endif /** + * Retrieves the sample specification of the sound. + * \param sound The sound to retrieve from. + * \return The sample specification of the sound. + * \note This function creates a reader from the sound and deletes it again. + */ +extern AUD_API AUD_Specs AUD_Sound_getSpecs(AUD_Sound* sound); + +/** + * Retrieves the approximate length of the sound. + * \param sound The sound to retrieve from. + * \return The length of the sound in samples. + * \note This function creates a reader from the sound and deletes it again. + */ +extern AUD_API int AUD_getLength(AUD_Sound* sound); + +/** + * Reads a sound's samples into memory. + * \param sound The sound to read. + * \param length Pointer to store the length of memory read. + * \param specs Pointer to store the data's sample specification. + * \return A pointer to the sample data. + * \warning The data has to be freed with AUD_Sound_freeData. + */ +extern AUD_API sample_t* AUD_Sound_data(AUD_Sound* sound, int* length, AUD_Specs* specs); + +/** + * Frees a buffer previously allocated with AUD_Sound_data. + * \param data The buffer to be freed. + */ +extern AUD_API void AUD_Sound_freeData(sample_t* data); + +/** + * Writes the sound to a file. + * \param sound The sound to write. + * \param filename The path to write to.. + * \param rate The sample rate to write with. + * \param channels The number of channels to write with. + * \param format The sample format to write with. + * \param container The container format for the file. + * \param codec The codec to use in the file. + * \param bitrate The bitrate to write with. + * \param buffersize The size of the writing buffer. + * \return A nullptr or an error message in case of error. + * \note Most parameters can be set to zero for default values. + */ +extern AUD_API const char* AUD_Sound_write(AUD_Sound* sound, const char* filename, AUD_SampleRate rate, AUD_Channels channels, AUD_SampleFormat format, AUD_Container container, AUD_Codec codec, int bitrate, int buffersize); + +/** + * Creates a sound from a data buffer. + * \param data The data as interleaved samples. + * \param length The data's length in samples. + * \param specs The data's sample specification. + * \return A handle of the sound. + * \note The data gets copied to an internal memory buffer. + * The pointer does not need to stay valid for the lifetime of the object. + */ +extern AUD_API AUD_Sound* AUD_Sound_buffer(sample_t* data, int length, AUD_Specs specs); + +/** * Loads a sound file from a memory buffer. * \param buffer The buffer which contains the sound file. * \param size The size of the buffer. @@ -204,6 +263,15 @@ extern AUD_API AUD_Sound* AUD_Sound_rechannel(AUD_Sound* sound, AUD_Channels channels); /** + * Resamples the sound. + * \param sound The sound to resample. + * \param rate The new sample rate. + * \param high_quality When true use a higher quality but slower resampler. + * \return The resampled sound. + */ +extern AUD_API AUD_Sound* AUD_Sound_resample(AUD_Sound* sound, AUD_SampleRate rate, bool high_quality = false); + +/** * Reverses a sound. Make sure the sound source can be reversed. * \param sound The sound to reverse. * \return A handle of the reversed sound. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/bindings/doc/conf.py.in new/audaspace-1.1/bindings/doc/conf.py.in --- old/audaspace-1.0/bindings/doc/conf.py.in 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/bindings/doc/conf.py.in 2015-10-13 21:55:59.000000000 +0200 @@ -101,7 +101,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/bindings/python/PySound.cpp new/audaspace-1.1/bindings/python/PySound.cpp --- old/audaspace-1.0/bindings/python/PySound.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/bindings/python/PySound.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -18,6 +18,7 @@ #include "Exception.h" #include "file/File.h" +#include "file/FileWriter.h" #include "util/StreamBuffer.h" #include "generator/Sawtooth.h" #include "generator/Silence.h" @@ -40,12 +41,18 @@ #include "fx/Threshold.h" #include "fx/Volume.h" #include "respec/ChannelMapper.h" +#include "respec/ChannelMapperReader.h" +#include "respec/LinearResample.h" +#include "respec/JOSResample.h" +#include "respec/JOSResampleReader.h" #include "sequence/Double.h" #include "sequence/PingPong.h" #include "sequence/Superpose.h" - +#include <cstring> #include <structmember.h> +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include <numpy/ndarrayobject.h> using namespace aud; @@ -91,6 +98,250 @@ return (PyObject *)self; } +PyDoc_STRVAR(M_aud_Sound_data_doc, + "data()\n\n" + "Retrieves the data of the sound as numpy array.\n\n" + ":return: A two dimensional numpy float array.\n" + ":rtype: :class:`numpy.ndarray`\n\n" + ".. note:: Best efficiency with cached sounds."); + +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()); + + Py_INCREF(array); + + return reinterpret_cast<PyObject*>(array); +} + +PyDoc_STRVAR(M_aud_Sound_write_doc, + "write(filename, rate, channels, format, container, codec, bitrate, buffersize)\n\n" + "Writes the sound to a file.\n\n" + ":arg filename: The path to write to.\n" + ":type filename: string\n" + ":arg rate: The sample rate to write with.\n" + ":type rate: int\n" + ":arg channels: The number of channels to write with.\n" + ":type channels: int\n" + ":arg format: The sample format to write with.\n" + ":type format: int\n" + ":arg container: The container format for the file.\n" + ":type container: int\n" + ":arg codec: The codec to use in the file.\n" + ":type codec: int\n" + ":arg bitrate: The bitrate to write with.\n" + ":type bitrate: int\n" + ":arg buffersize: The size of the writing buffer.\n" + ":type buffersize: int\n"); + +static PyObject * +Sound_write(Sound* self, PyObject* args, PyObject* kwds) +{ + const char* filename = nullptr; + int rate = RATE_INVALID; + Channels channels = CHANNELS_INVALID; + SampleFormat format = FORMAT_INVALID; + Container container = CONTAINER_INVALID; + Codec codec = CODEC_INVALID; + int bitrate = 0; + int buffersize = 0; + + static const char* kwlist[] = {"filename", "rate", "channels", "format", "container", "codec", "bitrate", "buffersize", nullptr}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|iiiiiii:write", const_cast<char**>(kwlist), &filename, &rate, &channels, &format, &container, &codec, &bitrate, &buffersize)) + return nullptr; + + try + { + std::shared_ptr<IReader> reader = (*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))->createReader(); + + DeviceSpecs specs; + specs.specs = reader->getSpecs(); + + if((rate != RATE_INVALID) && (specs.rate != rate)) + { + specs.rate = rate; + reader = std::make_shared<JOSResampleReader>(reader, rate); + } + + if((channels != CHANNELS_INVALID) && (specs.channels != channels)) + { + specs.channels = channels; + reader = std::make_shared<ChannelMapperReader>(reader, channels); + } + + if(format == FORMAT_INVALID) + format = FORMAT_S16; + specs.format = format; + + const char* invalid_container_error = "Container could not be determined from filename."; + + if(container == CONTAINER_INVALID) + { + std::string path = filename; + + if(path.length() < 4) + { + PyErr_SetString(AUDError, invalid_container_error); + return nullptr; + } + + std::string extension = path.substr(path.length() - 4); + + if(extension == ".ac3") + container = CONTAINER_AC3; + else if(extension == "flac") + container = CONTAINER_FLAC; + else if(extension == ".mkv") + container = CONTAINER_MATROSKA; + else if(extension == ".mp2") + container = CONTAINER_MP2; + else if(extension == ".mp3") + container = CONTAINER_MP3; + else if(extension == ".ogg") + container = CONTAINER_OGG; + else if(extension == ".wav") + container = CONTAINER_WAV; + else + { + PyErr_SetString(AUDError, invalid_container_error); + return nullptr; + } + } + + if(codec == CODEC_INVALID) + { + switch(container) + { + case CONTAINER_AC3: + codec = CODEC_AC3; + break; + case CONTAINER_FLAC: + codec = CODEC_FLAC; + break; + case CONTAINER_MATROSKA: + codec = CODEC_OPUS; + break; + case CONTAINER_MP2: + codec = CODEC_MP2; + break; + case CONTAINER_MP3: + codec = CODEC_MP3; + break; + case CONTAINER_OGG: + codec = CODEC_VORBIS; + break; + case CONTAINER_WAV: + codec = CODEC_PCM; + break; + default: + PyErr_SetString(AUDError, "Unknown container, cannot select default codec."); + return nullptr; + } + } + + if(buffersize <= 0) + buffersize = AUD_DEFAULT_BUFFER_SIZE; + + std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, specs, container, codec, bitrate); + FileWriter::writeReader(reader, writer, 0, buffersize); + } + catch(Exception& e) + { + PyErr_SetString(AUDError, e.what()); + return nullptr; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(M_aud_Sound_buffer_doc, + "buffer(data, rate)\n\n" + "Creates a sound from a data buffer.\n\n" + ":arg data: The data as two dimensional numpy array.\n" + ":type data: numpy.ndarray\n" + ":arg rate: The sample rate.\n" + ":type rate: double\n" + ":return: The created :class:`Sound` object.\n" + ":rtype: :class:`Sound`"); + +static PyObject * +Sound_buffer(PyTypeObject* type, PyObject* args) +{ + PyArrayObject* array = nullptr; + double rate = RATE_INVALID; + + if(!PyArg_ParseTuple(args, "Od:buffer", &array, &rate)) + return nullptr; + + if((!PyObject_TypeCheck(reinterpret_cast<PyObject*>(array), &PyArray_Type)) || (PyArray_TYPE(array) != NPY_FLOAT)) + { + PyErr_SetString(PyExc_TypeError, "The data needs to be supplied as float32 numpy array!"); + return nullptr; + } + + if(PyArray_NDIM(array) > 2) + { + PyErr_SetString(PyExc_TypeError, "The array needs to have one or two dimensions!"); + return nullptr; + } + + if(rate <= 0) + { + PyErr_SetString(PyExc_TypeError, "The sample rate has to be positive!"); + return nullptr; + } + + Specs specs; + specs.rate = rate; + specs.channels = CHANNELS_MONO; + + if(PyArray_NDIM(array) == 2) + specs.channels = static_cast<Channels>(PyArray_DIM(array, 1)); + + int size = PyArray_DIM(array, 0) * AUD_SAMPLE_SIZE(specs); + + std::shared_ptr<Buffer> buffer = std::make_shared<Buffer>(size); + + std::memcpy(buffer->getBuffer(), PyArray_DATA(array), size); + + Sound* self; + + self = (Sound*)type->tp_alloc(type, 0); + if(self != nullptr) + { + try + { + self->sound = new std::shared_ptr<StreamBuffer>(new StreamBuffer(buffer, specs)); + } + catch(Exception& e) + { + Py_DECREF(self); + PyErr_SetString(AUDError, e.what()); + return nullptr; + } + } + + return (PyObject *)self; +} + PyDoc_STRVAR(M_aud_Sound_cache_doc, "cache()\n\n" "Caches a sound into RAM.\n" @@ -947,6 +1198,61 @@ return (PyObject *)parent; } +PyDoc_STRVAR(M_aud_Sound_resample_doc, + "resample(rate, high_quality)\n\n" + "Resamples the sound.\n\n" + ":arg rate: The new sample rate.\n" + ":type rate: double\n" + ":arg high_quality: When true use a higher quality but slower resampler.\n" + ":type high_quality: bool\n" + ":return: The created :class:`Sound` object.\n" + ":rtype: :class:`Sound`"); + +static PyObject * +Sound_resample(Sound* self, PyObject* args) +{ + double rate; + PyObject* high_qualityo; + bool high_quality = false; + + if(!PyArg_ParseTuple(args, "d|O:resample", &rate, &high_qualityo)) + return nullptr; + + if(!PyBool_Check(high_qualityo)) + { + PyErr_SetString(PyExc_TypeError, "high_quality is not a boolean!"); + return nullptr; + } + + high_quality = high_qualityo == Py_True; + + PyTypeObject* type = Py_TYPE(self); + Sound* parent = (Sound*)type->tp_alloc(type, 0); + + if(parent != nullptr) + { + try + { + DeviceSpecs specs; + specs.channels = CHANNELS_INVALID; + specs.rate = rate; + specs.format = FORMAT_INVALID; + if(high_quality) + parent->sound = new std::shared_ptr<ISound>(new JOSResample(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), specs)); + else + parent->sound = new std::shared_ptr<ISound>(new LinearResample(*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound), specs)); + } + catch(Exception& e) + { + Py_DECREF(parent); + PyErr_SetString(AUDError, e.what()); + return nullptr; + } + } + + return (PyObject *)parent; +} + PyDoc_STRVAR(M_aud_Sound_reverse_doc, "reverse()\n\n" "Plays a sound reversed.\n\n" @@ -1204,6 +1510,15 @@ } static PyMethodDef Sound_methods[] = { + {"data", (PyCFunction)Sound_data, METH_NOARGS, + M_aud_Sound_data_doc + }, + {"write", (PyCFunction)Sound_write, METH_VARARGS | METH_KEYWORDS, + M_aud_Sound_write_doc + }, + {"buffer", (PyCFunction)Sound_buffer, METH_VARARGS | METH_CLASS, + M_aud_Sound_buffer_doc + }, {"cache", (PyCFunction)Sound_cache, METH_NOARGS, M_aud_Sound_cache_doc }, @@ -1264,6 +1579,9 @@ {"rechannel", (PyCFunction)Sound_rechannel, METH_VARARGS, M_aud_Sound_rechannel_doc }, + {"resample", (PyCFunction)Sound_resample, METH_VARARGS, + M_aud_Sound_resample_doc + }, {"reverse", (PyCFunction)Sound_reverse, METH_NOARGS, M_aud_Sound_reverse_doc }, @@ -1288,6 +1606,50 @@ {nullptr} /* Sentinel */ }; +PyDoc_STRVAR(M_aud_Sound_specs_doc, + "The sample specification of the sound as a tuple with rate and channel count."); + +static PyObject * +Sound_get_specs(Sound* self, void* nothing) +{ + try + { + Specs specs = (*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))->createReader()->getSpecs(); + return Py_BuildValue("(di)", specs.rate, specs.channels); + } + catch(Exception& e) + { + PyErr_SetString(AUDError, e.what()); + return nullptr; + } +} + +PyDoc_STRVAR(M_aud_Sound_length_doc, + "The sample specification of the sound as a tuple with rate and channel count."); + +static PyObject * +Sound_get_length(Sound* self, void* nothing) +{ + try + { + int length = (*reinterpret_cast<std::shared_ptr<ISound>*>(self->sound))->createReader()->getLength(); + return Py_BuildValue("i", length); + } + catch(Exception& e) + { + PyErr_SetString(AUDError, e.what()); + return nullptr; + } +} + +static PyGetSetDef Sound_properties[] = { + {(char*)"specs", (getter)Sound_get_specs, nullptr, + M_aud_Sound_specs_doc, nullptr }, + {(char*)"length", (getter)Sound_get_length, nullptr, + M_aud_Sound_length_doc, nullptr }, + {nullptr} /* Sentinel */ +}; + PyDoc_STRVAR(M_aud_Sound_doc, "Sound objects are immutable and represent a sound that can be " "played simultaneously multiple times. They are called factories " @@ -1324,7 +1686,7 @@ 0, /* tp_iternext */ Sound_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + Sound_properties, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ @@ -1354,6 +1716,8 @@ bool initializeSound() { + import_array(); + return PyType_Ready(&SoundType) >= 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/bindings/python/setup.py.in new/audaspace-1.1/bindings/python/setup.py.in --- old/audaspace-1.0/bindings/python/setup.py.in 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/bindings/python/setup.py.in 2015-10-13 21:55:59.000000000 +0200 @@ -3,8 +3,26 @@ import sys import os import codecs +import numpy + +from distutils.core import setup, Extension + +if len(sys.argv) > 2 and sys.argv[1] == '--build-docs': + import subprocess + from distutils.core import Distribution + from distutils.command.build import build + + dist = Distribution() + cmd = build(dist) + cmd.finalize_options() + #print(cmd.build_platlib) + + os.environ['PYTHONPATH'] = os.path.join(os.getcwd(), cmd.build_platlib) + os.environ['LD_LIBRARY_PATH'] = os.getcwd() + + ret = subprocess.call(sys.argv[2:]) + sys.exit(ret) -from setuptools import setup, Extension # the following line is not working due to https://bugs.python.org/issue9023 #source_directory = os.path.relpath('@PYTHON_SOURCE_DIRECTORY@') @@ -20,7 +38,7 @@ audaspace = Extension( 'aud', - include_dirs = ['@CMAKE_CURRENT_BINARY_DIR@', os.path.join(source_directory, '../../include')], + include_dirs = ['@CMAKE_CURRENT_BINARY_DIR@', os.path.join(source_directory, '../../include'), numpy.get_include()], libraries = ['audaspace'], library_dirs = ['.', 'Debug', 'Release'], language = 'c++', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/config/Audaspace.h.in new/audaspace-1.1/config/Audaspace.h.in --- old/audaspace-1.0/config/Audaspace.h.in 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/config/Audaspace.h.in 2015-10-13 21:55:59.000000000 +0200 @@ -47,15 +47,21 @@ * Used for hiding symbols from export in the shared library. */ +// the following two defines and undefines are a hack to silence an error by doxygen + /** * \def AUD_SHARED_LIBRARY * Defined when audaspace was built as a shared library. */ +#define AUD_SHARED_LIBRARY +#undef AUD_SHARED_LIBRARY /** * \def AUD_STATIC_LIBRARY * Defined when audaspace was built as a static library. */ + #define AUD_STATIC_LIBRARY + #undef AUD_STATIC_LIBRARY #define @AUD_LIBRARY_TYPE@ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/demos/audaconvert.cpp new/audaspace-1.1/demos/audaconvert.cpp --- old/audaspace-1.0/demos/audaconvert.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/demos/audaconvert.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -105,7 +105,7 @@ if(writer->getSpecs().rate != specs.rate) { specs.rate = writer->getSpecs().rate; - reader = std::shared_ptr<IReader>(new JOSResampleReader(reader, specs.specs)); + reader = std::shared_ptr<IReader>(new JOSResampleReader(reader, specs.rate)); } FileWriter::writeReader(reader, writer, 0, AUD_DEFAULT_BUFFER_SIZE); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/doc/Doxyfile.in new/audaspace-1.1/doc/Doxyfile.in --- old/audaspace-1.0/doc/Doxyfile.in 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/doc/Doxyfile.in 2015-10-13 21:55:59.000000000 +0200 @@ -1133,7 +1133,7 @@ # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_TIMESTAMP = YES +HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/doc/setup.dox new/audaspace-1.1/doc/setup.dox --- old/audaspace-1.0/doc/setup.dox 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/doc/setup.dox 2015-10-13 21:55:59.000000000 +0200 @@ -9,7 +9,7 @@ Build Dependencies ------------------ -Audaspace is written in C++ 11 so a fairly recent compiler (g++ 4.8.2, clang 3.3, MSVC 2013) is needed to build it. The following build dependencies are all optional, but without any it's neither possible to open sound files nor play back through the speakers. +Audaspace is written in C++ 11 so a fairly recent compiler (g++ 4.8.2, clang 3.3, MSVC 2013) is needed to build it. The build system used is CMake and you need at least version 3.0. The following build dependencies are all optional, but without any it's neither possible to open sound files nor play back through the speakers. For windows a library folder called build-dependencies can be downloaded from https://github.com/audaspace/audaspace/releases. - OpenAL (input/output device) - SDL (output device) @@ -25,10 +25,17 @@ For the most recent version you can use git to get the source code. - git clone https://github.com:audaspace/audaspace.git + git clone https://github.com/audaspace/audaspace.git -Configuration -------------- +Plugins +------- + +Before diving into the exact build steps for each platform, we will have a look at plugins. There are so far two types of plugins: input and output plugins. Input plugins are for reading audio files in many different formats and output plugins are for output devices on different platforms. During the configuration audaspace's standard plugins can be enabled with their repsective `WITH_*` and `PLUGIN_*` configuration option. Plugins are built as shared libraries. By default audaspace looks in the `DEFAULT_PLUGIN_PATH` for shared libraries it can load. Building with a dependency (`WITH_*`) but without enabling the respective `PLUGIN_*` option will compile the plugin directly into the library, so the plugin always gets loaded when the plugins are initialised. + +Building for Linux +------------------ + +### Configuration ### It is highly recommended to build audaspace outside of the actual source code in a specific build directory. @@ -57,25 +64,47 @@ This specific configuration is recommended for a system wide installation of audaspace where all build dependencies are required. -Building --------- +### Building ### After configuration the building is as easy as running make -Installation ------------- +### Installation ### Installation is then also simple using make install -Using the library ------------------ +### Using the library ### When audaspace is installed to the system, the required configuration for _pkgconfig_ is also installed and pkgconfig can then be used to compile projects with audaspace. It is also possible to build audaspace as a static library and use it directly in a project. For this the library has to be configured accordingly with ccmake and after building the resulting library file can be added to the project's build system. +Building for Windows +-------------------- + +### Configuration ### + +Using cmake-gui select Visual Studio 2013 or 2015 for the architecture you want to build for and choose audaspace's source directory and a build directory. It is highly recommended to build audaspace outside of the source directory. During the first configuration cmake tries to find the dependencies. Dependencies that are not installed on the system are automatically disabled. To prevent this, enable `WITH_STRICT_DEPENDENCIES`. To use the build dependencies folder from the website, set the `LIBRARY_PATH` to point to the extracted directory. Also don't forget to set the `CMAKE_INSTALL_PREFIX` to a path where your user account can install to. Finally enable the dependencies that you want to use (`WITH_*`), configure and generate. + +### Building ### + +Open the project in Visual Studio and set the configuration to Release. Then you can simply hit the build button. + +### Installation ### + +To install audaspace to your target folder, build the INSTALL target. +Note that if you don't use the libraries folder provided on the website, the INSTALL target might fail and you need to copy the files manually, including the dlls of the dependencies. + +### Using the library ### + +To use audaspace in your project, configure the include path and the libraries that you need, which you can find in the include and lib directories in your installation path. + +### Notes for plugins on windows ### + +- FFMPEG: Due to a problem with FFMPEG's 32 bit libraries, it is necessary to disable SAFESEH for the audffmpeg build target inside Visual Studio (Properties, Linker, Advanced). This has to be done after each generate step of CMake. +- Jack: If no jack server is running on windows and your application or one of the demos tries to use the jack plugin, this adds a long delay to the device initialisation. In case you don't need jack, make sure to disable the plugin or for the prebuilt version of audaspace simply delete audjack.dll (and any files with jack in the name to clean up). + */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/include/respec/JOSResampleReader.h new/audaspace-1.1/include/respec/JOSResampleReader.h --- old/audaspace-1.0/include/respec/JOSResampleReader.h 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/include/respec/JOSResampleReader.h 2015-10-13 21:55:59.000000000 +0200 @@ -115,9 +115,9 @@ /** * Creates a resampling reader. * \param reader The reader to mix. - * \param specs The target specification. + * \param rate The target sampling rate. */ - JOSResampleReader(std::shared_ptr<IReader> reader, Specs specs); + JOSResampleReader(std::shared_ptr<IReader> reader, SampleRate rate); virtual void seek(int position); virtual int getLength() const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/include/respec/LinearResampleReader.h new/audaspace-1.1/include/respec/LinearResampleReader.h --- old/audaspace-1.0/include/respec/LinearResampleReader.h 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/include/respec/LinearResampleReader.h 2015-10-13 21:55:59.000000000 +0200 @@ -66,9 +66,9 @@ /** * Creates a resampling reader. * \param reader The reader to mix. - * \param specs The target specification. + * \param rate The target sampling rate. */ - LinearResampleReader(std::shared_ptr<IReader> reader, Specs specs); + LinearResampleReader(std::shared_ptr<IReader> reader, SampleRate rate); virtual void seek(int position); virtual int getLength() const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/include/util/StreamBuffer.h new/audaspace-1.1/include/util/StreamBuffer.h --- old/audaspace-1.0/include/util/StreamBuffer.h 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/include/util/StreamBuffer.h 2015-10-13 21:55:59.000000000 +0200 @@ -59,6 +59,26 @@ */ StreamBuffer(std::shared_ptr<ISound> sound); + /** + * Creates the sound from an preexisting buffer. + * \param buffer The buffer to stream from. + * \param specs The specification of the data in the buffer. + * \exception Exception Thrown if the reader cannot be created. + */ + StreamBuffer(std::shared_ptr<Buffer> buffer, Specs specs); + + /** + * Returns the buffer to be streamed. + * @return The buffer to stream. + */ + std::shared_ptr<Buffer> getBuffer(); + + /** + * Returns the specification of the buffer. + * @return The specification of the buffer. + */ + Specs getSpecs(); + virtual std::shared_ptr<IReader> createReader(); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/packages/pkgconfig/audaspace.pc.in new/audaspace-1.1/packages/pkgconfig/audaspace.pc.in --- old/audaspace-1.0/packages/pkgconfig/audaspace.pc.in 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/packages/pkgconfig/audaspace.pc.in 2015-10-13 21:55:59.000000000 +0200 @@ -1,6 +1,6 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -libdir=${exec_prefix}/lib +libdir=@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/include Name: audaspace diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/plugins/ffmpeg/FFMPEGWriter.cpp new/audaspace-1.1/plugins/ffmpeg/FFMPEGWriter.cpp --- old/audaspace-1.0/plugins/ffmpeg/FFMPEGWriter.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/plugins/ffmpeg/FFMPEGWriter.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -37,7 +37,7 @@ sample_t* dbuf = m_deinterleave_buffer.getBuffer(); // deinterleave - int single_size = AUD_FORMAT_SIZE(m_specs.format); + int single_size = sizeof(sample_t); for(int channel = 0; channel < m_specs.channels; channel++) { for(int i = 0; i < m_input_buffer.getSize() / AUD_SAMPLE_SIZE(m_specs); i++) @@ -71,14 +71,13 @@ frame->nb_samples = m_input_samples; frame->format = m_codecCtx->sample_fmt; + frame->channel_layout = m_codecCtx->channel_layout; - if(avcodec_fill_audio_frame(frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_samples * AUD_DEVICE_SAMPLE_SIZE(m_specs), 1) < 0) + if(avcodec_fill_audio_frame(frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0) AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg."); - if(m_codecCtx->coded_frame && m_codecCtx->coded_frame->pts != AV_NOPTS_VALUE) - frame->pts = av_rescale_q(m_codecCtx->coded_frame->pts, m_codecCtx->time_base, m_stream->time_base); - else - frame->pts = AV_NOPTS_VALUE; + AVRational sample_time = { 1, static_cast<int>(m_specs.rate) }; + frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time); if(avcodec_encode_audio2(m_codecCtx, &packet, frame, &got_packet)) { @@ -419,9 +418,9 @@ m_input_samples = length; - encode(); - m_position += length; + + encode(); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/src/devices/SoftwareDevice.cpp new/audaspace-1.1/src/devices/SoftwareDevice.cpp --- old/audaspace-1.0/src/devices/SoftwareDevice.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/src/devices/SoftwareDevice.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -845,9 +845,9 @@ // resample if(m_quality) - resampler = std::shared_ptr<ResampleReader>(new JOSResampleReader(reader, m_specs.specs)); + resampler = std::shared_ptr<ResampleReader>(new JOSResampleReader(reader, m_specs.rate)); else - resampler = std::shared_ptr<ResampleReader>(new LinearResampleReader(reader, m_specs.specs)); + resampler = std::shared_ptr<ResampleReader>(new LinearResampleReader(reader, m_specs.rate)); reader = std::shared_ptr<IReader>(resampler); // rechannel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/src/respec/JOSResample.cpp new/audaspace-1.1/src/respec/JOSResample.cpp --- old/audaspace-1.0/src/respec/JOSResample.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/src/respec/JOSResample.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -27,7 +27,7 @@ std::shared_ptr<IReader> JOSResample::createReader() { - return std::shared_ptr<IReader>(new JOSResampleReader(getReader(), m_specs.specs)); + return std::shared_ptr<IReader>(new JOSResampleReader(getReader(), m_specs.rate)); } AUD_NAMESPACE_END diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/src/respec/JOSResampleReader.cpp new/audaspace-1.1/src/respec/JOSResampleReader.cpp --- old/audaspace-1.0/src/respec/JOSResampleReader.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/src/respec/JOSResampleReader.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -31,8 +31,8 @@ AUD_NAMESPACE_BEGIN -JOSResampleReader::JOSResampleReader(std::shared_ptr<IReader> reader, Specs specs) : - ResampleReader(reader, specs.rate), +JOSResampleReader::JOSResampleReader(std::shared_ptr<IReader> reader, SampleRate rate) : + ResampleReader(reader, rate), m_channels(CHANNELS_INVALID), m_n(0), m_P(0), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/src/respec/LinearResample.cpp new/audaspace-1.1/src/respec/LinearResample.cpp --- old/audaspace-1.0/src/respec/LinearResample.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/src/respec/LinearResample.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -26,7 +26,7 @@ std::shared_ptr<IReader> LinearResample::createReader() { - return std::shared_ptr<IReader>(new LinearResampleReader(getReader(), m_specs.specs)); + return std::shared_ptr<IReader>(new LinearResampleReader(getReader(), m_specs.rate)); } AUD_NAMESPACE_END diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/src/respec/LinearResampleReader.cpp new/audaspace-1.1/src/respec/LinearResampleReader.cpp --- old/audaspace-1.0/src/respec/LinearResampleReader.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/src/respec/LinearResampleReader.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -21,14 +21,13 @@ AUD_NAMESPACE_BEGIN -LinearResampleReader::LinearResampleReader(std::shared_ptr<IReader> reader, - Specs specs) : - ResampleReader(reader, specs.rate), +LinearResampleReader::LinearResampleReader(std::shared_ptr<IReader> reader, SampleRate rate) : + ResampleReader(reader, rate), m_channels(reader->getSpecs().channels), m_cache_pos(0), m_cache_ok(false) { - specs.channels = m_channels; + Specs specs = { rate, m_channels }; m_cache.resize(2 * AUD_SAMPLE_SIZE(specs)); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/audaspace-1.0/src/util/StreamBuffer.cpp new/audaspace-1.1/src/util/StreamBuffer.cpp --- old/audaspace-1.0/src/util/StreamBuffer.cpp 2015-08-12 11:07:37.000000000 +0200 +++ new/audaspace-1.1/src/util/StreamBuffer.cpp 2015-10-13 21:55:59.000000000 +0200 @@ -60,6 +60,21 @@ m_buffer->resize(index * sample_size, true); } +StreamBuffer::StreamBuffer(std::shared_ptr<Buffer> buffer, Specs specs) : + m_buffer(buffer), m_specs(specs) +{ +} + +std::shared_ptr<Buffer> StreamBuffer::getBuffer() +{ + return m_buffer; +} + +Specs StreamBuffer::getSpecs() +{ + return m_specs; +} + std::shared_ptr<IReader> StreamBuffer::createReader() { return std::shared_ptr<IReader>(new BufferReader(m_buffer, m_specs));
