Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
74bed04
Add reusable sequencer groups
Sep 3, 2026
066bc1f
Expand sequencer group behavior coverage
Sep 3, 2026
83ae7f1
Document sequencer group API
Sep 3, 2026
1098528
Cover sequencer group identity and rollover
Sep 3, 2026
45fc871
Add sequencer group usage guides
Sep 3, 2026
b1e995f
Align sequencer group terminology and links
Sep 4, 2026
c3ebcae
Harden sequencer group validation and diagnostics
Sep 4, 2026
ac8ea86
Expand sequencer group edge-case coverage
Sep 4, 2026
6c9829c
Unify sequencer group tick processing
Sep 4, 2026
2c1c052
Cover sequencer group control boundaries
Sep 4, 2026
2aa4323
Clarify sequencer group contracts and errors
Sep 4, 2026
b791eb2
Cover sequencer group republish and tag edges
Sep 4, 2026
90b62c6
Simplify reusable sequences around sequencer tags
Sep 4, 2026
bc3c85b
Document reusable tagged sequences
Sep 4, 2026
16c7e51
Rewrite sequence guides for the simplified API
Sep 4, 2026
29aa50a
Make sequencer tags cumulative sequences
Sep 4, 2026
06309fa
Document cumulative sequencer tags
Sep 4, 2026
2139516
Align sequence test terminology
Sep 4, 2026
fca1579
Remove retired sequence append from Godot
Sep 4, 2026
2669c3a
Cover concurrent sequence definition generations
Sep 4, 2026
b2a8865
Move sequence version reclamation off render path
Sep 4, 2026
7c98ad2
Reclaim sequence versions at control boundary
Sep 4, 2026
b6f559a
Defer render-fired sequence reset cleanup
Sep 4, 2026
0198b50
Make sequence triggers note-like and strict
Sep 4, 2026
361ac40
Migrate first-party sequencer callers
Sep 4, 2026
3060cc0
Test sequence publication allocation failures
Sep 4, 2026
f22307a
Cover concurrent sequence publication retry
Sep 4, 2026
dcbd284
Define bounded sequence composition semantics
Sep 4, 2026
092941c
Accept note-like sequence control velocity
Sep 4, 2026
33f4c01
Preserve existing config member offsets
Sep 4, 2026
ab5f302
Document and test sequence API migration
Sep 4, 2026
36aa150
Simplify stored sequence slots
Sep 4, 2026
380f20e
Ignore generated sequence test binaries
Sep 4, 2026
4aab0fc
Use explicit run state for sequence control
Sep 4, 2026
cc2407f
Document boolean sequence run control
Sep 4, 2026
841ccd2
Expose named sequence control actions
Sep 4, 2026
f03875f
Document start stop and gate actions
Sep 4, 2026
596047b
Document reusable sequence model and compatibility
Sep 4, 2026
065a229
Separate render and external sequence dispatch
Sep 4, 2026
98873a9
Make same-tick sequence controls slot independent
Sep 4, 2026
1b1e527
Test concurrent sequence render and control
Sep 4, 2026
fc3c9e5
Reject unrepresentable sequence capacities
Sep 4, 2026
1fd5e22
Validate sequence integers without truncation
Sep 4, 2026
04db763
Define strict wrap-safe sequence timing
Sep 4, 2026
10d5976
Clarify sequence checks and terminology
Sep 4, 2026
8305129
Test sequence lifetime across the uint32 clock
Sep 4, 2026
ec94860
Preserve legacy omitted tick fields
Sep 4, 2026
f8df2b2
Align sequence controls correctly across clock wrap
Sep 4, 2026
83e883d
Cover sequence allocation failure boundaries
Sep 4, 2026
e69f537
Stress sequence publication during rendering
Sep 4, 2026
ab2a02e
Clarify sequence compatibility boundaries
Sep 4, 2026
9aa19c9
Run Godot platform matrix for pre-merge validation
Sep 5, 2026
f2534ec
Run sequence sanitizers for pre-merge validation
Sep 5, 2026
e0b2c71
Install sanitizer build dependency
Sep 5, 2026
8106de1
Scope leak checks to lifecycle tests
Sep 5, 2026
820e4e1
Isolate sequence leaks from baseline filter leaks
Sep 5, 2026
2f67504
Exclude baseline patch pool leaks
Sep 5, 2026
328e766
Validate Windows beyond baseline M_PI failure
Sep 5, 2026
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
7 changes: 7 additions & 0 deletions .github/sequence-lsan.supp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# amy_reset_oscs() reinitializes the global bus filters without releasing the
# previous filter arrays. This is present on the Shorepine-main baseline and is
# outside the reusable-sequence ownership being validated here.
leak:filters_init
# Repeated amy_start()/amy_stop() in the baseline leaves replaced patch-slot
# arrays allocated as well. Keep sequence allocations visible.
leak:patches_init
2 changes: 1 addition & 1 deletion .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ jobs:
python-version: '3.13'

