mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
100 lines
3.5 KiB
Markdown
100 lines
3.5 KiB
Markdown
# Jukebox Example
|
|
|
|
Adds one song authored note-by-note in Lua, swaps it in as the Pallet Town
|
|
theme, replaces Mew's cry, and ships a jukebox screen that lists every song
|
|
in the merged registry.
|
|
|
|
**Persona: the Musician.** Nothing here is a `.ogg`. The song is a
|
|
Game Boy channel program assembled at load time by `ChipAsm`.
|
|
|
|
## Try it
|
|
|
|
```sh
|
|
python3 tools/modkit.py validate mods/examples/example_jukebox --base imported
|
|
luajit mods/examples/example_jukebox/tests/example_jukebox_test.lua
|
|
|
|
# render the song to a wav to hear it without launching the game
|
|
python3 tools/modkit.py bounce Music_ExamplePalletRain --seconds 20 --out bounce
|
|
```
|
|
|
|
Enable it (`example_jukebox = true` under `mods` in `options.lua`, or the
|
|
F10 manager), then open **OPTIONS → JUKEBOX**.
|
|
|
|
## What it demonstrates
|
|
|
|
| Seam | Where |
|
|
|---|---|
|
|
| `content.music:register` (ChipAsm DSL) | `song.lua` + `main.lua` |
|
|
| `content.cries:override` (chip program) | `main.lua` |
|
|
| `hooks:wrap("music.select")` | `main.lua` — one choke point covers map, battle and jingle music |
|
|
| `content.screens:register` | `main.lua` — a screen factory the engine instantiates by id |
|
|
| `hooks:wrap("ui.options.rows")` | `main.lua` — how the player reaches the screen |
|
|
| `content.music:each` | `main.lua` — the jukebox list is the merged view, not a hard-coded array |
|
|
| `mod:read` | `main.lua` — loading a sibling file through the loader's filesystem |
|
|
|
|
## Authoring a song
|
|
|
|
`song.lua` returns what `ChipAsm.song{...}` builds: a self-contained
|
|
program blob plus its channel layout. Events are Lua tables, one per
|
|
command:
|
|
|
|
```lua
|
|
{ duty = 2 },
|
|
{ notetype = { speed = 12, volume = 11, fade = 2 } },
|
|
{ octave = 4 },
|
|
{ label = "lead" },
|
|
{ note = "E", len = 6 }, { note = "D", len = 2 },
|
|
{ loop = { count = 0, to = "lead" } },
|
|
```
|
|
|
|
The assembler is the validator. An unknown note name or an out-of-range
|
|
length raises *there*, naming the channel and event index, and `main.lua`
|
|
turns that into one mod-attributed load error. The music system never
|
|
latches on a bad program, because a bad program never reaches it.
|
|
|
|
Two shapes share the `music` registry and are dispatched per definition,
|
|
not by a global flag: `{ chip = ... }` for an authored program and
|
|
`{ file = "..." }` for an audio file. This example uses the first; a file
|
|
track is one line:
|
|
|
|
```lua
|
|
mod.content.music:register("Music_MyTheme", { file = mod.path .. "/theme.ogg" })
|
|
```
|
|
|
|
Note the cry uses `ChipAsm.sfx{...}.chip` — the assembler returns
|
|
`{ chip = program }`, and a cry record wants the program under its own
|
|
`chip` key.
|
|
|
|
## Deferring is the parity guarantee
|
|
|
|
```lua
|
|
mod.hooks:wrap("music.select", function(next, chosen, ctx)
|
|
if ctx and ctx.reason == "map" and ctx.mapId == "PALLET_TOWN" then
|
|
return next(SONG_ID, ctx)
|
|
end
|
|
return next(chosen, ctx)
|
|
end)
|
|
```
|
|
|
|
Every path that is not Pallet Town calls `next(chosen, ctx)` with the
|
|
argument it was given, so playback everywhere else is exactly what it was
|
|
before the mod loaded.
|
|
|
|
## Empty state
|
|
|
|
The jukebox is a `ListMenu`, which draws `Nothing here.` when its item list
|
|
is empty rather than an empty frame. That cannot happen with the engine's
|
|
45 songs present, but it is the behavior a mod screen owes the player.
|
|
|
|
## Permissions
|
|
|
|
This mod declares `engine_internals`, because playing a song from a screen
|
|
currently needs `require("src.core.Music")` — the mod surface has no audio
|
|
playback facade yet. Declaring it is the honest path: `modkit validate`
|
|
accepts a declared require and flags an undeclared one.
|
|
|
|
## Credits
|
|
|
|
- Pallet Rain arrangement: this project.
|
|
- pret/pokered: the channel command set `ChipAsm` assembles to.
|