You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/development/guidelines.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ These rules govern the Python in this repository. They complement
31
31
1. An `__init__` exposes only names from within its own tree hierarchy.
32
32
1. Give each module a single area of responsibility.
33
33
1. If a module contains many class and function definitions, split into a subpackage divided by a single concern.
34
-
1. If a private function serves only a class in the module it lives, move it to the class as a static/class method or isolate helper functions into a separate utility module.
34
+
1. If a private function (or public that does not have any external consumers) serves only a class in the module it lives, move it to the class as a static/class method or isolate helper functions into a separate utility module.
35
35
1. Prefer subpackages over a flat directory structure.
36
36
1. Isolate platform-, desktop-, or external-tool-specific behaviour behind a `Protocol` with one implementation per target, selected by a runtime factory that probes availability and environment. Callers depend only on the `Protocol` and stay platform-agnostic.
37
37
1. Wrap a third-party library or OS tool whose behaviour differs across platforms behind our own typed interface, and encode each quirk inside the matching implementation. A comment naming the third-party behaviour is warranted there.
@@ -86,6 +86,7 @@ These rules govern the Python in this repository. They complement
86
86
1. A test file mirrors the ownership of the code it exercises.
87
87
1. When functionality moves between packages, move its direct unit tests in the same change.
88
88
1. Parametrize tests that share a body, using a test-case dataclass.
89
+
1. Test case classes and cases themselves should be defined inside the testing class, unless these objects are shared between test classes. A suite inherits from `BaseTestSuite` and names its case class `TestCase`, which inherits from `BaseRegularTestCase`, or from `BaseAutolabelTestCase` where the case derives its own label. The parametrized argument carries the case as `test_case`.
89
90
1. For a multi-step scenario, use a test-scenario suite class — a series of functions with assertions.
90
91
1. Prefer fixtures over factories, and define shared fixtures in an appropriate place.
91
92
1. Do not assert default values of configurations, layouts, settings, and similar. Defaults are not contracts, and pinning them overconstrains the tests. Test behavior instead: validation bounds, serialization round-trips, and invariants. The exception is when values must match by contract rather than equal a chosen constant — e.g. project metadata at creation or after a save/load round-trip should be asserted to match, never hardcoded to a version string.
Copy file name to clipboardExpand all lines: docs/formats/bitphase.md
+13-5Lines changed: 13 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -69,7 +69,7 @@ carries every register value the channel takes for that tick. From
69
69
| Field | Range | Runtime meaning | What the exporter writes |
70
70
| --- | --- | --- | --- |
71
71
|`pulseWidth`| 0–3 | square duty cycle; on the noise channel, any nonzero value selects the short LFSR | the duty-cycle envelope item (squares), the short/long mode (noise), a flat value (triangle) |
72
-
|`volumeOrRate`| 0–15 | the literal channel volume while `envelope` stays off | the volume envelope item |
72
+
|`volumeOrRate`| 0–15 | the literal channel volume while `envelope` stays off | the volume envelope item, or a full level where the slice leaves its volume to the channel|
73
73
|`envelope`| bool | reads `volumeOrRate` as a hardware decay rate |`false`, so each item is the volume itself |
74
74
|`soundLength`| 0–511 | length counter in ticks; `0` holds the note |`0`, so the volume envelope alone shapes the note |
75
75
|`toneAdd`| −4096–4095 | period offset added to the tuning-table period (squares and triangle) |`0` in a document, the pitch contour in a preset |
@@ -79,10 +79,18 @@ carries every register value the channel takes for that tick. From
79
79
80
80
**Looping.** Playback returns to the instrument's `loop` row once it runs off the end,
81
81
which is the only mode there is. A looping slice therefore sets `loop = 0` so its
82
-
envelopes repeat from the start while the note is held; a one-shot sets
83
-
`loop = len - 1`, and since the volume envelope ends on a note-off item, the
84
-
instrument rests in silence once it has played through. A sample's `loop` flag drives
85
-
this, the same flag the FamiTracker exporter reads.
82
+
envelopes repeat from the start while the note is held; a one-shot sets `loop = len - 1`
83
+
and rests on the level that row carries — silence where the volume envelope ends on a
84
+
note-off item, the channel's own level where the slice holds its volume. A sample's
85
+
`loop` flag drives this, the same flag the FamiTracker exporter reads.
86
+
87
+
**A held volume.** A slice whose volume envelope carries no item leaves its level to the
88
+
channel, so the exporter writes a full `volumeOrRate` for every frame the slice
89
+
describes. Playback combines a row's level with the pattern's volume column through a
90
+
PT3 volume table, where a full-level row comes out at the column's own level, so those
91
+
rows sound at whatever level the channel carries — the same reading FamiTracker gives a
92
+
disabled volume sequence. A slice describing no frame at all is what writes a single
93
+
silent row, the smallest instrument Bitphase plays.
86
94
87
95
**Equal lengths.** Instrument rows and table rows advance on independent per-tick
88
96
counters, so they share a length and a loop point and stay in step for as long as the
0 commit comments