cycsound 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cycsound-0.2.0/.github/workflows/wheels.yml +112 -0
- cycsound-0.2.0/.gitignore +69 -0
- cycsound-0.2.0/CHANGELOG.md +379 -0
- cycsound-0.2.0/CMakeLists.txt +193 -0
- cycsound-0.2.0/LICENSE +26 -0
- cycsound-0.2.0/Makefile +111 -0
- cycsound-0.2.0/PKG-INFO +305 -0
- cycsound-0.2.0/README.md +274 -0
- cycsound-0.2.0/TODO.md +15 -0
- cycsound-0.2.0/docs/comparison.md +138 -0
- cycsound-0.2.0/docs/ctcsound.py +2853 -0
- cycsound-0.2.0/docs/dev/deadlock-audit.md +121 -0
- cycsound-0.2.0/docs/dev/issues/01-reset-drops-message-string-callback.md +54 -0
- cycsound-0.2.0/docs/dev/issues/02-sensekey-ignores-keyboard-callback.md +67 -0
- cycsound-0.2.0/docs/dev/issues/03-udp-console-ignores-string-callback.md +61 -0
- cycsound-0.2.0/docs/dev/issues/04-init-pvs-channel-before-start-segfault.md +43 -0
- cycsound-0.2.0/docs/dev/issues/05-set-pvs-data-overread.md +60 -0
- cycsound-0.2.0/docs/dev/issues/06-kill-instance-unlocks-unowned-mutex.md +35 -0
- cycsound-0.2.0/docs/dev/issues/07-atexit-destroy-runs-host-callbacks.md +28 -0
- cycsound-0.2.0/docs/dev/issues/08-channel-creation-race.md +73 -0
- cycsound-0.2.0/docs/dev/issues/09-ugen-init-error-longjmp.md +69 -0
- cycsound-0.2.0/docs/dev/issues/10-append-opcode-keeps-caller-strings.md +72 -0
- cycsound-0.2.0/docs/dev/issues/11-readline-host-mode-claims-stdin.md +80 -0
- cycsound-0.2.0/docs/dev/issues/README.md +21 -0
- cycsound-0.2.0/docs/scratch.py +41 -0
- cycsound-0.2.0/include/arrays.h +381 -0
- cycsound-0.2.0/include/cfgvar.h +252 -0
- cycsound-0.2.0/include/coreDefs.h +179 -0
- cycsound-0.2.0/include/csPerfThread.h +187 -0
- cycsound-0.2.0/include/csPerfThread.hpp +268 -0
- cycsound-0.2.0/include/cs_par_structs.h +69 -0
- cycsound-0.2.0/include/csdebug.h +487 -0
- cycsound-0.2.0/include/csdl.h +200 -0
- cycsound-0.2.0/include/csound.h +1594 -0
- cycsound-0.2.0/include/csound.hpp +548 -0
- cycsound-0.2.0/include/csoundCore.h +1982 -0
- cycsound-0.2.0/include/csound_circular_buffer.h +127 -0
- cycsound-0.2.0/include/csound_compiler.h +93 -0
- cycsound-0.2.0/include/csound_data_structures.h +132 -0
- cycsound-0.2.0/include/csound_files.h +228 -0
- cycsound-0.2.0/include/csound_graph_display.h +72 -0
- cycsound-0.2.0/include/csound_misc.h +237 -0
- cycsound-0.2.0/include/csound_rtaudio.h +98 -0
- cycsound-0.2.0/include/csound_rtmidi.h +110 -0
- cycsound-0.2.0/include/csound_server.h +69 -0
- cycsound-0.2.0/include/csound_structs.h +32 -0
- cycsound-0.2.0/include/csound_threads.h +228 -0
- cycsound-0.2.0/include/csound_type_system.h +182 -0
- cycsound-0.2.0/include/csound_types.h +50 -0
- cycsound-0.2.0/include/cwindow.h +92 -0
- cycsound-0.2.0/include/float-version.h +34 -0
- cycsound-0.2.0/include/interlocks.h +61 -0
- cycsound-0.2.0/include/modload.h +58 -0
- cycsound-0.2.0/include/msg_attr.h +72 -0
- cycsound-0.2.0/include/plugin.h +1250 -0
- cycsound-0.2.0/include/pstream.h +282 -0
- cycsound-0.2.0/include/pvfileio.h +166 -0
- cycsound-0.2.0/include/soundfile.h +235 -0
- cycsound-0.2.0/include/soundio.h +78 -0
- cycsound-0.2.0/include/sysdep.h +678 -0
- cycsound-0.2.0/include/text.h +140 -0
- cycsound-0.2.0/include/ugen.h +254 -0
- cycsound-0.2.0/include/version.h +48 -0
- cycsound-0.2.0/pyproject.toml +99 -0
- cycsound-0.2.0/scripts/gen.py +42 -0
- cycsound-0.2.0/scripts/load_csnd.py +4 -0
- cycsound-0.2.0/scripts/parse.py +71 -0
- cycsound-0.2.0/scripts/vendor_csound7.sh +135 -0
- cycsound-0.2.0/src/cycsound/__init__.py +111 -0
- cycsound-0.2.0/src/cycsound/__main__.py +273 -0
- cycsound-0.2.0/src/cycsound/_core.pyx +3420 -0
- cycsound-0.2.0/src/cycsound/csound.pxd +616 -0
- cycsound-0.2.0/tests/README.md +8 -0
- cycsound-0.2.0/tests/diskgrain.csd +69 -0
- cycsound-0.2.0/tests/example11.py +77 -0
- cycsound-0.2.0/tests/example12.py +101 -0
- cycsound-0.2.0/tests/example8.py +100 -0
- cycsound-0.2.0/tests/example9.py +93 -0
- cycsound-0.2.0/tests/init.py +6 -0
- cycsound-0.2.0/tests/marimba.aif +0 -0
- cycsound-0.2.0/tests/singFemale.aif +0 -0
- cycsound-0.2.0/tests/test1.csd +18 -0
- cycsound-0.2.0/tests/test_array_channel.py +98 -0
- cycsound-0.2.0/tests/test_callbacks.py +467 -0
- cycsound-0.2.0/tests/test_channel_control.py +65 -0
- cycsound-0.2.0/tests/test_channel_hints.py +82 -0
- cycsound-0.2.0/tests/test_channel_update.py +112 -0
- cycsound-0.2.0/tests/test_circular_buffer.py +55 -0
- cycsound-0.2.0/tests/test_cli.py +105 -0
- cycsound-0.2.0/tests/test_compile_file.py +19 -0
- cycsound-0.2.0/tests/test_compile_file2.py +24 -0
- cycsound-0.2.0/tests/test_compile_text.py +27 -0
- cycsound-0.2.0/tests/test_cs7_700.py +121 -0
- cycsound-0.2.0/tests/test_cs7_beta18.py +216 -0
- cycsound-0.2.0/tests/test_cycsound.py +248 -0
- cycsound-0.2.0/tests/test_generate.py +41 -0
- cycsound-0.2.0/tests/test_graph_files.py +113 -0
- cycsound-0.2.0/tests/test_init.py +9 -0
- cycsound-0.2.0/tests/test_loop.py +29 -0
- cycsound-0.2.0/tests/test_midi.py +62 -0
- cycsound-0.2.0/tests/test_midi_host.py +157 -0
- cycsound-0.2.0/tests/test_opcodes_hostdata.py +70 -0
- cycsound-0.2.0/tests/test_perf_thread.py +238 -0
- cycsound-0.2.0/tests/test_recompile.py +34 -0
- cycsound-0.2.0/tests/test_thread.py +43 -0
- cycsound-0.2.0/tests/test_ugen.py +332 -0
- cycsound-0.2.0/uv.lock +651 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Build Wheels
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Every commit on every branch. A branches filter with no tags filter
|
|
5
|
+
# excludes tag pushes, so the publish job stays off.
|
|
6
|
+
push:
|
|
7
|
+
branches: ["**"]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
# A newer push to the same branch cancels the run in progress.
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build_wheels:
|
|
17
|
+
name: Build wheels on ${{ matrix.os }}
|
|
18
|
+
runs-on: ${{ matrix.os }}
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
# macos-13 is retired; macos-15-intel builds the x86_64 wheels.
|
|
23
|
+
os: [ubuntu-latest, macos-15-intel, macos-14, windows-latest]
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v7
|
|
27
|
+
|
|
28
|
+
# Linux and macOS builds vendor the Csound 7 release binaries during
|
|
29
|
+
# the CMake configure step (scripts/vendor_csound7.sh). Package managers
|
|
30
|
+
# (apt, Homebrew, choco) still ship Csound 6, which this wrapper does not
|
|
31
|
+
# target. cibuildwheel settings live in pyproject.toml.
|
|
32
|
+
- name: Install Csound 7 (Windows)
|
|
33
|
+
if: runner.os == 'Windows'
|
|
34
|
+
shell: pwsh
|
|
35
|
+
run: |
|
|
36
|
+
$zip = Join-Path $env:RUNNER_TEMP csound.zip
|
|
37
|
+
$dir = Join-Path $env:RUNNER_TEMP csound
|
|
38
|
+
Invoke-WebRequest https://github.com/csound/csound/releases/download/7.0.0/csound-windows-7.0.0.zip -OutFile $zip
|
|
39
|
+
Expand-Archive $zip -DestinationPath $dir
|
|
40
|
+
$exe = Get-ChildItem $dir -Recurse -Filter *.exe | Select-Object -First 1
|
|
41
|
+
# Inno Setup installer; pin the path CMakeLists.txt expects.
|
|
42
|
+
Start-Process $exe.FullName -Wait -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART','/DIR="C:\Program Files\Csound7_x64"'
|
|
43
|
+
Get-ChildItem 'C:\Program Files\Csound7_x64' -Recurse -Include csound64.*,csound.h | Select-Object FullName
|
|
44
|
+
|
|
45
|
+
- name: Build wheels
|
|
46
|
+
uses: pypa/cibuildwheel@v3.3.1
|
|
47
|
+
|
|
48
|
+
- uses: actions/upload-artifact@v7
|
|
49
|
+
with:
|
|
50
|
+
name: wheels-${{ matrix.os }}
|
|
51
|
+
path: ./wheelhouse/*.whl
|
|
52
|
+
|
|
53
|
+
build_sdist:
|
|
54
|
+
name: Build source distribution
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v7
|
|
58
|
+
|
|
59
|
+
- name: Build sdist
|
|
60
|
+
run: pipx run build --sdist
|
|
61
|
+
|
|
62
|
+
- uses: actions/upload-artifact@v7
|
|
63
|
+
with:
|
|
64
|
+
name: sdist
|
|
65
|
+
path: dist/*.tar.gz
|
|
66
|
+
|
|
67
|
+
# One download with every wheel and the sdist. Runs when some builds fail,
|
|
68
|
+
# so the successful ones are still downloadable.
|
|
69
|
+
collect:
|
|
70
|
+
name: Collect distributions
|
|
71
|
+
needs: [build_wheels, build_sdist]
|
|
72
|
+
if: ${{ !cancelled() }}
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
steps:
|
|
75
|
+
- uses: actions/download-artifact@v8
|
|
76
|
+
with:
|
|
77
|
+
path: dist
|
|
78
|
+
merge-multiple: true
|
|
79
|
+
|
|
80
|
+
- run: ls -l dist
|
|
81
|
+
|
|
82
|
+
- uses: actions/upload-artifact@v7
|
|
83
|
+
with:
|
|
84
|
+
name: cycsound-dist
|
|
85
|
+
path: dist/*
|
|
86
|
+
if-no-files-found: error
|
|
87
|
+
|
|
88
|
+
publish:
|
|
89
|
+
name: Publish to PyPI
|
|
90
|
+
needs: [build_wheels, build_sdist]
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
93
|
+
environment:
|
|
94
|
+
name: pypi
|
|
95
|
+
url: https://pypi.org/p/cycsound
|
|
96
|
+
permissions:
|
|
97
|
+
id-token: write
|
|
98
|
+
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/download-artifact@v8
|
|
101
|
+
with:
|
|
102
|
+
pattern: wheels-*
|
|
103
|
+
path: dist
|
|
104
|
+
merge-multiple: true
|
|
105
|
+
|
|
106
|
+
- uses: actions/download-artifact@v8
|
|
107
|
+
with:
|
|
108
|
+
name: sdist
|
|
109
|
+
path: dist
|
|
110
|
+
|
|
111
|
+
- name: Publish to PyPI
|
|
112
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
__pycache__
|
|
3
|
+
*.pyc
|
|
4
|
+
.pytest_cache
|
|
5
|
+
.venv
|
|
6
|
+
cycsound.c
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
tests/test.aif
|
|
10
|
+
|
|
11
|
+
# Prerequisites
|
|
12
|
+
*.d
|
|
13
|
+
|
|
14
|
+
# Object files
|
|
15
|
+
*.o
|
|
16
|
+
*.ko
|
|
17
|
+
*.obj
|
|
18
|
+
*.elf
|
|
19
|
+
|
|
20
|
+
# Linker output
|
|
21
|
+
*.ilk
|
|
22
|
+
*.map
|
|
23
|
+
*.exp
|
|
24
|
+
|
|
25
|
+
# Precompiled Headers
|
|
26
|
+
*.gch
|
|
27
|
+
*.pch
|
|
28
|
+
|
|
29
|
+
# Libraries
|
|
30
|
+
*.lib
|
|
31
|
+
*.a
|
|
32
|
+
*.la
|
|
33
|
+
*.lo
|
|
34
|
+
|
|
35
|
+
# Shared objects (inc. Windows DLLs)
|
|
36
|
+
*.dll
|
|
37
|
+
*.so
|
|
38
|
+
*.so.*
|
|
39
|
+
*.dylib
|
|
40
|
+
|
|
41
|
+
# Executables
|
|
42
|
+
*.exe
|
|
43
|
+
*.out
|
|
44
|
+
*.app
|
|
45
|
+
*.i*86
|
|
46
|
+
*.x86_64
|
|
47
|
+
*.hex
|
|
48
|
+
|
|
49
|
+
# Debug files
|
|
50
|
+
*.dSYM/
|
|
51
|
+
*.su
|
|
52
|
+
*.idb
|
|
53
|
+
*.pdb
|
|
54
|
+
|
|
55
|
+
# Kernel Module Compile Results
|
|
56
|
+
*.mod*
|
|
57
|
+
*.cmd
|
|
58
|
+
.tmp_versions/
|
|
59
|
+
modules.order
|
|
60
|
+
Module.symvers
|
|
61
|
+
Mkfile.old
|
|
62
|
+
dkms.conf
|
|
63
|
+
|
|
64
|
+
# claude
|
|
65
|
+
.claude
|
|
66
|
+
CLAUDE.md
|
|
67
|
+
|
|
68
|
+
# vendored Csound 7 framework (fetched via scripts/vendor_csound7.sh)
|
|
69
|
+
vendor/
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
Sync to Csound **7.0.0** (from beta.16).
|
|
11
|
+
|
|
12
|
+
### Build
|
|
13
|
+
|
|
14
|
+
- `scripts/vendor_csound7.sh` now defaults to the `7.0.0` tag and
|
|
15
|
+
vendors on Linux as well as macOS. On Linux it stages the
|
|
16
|
+
`csound-linux-minimal-x86_64` release asset as `vendor/lib/` (the shared
|
|
17
|
+
library) and `vendor/plugins/` (the opcode plugins), and gives the plugins an
|
|
18
|
+
rpath to the vendored library when `patchelf` is available.
|
|
19
|
+
- `CMakeLists.txt`: the Linux branch links the vendored `libcsound64.so` with an
|
|
20
|
+
rpath instead of a system `csound64`, and takes its headers from the
|
|
21
|
+
repo-local `include/` (the Linux release ships none). It auto-runs the
|
|
22
|
+
vendoring script when the library is missing, as the macOS branch does. A
|
|
23
|
+
distro `csound` package is Csound 6, whose host API this wrapper does not
|
|
24
|
+
target.
|
|
25
|
+
- `CMakeLists.txt`: the Windows branch points at `C:/Program Files/Csound7_x64`
|
|
26
|
+
(was `Csound6_x64`) and exposes `CSOUND_ROOT` as a cache variable.
|
|
27
|
+
- `Makefile`: the vendoring prerequisite resolves per platform
|
|
28
|
+
(`vendor/CsoundLib64.framework` on macOS, `vendor/lib/libcsound64.so`
|
|
29
|
+
elsewhere).
|
|
30
|
+
- CI and `cibuildwheel` no longer install a system Csound 6 on Linux/macOS;
|
|
31
|
+
those builds vendor Csound 7 during CMake configure.
|
|
32
|
+
- `include/` synced to the beta.18 headers. beta.18 renames `MYFLT` to
|
|
33
|
+
`cs_float` (`csound_types.h`) and re-declares `MYFLT` as a deprecated
|
|
34
|
+
typedef, so the `MYFLT=double` compile definition is dropped: it expanded
|
|
35
|
+
that typedef to `typedef cs_float double` and broke the build.
|
|
36
|
+
- `include/` synced to the 7.0.0 headers. No wrapped signature changed;
|
|
37
|
+
`OPARMS` gains a trailing `no_deprecated_warnings` field.
|
|
38
|
+
- Wheels: the upstream 7.0.0 binaries raise the platform floors. macOS wheels
|
|
39
|
+
target 12.0, and Linux wheels build on `manylinux_2_34` because
|
|
40
|
+
`libcsound64.so` needs `GLIBC_2.29`. Windows CI installs the 7.0.0 release
|
|
41
|
+
(choco ships 6.17), and `delvewheel` bundles `csound64.dll`. `macos-13`
|
|
42
|
+
(retired) is replaced by `macos-15-intel`. cibuildwheel settings now live
|
|
43
|
+
only in `pyproject.toml`. The wheel workflow runs on every branch push;
|
|
44
|
+
tag pushes, and so PyPI publishing, stay off.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- `Csound.event()` raises `RuntimeError` when called synchronously before
|
|
49
|
+
`start()`. Csound dropped such events silently (both `i` and `f`). Use
|
|
50
|
+
`event_string()`, or `async_=True` for at most 1024 queued events.
|
|
51
|
+
- `set_keyboard_callback()` registers its C function once and swaps only the
|
|
52
|
+
Python callable, including on `None`. Csound frees keyboard-list entries
|
|
53
|
+
without a lock while the performing thread walks the list.
|
|
54
|
+
- The C host data of a `Csound` instance now points at its callback state,
|
|
55
|
+
not at the `host_data` object. Code that read `csoundGetHostData()` from
|
|
56
|
+
Cython must use `Csound.host_data`.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- `run()` returned 0 when performance failed. In 7.0.0 `csoundPerformKsmps`
|
|
61
|
+
returns a negative value on error, e.g. on re-entry from a callback during
|
|
62
|
+
a render pass. `run()` now returns that value.
|
|
63
|
+
- `compile_tree()` and `udp_server_close()` deadlocked with a callback set. A
|
|
64
|
+
performing thread holds `API_lock` while its callback waits for the GIL.
|
|
65
|
+
`compile_tree` held the GIL while its sync merge waited for `API_lock`.
|
|
66
|
+
`udp_server_close` held it while joining a server thread that prints on
|
|
67
|
+
exit. Both now release the GIL. See `docs/dev/deadlock-audit.md`.
|
|
68
|
+
- `udp_console()` and a message callback or hook now raise `RuntimeError`
|
|
69
|
+
while the other is active: the console replaces Csound's message callback.
|
|
70
|
+
`stop_udp_console()` re-installs the callback.
|
|
71
|
+
- Callback workarounds for Csound behaviour, found while adding callbacks
|
|
72
|
+
(upstream drafts in `docs/dev/issues/`):
|
|
73
|
+
- `reset()` reverts the message string callback to the default printer;
|
|
74
|
+
the wrapper re-installs it.
|
|
75
|
+
- `csoundDoCallback_` returns 1 even when a keyboard callback succeeds, so
|
|
76
|
+
`sensekey` polled stdin and overwrote the key. Registering a keyboard
|
|
77
|
+
callback or hook now calls `csoundKeyPress(cs, 0)`, which stops the
|
|
78
|
+
polling, and repeats it after `reset()`.
|
|
79
|
+
- Csound's C atexit handler destroys live instances after Python has
|
|
80
|
+
finalized. A message callback then blocked forever waiting for the GIL.
|
|
81
|
+
Callbacks are now detached from live instances in a Python atexit
|
|
82
|
+
handler, and the trampolines skip Python once finalization starts.
|
|
83
|
+
- `Csound.get_control_channel_hints()` leaked the `attributes` string; Csound
|
|
84
|
+
allocates a copy per call, now released with
|
|
85
|
+
`csoundDeleteControlChannelHints`.
|
|
86
|
+
- Linux: the extension is now loaded with `RTLD_GLOBAL`, and `OPCODE7DIR64` is
|
|
87
|
+
pointed at `vendor/plugins` for a source build when it is unset. The Linux
|
|
88
|
+
release is a minimal build whose opcode library ships as external plugins;
|
|
89
|
+
those resolve Csound symbols out of the global symbol namespace, so without
|
|
90
|
+
this they failed to register silently and orchestras using them (`vco2`,
|
|
91
|
+
`moogladder`, `diskgrain`, ...) did not compile.
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- `csound.pxd` now declares the full public surface of Csound 7's `csound.h`.
|
|
96
|
+
Previously missing: the message callbacks (`csoundSetMessageCallback`,
|
|
97
|
+
`csoundSetMessageStringCallback`, `csoundSetDefaultMessageCallback`,
|
|
98
|
+
`csoundMessageV`), the keyboard callbacks
|
|
99
|
+
(`csoundRegisterKeyboardCallback`/`csoundRemoveKeyboardCallback`), the
|
|
100
|
+
input/output channel callbacks, `csoundGetChannelVarType`, the array/string/
|
|
101
|
+
fsig channel data accessors (`csoundInitArrayChannel`, `csoundArrayData*`,
|
|
102
|
+
`csoundGet`/`SetArrayData`, `csoundGet`/`SetStringData`,
|
|
103
|
+
`csoundInitPvsChannel`, `csoundPvsData*`, `csoundGet`/`SetPvsData`),
|
|
104
|
+
`csoundAppendOpcode`/`csoundAppendOpcodes`, the `DEBUG_STATUS` levels, the
|
|
105
|
+
`CSOUNDINIT_*` flags and the `CSOUND_CALLBACK_KBD_*` types.
|
|
106
|
+
- `Csound.set_audio_channel(name, block)` / `Csound.get_audio_channel(name)` -
|
|
107
|
+
read and write a ksmps-sized block on an audio channel.
|
|
108
|
+
- `Csound.set_control_channel_hints(...)` /
|
|
109
|
+
`Csound.get_control_channel_hints(name)` - control channel display hints,
|
|
110
|
+
with a `ChannelBehavior` enum for the behaviour values.
|
|
111
|
+
- `Csound.run_utility(name, *args)` - `csoundRunUtility`.
|
|
112
|
+
- `set_global_env(name, value)` and `sleep(milliseconds)` module functions.
|
|
113
|
+
- beta.18 host API:
|
|
114
|
+
- `Csound.set_command_line_args(*args)` / `get_command_line_args()` - the
|
|
115
|
+
arguments after `--` that the orchestra reads with `argv`.
|
|
116
|
+
- `Csound.copy_channel(source, dest)` - `csoundGetChannel` +
|
|
117
|
+
`csoundSetChannel`; copies a channel of any type. A raw `CS_VAR_MEM`
|
|
118
|
+
handle is not exposed: Python cannot interpret it without the type system.
|
|
119
|
+
- `Csound.init_pvs_channel(...)`, `set_pvs_channel(name, data)`,
|
|
120
|
+
`get_pvs_channel(name, data)`, and the `PvsData`, `PvsWindow` and
|
|
121
|
+
`PvsFormat` types. `init_pvs_channel` raises before `start()` because
|
|
122
|
+
Csound segfaults allocating the frame then. A `PvsData` raises after
|
|
123
|
+
`reset()` instead of reading freed memory. `PvsData.set_frame` writes
|
|
124
|
+
exactly `fft_size + 2` floats instead of calling `csoundSetPvsData`, which
|
|
125
|
+
copies the allocated frame size and overreads once a smaller frame has
|
|
126
|
+
been copied in.
|
|
127
|
+
- `Csound.readline_push_text(text)` - input for the `readline` opcode.
|
|
128
|
+
- `Csound.perform_output_fade(frames)` - a no-op without realtime output.
|
|
129
|
+
- `get_size_of_cs_float()` / `get_size_of_cs_double()`;
|
|
130
|
+
`get_size_of_myflt` is kept as an alias.
|
|
131
|
+
- `Params.recursion_depth`.
|
|
132
|
+
- 7.0.0 host API: `Csound.set_readline_callback(callback)` and
|
|
133
|
+
`readline_submit(request_id, text)`, host-side input for the `readline`
|
|
134
|
+
opcode. `callback(request_id, prompt)` gets the prompt when a line request
|
|
135
|
+
opens and `None` when it closes. 7.0.0 `readline` claims stdin for the whole
|
|
136
|
+
process even in this mode, so a second live instance gets an init error
|
|
137
|
+
(`docs/dev/issues/11-readline-host-mode-claims-stdin.md`).
|
|
138
|
+
- Host-implemented realtime MIDI (`csound_rtmidi.h`), for use with
|
|
139
|
+
`set_host_midi_io()`: `set_midi_in_callbacks(open, read, close)`,
|
|
140
|
+
`set_midi_out_callbacks(open, write, close)`,
|
|
141
|
+
`set_midi_device_list_callback()` and `set_midi_error_string_hook()`. Each
|
|
142
|
+
slot takes a Python callable or a C function address. `open` returns a
|
|
143
|
+
handle object that `read`/`write`/`close` receive, so no `void **` user data
|
|
144
|
+
reaches Python. A raised exception returns -1 to Csound. The wrapper
|
|
145
|
+
re-installs the callbacks after `reset()`, which replaces them with
|
|
146
|
+
Csound's dummies.
|
|
147
|
+
- Unit generator API (`ugen.h`): `Csound.ugen_factory()` returns a
|
|
148
|
+
`UgenFactory`, which creates `Ugen`, `UgenVar`, `UgenContext` and
|
|
149
|
+
`UgenGraph` objects and lists opcode entries. Each object keeps its parents
|
|
150
|
+
alive, because `csoundUgenDelete()` runs the opcode's deinit against the
|
|
151
|
+
factory's or context's state, and a wired input reads its source's memory.
|
|
152
|
+
The objects raise after `reset()`, which frees their pool memory.
|
|
153
|
+
`set_input_var()` rejects mismatched types, and `UgenVar.value` rejects
|
|
154
|
+
non-scalars: Csound checks neither, and a k source on an a input reads
|
|
155
|
+
ksmps floats from a one-float slot. `Ugen.set_in_value()`,
|
|
156
|
+
`get_out_value()`, `set_in_string()` and `get_out_string()` call the
|
|
157
|
+
`csoundUgen*Value`/`*String` index helpers directly with the same guards;
|
|
158
|
+
they avoid a `UgenVar` per call (about 45 ns vs 105 ns).
|
|
159
|
+
`UgenGraph.delete_all()` frees the graph and its Ugens immediately
|
|
160
|
+
(`csoundUgenGraphDeleteAll`), so deinit runs without waiting for the GC.
|
|
161
|
+
It refuses a Ugen that occurs twice, sits in another graph, or feeds a Ugen
|
|
162
|
+
outside the graph, since each would then use freed memory; afterwards the
|
|
163
|
+
deleted objects raise on use. `Ugen.delete()` does the same for one Ugen
|
|
164
|
+
(`csoundUgenDelete`) and refuses while any graph holds it. An opcode init error crashes the
|
|
165
|
+
process (`docs/dev/issues/09-ugen-init-error-longjmp.md`).
|
|
166
|
+
- Array channels: `Csound.init_array_channel(name, type, sizes)` returns an
|
|
167
|
+
`ArrayChannel` with `type`, `sizes`, flat `get()`/`set()` for i/k/a arrays
|
|
168
|
+
and `get_string()`/`set_string()` for S arrays. Element strides come from
|
|
169
|
+
`ARRAYDAT`, so the build now includes the plugin header `csdl.h`.
|
|
170
|
+
`set_string()` refuses elements whose buffer aliases another string:
|
|
171
|
+
`csoundSetStringData()` would write into, or reallocate, memory it does not
|
|
172
|
+
own.
|
|
173
|
+
- `Csound.create_circular_buffer(size, element_size)` returns a
|
|
174
|
+
`CircularBuffer` (Csound's single-reader, single-writer ring buffer) that
|
|
175
|
+
moves bytes in whole elements and exposes its `address` for C code.
|
|
176
|
+
- Graph display: `set_is_graphable()` and `set_graph_callbacks(make, draw,
|
|
177
|
+
kill, exit)`. Python callbacks get a `GraphWindow` snapshot, since the
|
|
178
|
+
`WINDAT` belongs to Csound; `make()` may return the window's `windid`. The
|
|
179
|
+
wrapper re-applies both after `reset()`: reset clears the graphable flag,
|
|
180
|
+
and a `-d` run leaves no-op callbacks in the block reset preserves. Csound
|
|
181
|
+
7.0.0 never calls `kill`.
|
|
182
|
+
- File callbacks: `set_file_open_callback()` (notification, with a
|
|
183
|
+
`FileType` enum), `set_open_file_callback()` and
|
|
184
|
+
`set_open_sound_file_callback()` (return a `FILE *` or sound-file handle
|
|
185
|
+
address, or None to let Csound open the file), and
|
|
186
|
+
`set_sndfile_callbacks(address)`. Csound reverts the sndfile callbacks on
|
|
187
|
+
`reset()`, so the wrapper keeps a copy of the struct and re-applies it.
|
|
188
|
+
- `append_opcode()` (C function addresses) and `append_opcodes()` (an
|
|
189
|
+
`OENTRY` array) register C opcodes; `OPDS_SIZE` locates the argument
|
|
190
|
+
pointers. Csound keeps the name and type-string pointers instead of copying
|
|
191
|
+
them, so `append_opcode()` holds the encoded strings until `reset()`
|
|
192
|
+
(`docs/dev/issues/10-append-opcode-keeps-caller-strings.md`).
|
|
193
|
+
- `Csound.host_data` is settable. `csoundSetHostData` itself stays
|
|
194
|
+
unexposed: the C host data routes callbacks to the instance.
|
|
195
|
+
- Callbacks for messages, `invalue`/`outvalue` channels and keyboard input,
|
|
196
|
+
at two levels:
|
|
197
|
+
- Python callables, called with the GIL: `set_message_callback`,
|
|
198
|
+
`set_input_channel_callback`, `set_output_channel_callback`,
|
|
199
|
+
`set_keyboard_callback`, with a `KeyCallbackType` enum.
|
|
200
|
+
- C function pointers, passed as int addresses and called without the GIL:
|
|
201
|
+
`set_message_hook`, `set_input_channel_hook`, `set_output_channel_hook`,
|
|
202
|
+
`register_keyboard_hook` / `remove_keyboard_hook`. Addresses over a
|
|
203
|
+
Cython-level API because the wheel ships no `.pxd`; any C-callable
|
|
204
|
+
(Cython, ctypes, cffi, numba `cfunc`) works.
|
|
205
|
+
|
|
206
|
+
A hook and a callback may share a slot; the hook runs first. A message
|
|
207
|
+
callback and the message buffer cannot both be set, since Csound routes to
|
|
208
|
+
one: each setter raises `RuntimeError` while the other is active.
|
|
209
|
+
- `Csound.host_data` returns the constructor's `host_data`.
|
|
210
|
+
- `CsoundPerformanceThread(csound)`: performs a started instance on a native
|
|
211
|
+
thread, wrapping Csound's `csPerfThread` C API. Its unbounded, locked
|
|
212
|
+
message queue is the safe way to send events, code and score changes from
|
|
213
|
+
other threads. The Csound API's own `async` queue holds 1024 entries and
|
|
214
|
+
busy-waits when full. Process callbacks come at both levels
|
|
215
|
+
(`set_process_callback`, `set_process_hook`). `eval_code` and
|
|
216
|
+
`request_callback` run Python on the performance thread. `join`,
|
|
217
|
+
`flush_message_queue` and destruction release the GIL, and live threads
|
|
218
|
+
are stopped at interpreter exit. `tests/test_thread.py` is rewritten for
|
|
219
|
+
the Csound 7 API and no longer skipped.
|
|
220
|
+
|
|
221
|
+
### Known gaps
|
|
222
|
+
|
|
223
|
+
Declared in `csound.pxd` but not exposed: `csoundTableCopyOut`,
|
|
224
|
+
`csoundScoreSort`/`csoundScoreExtract` (`FILE *` arguments), `csoundMessageV`
|
|
225
|
+
(`va_list`), `csoundSetDefaultMessageCallback`, and `csoundGetChannelVarType`
|
|
226
|
+
(`get_channel_var_type_name()` returns the same name).
|
|
227
|
+
|
|
228
|
+
## [0.2.0]
|
|
229
|
+
|
|
230
|
+
Port from Csound 6 to **Csound 7** (beta). Csound 7 reworked the host C API, so
|
|
231
|
+
this is a breaking change to both the build and the Python API.
|
|
232
|
+
|
|
233
|
+
### Build
|
|
234
|
+
|
|
235
|
+
- Target the Csound 7 `CsoundLib64.framework` on macOS, vendored into a
|
|
236
|
+
repo-local `vendor/` directory by `scripts/vendor_csound7.sh` (downloads the
|
|
237
|
+
beta `.pkg`, extracts the framework, repoints its install id, and re-signs).
|
|
238
|
+
`/Library/Frameworks` is no longer used, so a Csound 6 install can coexist.
|
|
239
|
+
- The framework is downloaded over plain HTTPS with `curl` (with a `wget`
|
|
240
|
+
fallback) from the public GitHub release asset -- no GitHub account or `gh`
|
|
241
|
+
CLI required. A tag can be passed to the script, e.g.
|
|
242
|
+
`scripts/vendor_csound7.sh 7.0.0-beta.16`.
|
|
243
|
+
- The framework is fetched automatically when missing: the `build`/`test`/`sync`
|
|
244
|
+
Makefile targets carry an order-only prerequisite on
|
|
245
|
+
`vendor/CsoundLib64.framework`, and `CMakeLists.txt` also runs the vendoring
|
|
246
|
+
script during configure (covering `pip install .` / `uv build`, which do not
|
|
247
|
+
go through `make`).
|
|
248
|
+
- `CMakeLists.txt` points at the vendored framework; macOS static linking is
|
|
249
|
+
disabled (the framework ships dynamic libraries only).
|
|
250
|
+
- `include/` headers refreshed to the Csound 7 set.
|
|
251
|
+
- `make test` now invokes `python -m pytest`.
|
|
252
|
+
|
|
253
|
+
### Changed / Added (Python API mirrors Csound 7)
|
|
254
|
+
|
|
255
|
+
- `Csound(host_data=None, opcodedir=None)` - `csoundCreate` takes an opcode
|
|
256
|
+
directory override.
|
|
257
|
+
- `compile_orc(orc, async_=False)` - merged async flag (no `compile_orc_async`).
|
|
258
|
+
- `compile_csd(file)` / `compile_csd_text(text)` - both call `csoundCompileCSD`.
|
|
259
|
+
- `event(type, params, async_=False)` and `event_string(message, async_=False)`
|
|
260
|
+
replace `read_score`, `input_message`, and the `score_event*` family.
|
|
261
|
+
- `get_instr_number(name)`, `get_kcounter()`, `err_cnt()`, `lock_channel()` /
|
|
262
|
+
`unlock_channel()`, `set_host_audio_io()` / `set_host_midi_io()`,
|
|
263
|
+
`get_channels(is_input)` (plus `get_nchnls()`/`get_nchnls_input()` helpers).
|
|
264
|
+
- `get_params()` returns a **read-only** `Params` view of the `OPARMS` struct;
|
|
265
|
+
`set_params()` was removed (options are set via `set_option`).
|
|
266
|
+
- New `EventType` and `ChannelType` `cpdef` enums.
|
|
267
|
+
- Context manager now calls `reset()` on exit (there is no `csoundCleanup`).
|
|
268
|
+
- Pure-Python channel/table helpers: `list_channels()`, `get_string_channel()`,
|
|
269
|
+
`get_table()`, `get_table_args()`, `set_table()`, `get_audio_dev_list()`,
|
|
270
|
+
`get_midi_dev_list()`, `get_module()`.
|
|
271
|
+
|
|
272
|
+
### Removed (no Csound 7 equivalent)
|
|
273
|
+
|
|
274
|
+
- `get_api_version()`, `set_opcode_dir()`, `FileType` enum.
|
|
275
|
+
- `perform()`, `perform_buffer()`, `stop()`, `cleanup()`.
|
|
276
|
+
- `read_score()`, `score_event*`, `input_message*`, `kill_instance()`.
|
|
277
|
+
- `table_get()` / `table_set()` single-slot accessors; the input/output buffer
|
|
278
|
+
and spin-sample accessors; `is_named_gen()` / `get_named_gen()`.
|
|
279
|
+
- Low-level Cython-only helpers for threads, mutexes, circular buffers, global
|
|
280
|
+
variables, utilities, RNG, timers, and the various callback setters were not
|
|
281
|
+
carried over in this port and may be re-added against the Csound 7 callback
|
|
282
|
+
API in a later release.
|
|
283
|
+
|
|
284
|
+
## [0.1.0]
|
|
285
|
+
|
|
286
|
+
### Added
|
|
287
|
+
|
|
288
|
+
- Initial scikit-build-core based build system
|
|
289
|
+
- **Context manager support** for `Csound` class:
|
|
290
|
+
```python
|
|
291
|
+
with cycsound.Csound() as cs:
|
|
292
|
+
cs.compile_csd("score.csd")
|
|
293
|
+
cs.run()
|
|
294
|
+
# cleanup() called automatically
|
|
295
|
+
```
|
|
296
|
+
- **`run()` method** - convenience method to perform entire score
|
|
297
|
+
- **`Status` enum** (`cpdef enum`) - Csound return status codes:
|
|
298
|
+
- `Status.SUCCESS`, `Status.ERROR`, `Status.INITIALIZATION`
|
|
299
|
+
- `Status.PERFORMANCE`, `Status.MEMORY`, `Status.SIGNAL`
|
|
300
|
+
- **`FileType` enum** (`cpdef enum`) - 66 Csound file type constants:
|
|
301
|
+
- Audio: `WAVE`, `FLAC`, `OGG`, `AIFF`, `AU`, `CAF`, `MPEG`, etc.
|
|
302
|
+
- Csound: `UNIFIED_CSD`, `ORCHESTRA`, `SCORE`
|
|
303
|
+
- MIDI: `STD_MIDI`, `MIDI_SYSEX`, `SOUNDFONT`
|
|
304
|
+
- Analysis: `HETRO`, `PVC`, `PVCEX`, `CVANAL`, `LPC`, `ATS`, `SDIF`
|
|
305
|
+
- Command-line interface (`cycsound` command):
|
|
306
|
+
- `play` - Play CSD files in real-time
|
|
307
|
+
- `render` - Render CSD to audio files (WAV, AIFF, FLAC, OGG)
|
|
308
|
+
- `check` - Validate CSD syntax
|
|
309
|
+
- `info` - Display Csound version information
|
|
310
|
+
- `eval` - Evaluate orchestra code
|
|
311
|
+
- Static linking support for macOS (`make wheel-static` or `-C cmake.define.STATIC=ON`)
|
|
312
|
+
- Bundles Csound and all audio codec libraries
|
|
313
|
+
- Produces standalone wheel (~2MB) requiring no Csound installation
|
|
314
|
+
- Only depends on system libraries and macOS frameworks
|
|
315
|
+
- CMakeLists.txt with platform-specific Csound library detection:
|
|
316
|
+
- macOS: CsoundLib64 framework at `/Library/Frameworks/`
|
|
317
|
+
- Windows: Csound6_x64 installation at `C:/Program Files/Csound6_x64/`
|
|
318
|
+
- Linux: System `csound64` library
|
|
319
|
+
- Test suite with 36 tests covering:
|
|
320
|
+
- Core API functions (version, options, compilation, performance)
|
|
321
|
+
- CLI commands (play, render, check, info, eval)
|
|
322
|
+
- Channel control and updates
|
|
323
|
+
- Threading and recompilation
|
|
324
|
+
- MIDI functionality
|
|
325
|
+
- GIL release support for all blocking operations, enabling true multi-threading
|
|
326
|
+
- GitHub Actions workflow for CI/CD with cibuildwheel
|
|
327
|
+
- PyPI publication support (`make publish`, `make publish-test`)
|
|
328
|
+
|
|
329
|
+
### Changed
|
|
330
|
+
|
|
331
|
+
- **Build system**: Migrated from setuptools/Cython to scikit-build-core/CMake
|
|
332
|
+
- **Project structure**: Reorganized to `src/cycsound/` layout
|
|
333
|
+
- **API naming**: Renamed `csoundInitialize()` to `initialize()` for consistency
|
|
334
|
+
- **GIL handling**: Added `nogil` declarations to all 219 C API functions in `csound.pxd`
|
|
335
|
+
- **Performance methods**: Now release the GIL during execution:
|
|
336
|
+
- `perform()`, `perform_ksmps()`, `perform_buffer()`
|
|
337
|
+
- `start()`, `stop()`, `cleanup()`, `reset()`
|
|
338
|
+
- **Compilation methods**: Now release the GIL during execution:
|
|
339
|
+
- `compile_orc()`, `compile_orc_async()`, `eval_code()`
|
|
340
|
+
- `compile_args()`, `compile()`, `compile_csd()`, `compile_csd_text()`
|
|
341
|
+
- **Score methods**: `read_score()`, `read_score_async()` now release the GIL
|
|
342
|
+
- **Threading primitives**: All blocking operations release the GIL:
|
|
343
|
+
- `join_thread()`, `wait_thread_lock()`, `wait_thread_lock_no_timeout()`
|
|
344
|
+
- `lock_mutex()`, `wait_barrier()`, `cond_wait()`, `sleep()`, `spin_lock()`
|
|
345
|
+
- **Status return types**: Functions now return `Status` enum instead of `int`:
|
|
346
|
+
- `set_option()`, `udp_server_start()`, `udp_server_close()`, `upd_console()`
|
|
347
|
+
- Allows comparison with `Status.SUCCESS`, `Status.ERROR`, etc.
|
|
348
|
+
|
|
349
|
+
### Fixed
|
|
350
|
+
|
|
351
|
+
- GIL contention issues that prevented effective multi-threading
|
|
352
|
+
- GUI freezing when calling blocking Csound operations
|
|
353
|
+
|
|
354
|
+
### API Coverage
|
|
355
|
+
|
|
356
|
+
- 98.6% coverage of the Csound C API (216/219 functions)
|
|
357
|
+
- Intentionally unwrapped (3 functions using `va_list`):
|
|
358
|
+
- `csoundMessageV` - use `message()` instead
|
|
359
|
+
- `csoundSetDefaultMessageCallback` - use `set_message_string_callback()` instead
|
|
360
|
+
- `csoundSetMessageCallback` - use `set_message_string_callback()` instead
|
|
361
|
+
|
|
362
|
+
### Build Requirements
|
|
363
|
+
|
|
364
|
+
- Python >= 3.9
|
|
365
|
+
- scikit-build-core
|
|
366
|
+
- Cython
|
|
367
|
+
- CMake >= 3.15
|
|
368
|
+
- Csound 6.x installed:
|
|
369
|
+
- macOS: CsoundLib64.framework in `/Library/Frameworks/`
|
|
370
|
+
- Windows: Csound6_x64 in `C:/Program Files/`
|
|
371
|
+
- Linux: libcsound64 development package
|
|
372
|
+
|
|
373
|
+
### Static Build Requirements (macOS only)
|
|
374
|
+
|
|
375
|
+
For `make wheel-static`:
|
|
376
|
+
- Homebrew with static libraries installed:
|
|
377
|
+
- `brew install libsndfile flac opus libvorbis libogg mpg123 lame`
|
|
378
|
+
- Static libraries from CsoundLib64.framework:
|
|
379
|
+
- `libCsoundLib64.a`, `libcsnd6.a`
|