-
Notifications
You must be signed in to change notification settings - Fork 5
Add alpha mask system for virtual channel gating #13
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
Open
oisee
wants to merge
6
commits into
paator:main
Choose a base branch
from
oisee:feature/alpha-mask
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
db91ffc
Add alpha field to instrument system (Phase 1)
oisee f96d27b
Add fill column / alpha mask description to README
oisee 561fbfe
Add navigation shortcuts, natural tuning roots, editor UX improvements
oisee dcc1208
Make alpha functional in audio engine (Phase 2)
oisee 53ee064
Make alpha the sole gating mechanism for virtual channel mixing
oisee 493f775
Update README with alpha mask virtual channel gating docs
oisee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,48 @@ | ||
| Bitphase is a chiptune tracker for creating music on retro sound chips. Built with Svelte 5, TypeScript, Vite, and Tailwind 4. | ||
| # CLAUDE.md | ||
|
|
||
| ## Architecture | ||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ### Directory Structure | ||
| ## Overview | ||
|
|
||
| - `src/lib/chips/` - Chip implementations (currently AY-8910). Each chip has: `schema.ts` (channel/field definitions), `adapter.ts` (data manipulation), `renderer.ts` (pattern display), `types.ts` | ||
| - `src/lib/models/` - Domain models: `project.ts`, `song.ts`, `project-fields.ts` | ||
| - `src/lib/services/` - Business logic: `audio/`, `file/` (import/export), `pattern/` (editing, navigation, clipboard), `project/`, `modal/` | ||
| - `src/lib/stores/` - Reactive state using `.svelte.ts` files with `$state` rune | ||
| - `src/lib/ui-rendering/` - Canvas-based renderers for pattern editor and order list | ||
| - `src/lib/components/` - UI components organized by feature (Menu, Song, Tables, Instruments, Modal, etc.) | ||
| - `src/lib/config/` - App configuration (menu definitions, settings) | ||
| - `tests/` - Test files mirroring src structure | ||
| Bitphase is a chiptune tracker for creating music on retro sound chips. Built with Svelte 5, TypeScript, Vite, and Tailwind 4. Currently supports AY-3-8910/YM2149F chip, with architecture designed for future chip support. | ||
|
|
||
| ### Key Patterns | ||
| ## Commands | ||
|
|
||
| - **Chip abstraction**: Never hardcode chip-specific features. Use `src/lib/chips/base/schema.ts` for generic definitions. Chips implement adapters and renderers extending base classes. | ||
| - **State management**: Use Svelte 5 runes (`$state`, `$derived`, `$effect`) in `.svelte.ts` files. Do not use writable stores. | ||
| - **Pattern editing**: Field-based editing system in `src/lib/services/pattern/editing/` with strategies per field type. | ||
| - `pnpm dev` — Start dev server (builds WASM first) | ||
| - `pnpm build` — Production build | ||
| - `pnpm check` — TypeScript and Svelte type checking (run this to catch lint errors) | ||
| - `pnpm test` — Run tests in watch mode (vitest) | ||
| - `pnpm test:run` — Run tests once | ||
| - `pnpm vitest run tests/path/to/file.test.ts` — Run a single test file | ||
| - `pnpm build:wasm` — Rebuild WASM only (requires Emscripten SDK with `emcc` in PATH) | ||
|
|
||
| ### External Dependencies | ||
| ## Architecture | ||
|
|
||
| - `external/ayumi/` - AY-8910 emulator C code, compiled to WASM via Emscripten | ||
| - WASM output goes to `public/ayumi.wasm` | ||
| ### Directory Structure | ||
|
|
||
| ### Path Alias | ||
| - `src/lib/chips/` — Chip implementations. Each chip has: `schema.ts`, `adapter.ts`, `renderer.ts`, `types.ts` | ||
| - `base/` — Base interfaces and generic definitions | ||
| - `ay/` — AY-3-8910 implementation | ||
| - `src/lib/models/` — Domain models: `project.ts`, `song.ts`, `project-fields.ts` | ||
| - `src/lib/services/` — Business logic: `audio/`, `file/` (import/export), `pattern/` (editing, navigation, clipboard), `project/`, `modal/` | ||
| - `src/lib/stores/` — Reactive state using `.svelte.ts` files with `$state` rune | ||
| - `src/lib/ui-rendering/` — Canvas-based renderers for pattern editor and order list | ||
| - `src/lib/components/` — UI components organized by feature | ||
| - `src/lib/config/` — App configuration (menu definitions, settings) | ||
| - `tests/` — Test files mirroring `src/` structure | ||
| - `external/ayumi/` — AY-8910 emulator C code, compiled to WASM → `public/ayumi.wasm` | ||
|
|
||
| `@` maps to `./src` (configured in vite and vitest) | ||
| ### Key Patterns | ||
|
|
||
| - Svelte 5 syntax only (runes, `onclick` not `on:click`) | ||
| - No comments in code - write self-documenting code | ||
| - Tailwind 4 for styling | ||
| - Follow KISS, DRY, SOLID principles. Keep very good OOP practices. | ||
| - Tests go in `tests/` directory mirroring `src/` structure | ||
| - **Chip abstraction**: Never hardcode chip-specific features in generic code. Use `src/lib/chips/base/schema.ts` for generic definitions. Chips implement adapters and renderers extending base classes. AY-specific code must stay in `src/lib/chips/ay/`. | ||
| - **State management**: Svelte 5 runes (`$state`, `$derived`, `$effect`) in `.svelte.ts` files. Do not use writable stores. | ||
| - **Pattern editing**: Field-based editing system in `src/lib/services/pattern/editing/` with strategies per field type. | ||
| - **Path alias**: `@` maps to `./src` (configured in both vite and vitest). | ||
|
|
||
| Currently bitphase supports only AY-8910/YM2149F chip, but architecture needs to support other chips in the future. Therefore, it is important to keep the code modular and easy to extend. Using AY specific code in generic parts is not allowed, because when we get to the point of adding another chip, we will have to rewrite a lot of code. | ||
| ## Code Style | ||
|
|
||
| Please never allow lint errors. If you see any, fix them. We had lots of production bugs because of lint errors. | ||
| - Svelte 5 syntax only — runes, `onclick` not `on:click`, `{#snippet}` not slots | ||
| - No comments in code — write self-documenting code | ||
| - Tailwind 4 for styling | ||
| - Follow KISS, DRY, SOLID principles with good OOP practices | ||
| - Never allow lint errors — run `pnpm check` to verify. We had production bugs from lint errors. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,54 @@ | |
|
|
||
| A modern web-based chiptune tracker designed for creating music on retro sound chips. Currently supports the AY-3-8910 / YM2149F chip (used in ZX Spectrum and other 8-bit computers), with plans to support additional chips in the future. | ||
|
|
||
| ## Changelog | ||
|
|
||
| ### Pattern Editor Navigation | ||
| - **Ctrl+Left / Ctrl+Right** — Jump between channels | ||
| - **Ctrl+Up / Ctrl+Down** — Jump to first / last row (Home / End) | ||
|
|
||
| ### Natural Tuning Tables | ||
| - Natural (just intonation) tuning now supports **all 12 root notes** (C through B) | ||
| - Root note selector appears when Natural tuning table is selected | ||
| - Uses just intonation ratios: 1, 16/15, 9/8, 6/5, 5/4, 4/3, 64/45, 3/2, 8/5, 5/3, 16/9, 15/8 | ||
|
|
||
| ### Instrument Editor | ||
| - **Duplicate row** button (copy icon) per row | ||
| - **Add new row** button at the top of the table | ||
| - Row actions always visible: delete, duplicate, delete-below | ||
|
|
||
| ### Table Editor (Arpeggios) | ||
| - **Duplicate row** button (copy icon) per row | ||
| - **Add new row** button at the top of the table | ||
|
|
||
| ### Resizable Right Panel | ||
| - Drag the left edge of the right panel to resize | ||
| - Panel width persisted across sessions (localStorage) | ||
|
|
||
| ### Persistent Settings | ||
| - **Hex mode** toggle persisted across browser sessions (shared between Instruments and Tables views) | ||
|
|
||
| ### Alpha Mask (Virtual Channel Gating) | ||
|
|
||
| Each instrument row has an **alpha** field (0–F), visible as the **α** column in the instrument editor. Alpha controls **virtual channel priority** — it determines which virtual channel gets to play on a shared hardware channel. | ||
|
|
||
| **How it works:** | ||
|
|
||
| When multiple virtual channels (e.g. A, A', A'') share one hardware channel, alpha on the **primary** (leftmost) channel acts as a gate: | ||
|
|
||
| - **Alpha = F (15)**: Fully opaque — primary channel always wins, even if silent. This is the default, so existing songs are unaffected. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a case of file that worked fine before these changes but now doesn't work properly despite all instruments getting 0xF alpha by default. Gonna send you a dm, because our beloved .btp isn't supported on github 👍 |
||
| - **Alpha = 0**: Fully transparent — any active underlying channel punches through. | ||
| - **Alpha 1–E**: Threshold gate — an underlying channel wins only if its alpha **exceeds** the primary's alpha. | ||
| - Among qualifying underlying channels, **leftmost** (highest priority) wins. | ||
| - If no underlying channel qualifies, the primary still plays. | ||
|
|
||
| **Key detail:** Alpha is the **sole gating mechanism**. A silent primary with alpha=F produces opaque silence (blocks underlying channels). A silent primary with alpha=0 is transparent (lets underlying channels through). Volume and mixer state do not affect priority. | ||
|
|
||
| **Gating instrument pattern:** | ||
| Create a looping instrument on the primary channel with volume=0 throughout. Set alpha=F on ticks where you want silence, and alpha=0 on ticks where underlying channels should play. This creates rhythmic punch-through patterns without the primary producing any sound. | ||
|
|
||
| Alpha values are stored in `.btp` files and default to 15 for older files and VT2/PT3 imports. Single-channel playback (no virtual channels) is unaffected by alpha. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Node.js** (v18 or higher) | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing this rule for Claude? ^^ is it covered by other new rules perhaps?