Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/miniaudio #122

Merged
merged 34 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e32549e
Initial integration of miniaudio
ideoforms Oct 20, 2024
348179d
More work on miniaudio: List device/backend names
ideoforms Oct 20, 2024
9e28baa
GitHub Actions: Download miniaudio.h
ideoforms Oct 20, 2024
f439ce0
miniaudio: Add backend selector
ideoforms Oct 21, 2024
e47a02e
miniaudio: Add AudioIn support
ideoforms Oct 21, 2024
8d4c55e
Fix handling of newlines and quotes in pydocs
ideoforms Oct 21, 2024
f6f827f
miniaudio: Fix warnings
ideoforms Oct 21, 2024
6ac2efa
miniaudio: Further integration; retire old audio hardware layers
ideoforms Oct 21, 2024
bf47436
miniaudio: Further integration; retire old audio hardware layers
ideoforms Oct 21, 2024
6b60469
miniaudio: Switch to using static methods for querying backends/devices
ideoforms Oct 21, 2024
5312af4
Update CONTRIBUTING.md
ideoforms Oct 21, 2024
7f754c4
miniaudio: Add config.coreaudio.allowNominalSampleRateChange
ideoforms Oct 21, 2024
231de5f
miniaudio: Comments
ideoforms Oct 21, 2024
0cdd3d8
miniaudio: Add support for enumerating input devices
ideoforms Oct 21, 2024
5474da3
Fix list-backend-names
ideoforms Oct 21, 2024
f10d489
miniaudio: Support for selecting input device
ideoforms Oct 22, 2024
6be01ee
Input RingQueue tests
ideoforms Oct 24, 2024
3f290ad
miniaudio: Fix RingBuffer glitching on Linux with mutexes
ideoforms Oct 24, 2024
6ca7a85
Add Python bindings and tests for RingBuffer; fix read/write head pos…
ideoforms Oct 24, 2024
99cd5e6
Add Python bindings and tests for RingBuffer; fix read/write head pos…
ideoforms Oct 24, 2024
963ccd2
AudioGraph: Convert to a singleton, and generate a warning if multip…
ideoforms Oct 27, 2024
cf69360
Build system updates for Windows
ideoforms Oct 27, 2024
4ab5c5f
Merge branch 'feature/miniaudio' of github.com:ideoforms/signalflow i…
ideoforms Oct 27, 2024
44a3373
Fix graph destruction test by calling graph.destroy()
ideoforms Oct 27, 2024
397fcd6
Add signalflow_msleep
ideoforms Oct 27, 2024
b682a5a
Fix Linux build
ideoforms Oct 27, 2024
5c792e4
Fix Linux build
ideoforms Oct 27, 2024
e33a73e
Remove libsoundio from GitHub actions; update Windows build docs
ideoforms Oct 28, 2024
7474168
Update .gitignore
ideoforms Oct 28, 2024
ed7e565
macOS build fixes
ideoforms Oct 28, 2024
667358f
Update installation docs
ideoforms Oct 28, 2024
f0f79ec
Update version to 0.5.0
ideoforms Oct 28, 2024
799d614
GitHub Actions: Add Python 3.13 to wheels build
ideoforms Oct 28, 2024
4a0633e
Update CHANGELOG
ideoforms Oct 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading