Skip to content

Commit

Permalink
Merge pull request #122 from ideoforms/feature/miniaudio
Browse files Browse the repository at this point in the history
Feature/miniaudio
  • Loading branch information
ideoforms authored Oct 28, 2024
2 parents 18f7d44 + 4a0633e commit 9651f3f
Show file tree
Hide file tree
Showing 48 changed files with 1,209 additions and 1,146 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ jobs:
run: |
sudo rm -rf /home/linuxbrew
sudo apt-get update -y
sudo apt-get install libasound2-dev libsoundio-dev libsndfile1-dev fftw3-dev -y
sudo apt-get install libasound2-dev libsndfile1-dev fftw3-dev -y
sudo apt-get install python3 python3-setuptools python3-pip
# Requires setuptools >= 62.1 for `python setup.py test`, as earlier versions
# used a different build path to the .so file as located in tests/__init__.py
# 2024-07-29: Require importlib_metadata for now due to this:
# https://github.com/pypa/setuptools/issues/4478
sudo pip3 install -U pytest numpy scipy setuptools>=62.1.0 importlib_metadata
curl https://raw.githubusercontent.com/mackron/miniaudio/master/miniaudio.h -o source/include/signalflow/node/io/output/miniaudio-library.h
- name: Configure
run: mkdir build && cd build && cmake ..
- name: Make
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ jobs:
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_BUILD: cp38-manylinux* cp39-manylinux* cp310-manylinux* cp311-manylinux* cp312-manylinux*
CIBW_BUILD: cp38-manylinux* cp39-manylinux* cp310-manylinux* cp311-manylinux* cp312-manylinux* cp313-manylinux*
CIBW_ARCHS_MACOS: arm64 x86_64
CIBW_ARCHS_LINUX: x86_64
CIBW_BEFORE_ALL_LINUX: >
yum install -y fftw-devel wget python3 sudo gcc &&
wget https://github.com/jackaudio/jack2/archive/v1.9.22.tar.gz && tar xzf v1.9.22.tar.gz && cd jack2-1.9.22 && python3 ./waf configure && /usr/bin/sudo python3 ./waf install && cd .. &&
wget https://www.alsa-project.org/files/pub/lib/alsa-lib-1.2.9.tar.bz2 && tar xjf alsa-lib-1.2.9.tar.bz2 && cd alsa-lib-1.2.9 && ./configure && make && /usr/bin/sudo make install && cd .. &&
git clone https://github.com/libsndfile/libsndfile.git && cd libsndfile && cmake -DBUILD_SHARED_LIBS=1 . && make && make install && cd .. &&
git clone https://github.com/andrewrk/libsoundio.git && cd libsoundio && cmake . && make && make install
CIBW_BEFORE_ALL_MACOS: brew install cmake python libsndfile libsoundio
git clone https://github.com/libsndfile/libsndfile.git && cd libsndfile && cmake -DBUILD_SHARED_LIBS=1 . && make && make install && cd ..
CIBW_BEFORE_ALL_MACOS: brew install cmake python libsndfile

- uses: actions/upload-artifact@v3
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ dist
.coverage
.ipynb_checkpoints
wheelhouse/
.vscode
.vs
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# CHANGELOG

## [v0.5.0](https://github.com/ideoforms/signalflow/tree/v0.5.0) (2024-10-28)

- Replaced the `libsoundio` audio abstraction layer with `miniaudio`, heralding first-class Windows and Linux support.
- Retired historical `AudioOut` classes for different operating systems, and refactored querying of inputs/outputs/backends
- `AudioGraphConfig`: Added `auto_record` flag, to automatically record all output in timestamped audio files
- Added support for instantiating `AudioGraph` and `AudioGraphConfig` with the path of a config file
- Modified `AudioGraph` to become a singleton, and throw a warning instead of an exception upon attempting to create a second `AudioGraph`
- Added Python bindings and added unit tests for `SampleRingBuffer` and `SampleRingQueue` classes
- Nodes:
- Added `Bus` node, to act as a fixed-channel summer with variable inputs
- Added `Maraca` node, a simple physically-inspired model of a shaker, after Cook (1997)
- Added `ChannelOffset` node to offset a node's output by `N` channels, and `node.play(output_channel=N)` syntax
- Added `SelectInput` node, to pass the output of an input whose index can be modulated at audio rate
- Added `HistoryBufferWriter` node to capture a rolling signal history window, useful for oscilloscope UI display
- Added `Accumulator` node, to accumulate energy with some leaky decay coefficient, and accompanying `calculate_decay_coefficient` function
- Added abstract `VariableInputNode` class
- Added `stutter_probability` and `stutter_advance_time` inputs to `Stutter`

