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
4 changes: 4 additions & 0 deletions examples/poly106_demo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""Play the Poly106: a pad progression, a bass line, brass stabs and a lead.

python examples/poly106_demo.py # writes wav_exports/poly106_demo.wav
Expand Down
4 changes: 4 additions & 0 deletions examples/poly80_bench_mix.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""The Poly80's cost with one channel heard: Init, eight notes, ``mix`` at channel I.

python examples/poly80_bench_mix.py # CPython
Expand Down
4 changes: 4 additions & 0 deletions examples/poly_bench.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""How much of real time a polyphonic instrument takes.

python examples/poly_bench.py [voice] [voices] # CPython
Expand Down
4 changes: 4 additions & 0 deletions examples/poly_render.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""Render chords through the polyphonic adapter and check the steals for clicks.

python examples/poly_render.py [voice] # CPython
Expand Down
2 changes: 1 addition & 1 deletion lib/audioinstruments/_rack/_lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""Import a package's public names on first use.

A package keeps a table of name -> submodule path and defines a module-level
``__getattr__`` that calls :func:`load`. The first ``pkg.Name`` imports only the
``__getattr__`` that calls `load`. The first ``pkg.Name`` imports only the
submodule that holds ``Name`` and stores the result in the package's globals,
so every later access is a plain attribute read.
"""
Expand Down
6 changes: 3 additions & 3 deletions lib/audioinstruments/_rack/dsp/ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
each swept by the sum of a slow and a fast LFO, the three 120 degrees apart on
both. Their sum in mono is steady (the three sweeps add to zero), while the
left and right sides each take a different mix of the three and spread apart.
It is a different animal from :class:`~audioinstruments._rack.dsp.chorus.BBDChorusCore`, which
It is a different animal from `BBDChorusCore <audioinstruments._rack.dsp.chorus.BBDChorusCore>`, which
is two lines swept in antiphase by one triangle with the dry signal always
mixed in, so it sits beside it on the same node.

Expand All @@ -27,7 +27,7 @@

Those are the defaults. The number of lines and everything about each one are
constructor parameters, so a different ensemble is a different list of
:class:`EnsembleLine` and a few keywords, not a different core: each line has
`EnsembleLine` and a few keywords, not a different core: each line has
its own slow rate, fast ratio, phase (a fraction of a period, on both sweeps;
0.5 turns the sweep upside down), a level into the left and the right side,
and a ``mix`` for its own node (2 is the wet alone, 1 the dry plus the wet).
Expand Down Expand Up @@ -186,7 +186,7 @@ def sweep_table(sweep, table_len=TABLE_LEN):
class EnsembleCore:
"""Swept lines, wet only, and a bypass input that is as late as they are.

