- Introduced detailed analysis for the Minecart system, highlighting its state machine, track system, and areas for improvement. - Created an NPCs analysis document, summarizing various NPC sprites and their functionalities. - Added an Objects analysis document, covering interactive elements like collectibles, ice blocks, and minecarts. - Documented the Overlord sprite system, detailing its role in spawning other sprites and managing events. - Compiled a Dungeons & Indoor Areas document, outlining custom room tags, enhanced mechanics, and advanced collision systems. - Developed an Overworld Systems Analysis, focusing on the ZSCustomOverworld architecture and its core features. - Added a Time System document, explaining the in-game clock and day/night cycle management. - Documented the ZScream Custom Overworld, detailing its data-driven approach and key features.
138 lines
7.1 KiB
Markdown
138 lines
7.1 KiB
Markdown
# Music Creation Guide
|
|
|
|
This document details the process for creating and integrating custom music into Oracle of Secrets. The project uses the native Super Nintendo Packet Chip (N-SPC) music format, abstracted through a powerful set of `asar` macros.
|
|
|
|
## 1. N-SPC Music Format Primer
|
|
|
|
Music in the N-SPC engine is structured around eight independent channels. Each channel is a stream of bytes that are read sequentially. The stream consists of two types of data:
|
|
|
|
- **Commands:** Special bytes (from `$E0` to `$FF`) that control aspects of the sound, such as setting the instrument, changing volume, or calling a subroutine.
|
|
- **Notes:** A note consists of a duration byte followed by one or more tone bytes. The duration byte (e.g., `$48` for a quarter note) determines how long the following tone(s) will play.
|
|
|
|
## 2. The Macro System (`Core/music_macros.asm`)
|
|
|
|
To make composing more intuitive, the project uses a comprehensive library of macros that wrap the raw N-SPC commands into readable names. All music files must include `Core/music_macros.asm`.
|
|
|
|
### Key Concepts
|
|
|
|
- **Note Durations:** Constants are defined for standard note lengths (e.g., `!4th`, `!8th`, `!16th`).
|
|
- **Note Tones:** Constants are defined for all notes across several octaves (e.g., `C4`, `G4s` for G#4, `A5`).
|
|
- **Special Notes:** `Tie` (`$C8`) continues the previous note for the new duration, and `Rest` (`$C9`) signifies silence.
|
|
|
|
### Core Macros
|
|
|
|
- **`%SetInstrument(id)`:** Sets the instrument for the current channel (e.g., `%SetInstrument($09)` for Strings). Helper macros like `%Strings()`, `%Piano()`, etc., exist for common instruments.
|
|
- **`%SetTempo(value)`:** Sets the overall playback speed of the song.
|
|
- **`%SetMasterVolume(value)` / `%SetChannelVolume(value)`:** Sets the volume for the entire song or just the current channel.
|
|
- **`%CallSubroutine(address, repeats)`:** The most important macro for structuring songs. It jumps to a labeled subroutine, plays it `repeats+1` times, and then returns. **This is the primary method for looping musical phrases.**
|
|
- **`%VibratoOn(delay, rate, depth)`:** Adds a vibrato effect.
|
|
- **`%TremoloOn(delay, rate, depth)`:** Adds a tremolo (volume fluctuation) effect.
|
|
- **`%SetPan(value)`:** Sets the stereo position (left/right) of the channel.
|
|
- **`%EchoVBits(switch, left, right)`:** Enables and configures echo for the channel.
|
|
|
|
## 3. Song File Structure
|
|
|
|
Every song `.asm` file follows a standard structure.
|
|
|
|
#### 1. Header
|
|
|
|
The file begins with a header that defines metadata for the song engine.
|
|
|
|
```asm
|
|
MyNewSong:
|
|
!ARAMAddr = $D86A ; Base address in ARAM for this song
|
|
dw !ARAMAddr+$0A ; Pointer to the Intro section
|
|
dw !ARAMAddr+$1A ; Pointer to the Main (looping) section
|
|
dw $00FF ; Default fade-in
|
|
dw !ARAMAddr+$02 ; Start of the looping section data
|
|
dw $0000
|
|
```
|
|
|
|
#### 2. Channel Pointers
|
|
|
|
Next is a table of pointers to each of the eight channel data blocks. The `!ARAMC` constant is used to make these pointers relative to the song's ARAM address.
|
|
|
|
```asm
|
|
.Channels
|
|
!ARAMC = !ARAMAddr-MyNewSong
|
|
dw .Channel0+!ARAMC
|
|
dw .Channel1+!ARAMC
|
|
; ...up to 8 channels, use dw $0000 for unused channels
|
|
```
|
|
|
|
#### 3. Channel Data
|
|
|
|
Each channel is a block of code containing commands and notes.
|
|
|
|
```asm
|
|
.Channel0
|
|
%SetMasterVolume($DA)
|
|
%SetTempo(62)
|
|
%SetInstrument($02) ; Tympani
|
|
%SetDurationN(!4th, $7F)
|
|
%CallSubroutine(.sub1+!ARAMC, 23) ; Call subroutine .sub1 24 times
|
|
db End ; $00, signifies end of channel data
|
|
```
|
|
|
|
#### 4. Subroutines
|
|
|
|
The bulk of a song is made of small, labeled subroutines containing musical phrases. These are placed after the channel data.
|
|
|
|
```asm
|
|
.sub1
|
|
db !4th, B1, B1, !8th, Tie, C2, !4th, F3s
|
|
db End ; Subroutines must also end with $00
|
|
```
|
|
|
|
## 4. How to Add a New Song
|
|
|
|
1. **Create the File:** Create a new `.asm` file in the `Music/` directory.
|
|
2. **Copy Template:** Copy the contents of an existing song (e.g., `stone_tower_temple_v2.asm`) into your new file to use as a template.
|
|
3. **Set Header:** Change the main label (e.g., `MyNewSong:`) and set the `!ARAMAddr`. This address must be unique and not conflict with other songs.
|
|
4. **Compose:** Write your music in the channel and subroutine blocks using the note constants and macros.
|
|
5. **Integrate the Song:**
|
|
- Open `Music/all_music.asm` and add an `incsrc` for your new file.
|
|
- To replace a vanilla song, find its label in the ROM map and use `org` to place your new song at that address. For example, to replace the Lost Woods theme:
|
|
```asm
|
|
org $1AADDE ; Original address of Lost Woods theme
|
|
incsrc "Music/MyNewSong.asm"
|
|
```
|
|
- To add a new song to the expanded Dark World bank, open `Music/expanded.asm` and add a new entry to the `SongBank_OverworldExpanded_Main` table.
|
|
|
|
## 5. Proposals for Improved Organization
|
|
|
|
The current system is functional but can be made more readable and maintainable.
|
|
|
|
1. **Standardize Subroutine Naming:** The current convention of `.sub1`, `.sub101`, etc., is ambiguous. A clearer naming scheme would greatly improve readability.
|
|
- **Proposal:** Name subroutines based on their musical function, like `.MelodyVerseA`, `.BasslineIntro`, `.PercussionFill1`. This makes the main channel blocks easier to read as a high-level song structure.
|
|
|
|
2. **Create a Common Patterns Library:** Many songs use similar rhythmic or melodic patterns (e.g., a standard 4/4 drum beat, an arpeggiated chord).
|
|
- **Proposal:** Create a `Music/common_patterns.asm` file. This file could contain a library of generic, reusable subroutines for things like drum patterns, basslines, or common arpeggios. Songs could then `incsrc` this library and call these patterns, reducing code duplication and speeding up composition.
|
|
|
|
3. **Develop Advanced Composition Macros:** The existing helper macros are basic. More advanced macros could abstract away the manual process of defining and calling subroutines.
|
|
- **Proposal:**
|
|
- `%DefineMeasure(Name, Notes...)`: A macro that takes a name and a list of notes and automatically creates a correctly formatted subroutine block.
|
|
- `%PlayMeasure(Name, Repeats)`: A macro that automatically calculates the relative address (`+!ARAMC`) and calls `%CallSubroutine`.
|
|
|
|
- **Example Workflow with Proposed Macros:**
|
|
```asm
|
|
; --- Subroutine Definitions ---
|
|
%DefineMeasure(VerseMelody, !8th, C4, D4, E4, F4, G4, A4, B4, C5)
|
|
%DefineMeasure(VerseBass, !4th, C2, G2, A2, F2)
|
|
|
|
; --- Channel Data ---
|
|
.Channel0
|
|
; ... setup ...
|
|
%PlayMeasure(VerseMelody, 4) ; Plays the melody 4 times
|
|
db End
|
|
|
|
.Channel1
|
|
; ... setup ...
|
|
%PlayMeasure(VerseBass, 4) ; Plays the bassline 4 times
|
|
db End
|
|
```
|
|
This approach would make the main channel data blocks read like a high-level song arrangement, significantly improving clarity.
|
|
|
|
4. **Improve In-File Documentation:**
|
|
- **Proposal:** Encourage the use of comments to label major song sections directly within the channel data (e.g., `; --- VERSE 1 ---`, `; --- CHORUS ---`). This provides crucial signposting when navigating complex song files.
|