- name: Check generated C API bindings are in sync
run: make check-c-api
run: make check-c-api js-api-test

godot-build:
# Build the Godot GDExtension for Linux. amy_midi.c is excluded from the
Expand Down
11 changes: 3 additions & 8 deletions .github/workflows/godot-addon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
tags:
- '*'
pull_request:
branches: [ "main" ]
workflow_dispatch:

permissions:
Expand All @@ -15,14 +17,6 @@ jobs:
fail-fast: false
matrix:
include:
- name: macOS
runner: macos-latest
platform: macos
arch: universal
- name: Linux
runner: ubuntu-22.04
platform: linux
arch: x86_64
- name: Windows
runner: windows-latest
platform: windows
Expand Down Expand Up @@ -71,6 +65,7 @@ jobs:

package:
needs: build
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
name: Package Addon

Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/premerge-sequence-sanitizers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Pre-merge sequence sanitizers

on:
pull_request:
branches: [ "main" ]

jobs:
address-and-leak:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install header-generation dependency
run: pip install numpy
- name: Build sequence tests with AddressSanitizer
run: >-
make tests/test_sequencer_active tests/test_sequencer_bounds
tests/test_sequencer_sequences tests/test_sequencer_oom
tests/test_sequencer_concurrency
CFLAGS="-O1 -g -Wall -Wextra -Wno-unused-parameter
-Wno-strict-aliasing -Wno-float-conversion
-Wno-missing-declarations -Wpointer-arith -DAMY_WAVETABLE
-fsanitize=address -fno-omit-frame-pointer"
- name: Run legacy tests without process-exit leak checks
env:
ASAN_OPTIONS: detect_leaks=0:halt_on_error=1
run: |
tests/test_sequencer_active
tests/test_sequencer_bounds
- name: Run lifecycle tests with leak detection
env:
ASAN_OPTIONS: detect_leaks=1:halt_on_error=1
LSAN_OPTIONS: suppressions=.github/sequence-lsan.supp:print_suppressions=1
run: |
tests/test_sequencer_sequences
tests/test_sequencer_oom
tests/test_sequencer_concurrency

thread:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install header-generation dependency
run: pip install numpy
- name: Build the concurrency test with ThreadSanitizer
run: >-
make tests/test_sequencer_concurrency
CFLAGS="-O1 -g -Wall -Wextra -Wno-unused-parameter
-Wno-strict-aliasing -Wno-float-conversion
-Wno-missing-declarations -Wpointer-arith -DAMY_WAVETABLE
-fsanitize=thread -fno-omit-frame-pointer"
- name: Run the concurrency test
env:
TSAN_OPTIONS: halt_on_error=1
run: tests/test_sequencer_concurrency
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tests/tst
tests/test_clock_wrap
tests/test_sequencer_active
tests/test_sequencer_bounds
tests/test_sequencer_sequences
tests/test_sequencer_oom
tests/test_sequencer_concurrency
tests/test_bus_config
tests/test_patch_slots
tests/test_synth_readout
Expand Down
29 changes: 26 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ EMSCRIPTEN_OPTIONS = -s WASM=1 --bind \
-s ASYNCIFY -s ASYNCIFY_STACK_SIZE=128000
PYTHON = python3

.PHONY: default all clean amy-module test ctest web deploy-web godot-api c-api check-c-api
.PHONY: default all clean amy-module test ctest web deploy-web godot-api c-api check-c-api js-api-test

default: $(TARGET)
all: default
Expand All @@ -83,6 +83,9 @@ check-c-api:
$(PYTHON) scripts/gen_patches_js.py --check
$(PYTHON) scripts/gen_pcm_presets_js.py --check

js-api-test:
node tests/test_js_api.js