``lines`` is a sequence of :class:`EnsembleLine` (the string ensemble's
``lines`` is a sequence of `EnsembleLine` (the string ensemble's
three by default). The other keywords are the delay every line sweeps
around (``centre_ms``), the depths of the slow and fast sweeps in ms, the
lines' low-pass (``tone_hz``), the length of a sweep table and the slow
Expand Down
14 changes: 7 additions & 7 deletions lib/audioinstruments/_rack/dsp/organ.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
An organ voice is a few pitches a key switches on together, each at a fixed
interval from the key (a footage: 8' is the key's own pitch, 16' an octave
under it, 4' an octave over it), each at a level a drawbar or a tab sets.
:class:`DrawbarToneCore` sums those pitches into one single-cycle table at a
`DrawbarToneCore` sums those pitches into one single-cycle table at a
base pitch every footage is a whole harmonic of, and synthio plays the table.
What each footage sounds like is the ``partial`` it is given: a tonewheel's is
a near-sine (:func:`sine_partial`); a divide-down organ's is a square or a
a near-sine (`sine_partial`); a divide-down organ's is a square or a
pulse, which is one more function of the same form that sums a few odd sines.
Which harmonic each footage plays on a given key (the foldback at the ends of
the keyboard) belongs to the organ, so the voice hands the core both the
Expand All @@ -17,8 +17,8 @@
A tonewheel organ has 91 wheels on one shaft, each in front of a pickup, so
every pitch is a near-sine that is always turning; a key closes nine contacts
that connect nine of them to the drawbars' busbars. The nine footages and the
harmonic each takes of the 16' pitch are in :data:`TONEWHEEL_FOOTAGES`;
:func:`tonewheel_harmonics` folds them at the keyboard's ends, as the organ
harmonic each takes of the 16' pitch are in `TONEWHEEL_FOOTAGES`;
`tonewheel_harmonics` folds them at the keyboard's ends, as the organ
does because it has no wheels past its top and bottom.
"""

Expand Down Expand Up @@ -117,14 +117,14 @@ class DrawbarToneCore:

``harmonics`` lists every harmonic of the base pitch a footage may be asked
to play (their partials are fetched once, here); ``partial(h)`` gives the
table of one footage at harmonic ``h`` (:func:`sine_partial` by default);
table of one footage at harmonic ``h`` (`sine_partial` by default);
``base_ratio`` is the table's pitch against the key's (0.5: the table is at
16', so the 8' is its second harmonic); ``level`` scales the sum;
``table_len`` is the table's length, which every partial shares (synthio
plays the table without interpolating, so a longer one sounds cleaner).

:meth:`set_levels` rebuilds the table when a level or a harmonic changes,
in buffers the core owns. :meth:`render` plays it through a
`set_levels` rebuilds the table when a level or a harmonic changes,
in buffers the core owns. `render` plays it through a
``ChunkedBridge``, so the tone trails the controls by 256 frames. The
contacts (a 3 ms ramp each way) follow the gate 256 frames late too, which
is when the tone at the key's pitch arrives, so a note never begins on the
Expand Down
6 changes: 3 additions & 3 deletions lib/audioinstruments/_rack/modules/combo_organ/voice.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def _band_hz(note):


def _rolloff(hz):
"""The divider's level at ``hz`` (48 kHz), from :data:`ROLLOFF`."""
"""The divider's level at ``hz`` (48 kHz), from `ROLLOFF`."""
x = hz / 1000.0
i = int(x)
if i >= len(ROLLOFF) - 1:
Expand Down Expand Up @@ -202,7 +202,7 @@ def __init__(self):
self._sine = None

def partial(self, key):
"""The partial ``DrawbarToneCore`` sums for a footage key (see :func:`footage_key`)."""
"""The partial ``DrawbarToneCore`` sums for a footage key (see `footage_key`)."""
table = self.squares.get(key)
if table is None:
table = self._square(key[0], key[1], key[2])
Expand Down Expand Up @@ -232,7 +232,7 @@ def _rank_table(self, count):

def _square(self, h, count, f1):
"""An int16 table holding ``h`` cycles of a square of ``count`` odd harmonics,
:data:`PARTIAL_UNIT` counts high, each harmonic rolled off as a divider's
`PARTIAL_UNIT` counts high, each harmonic rolled off as a divider's
square at ``f1`` Hz would be."""
n = TONE_LEN
sine = self._sine
Expand Down
2 changes: 1 addition & 1 deletion lib/audioinstruments/_rack/sequencer.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def retrack(self, instrument, index=0, pattern=None):
For a player changing kit mid-bar. The steps already on the queue
belong to the instrument that is leaving, so they are taken back
here rather than left to sound on a machine the dropdown says is
gone; :meth:`relay` lays them again on the new one.
gone; `relay` lays them again on the new one.
"""
if not instrument.schedulable:
raise ValueError("%r cannot be scheduled" % instrument)
Expand Down
6 changes: 5 additions & 1 deletion tests/support/fake_pump.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""A stand-in for ``audiopump.Events`` and ``audiopump.now`` for the sequencer.

A `Sequencer` writes to its queue through two calls, ``q.at(frame, op,
Expand All @@ -9,7 +13,7 @@
wrapping comparison, hands back a token counting from 1, and answers **0**
rather than raising when the queue is full;
* ``cancel()`` is True only while the event is still pending;
* :meth:`Events.apply` applies every event inside ``[now, now + block)`` in
* `Events.apply` applies every event inside ``[now, now + block)`` in
frame order, and counts late ones;
* ``stats()`` returns the numbers in the same order.

Expand Down
4 changes: 4 additions & 0 deletions tests/support/sf2_builder.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""Write a SoundFont 2 bank from scratch, for the `_sf2` reader's tests.

Nothing here reads a `.sf2`; it only writes one, chunk by chunk, from the
Expand Down
4 changes: 4 additions & 0 deletions tests/support/sf2_play.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""Render a SoundFont instrument and measure what came out, for the
`soundfont` tests. No numpy: these run wherever audiodsp builds."""

Expand Down
4 changes: 4 additions & 0 deletions tests/support/sf2_smoke.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""Build the tiny bank, read it back, check it: the one check that runs on
every interpreter.

Expand Down
4 changes: 4 additions & 0 deletions tests/test_midi_dispatch.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""`audioinstruments._rack.midi_dispatch`: MIDI in, instrument methods out.

A recording instrument checks what each kind of input becomes: bytes with
Expand Down
4 changes: 4 additions & 0 deletions tests/test_sequencer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""`audioinstruments._rack.sequencer.Sequencer`, driven by a clock a test moves.

The sequencer's whole claim is that the groove does not depend on when
Expand Down
4 changes: 4 additions & 0 deletions tests/test_sf2.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""`_sf2`: a SoundFont 2 bank read back exactly.

The bank under test is written by `tests/support/sf2_builder.py` from the
Expand Down
4 changes: 4 additions & 0 deletions tests/test_soundfont.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""`soundfont` and `soundfont_drums` on the bank `sf2_builder` writes.

The plumbing, without a real bank: how the bank is found, the patch list
Expand Down
4 changes: 4 additions & 0 deletions tests/test_soundfont_gm.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""The General MIDI gate: a real bank plays every program and the kit.

Against FluidR3_GM.sf2 (MIT), looked for at `$FLUIDR3_GM`, then
Expand Down
4 changes: 4 additions & 0 deletions tests/test_soundfont_heap.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT

"""A second SoundFont instrument after a big bank has loaded.

Resolving every preset when a bank opened left a MicroPython heap in pieces
Expand Down
Loading