Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,27 @@ jobs:

- name: Import smoke test
run: python -c "import tachyaudio as ta; print(ta.get_backend().name); print(len(ta.list_devices()))"

windows:
name: Windows Python ${{ matrix.python-version }}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install package
run: python -m pip install .

- name: Run tests
run: python -m unittest discover -s tests

- name: Import smoke test
run: python -c "import tachyaudio as ta; assert ta.get_backend().name == 'miniaudio'; print(len(ta.list_devices()))"
22 changes: 22 additions & 0 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,25 @@ jobs:
with:
name: macos-wheels
path: wheelhouse/*.whl

windows:
name: Build Windows wheels
runs-on: windows-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install cibuildwheel
run: python -m pip install cibuildwheel

- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse

- uses: actions/upload-artifact@v4
with:
name: windows-wheels
path: wheelhouse/*.whl
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ public APIs may still change while the backend design stabilizes.

## [Unreleased]

### Added

- Added Windows native backend support through vendored `miniaudio` using
WASAPI.
- Added Windows CI test coverage and Windows wheel build artifacts.

### Changed

- Shared the miniaudio stream implementation across Linux and Windows with a
small native lock/sleep portability layer.

## [0.2.0b1] - 2026-06-12

### Added
Expand Down
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
`tachyaudio` is a low-level audio package intended to replace tachypy’s direct
dependency on `sounddevice`/PortAudio over time.

Status: beta. The native backend currently supports macOS through Core Audio and
Linux through vendored `miniaudio`. Windows support is planned but intentionally
deferred until Windows test hardware is available.
Status: beta. The native backend currently supports macOS through Core Audio,
Linux through vendored `miniaudio`, and Windows through vendored `miniaudio`
using WASAPI.

## Goals

Expand Down Expand Up @@ -37,7 +37,7 @@ stats = ta.play(samples, sample_rate=48_000, channels=2)
```

The native backend currently supports device enumeration, float32 output
playback, and nonblocking float32 input capture on macOS and Linux.
playback, and nonblocking float32 input capture on macOS, Linux, and Windows.

`OutputStream` is currently a continuous stream. Write audio before or during
playback; if the stream runs out of queued frames it outputs silence and counts
Expand All @@ -58,8 +58,8 @@ Use blocking helpers when callers need complete buffer transfer:
- `InputStream.read_exactly(frame_count, timeout=None)`: wait until exactly the
requested number of frames has been captured

Full-duplex capture/playback is exposed as `DuplexStream`. Native macOS and
Linux support is available.
Full-duplex capture/playback is exposed as `DuplexStream`. Native macOS, Linux,
and Windows support is available.

Lifecycle semantics:

Expand Down Expand Up @@ -111,8 +111,9 @@ PYTHONPATH=src python3 examples/capture_level.py
frames up to `frame_count`.

On macOS, a restricted sandbox may hide Core Audio devices. On Linux, sandboxed
processes may be unable to reach the user PipeWire/PulseAudio server. If
`tachyaudio.list_devices()` returns an empty tuple or only generic ALSA devices
in a sandboxed environment, verify from an unsandboxed terminal before debugging
the backend. Headless Linux containers may return no devices while still being
able to build and import the native extension.
processes may be unable to reach the user PipeWire/PulseAudio server. On
Windows, remote/headless sessions may expose different WASAPI endpoints than an
interactive desktop login. If `tachyaudio.list_devices()` returns an empty tuple
or unexpected devices in a sandboxed environment, verify from an unsandboxed
terminal before debugging the backend. Headless Linux containers may return no
devices while still being able to build and import the native extension.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
Expand Down
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

extra_link_args: list[str] = []
extra_compile_args: list[str] = []
libraries: list[str] = []

if sys.platform == "darwin":
extra_link_args.extend(
Expand All @@ -15,6 +16,8 @@
elif sys.platform.startswith("linux"):
extra_compile_args.append("-pthread")
extra_link_args.extend(["-pthread", "-ldl", "-lm"])
elif sys.platform == "win32":
libraries.extend(["ole32", "uuid", "avrt"])


setup(
Expand All @@ -24,6 +27,7 @@
sources=["src/tachyaudio/_native.c"],
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
libraries=libraries,
)
]
)
Loading
Loading