SOURCES += src/algorithms.c src/amy.c src/envelope.c src/examples.c src/parse.c \
src/filters.c src/oscillators.c src/pcm.c src/interp_partials.c src/custom.c \
src/delay.c src/log2_exp2.c src/patches.c src/transfer.c src/sequencer.c \
Expand Down Expand Up @@ -124,26 +127,46 @@ amy-message: $(OBJECTS) src/amy-message.o
# Plain C tests for things the audio-rendering suite can't reach -- e.g. clock
# rollovers 50 days out, which you can only hit by fast-forwarding the counters.
CTESTS = tests/test_clock_wrap tests/test_sequencer_active tests/test_sequencer_bounds \
tests/test_sequencer_sequences \
tests/test_sequencer_oom \
tests/test_sequencer_concurrency \
tests/test_bus_config tests/test_patch_slots \
tests/test_synth_readout tests/test_log2_lut tests/test_clone_on_grow \
tests/test_timebase_reset tests/test_osc_free_on_release \
tests/test_voice_osc_range tests/test_dist_coefs tests/test_dist_scope

# Static pattern rules, so these win over the generic %.o: %.c above (which
# would compile without -Isrc and fail to find amy.h).
$(addsuffix .o,$(CTESTS)): %.o: %.c $(HEADERS) src/patches.h
SEQUENCE_SPECIAL_TESTS = tests/test_sequencer_oom tests/test_sequencer_concurrency

$(addsuffix .o,$(filter-out $(SEQUENCE_SPECIAL_TESTS),$(CTESTS))): %.o: %.c $(HEADERS) src/patches.h
$(CC) $(CFLAGS) -Isrc -c $< -o $@

$(CTESTS): %: %.o $(OBJECTS)
$(filter-out $(SEQUENCE_SPECIAL_TESTS),$(CTESTS)): %: %.o $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) $< -Wall $(LIBS) -o $@

# Build only the sequencer and its OOM test with the test-only allocation hook;
# every other test and every production target uses the ordinary object.
tests/sequencer_testing_impl.o: src/sequencer.c $(HEADERS) src/patches.h
$(CC) $(CFLAGS) -DAMY_SEQUENCE_TESTING -c $< -o $@

tests/test_sequencer_oom.o: tests/test_sequencer_oom.c $(HEADERS) src/patches.h
$(CC) $(CFLAGS) -DAMY_SEQUENCE_TESTING -Isrc -c $< -o $@

tests/test_sequencer_concurrency.o: tests/test_sequencer_concurrency.c $(HEADERS) src/patches.h
$(CC) $(CFLAGS) -DAMY_SEQUENCE_TESTING -Isrc -c $< -o $@

$(SEQUENCE_SPECIAL_TESTS): %: %.o tests/sequencer_testing_impl.o $(filter-out src/sequencer.o,$(OBJECTS))
$(CC) $(CFLAGS) $(filter-out src/sequencer.o,$(OBJECTS)) tests/sequencer_testing_impl.o $< -Wall $(LIBS) -o $@

ctest: $(CTESTS)
@for t in $(CTESTS); do echo "== $$t"; ./$$t || exit 1; done

amy-module: amy-example
${EXTRA_PIP_ENV} ${PYTHON} -m pip install -r requirements.txt; touch src/amy.c; ${EXTRA_PIP_ENV} ${PYTHON} -m pip install . --force-reinstall --no-deps; cd ..

test: amy-module
${PYTHON} tests/test_sequence_api.py
${PYTHON} -m amy.test

qtest: amy-module
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ AMY was built by [DAn Ellis](https://research.google/people/DanEllis/) and [Bria
* [**Interactive AMY tutorial**](https://shorepine.github.io/amy/tutorial.html)
* [**AMY API**](docs/api.md)
* [**AMY Synthesizer Details**](docs/synth.md)
* [**AMY Reusable Sequences**](docs/sequencer-sequences.md)
* [**Distortion in AMY**](docs/distortions.md)
* [**AMY's MIDI specification**](docs/midi.md)
* [**AMY in Arduino Getting Started**](docs/arduino.md)
Expand Down Expand Up @@ -171,6 +172,7 @@ It's good to understand what wire messages are but you don't need to construct t
* [**Interactive AMY tutorial**](https://shorepine.github.io/amy/tutorial.html)
* [**AMY API**](docs/api.md)
* [**AMY Synthesizer Details**](docs/synth.md)
* [**AMY Reusable Sequences**](docs/sequencer-sequences.md)
* [**Distortion in AMY**](docs/distortions.md)
* [**AMY's MIDI specification**](docs/midi.md)
* [**AMY in Arduino Getting Started**](docs/arduino.md)
Expand Down
Loading
Loading