## [v0.4.10](https://github.com/ideoforms/signalflow/tree/v0.4.10) (2024-08-13)

- Added `TriggerRoundRobin` node, to sequentially distribute triggers across outputs
Expand Down
148 changes: 77 additions & 71 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,47 @@
#-------------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.15.0)

#--------------------------------------------------------------------------------
# Allow deployment on older versions of macOS (back to 10.14 Mojave),
# and default to the include/lib paths of the current Python virtualenv
# (important for cross-compiling wheels)
#--------------------------------------------------------------------------------
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum macOS deployment version" FORCE)
set(Python_FIND_VIRTUALENV STANDARD)
set(Python_FIND_FRAMEWORKS LAST)

#-------------------------------------------------------------------------------
# Note that project() call should come after set CMAKE_OSX_DEPLOYMENT_TARGET,
# but CMAKE_SYSTEM_NAME is only available *after* project(), so any platform-
# dependent code should come later on.
#-------------------------------------------------------------------------------
project(SignalFlow C CXX)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Develop)
endif()

if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
#-------------------------------------------------------------------------------
# On Apple, build the current native system by default
#-------------------------------------------------------------------------------
if (NOT CMAKE_OSX_ARCHITECTURES)
execute_process(COMMAND uname -m
OUTPUT_VARIABLE CMAKE_OSX_ARCHITECTURES
OUTPUT_STRIP_TRAILING_WHITESPACE)
OUTPUT_VARIABLE CMAKE_OSX_ARCHITECTURES
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()

#-------------------------------------------------------------------------------
# Select the appropriate homebrew prefix by architecture
# Select the appropriate homebrew prefix by architecture.
# This is necessary so that the library is correctly linked against
# dependencies later on.
#-------------------------------------------------------------------------------
if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
set(CMAKE_PREFIX_PATH /opt/homebrew)
else()
set(CMAKE_PREFIX_PATH /usr/local)
endif()

#--------------------------------------------------------------------------------
# Allow deployment on older versions of macOS (back to 10.14 Mojave),
# and default to the include/lib paths of the current Python virtualenv
# (important for cross-compiling wheels)
#--------------------------------------------------------------------------------
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum macOS deployment version" FORCE)
set(Python_FIND_VIRTUALENV STANDARD)
set(Python_FIND_FRAMEWORKS LAST)
endif()

# project call should come after set CMAKE_OSX_DEPLOYMENT_TARGET
project(SignalFlow C CXX)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Develop)
endif()


#--------------------------------------------------------------------------------
# Print config setup to help with debugging
#--------------------------------------------------------------------------------
Expand All @@ -55,25 +60,32 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_MACOSX_RPATH 1)

#-------------------------------------------------------------------------------
# Shared compiler flags.
# Compiler flags for optimisations, warnings, etc.
#-------------------------------------------------------------------------------

if (NOT MSVC)
if (MSVC)
#-------------------------------------------------------------------------------
# Windows Visual C: Enable parallelisation
#-------------------------------------------------------------------------------
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
else()
#-------------------------------------------------------------------------------
# GCC/Clang: Enable strict compiler warnings
#-------------------------------------------------------------------------------
add_compile_options(
-pedantic
-fPIC
-Wall
)
endif()

#-------------------------------------------------------------------------------
# Hide superfluous compiler warnings on macOS
#-------------------------------------------------------------------------------
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_compile_options(
-Wno-gnu-zero-variadic-macro-arguments
-Wno-vla-extension
)
#-------------------------------------------------------------------------------
# Hide superfluous compiler warnings on macOS
#-------------------------------------------------------------------------------
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_compile_options(
-Wno-gnu-zero-variadic-macro-arguments
-Wno-vla-extension
)
endif()
endif()

