bitcomposer 2.0.0rc2__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/PKG-INFO +210 -152
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/README.md +209 -151
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/__init__.py +1 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/cli.py +21 -7
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/composer.py +2 -2
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/instruments.py +4 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/__init__.py +4 -3
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/bit.py +32 -9
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/library.py +18 -9
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/megamanx.py +1 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/packfile.py +51 -5
- bitcomposer-2.1.0/bitcomposer/performance.py +213 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/backend.py +50 -8
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/engine.py +259 -11
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/icons/bitcomposer.svg +9 -5
- bitcomposer-2.1.0/bitcomposer/player/level.py +159 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/openmpt.py +47 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/qml/Main.qml +303 -116
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/update.py +3 -3
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/window.py +1 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/samples/__init__.py +26 -3
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/score.py +25 -5
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/__main__.py +3 -2
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/brr.py +4 -4
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/convert.py +10 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/tuning.py +23 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/beat.py +86 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/drums.py +22 -2
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/events.py +19 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/harmony.py +1 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/lead.py +104 -34
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/pack.py +65 -9
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/packtables.py +66 -12
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/phrases.py +2 -2
- bitcomposer-2.1.0/bitcomposer/translate/reading.py +245 -0
- bitcomposer-2.1.0/bitcomposer/translate/rhythm/__init__.py +9 -0
- bitcomposer-2.1.0/bitcomposer/translate/rhythm/arrangement.py +4126 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/rhythm/cells.py +137 -19
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/rhythm/chords.py +18 -0
- bitcomposer-2.1.0/bitcomposer/translate/rhythm/own.py +73 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/rhythm/readings.py +410 -18
- bitcomposer-2.1.0/bitcomposer/translate/roles.py +599 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/store.py +34 -3
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/tables.py +17 -7
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/vocab.py +1 -1
- bitcomposer-2.1.0/bitcomposer/translate/whole/__init__.py +8 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/whole/measures.py +12 -4
- bitcomposer-2.1.0/bitcomposer/translate/whole/own.py +71 -0
- bitcomposer-2.1.0/bitcomposer/translate/whole/plan.py +4873 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/whole/render.py +417 -53
- bitcomposer-2.1.0/bitcomposer/translate/whole/settle.py +624 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/writer/__init__.py +2 -2
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/writer/figures.py +10 -4
- bitcomposer-2.1.0/bitcomposer/translate/writer/parts.py +1150 -0
- bitcomposer-2.1.0/bitcomposer/translate/writer/tune.py +2121 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/writer/upper.py +150 -17
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/vocabularies/__init__.py +2 -2
- bitcomposer-2.1.0/bitcomposer/vocabularies/default.json.gz +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/written.py +27 -14
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer.egg-info/PKG-INFO +210 -152
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer.egg-info/SOURCES.txt +6 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_arrangement.py +1 -1
- bitcomposer-2.1.0/tests/test_lead.py +145 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_library.py +18 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_packfile.py +53 -0
- bitcomposer-2.1.0/tests/test_performance.py +179 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_player.py +493 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_score.py +19 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_tables.py +429 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_translate.py +294 -9
- bitcomposer-2.1.0/tests/test_whole.py +7068 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_writer.py +1 -1
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_written.py +67 -4
- bitcomposer-2.0.0rc2/bitcomposer/translate/reading.py +0 -97
- bitcomposer-2.0.0rc2/bitcomposer/translate/rhythm/__init__.py +0 -8
- bitcomposer-2.0.0rc2/bitcomposer/translate/rhythm/arrangement.py +0 -1292
- bitcomposer-2.0.0rc2/bitcomposer/translate/roles.py +0 -262
- bitcomposer-2.0.0rc2/bitcomposer/translate/whole/__init__.py +0 -5
- bitcomposer-2.0.0rc2/bitcomposer/translate/whole/plan.py +0 -1373
- bitcomposer-2.0.0rc2/bitcomposer/translate/writer/parts.py +0 -588
- bitcomposer-2.0.0rc2/bitcomposer/translate/writer/tune.py +0 -1273
- bitcomposer-2.0.0rc2/bitcomposer/vocabularies/default.json.gz +0 -0
- bitcomposer-2.0.0rc2/tests/test_lead.py +0 -45
- bitcomposer-2.0.0rc2/tests/test_whole.py +0 -1367
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/LICENSE +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/__main__.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/arp.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/bass.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/builder.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/drums.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/echo.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/harmony.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/it_format.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/melody.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/mix.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/names.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/evermore.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/ffvi.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/packs/mana.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/pattern.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/__init__.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/__main__.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/app.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/audio.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/autostart.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/desktop.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/fonts/JetBrainsMono-Bold.ttf +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/fonts/JetBrainsMono-Regular.ttf +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/fonts/LICENSE.txt +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/fonts/OFL-Silkscreen.txt +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/fonts/Silkscreen-Bold.ttf +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/fonts/Silkscreen-Regular.ttf +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/mediakeys_win.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/player/mpris.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/registers.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/samples/chip.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/samples/dsp.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/samples/genesis.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/samples/snes.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/__init__.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/emulate.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/it_song.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/notes.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/spc/snes_chip.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/structure.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/theory.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/__init__.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/__main__.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/against.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/archives.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/form.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/games.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/harness.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/measures.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/phase.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/reference.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer/translate/rhythm/form.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer.egg-info/dependency_links.txt +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer.egg-info/entry_points.txt +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer.egg-info/requires.txt +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/bitcomposer.egg-info/top_level.txt +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/pyproject.toml +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/setup.cfg +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_determinism.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_format.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_packs.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_pattern.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_samples.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_spc.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_spc_check.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_spc_convert.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_spc_notes.py +0 -0
- {bitcomposer-2.0.0rc2 → bitcomposer-2.1.0}/tests/test_theory.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bitcomposer
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Procedural 16-bit chiptune music generator — creates Impulse Tracker (.it) files
|
|
5
5
|
Author-email: CatDogBark <catdogbark@pm.me>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -36,29 +36,31 @@ Dynamic: license-file
|
|
|
36
36
|
[](https://github.com/CatDogBark/bitComposer/releases/latest)
|
|
37
37
|

|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
current one ends, with a live mixer, on Linux and Windows; a
|
|
41
|
-
and a
|
|
39
|
+
16-bit game music, written while you listen. A player that writes the next
|
|
40
|
+
song as the current one ends, with a live mixer, on Linux and Windows; a
|
|
41
|
+
command line and a library underneath, pure Python with no dependencies,
|
|
42
42
|
writing Impulse Tracker `.it` modules any tracker player reads.
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
Since 2.0 every song is written the way game soundtracks are put together:
|
|
45
|
+
drawn whole from a vocabulary of counted habits (how the band is balanced,
|
|
46
|
+
how its figures repeat and vary, where the tune comes back), taken from
|
|
47
|
+
the readings of a soundtrack's songs. The vocabulary that ships was
|
|
48
|
+
learned from Final Fantasy VI's 68 songs, as statistics with none of the
|
|
49
|
+
game's notes or samples. The songs play on bitComposer's own sound set,
|
|
50
|
+
generic instruments synthesised here, on one of Classic's four styled
|
|
51
|
+
sets, or on a game's own samples. More under [What GENERATE
|
|
52
|
+
writes](#what-generate-writes).
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- **chip** — square, pulse and triangle waves. Closest to NES and Game Boy.
|
|
54
|
+
Your own games too: the player's LIBRARY screen reads a game's SPC files
|
|
55
|
+
into a pack of its samples and, with 40 songs or more, a vocabulary of its
|
|
56
|
+
own to write from ([Packs from your games](#packs-from-your-games)).
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
games](#packs-from-your-games)).
|
|
58
|
+
The 1.x generator stays as [Classic](#classic), with its own knobs and
|
|
59
|
+
eight sounds, the chip and Genesis palettes among them.
|
|
58
60
|
|
|
59
|
-
**[Listen in your browser](https://catdogbark.github.io/bitComposer/)** — the actual modules, played live by libopenmpt in WebAssembly:
|
|
61
|
+
**[Listen in your browser](https://catdogbark.github.io/bitComposer/)** — the actual modules, played live by libopenmpt in WebAssembly: five songs from the writer, seeds 1 to 5, and one each from six of Classic's sounds.
|
|
60
62
|
|
|
61
|
-
**Reproducible, not frozen.** The same seed on the same version gives the same song, byte for byte. A new version may change what a seed draws
|
|
63
|
+
**Reproducible, not frozen.** The same seed on the same version gives the same song, byte for byte. A new version may change what a seed draws; a Classic song's message records the version that wrote it.
|
|
62
64
|
|
|
63
65
|
## Install
|
|
64
66
|
|
|
@@ -119,164 +121,90 @@ anything built on libopenmpt.
|
|
|
119
121
|
Python 3.10 or newer. The generator has no dependencies; the player's
|
|
120
122
|
window is Qt (PySide6, installed with the package).
|
|
121
123
|
|
|
122
|
-
## Sounds
|
|
123
|
-
|
|
124
|
-
A style pack pairs an instrument set with the arrangement habits of the score it imitates. Each is built from the game's SPC snapshots: every sample decoded and profiled, matched to the community's instrument tables where they exist, and re-synthesised; nothing from the games is in the repository.
|
|
125
|
-
|
|
126
|
-
- `ffvi`: every voice modelled on the game's own sample bank and named by its instrument table: the chorused string section, flutes in chords, the dark synth lead of Locke and the Returners, trumpet, trombone, oboe, Terra's and Cyan's pan flutes, cello, choir, pipe organ and rock organ, the Aria's soprano, the Battle theme's distortion guitar, piano, harp, picked string, acoustic guitar, tubular bell, xylophone, a bass guitar and a kit of its own (kick, snare, hats, cymbal, timpani, wood block), with ostinato strings, a brass counter-line in the chorus, timpani rolls into sections and the game's short, wet echo.
|
|
127
|
-
- `mana`: every voice modelled on the game's own sample bank: a soft slow-breathed flute, bright chorused strings, an 'ah' choir, a high whistle, soft and synth brass, marimba, vibraphone, electric piano, tubular bell, reed, accordion, glass and sine pads, fingered, electric and slap basses and a kit of its own (kick, snare, hats, crash, tom, castanet), with major and pentatonic keys, syncopated harmony, bouncy arps, light swing, the kick and snare set back and the game's one-row echo.
|
|
128
|
-
- `evermore`: every voice modelled on the game's own sample bank: a slow bright string swell, a warm pad, a dark pad, a glass bell, a breathy flute, a reed, an "oo" choir, harp, tinker music box, piano, pluck and kalimba, a textured drone and a wind loop, a bass, and a quiet kit (soft kick, frame drum, brushes, hat, cymbal, wood ping), with slow tempos, sustained harmony, a drone bass, sparse or no drums, long linear forms and the game's sparing 80 ms echo.
|
|
129
|
-
- `megamanx`: every voice modelled on the game's own sample bank and named by it: a driven, chorused lead guitar, a chugging rhythm guitar on power chords, the overdrive guitar for arps and counter-lines, synth brass, strings, a guitar swell pad, a saw pad, organ, the boomer synth lead, square and bright leads, a hollow wave, a bell synth, an acoustic pluck, the orchestra hit for stabs, slap and synth basses on a riff, and a tight kit, at fast tempos in minor keys with the game's 48 ms slapback echo.
|
|
130
|
-
|
|
131
|
-
`--sound` picks a palette or a pack in one word; left to chance, the four packs together weigh as much as plain snes.
|
|
132
|
-
|
|
133
|
-
- **snes** — sampled-style voices rendered the way the SNES actually made sound: strings, brass, a formant choir, flute, organ, e-piano, bells, plucks and a gated drum kit at 16 kHz with loop points, passed through a BRR codec model for the grain, with the lead, harmony and arp through an echo modelled on the SNES unit's result: fading, darkening repeats on a beat fraction, drawn per song.
|
|
134
|
-
- **genesis** — FM bells, brass, organ and bass.
|
|
135
|
-
- **chip** — square, pulse and triangle waves.
|
|
136
|
-
|
|
137
|
-
## What you can steer
|
|
138
|
-
|
|
139
|
-
Everything defaults to `random`.
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
--sound chip|snes|genesis|ffvi|mana|evermore|megamanx the sound in one word: a palette or a style pack (overrides the two below)
|
|
143
|
-
--style chip|snes|genesis sound palette
|
|
144
|
-
--pack ffvi|mana|evermore|megamanx|none|random style pack: an instrument set with the habits of the scores it imitates (a pack implies snes)
|
|
145
|
-
--pack-file PACK.json a pack as data, with its own voices as WAV files (docs/PACKS.md); overrides --pack and --sound
|
|
146
|
-
--echo on|off|random echo (random: 70% of snes songs, never chip or genesis)
|
|
147
|
-
--echo-wet light|normal|wet|random how much of the lead, harmony and arp the echo carries
|
|
148
|
-
--echo-delay eighth|dotted|quarter|slap|row|random beat fraction between repeats, a 48 ms slap, or one row (random: weighted by tempo)
|
|
149
|
-
--echo-stereo bounce|centre|random repeats alternate sides, or sit under their source
|
|
150
|
-
--keys moving|home moving: choruses/bridges may change key; home: stay put
|
|
151
|
-
--tempo slow|medium|fast 80–110 / 110–140 / 140–180 BPM
|
|
152
|
-
--energy chill|normal|intense density and arrangement weight
|
|
153
|
-
--scale minor|major|pentatonic
|
|
154
|
-
--form standard|aaba|rondo|short|linear
|
|
155
|
-
--drum-density sparse|normal|busy --no-fills --swing off|light|heavy
|
|
156
|
-
--melody simple|phrased phrased = motif-based, has a hook
|
|
157
|
-
--harmony-voicing thin|full two real voices, or three
|
|
158
|
-
--harmony-mode stabs|sustain|rhythmic
|
|
159
|
-
--bass-weight heavy|medium|light
|
|
160
|
-
--lead-shift SEMITONES move the lead's window (negative lowers it); default: the sound's own
|
|
161
|
-
--name title|timestamp file naming; --prefix / --suffix add a marker ("(auto) " is the player's)
|
|
162
|
-
-s SEED -n COUNT -o FILE -d DIR -v
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
Some starting points:
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
# Overworld — bright, sampled palette with echo
|
|
169
|
-
bitcomposer -d out --style snes --scale major --tempo medium --form standard
|
|
170
|
-
|
|
171
|
-
# FM boss fight
|
|
172
|
-
bitcomposer -d out --style genesis --tempo fast --energy intense --scale minor --drum-density busy --form short
|
|
173
|
-
|
|
174
|
-
# Game Boy flavour — square waves, thin harmony, no echo
|
|
175
|
-
bitcomposer -d out --style chip --echo off --harmony-voicing thin --bass-weight light --form short
|
|
176
|
-
|
|
177
|
-
# Credits roll
|
|
178
|
-
bitcomposer -d out --style snes --tempo slow --energy chill --scale major --drum-density sparse --no-fills --form linear
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## How it works
|
|
182
|
-
|
|
183
|
-
1. Pick a key and a scale weighted toward game music (minor pentatonic, dorian, harmonic minor, mixolydian…), then a progression for it. The tables include borrowed chords and secondary dominants — ♭VII, ♭VI, V/V — not just the diatonic set.
|
|
184
|
-
2. Choose a form and its energy curve; decide which sections repeat. Repeated sections draw the same music from the same seed, so the hook comes back.
|
|
185
|
-
3. Generate a motif (rhythm template plus contour) and vary it per bar in statement/answer pairs. Fourteen rhythm templates, six of them with 16th-note pushes and pickups.
|
|
186
|
-
4. Each four-bar pattern holds a chord timeline; about half the time the back two bars move to a related chord. Melody resolves onto chord tones at each change. Harmony is two or three real voices placed near fixed anchors, so it steps rather than leaps and keeps the chord's third; the anchors are set per voice family (pads low and wide, brass and guitars mid and close), the top voice stays under the lead's line, and a stab holds for as long as the voice needs to speak. Bass and arp follow and rest with the section's energy.
|
|
187
|
-
5. Drums come from one-bar templates by section and density, with fills, retriggered snare rolls and tick-level swing.
|
|
188
|
-
6. Instruments are synthesized per song from the chosen palette and written as samples. SNES voices get attack-then-loop sustain and the BRR treatment.
|
|
189
|
-
7. The echo: held lead notes and phrase endings come back as three fading, darkening repeats, the harmony and arp as lighter ones, each on return channels of their own, drums and bass dry. Everything is written as a 19-channel `.it` with the title and a song message (key, BPM, palette, form, seed, and a `layout:` line naming every channel's role) that trackers display.
|
|
190
|
-
|
|
191
|
-
Each song gets a title that reads the song: its scale, sound, energy and
|
|
192
|
-
tempo lean the words, so a slow minor Evermore piece and a fast Mega Man X
|
|
193
|
-
track are named differently (*Lunar Snow*, *Lighthouse of Steel*, *The
|
|
194
|
-
Power Plant of Sparks*).
|
|
195
|
-
|
|
196
|
-
## Measuring instead of guessing
|
|
197
|
-
|
|
198
|
-
`tools/analyze.py` parses `.it` files back from disk (stdlib only, independent
|
|
199
|
-
of the generator) and scores a batch on the things that correlate with
|
|
200
|
-
"sounds like a song": section reuse, motif repetition, rhythmic grid, chord
|
|
201
|
-
voicing variety, voice motion, effect vocabulary, drum density.
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
python3 tools/analyze.py 'out/*.it' # metric table
|
|
205
|
-
python3 tools/analyze.py --grid out/song.it # tracker-style pattern dump
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
[docs/ANALYSIS.md](docs/ANALYSIS.md) is the story of this project: the
|
|
209
|
-
output was once limited by three silent arrangement bugs that nine commits
|
|
210
|
-
of ear-checking never caught, and every improvement since has been measured
|
|
211
|
-
before and after. Read it before changing the generator.
|
|
212
|
-
|
|
213
|
-
Tests:
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
python3 -m unittest discover -s tests -v
|
|
217
|
-
```
|
|
218
|
-
|
|
219
124
|
## What GENERATE writes
|
|
220
125
|
|
|
221
126
|
```bash
|
|
222
127
|
bitcomposer -s 7 -v
|
|
223
128
|
```
|
|
224
129
|
|
|
225
|
-
writes a whole song the way the idiom's writer does (
|
|
130
|
+
writes a whole song the way the idiom's writer does ([docs/IDIOM.md](docs/IDIOM.md)): a
|
|
226
131
|
plan for the band, each part's figures bar by bar, a tune with a theme that
|
|
227
132
|
may come back, and the parts' balance, all drawn from a vocabulary of
|
|
228
133
|
counted habits, played on bitComposer's own sound set (generic
|
|
229
134
|
instruments, synthesised here from descriptions and modelled on no game's
|
|
230
135
|
bank, each fitted to its part by register and speed; `--pack ffvi`,
|
|
231
136
|
`mana`, `evermore` or `megamanx` borrows one of Classic's styled sets
|
|
232
|
-
instead) and rendered through the SNES back end
|
|
137
|
+
instead) and rendered through the SNES back end, under the player's
|
|
138
|
+
performance (`bitcomposer/performance.py`): the theme comes back with the
|
|
139
|
+
band, the loop plays twice, the echo and the vibrato on held notes of the tune
|
|
140
|
+
are the vocabulary's own words (FFVI's 0.20 echo at 80 ms, its vibrato on a
|
|
141
|
+
fifth of the tune's held notes). `--bare` writes without
|
|
142
|
+
it, the way the Song Checks do; `--no-carry-theme` and `--no-band-returns`
|
|
143
|
+
turn the two switches off. A seed names one song on
|
|
233
144
|
every machine. `--carry-theme` draws the tune's phrases again until its
|
|
234
145
|
theme comes back; `--band-returns` brings the chords, the bass or the
|
|
235
|
-
accompaniment back with it. In the player this is GENERATE
|
|
236
|
-
and
|
|
237
|
-
the
|
|
238
|
-
|
|
146
|
+
accompaniment back with it. In the player this is GENERATE on PLAY,
|
|
147
|
+
and WRITE AND PLAY on WRITE, where the two switches and a seed field sit;
|
|
148
|
+
[Classic](#classic), the 1.x generator, is WRITER: CLASSIC (1.X) there
|
|
149
|
+
(`--classic` on the command line).
|
|
239
150
|
|
|
240
151
|
Where the vocabulary comes from, plainly: the shipped one
|
|
241
|
-
(`bitcomposer/vocabularies/default.json.gz`,
|
|
242
|
-
readings of Final Fantasy VI's
|
|
152
|
+
(`bitcomposer/vocabularies/default.json.gz`, 625 KB) was fitted on the
|
|
153
|
+
readings of Final Fantasy VI's 68 songs, the game the writing was
|
|
243
154
|
measured against round by round until it held up by ear
|
|
244
|
-
(
|
|
155
|
+
([docs/idiom/phase-4-writing.md](docs/idiom/phase-4-writing.md)). It is the statistics of how that
|
|
245
156
|
music is put together, the counts of figures, moves, chord changes and
|
|
246
157
|
balances, and none of the game's samples or notes; a release check
|
|
247
158
|
(`tools/copycheck.py`) probes every four-bar window of hundreds of
|
|
248
159
|
written tunes against the games' phrases and ships nothing that copies
|
|
249
|
-
one.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
160
|
+
one. Each written song takes its skeleton from one of those songs, drawn,
|
|
161
|
+
as measured from its reading: its form and bar counts where they fit, its
|
|
162
|
+
tempo within a tenth, which parts play in each section, their levels and
|
|
163
|
+
how busy each line is. None of that song's notes come with it: the notes
|
|
164
|
+
are drawn from the counts over all of them. It is as far as the writing
|
|
165
|
+
has gone; vocabularies fitted on more games follow. Importing a game
|
|
166
|
+
(below) fits that game's own vocabulary beside its samples and recounts
|
|
167
|
+
one over everything you have imported; WRITE offers each under WRITTEN
|
|
168
|
+
FROM once 40 songs stand behind it (`--vocabulary pack:NAME`,
|
|
169
|
+
`--vocabulary library`).
|
|
170
|
+
|
|
171
|
+
Every word in the vocabulary, what it counts and why it exists, is in
|
|
172
|
+
[the vocabulary](docs/idiom/VOCABULARY.md), and [the vocabulary's
|
|
173
|
+
map](docs/idiom/vocabulary-map.md) draws, stage by stage, which words
|
|
174
|
+
condition which.
|
|
254
175
|
|
|
255
176
|
## Packs from your games
|
|
256
177
|
|
|
257
|
-
|
|
258
|
-
|
|
178
|
+
The player's LIBRARY screen makes a pack from a game's own
|
|
179
|
+
music. IMPORT a game's SPC set (a folder of `.spc` files, a zip, or
|
|
259
180
|
snesmusic.org's `.rsn`, a `.rar` or a `.7z`, which 7-Zip or unar on your
|
|
260
181
|
machine unpacks) and each song is run through an emulator of the SNES sound
|
|
261
182
|
hardware, read as music (the beat and bar, which voice is the melody, the
|
|
262
183
|
bass, the chords and the drums, the form) and the soundtrack made into a
|
|
263
184
|
pack: the samples the game plays each part with most, as its voices, a kit
|
|
264
185
|
of its drums, and the habits the readings give straight (tempo, major or
|
|
265
|
-
minor, how often a song has no drums, the echo).
|
|
266
|
-
|
|
267
|
-
notes) and move it; USE
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
186
|
+
minor, how often a song has no drums, the echo). SOUNDS shows each voice in
|
|
187
|
+
its part, to hear it, see why it was put there (in how many songs, how
|
|
188
|
+
many notes) and move it; USE ITS SOUNDS plays the next songs on them;
|
|
189
|
+
EXPORT writes the pack as one zip, and ADD A PACK brings an exported pack,
|
|
190
|
+
or a pack file, back. Importing a game again
|
|
191
|
+
starts its pack fresh. A game imported under an earlier version is
|
|
192
|
+
written the new way only once it is imported again: the newer reader
|
|
193
|
+
reads its songs again, and its vocabulary is counted with the words an
|
|
194
|
+
older import lacks.
|
|
195
|
+
|
|
196
|
+
An import also counts the game's own tables into its pack. With 40 songs
|
|
197
|
+
or more behind it the game has a vocabulary of its own: WRITE FROM IT in
|
|
198
|
+
LIBRARY, or its card under WRITE's WRITTEN FROM, writes the next songs the
|
|
199
|
+
way that game's are put together, and a library vocabulary recounted over
|
|
200
|
+
everything you have imported sits beside them (`--vocabulary pack:NAME`,
|
|
201
|
+
`--vocabulary library`). Under 40 songs a fitted vocabulary's drums are
|
|
202
|
+
not yet the game's, so none is offered.
|
|
275
203
|
|
|
276
204
|
The emulator, `bitcomposer-emu`, is a compiled package of its own with a
|
|
277
205
|
wheel for Linux (x86_64 and aarch64), Windows and macOS, so no toolchain
|
|
278
206
|
is needed. The Windows build carries it. On Linux,
|
|
279
|
-
`pipx install "bitcomposer[import]"` installs both, or
|
|
207
|
+
`pipx install "bitcomposer[import]"` installs both, or LIBRARY's GET THE
|
|
280
208
|
EMULATOR adds it to a player already installed, and UPDATE keeps both
|
|
281
209
|
current (`pip install "bitcomposer[import]"` elsewhere). Where no wheel
|
|
282
210
|
matches, it builds from source (Rust; CONTRIBUTING.md has how).
|
|
@@ -301,10 +229,21 @@ them stay on your machine, in your data folder
|
|
|
301
229
|
`bitcomposer-player` (Linux) and `bitComposer.exe` (Windows) are the same
|
|
302
230
|
program, an application of four screens under one header:
|
|
303
231
|
|
|
304
|
-
- **PLAY**: the song playing
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
232
|
+
- **PLAY**: one panel for the song playing (its title with its key, tempo
|
|
233
|
+
and form, MORE for the rest of what its file says), its position, the
|
|
234
|
+
transport, GENERATE and AUTO
|
|
235
|
+
(the "radio": the next song is written when this one ends); gain with a
|
|
236
|
+
soft limiter, WIDTH (the stereo width heard: SPEAKERS plays each voice
|
|
237
|
+
where its song puts it, HEADPHONES pulls the pans toward centre), each
|
|
238
|
+
channel's level as the band, with an M and an S on every part (M mutes
|
|
239
|
+
it, S plays it alone, or with the other parts whose S is lit; a part's
|
|
240
|
+
echo goes with it; for the song playing only, never written into the
|
|
241
|
+
file), and the songs in the
|
|
242
|
+
folder with KEEP. GAIN & WIDTH and the band fold to their headings on a
|
|
243
|
+
click, and the song list takes whatever height the window has left, so
|
|
244
|
+
the songs scroll and the screen over them stays put. Every song plays at one level: the player measures a
|
|
245
|
+
song once and trims it as it plays, so a quiet song and a loud one sit
|
|
246
|
+
side by side (SET → LEVEL turns it off; the files are not changed). Every song the player writes is provisional
|
|
308
247
|
(`(auto) <Title>.it`, so a file browser sorts them together) and pruned
|
|
309
248
|
after ten unless kept.
|
|
310
249
|
- **WRITE**: what the next song is written from (the vocabulary that
|
|
@@ -314,15 +253,16 @@ program, an application of four screens under one header:
|
|
|
314
253
|
switch at the bottom, with its own knobs (sound, tempo, energy, scale,
|
|
315
254
|
form, echo, bass, drums, harmony) and presets.
|
|
316
255
|
- **LIBRARY**: the games you have read. IMPORT reads a game's SPC set
|
|
317
|
-
into its sounds and, at 40 songs, its own vocabulary; ADD
|
|
318
|
-
exported pack; each game can lend its sounds, be written from,
|
|
256
|
+
into its sounds and, at 40 songs, its own vocabulary; ADD A PACK brings
|
|
257
|
+
in an exported pack; each game can lend its sounds, be written from,
|
|
319
258
|
be exported, renamed or deleted.
|
|
320
259
|
- **SOUNDS**: a game's samples by part, each heard with a click and moved
|
|
321
260
|
when the reading got it wrong.
|
|
322
261
|
|
|
323
262
|
MIX (a live mixer per channel, with the kit and the echo as buses, and
|
|
324
|
-
APPLY to write the mix into the file) and SET (
|
|
325
|
-
checks, release candidates) open as panels over
|
|
263
|
+
APPLY to write the mix into the file) and SET (one level for every song,
|
|
264
|
+
start at login, update checks, release candidates) open as panels over
|
|
265
|
+
the screen. The look is
|
|
326
266
|
the SNES era's own pixels, as styling only: the controls are ordinary
|
|
327
267
|
controls, the text is text, nothing sits on a fixed grid. The window
|
|
328
268
|
opens no taller than the screen it lands on (scrolling on a small or
|
|
@@ -341,9 +281,127 @@ the release's installer and runs it. A player installed from a release
|
|
|
341
281
|
candidate is offered the next candidate; a release player only releases,
|
|
342
282
|
unless SET → CANDIDATES asks for candidates too.
|
|
343
283
|
|
|
284
|
+
## Classic
|
|
285
|
+
|
|
286
|
+
Classic is the 1.x generator, kept whole in 2.0: WRITER: CLASSIC (1.X) on
|
|
287
|
+
the player's WRITE screen, `--classic` on the command line. It has no
|
|
288
|
+
vocabulary. Every run composes a new song from rules and tables of its
|
|
289
|
+
own: a motif-based melody with call-and-response phrasing, voice-led
|
|
290
|
+
harmony, bass, arpeggio and drums, arranged into a form (verse–chorus,
|
|
291
|
+
AABA, rondo, through-composed) with a drawn intro, an energy curve and a
|
|
292
|
+
real ending, titled after what it drew, between 1:15 and 3:30 long. Eight
|
|
293
|
+
sounds, picked with `--sound`:
|
|
294
|
+
|
|
295
|
+
- **snes** — sampled-style voices built the way the SNES made sound, through a BRR codec model and the SNES echo.
|
|
296
|
+
- **bit** — bitComposer's own sound set, the one the writer plays on by default: generic instruments synthesised here from descriptions, modelled on no game's bank.
|
|
297
|
+
- **ffvi**, **mana**, **evermore**, **megamanx** — style packs: an instrument set rebuilt from each game's own sound chip (every sample profiled, nothing copied) plus the arrangement habits of its score. Details under [Sounds](#sounds).
|
|
298
|
+
- **genesis** — FM bells, brass, organ and bass.
|
|
299
|
+
- **chip** — square, pulse and triangle waves. Closest to NES and Game Boy.
|
|
300
|
+
|
|
301
|
+
### Sounds
|
|
302
|
+
|
|
303
|
+
A style pack pairs an instrument set with the arrangement habits of the score it imitates. Each is built from the game's SPC snapshots: every sample decoded and profiled, matched to the community's instrument tables where they exist, and re-synthesised; nothing from the games is in the repository.
|
|
304
|
+
|
|
305
|
+
- `ffvi`: every voice modelled on the game's own sample bank and named by its instrument table: the chorused string section, flutes in chords, the dark synth lead of Locke and the Returners, trumpet, trombone, oboe, Terra's and Cyan's pan flutes, cello, choir, pipe organ and rock organ, the Aria's soprano, the Battle theme's distortion guitar, piano, harp, picked string, acoustic guitar, tubular bell, xylophone, a bass guitar and a kit of its own (kick, snare, hats, cymbal, timpani, wood block), with ostinato strings, a brass counter-line in the chorus, timpani rolls into sections and the game's short, wet echo.
|
|
306
|
+
- `mana`: every voice modelled on the game's own sample bank: a soft slow-breathed flute, bright chorused strings, an 'ah' choir, a high whistle, soft and synth brass, marimba, vibraphone, electric piano, tubular bell, reed, accordion, glass and sine pads, fingered, electric and slap basses and a kit of its own (kick, snare, hats, crash, tom, castanet), with major and pentatonic keys, syncopated harmony, bouncy arps, light swing, the kick and snare set back and the game's one-row echo.
|
|
307
|
+
- `evermore`: every voice modelled on the game's own sample bank: a slow bright string swell, a warm pad, a dark pad, a glass bell, a breathy flute, a reed, an "oo" choir, harp, tinker music box, piano, pluck and kalimba, a textured drone and a wind loop, a bass, and a quiet kit (soft kick, frame drum, brushes, hat, cymbal, wood ping), with slow tempos, sustained harmony, a drone bass, sparse or no drums, long linear forms and the game's sparing 80 ms echo.
|
|
308
|
+
- `megamanx`: every voice modelled on the game's own sample bank and named by it: a driven, chorused lead guitar, a chugging rhythm guitar on power chords, the overdrive guitar for arps and counter-lines, synth brass, strings, a guitar swell pad, a saw pad, organ, the boomer synth lead, square and bright leads, a hollow wave, a bell synth, an acoustic pluck, the orchestra hit for stabs, slap and synth basses on a riff, and a tight kit, at fast tempos in minor keys with the game's 48 ms slapback echo.
|
|
309
|
+
|
|
310
|
+
`--sound` picks a palette or a pack in one word; left to chance, the four style packs together weigh as much as plain snes, and bit as much as one of them.
|
|
311
|
+
|
|
312
|
+
- **snes** — sampled-style voices rendered the way the SNES actually made sound: strings, brass, a formant choir, flute, organ, e-piano, bells, plucks and a gated drum kit at 16 kHz with loop points, passed through a BRR codec model for the grain, with the lead, harmony and arp through an echo modelled on the SNES unit's result: fading, darkening repeats on a beat fraction, drawn per song.
|
|
313
|
+
- **genesis** — FM bells, brass, organ and bass.
|
|
314
|
+
- **chip** — square, pulse and triangle waves.
|
|
315
|
+
|
|
316
|
+
### What you can steer
|
|
317
|
+
|
|
318
|
+
With `--classic`, everything defaults to `random` but `--keys` (moving) and `--lead-shift` (the sound's own). Without it, of these a written song reads only `--pack`, `--pack-file`, `--echo off`, `--name`, `--prefix`, `--suffix` and the last line.
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
--sound chip|snes|genesis|bit|ffvi|mana|evermore|megamanx the sound in one word: a palette or a style pack (overrides the two below)
|
|
322
|
+
--style chip|snes|genesis sound palette
|
|
323
|
+
--pack bit|ffvi|mana|evermore|megamanx|none|random style pack: an instrument set with the habits of the scores it imitates (a pack implies snes)
|
|
324
|
+
--pack-file PACK.json a pack as data, with its own voices as WAV files (docs/PACKS.md); overrides --pack and --sound
|
|
325
|
+
--echo on|off|random echo (random: 70% of snes songs, never chip or genesis)
|
|
326
|
+
--echo-wet light|normal|wet|random how much of the lead, harmony and arp the echo carries
|
|
327
|
+
--echo-delay eighth|dotted|quarter|slap|row|random beat fraction between repeats, a 48 ms slap, or one row (random: weighted by tempo)
|
|
328
|
+
--echo-stereo bounce|centre|random repeats alternate sides, or sit under their source
|
|
329
|
+
--keys moving|home moving: choruses/bridges may change key; home: stay put
|
|
330
|
+
--tempo slow|medium|fast 80–110 / 110–140 / 140–180 BPM
|
|
331
|
+
--energy chill|normal|intense density and arrangement weight
|
|
332
|
+
--scale minor|major|pentatonic
|
|
333
|
+
--form standard|aaba|rondo|short|linear
|
|
334
|
+
--drum-density sparse|normal|busy --no-fills --swing off|light|heavy
|
|
335
|
+
--melody simple|phrased phrased = motif-based, has a hook
|
|
336
|
+
--harmony-voicing thin|full two real voices, or three
|
|
337
|
+
--harmony-mode stabs|sustain|rhythmic
|
|
338
|
+
--bass-weight heavy|medium|light
|
|
339
|
+
--lead-shift SEMITONES move the lead's window (negative lowers it); default: the sound's own
|
|
340
|
+
--name title|timestamp file naming; --prefix / --suffix add a marker ("(auto) " is the player's)
|
|
341
|
+
-s SEED -n COUNT -o FILE -d DIR -v
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Some starting points:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Overworld — bright, sampled palette with echo
|
|
348
|
+
bitcomposer --classic -d out --style snes --scale major --tempo medium --form standard
|
|
349
|
+
|
|
350
|
+
# FM boss fight
|
|
351
|
+
bitcomposer --classic -d out --style genesis --tempo fast --energy intense --scale minor --drum-density busy --form short
|
|
352
|
+
|
|
353
|
+
# Game Boy flavour — square waves, thin harmony, no echo
|
|
354
|
+
bitcomposer --classic -d out --style chip --echo off --harmony-voicing thin --bass-weight light --form short
|
|
355
|
+
|
|
356
|
+
# Credits roll
|
|
357
|
+
bitcomposer --classic -d out --style snes --tempo slow --energy chill --scale major --drum-density sparse --no-fills --form linear
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### How it works
|
|
361
|
+
|
|
362
|
+
1. Pick a key and a scale weighted toward game music (minor pentatonic, dorian, harmonic minor, mixolydian…), then a progression for it. The tables include borrowed chords and secondary dominants — ♭VII, ♭VI, V/V — not just the diatonic set.
|
|
363
|
+
2. Choose a form and its energy curve; decide which sections repeat. Repeated sections draw the same music from the same seed, so the hook comes back.
|
|
364
|
+
3. Generate a motif (rhythm template plus contour) and vary it per bar in statement/answer pairs. Fourteen rhythm templates, six of them with 16th-note pushes and pickups.
|
|
365
|
+
4. Each four-bar pattern holds a chord timeline; about half the time the back two bars move to a related chord. Melody resolves onto chord tones at each change. Harmony is two or three real voices placed near fixed anchors, so it steps rather than leaps and keeps the chord's third; the anchors are set per voice family (pads low and wide, brass and guitars mid and close), the top voice stays under the lead's line, and a stab holds for as long as the voice needs to speak. Bass and arp follow and rest with the section's energy.
|
|
366
|
+
5. Drums come from one-bar templates by section and density, with fills, retriggered snare rolls and tick-level swing.
|
|
367
|
+
6. Instruments are synthesized per song from the chosen palette and written as samples. SNES voices get attack-then-loop sustain and the BRR treatment.
|
|
368
|
+
7. The echo: held lead notes and phrase endings come back as three fading, darkening repeats, the harmony and arp as lighter ones, each on return channels of their own, drums and bass dry. Everything is written as a 19-channel `.it` with the title and a song message (key, BPM, palette, form, seed, and a `layout:` line naming every channel's role) that trackers display.
|
|
369
|
+
|
|
370
|
+
Each song gets a title that reads the song: its scale, sound, energy and
|
|
371
|
+
tempo lean the words, so a slow minor Evermore piece and a fast Mega Man X
|
|
372
|
+
track are named differently (*Lunar Snow*, *Lighthouse of Steel*, *The
|
|
373
|
+
Power Plant of Sparks*).
|
|
374
|
+
|
|
375
|
+
## Measuring instead of guessing
|
|
376
|
+
|
|
377
|
+
`tools/analyze.py` parses `.it` files back from disk (stdlib only, independent
|
|
378
|
+
of the generator) and scores a batch on the things that correlate with
|
|
379
|
+
"sounds like a song": section reuse, motif repetition, rhythmic grid, chord
|
|
380
|
+
voicing variety, voice motion, effect vocabulary, drum density.
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
python3 tools/analyze.py 'out/*.it' # metric table
|
|
384
|
+
python3 tools/analyze.py --grid out/song.it # tracker-style pattern dump
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
[docs/ANALYSIS.md](docs/ANALYSIS.md) is the story of this project: the
|
|
388
|
+
output was once limited by three silent arrangement bugs that nine commits
|
|
389
|
+
of ear-checking never caught, and every improvement since has been measured
|
|
390
|
+
before and after. Read it before changing Classic. The writer has its own
|
|
391
|
+
record: [docs/IDIOM.md](docs/IDIOM.md) for the plan, and [docs/idiom/phase-4-writing.md](docs/idiom/phase-4-writing.md)
|
|
392
|
+
for its rounds, each measured against Final Fantasy VI's own songs and
|
|
393
|
+
most passed by ear. What the written songs do that can sound odd, and why it
|
|
394
|
+
stands, is in [docs/LIMITS.md](docs/LIMITS.md).
|
|
395
|
+
|
|
396
|
+
Tests:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
python3 -m unittest discover -s tests -v
|
|
400
|
+
```
|
|
401
|
+
|
|
344
402
|
## Windows
|
|
345
403
|
|
|
346
|
-
Every release carries `bitComposer-setup.exe` (the installer) and `bitComposer-windows.zip` (the same `bitComposer` folder, no install), built by GitHub Actions on every
|
|
404
|
+
Every release carries `bitComposer-setup.exe` (the installer) and `bitComposer-windows.zip` (the same `bitComposer` folder, no install), built by GitHub Actions on every pull request into main and attached on the tag: `bitComposer.exe`, the player, with Qt, libopenmpt and the SNES emulator (for importing a game's music) beside it; and `bitcomposer-cli.exe`, the command line. The installer installs for your user by default (no administrator prompt; all users is an option on its first page), and the player's UPDATE button runs the next one quietly and reopens the player. Each build also renders the player offscreen at common screen sizes and scalings (1366×768, 1920×1080 at 100% and 150%, 2560×1440 at 125%, 4K at 200%), kept as the workflow's `player-screenshots-windows` artifact. Songs are `.it` files; [OpenMPT](https://openmpt.org) and XMPlay play them too. Windows releases are to be code-signed through the SignPath Foundation's programme for open-source projects (see [Code signing policy](#code-signing-policy)); until that is in place they are unsigned, so SmartScreen asks once ("More info", "Run anyway"). Smart App Control, where Windows 11 has it on, blocks unsigned programs outright with no such choice; bitComposer runs only with it off (Windows Security, App & browser control). With Python installed instead, `pipx install bitcomposer` gives the same programs as `bitcomposer-player` and `bitcomposer`.
|
|
347
405
|
|
|
348
406
|
## Code signing policy
|
|
349
407
|
|
|
@@ -364,7 +422,7 @@ bitComposer composes and plays music on your computer. It collects nothing about
|
|
|
364
422
|
|
|
365
423
|
One thing goes over the network on its own: when the player starts, it asks GitHub's public releases list (`api.github.com`) whether a newer version exists, so it can offer the UPDATE button. That request carries only what any web request does (your IP address and the program's name), and [GitHub's privacy statement](https://docs.github.com/site-policy/privacy-policies/github-general-privacy-statement) covers it. Turn it off in the player under SET → PLAYER → UPDATES. Updating itself downloads only when you press UPDATE: the installer from GitHub on Windows, the package from PyPI with pipx. GET THE EMULATOR downloads the emulator from PyPI the same way, and only when you press it. Importing a game's music reads your files on your machine and sends nothing.
|
|
366
424
|
|
|
367
|
-
The [listening page](https://catdogbark.github.io/bitComposer/) is a website: GitHub Pages serves it and Google Fonts serves its
|
|
425
|
+
The [listening page](https://catdogbark.github.io/bitComposer/) is a website: GitHub Pages serves it and Google Fonts serves its fonts, each under its own privacy policy. It plays the songs in your browser and keeps nothing.
|
|
368
426
|
|
|
369
427
|
## License and contact
|
|
370
428
|
|