include_directories(
Expand All @@ -84,15 +96,30 @@ include_directories(
source/lib/pybind11/include
)

#-------------------------------------------------------------------------------
# Compiler flags for debug vs release vs dev mode
#-------------------------------------------------------------------------------
if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
message("Building in debug mode")
add_compile_options(-ggdb3 -O0 -DDEBUG)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_compile_options(-O1)
else()
add_compile_options(-ggdb3 -O0 -DDEBUG)
endif()
elseif (${CMAKE_BUILD_TYPE} STREQUAL "Release")
message("Building in release mode")
add_compile_options(-O3 -funroll-loops)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_compile_options(-O2)
else()
add_compile_options(-O3 -funroll-loops)
endif()
else()
message("Building in dev mode")
add_compile_options(-O0)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_compile_options(-O1)
else()
add_compile_options(-O0)
endif()
endif()

#-------------------------------------------------------------------------------
Expand Down Expand Up @@ -130,57 +157,36 @@ add_library(signalflow SHARED ${SRC})
add_compile_definitions(SIGNALFLOW_VERSION="${SIGNALFLOW_VERSION}")

#-------------------------------------------------------------------------------
# Dependencies
# Dependency: libsndfile
#-------------------------------------------------------------------------------

set(SOUNDIO_BUILD_DIR "" CACHE PATH "Path to built SoundIO library (will use find_library if blank)")

if (SOUNDIO_BUILD_DIR)
set(SOUNDIO_INCLUDE_DIR "${SOUNDIO_BUILD_DIR}/.." CACHE PATH "Path to SoundIO include directory (ignored if SOUNDIO_BUILD_DIR is blank")
add_definitions(-DHAVE_SOUNDIO)
target_link_libraries(signalflow "${SOUNDIO_BUILD_DIR}/x64-Debug/soundio.lib")
include_directories(signalflow "${SOUNDIO_BUILD_DIR}/$<CONFIG>/")
include_directories(signalflow "${SOUNDIO_INCLUDE_DIR}/")
else()
find_library(SOUNDIO soundio)
if (SOUNDIO)
message("Found libsoundio")
add_definitions(-DHAVE_SOUNDIO)
target_link_libraries(signalflow ${SOUNDIO})
else()
message(SEND_ERROR "Couldn't find libsoundio")
endif()
endif()


set(SNDFILE_BUILD_DIR "" CACHE PATH "Path to build sndfile library (will use find_library if blank)")

if (SNDFILE_BUILD_DIR)
set(SNDFILE_INCLUDE_DIR "${SNDFILE_BUILD_DIR}/../include" CACHE PATH "Path to sndfile include directory (ignored if SNDFILE_BUILD_DIR is blank")
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(SNDFILE_BINARY_DIR "${PROJECT_SOURCE_DIR}/../libsndfile-1.2.2-win64" CACHE PATH "For Windows, path to downloaded sndfile directory")
add_definitions(-DHAVE_SNDFILE)
target_link_libraries(signalflow "${SNDFILE_BUILD_DIR}/sndfile")
include_directories(signalflow "${SNDFILE_BUILD_DIR}/include/")
include_directories(signalflow "${SNDFILE_INCLUDE_DIR}/")
target_link_libraries(signalflow "${SNDFILE_BINARY_DIR}/lib/sndfile.lib")
include_directories(signalflow "${SNDFILE_BINARY_DIR}/include/")
else()
find_library(SNDFILE sndfile)
if (SNDFILE)
message("Found sndfile")
add_definitions(-DHAVE_SNDFILE)
target_link_libraries(signalflow ${SNDFILE})
else()
message(SEND_ERROR "Couldn't find libsndfile")
else()
message(FATAL_ERROR "Couldn't find libsndfile")
endif()
endif()

#-------------------------------------------------------------------------------
# Dependency: fftw3
#-------------------------------------------------------------------------------
if (NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(FFTW_BUILD_DIR "" CACHE PATH "Path to prebuilt FFTW library (will use find_library if blank)")
if (FFTW_BUILD_DIR)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(FFTW_BUILD_DIR "${PROJECT_SOURCE_DIR}/../fftw-3.3.5-dll64" CACHE PATH "Path to prebuilt FFTW library (will use find_library if blank)")
include_directories("${FFTW_BUILD_DIR}")
add_definitions(-DFFT_FFTW)
target_link_libraries(signalflow
"${FFTW_BUILD_DIR}/libfftw3-3"
"${FFTW_BUILD_DIR}/libfftw3f-3"
"${FFTW_BUILD_DIR}/libfftw3l-3"
"${FFTW_BUILD_DIR}/libfftw3-3.lib"
"${FFTW_BUILD_DIR}/libfftw3f-3.lib"
"${FFTW_BUILD_DIR}/libfftw3l-3.lib"
)
else()
find_library(FFTW3F fftw3f)
Expand Down Expand Up @@ -225,4 +231,4 @@ endif()
# Install shared lib and all includes
#-------------------------------------------------------------------------------
install(TARGETS signalflow DESTINATION lib)
install(DIRECTORY source/include/signalflow DESTINATION include)
install(DIRECTORY source/include/signalflow DESTINATION include)
29 changes: 9 additions & 20 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Building from source assumes that you have a working installation of Python 3, i

To build on macOS from source, install dependencies with Homebrew:
```
brew install cmake libsndfile libsoundio
brew install cmake libsndfile
```

Clone this repository, then build and install with `pip`:
Expand All @@ -35,13 +35,8 @@ SignalFlow supports Linux (verified on Ubuntu 20.04 and Raspberry Pi OS buster)

To build the Python library from source on Linux, install dependencies with apt:
```
apt-get install -y git cmake g++ python3-pip libasound2-dev libsndfile1-dev libsoundio-dev fftw3-dev
```

If you experience an error on Raspberry Pi `libf77blas.so.3: cannot open shared object file`:

```
sudo apt-get install -y libatlas-base-dev
# If on Raspberry Pi: libfftw3-dev
apt-get install -y git cmake g++ python3-pip libasound2-dev libsndfile1-dev fftw3-dev
```

Clone this repository, then build and install with `pip`:
Expand All @@ -56,19 +51,13 @@ pip3 install .

### Windows

This is work in progress.

Currently, dependencies need to be downloaded and built by hand. These can be placed anywhere.

- https://github.com/timmb/libsoundio - check out the `fix-msvc` branch.
- Use CMake GUI to build libsoundio with Visual Studio 2019 with binaries in a subfolder of that repo named `build`. (Configure, Generate, Open project, Batch build all configurations)
- https://github.com/libsndfile/libsndfile
- Use CMake GUI to build libsndfile with Visual Studio 2019 with binaries in a subfolder of that repo named `build`. (Configure, Generate, Open project, Batch build all configurations)
- Download Windows binaries of FFTW from http://fftw.org/install/windows.html.

To build SignalFlow, use the CMake GUI. Press configure and you will see three empty fields to fill in with the path to the two build folders and the FFTW binaries folder (see above). Set these parameters then press Configure, then Generate then Open. Then build in Visual Studio 2019.
The build process for SignalFlow on 64-bit Windows has been verified with Visual Studio 2022 and CMake.

As of 2021-03-03, only the signalflow project has been ported to build correctly on Windows. Only tested in x64 and for Debug builds. Tested using Visual Studio 2019.
- Download Windows binaries of [FFTW](http://fftw.org/install/windows.html) and [libsndfile](https://github.com/libsndfile/libsndfile/releases/), and unzip them in the same filesystem location as the `signalflow` source directory
- Install Python 3, and dependencies: `python -m pip install build delvewheel`
- Build the binary wheel: `python -m build --wheel`
- Copy the libsndfile and fftw binaries into `dlls`
- Bundle the DLL dependencies with the wheel: `python -m delvewheel repair --add-path=dlls *.whl`

</details>

Expand Down
20 changes: 14 additions & 6 deletions auxiliary/cibuildwheel/make-macos-x86-arm64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,30 @@

ROOT=auxiliary/cibuildwheel

for VERSION in 38 39 310 311 312
for VERSION in 38 39 310 312 313 313
do
rm -r build
export CIBW_BUILD="cp${VERSION}-*"
export CIBW_BUILD_VERBOSITY=2
export CIBW_BUILD_VERBOSITY=1

. $ROOT/venv-$VERSION/bin/activate
pip3 install cibuildwheel
pip3 install cibuildwheel delocate

# For some reason, Python 3.13 seems to do additional validation on delocate which
# throws an exception when dependencies have a deployment target version set too high,
# and many of the dependencies on my build machine have a target of macOS 13 (Ventura).
# Need to verify whether the pre-3.13 builds are actually truly compatible with pre-Ventura!
if [ "$VERSION" == "313" ]; then
export MACOSX_DEPLOYMENT_TARGET=13.0
fi

#--------------------------------------------------------------------------------
# Make x86
# Make x86.
#--------------------------------------------------------------------------------
export REPAIR_LIBRARY_PATH=/usr/local/lib
export CIBW_ARCHS_MACOS="x86_64"
export CMAKE_OSX_ARCHITECTURES=x86_64
export CIBW_REPAIR_WHEEL_COMMAND_MACOS="DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
export CIBW_REPAIR_WHEEL_COMMAND_MACOS="DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel -w {dest_dir} -v {wheel}"

python3 -m cibuildwheel --output-dir wheelhouse --platform macos

Expand All @@ -33,7 +41,7 @@ do
export REPAIR_LIBRARY_PATH=/opt/homebrew/lib
export CIBW_ARCHS_MACOS="arm64"
export CMAKE_OSX_ARCHITECTURES=arm64
export CIBW_REPAIR_WHEEL_COMMAND_MACOS="DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
export CIBW_REPAIR_WHEEL_COMMAND_MACOS="DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel -w {dest_dir} -v {wheel}"

python3 -m cibuildwheel --output-dir wheelhouse --platform macos
done
Loading

0 comments on commit 9651f3f

Please sign in to comment.