.CHC
The .CHC file format is used in Gitaroo Man and Gitaroo Man Lives!. It contains the song charts and factors such as starting energy and damage. And while the file itself contains no audio or visuals, it determines which audio/visuals to use with different song charts.
Notes:
- Not everything has been verified on both consoles
- need to document some new findings by sonicfind et al
Data types used in this article (all little-endian):
- int32: signed 4-byte integer
- uint32: unsigned 4-byte integer
- float32: 4-byte floating-point decimal
File Layout
- 1 Song per file
- 1 or more Cues per file
- 1 or more SongSections per file (matches the number of Cues)
- 1 or more Conditions per SongSection
- 0 or more Charts per SongSection
- 1 or more Trace Line fragments per Chart
- 0 or more Phrase fragments per Chart
- 0 or more Guard fragments per Chart
- 1 Player Energy/Damage Factors per file
Song
First comes this section, which affects the entire song. It controls such things as volume and gameplay speed.
offset | size | data |
---|---|---|
+0x00 | 4 | Magic stamp, always 'SNGS' |
+0x04 | 4 | unknown constant 0x00001800 [ignored by game] |
+0x08 | 12 | all 0 [ignored by game] |
+0x14 | 4 | unknown value, always something like 0x000010xx [ignored by game] |
+0x18 | 12 | all 0 or junk values [ignored by game] |
+0x24 | 256 | PS2 version: null-terminated string: location of .IMC file used for this stage's music and sound effects.
|
PSP version: unused (PSP version doesn't use IMC files) |
The following pairs of values-- first and last frames-- each define a set of frames to be played from this stage's .SSQ file. (The SSQ file control the 3D models displayed in the background.)
offset | size | data | event that causes frames to play |
---|---|---|---|
+0x124 | 4 | float32: Win A first frame | Player wins the stage. |
+0x128 | 4 | float32: Win A last frame | |
+0x12C | 4 | float32: Win B first frame | None, Win B seems to be unused. (Note: I haven't checked whether multiplayer uses this) |
+0x130 | 4 | float32: Win B last frame | |
+0x134 | 4 | float32: Lost Pre first frame | Player loses the stage. |
+0x138 | 4 | float32: Lost Pre last frame | |
+0x13C | 4 | float32: Lose Post first frame | Loops endlessly after Lost Pre, while "Try Again?" is displayed onscreen. |
+0x140 | 4 | float32: Lose Post last frame |
The following values control volume and pan for different audio channels. Values are as follows:
- Volume: ranges from 0 to 32767
- Pan: ranges from 0 (left) to 32767 (right). 16383 places audio in the center.
offset | size | PS2 version data | PS2 version purpose | PSP version data | PSP version purpose |
---|---|---|---|---|---|
+0x144 | 4 | uint32: 1st channel volume | Background music [left channel] | unused | no effect |
0x148 | 4 | uint32: 1st channel pan | unused | ||
+0x14C | 4 | uint32: 2nd channel volume | Background music [right channel] | unused | no effect |
0x150 | 4 | uint32: 2nd channel pan | unused | ||
+0x154 | 4 | uint32: 3rd channel volume | Player 1 audio | uint32: 2nd track left channel volume | Player 1 audio [left channel] |
0x158 | 4 | uint32: 3rd channel pan | unused | ||
+0x15C | 4 | uint32: 4th channel volume | Player 2 audio | uint32: 2nd track right channel volume | Player 1 audio [right channel] |
0x160 | 4 | uint32: 4th channel pan | unused | ||
+0x164 | 4 | uint32: 5th channel volume | Player 3 audio; can be Player 1 audio [right channel] if stereo phrases are enabled | uint32: 3rd track left channel volume (Multi-player modes only) | Player 2 audio [left channel] in Multi-player modes, no effect in Single-player mode |
0x168 | 4 | uint32: 5th channel pan | unused | ||
+0x16C | 4 | uint32: 6th channel volume | Player 4 audio; can be Player 2 audio [right channel] if stereo phrases are enabled | uint32: 3rd track right channel volume (Multi-player modes only) | Player 2 audio [right channel] in Multi-player modes, no effect in Single-player mode |
0x170 | 4 | uint32: 6th channel pan | unused | ||
+0x174 | 4 | uint32: 7th channel volume | Voice & sound effects [left channel] | uint32: 3rd track left channel volume (Single-player mode only) | Player 2 audio [left channel] in Single-player mode, no effect in Multi-player modes |
0x178 | 4 | uint32: 7th channel pan | unused | ||
+0x17C | 4 | uint32: 8th channel volume | Voice & sound effects [right channel] | uint32: 3rd track right channel volume (Single-player mode only) | Player 2 audio [right channel] in Single-player mode, no effect in Multi-player modes |
0x180 | 4 | uint32: 8th channel pan | unused |
Continuing with the rest of this section:
offset | size | data |
---|---|---|
+0x184 | 4 | float32: gameplay speed factor. The lower this value, the faster the Trace Line and Guard marks go, making gameplay more difficult. Specifically, this might be the ratio of samples to pixels. The timing of trace lines, phrase bars, and guard marks are in samples (where 48000 samples = 1 second of music). So, with a speed factor of 240, a phrase bar of 24000 samples would appear 100 pixels long onscreen.
|
+0x188 | 4 | uint32: number of Cues that appear in this file. Also the number of SongSections, since there is always a Cue for each SongSection. |
Cue
Then come Cues, as many as were specified above (at address 0x188 of Song). A Cue is a pairing of audio and background visuals. Each Cue goes with a SongSection, e.g. the first Cue in the file goes with the first SongSection in the file. The Cue's audio and visuals will be played when its SongSection is played.
offset | size | data |
---|---|---|
+0x00 | 4 | uint32: index value for the cue. Seems to be based on the order of which each cue is added to the song, so indexes may skip forth or back a few numbers. [ignored by game] |
+0x04 | 16 | null-terminated string: seems to be unused. It's the name of an audio section like below, but the game doesn't seem to use it. Usually identical to the used one below, but in PS2 multiplayer charts you will often see a slightly different string here. |
+0x14 | 16 | null-terminated string: name of an audio section from the currently loaded .IMC file. PSP version: this instead refers to an audio file located in the "MS" or "MSE"/"MSJ" folder (relative to this CHC file's location on the disc). Usually "MSE" (English) or "MSJ" (Japanese) is used with single-player mode, and "MS" is used with multi-player mode, but the game is not consistent about this-- it depends on the level. |
+0x24 | 4 | float32: first frame to play from stage's .SSQ file |
+0x28 | 4 | float32: last frame to play from stage's .SSQ file |
+0x2C | 4 | probably junk [ignored by game] |
SongSection
Then come SongSections, as many as were specified above (at address 0x188 of Song). A SongSection contains Conditions and Charts. Also, each SongSection goes with a Cue, e.g. the first SongSection in the file goes with the first Cue in the file. When a SongSection is played, its Charts are displayed onscreen, and its Cue's audio and visuals are played in the background. Then as the SongSection finishes playing, its Conditions determine what to do next.
offset | size | data | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+0x00 | 4 | Magic stamp, always 'CHLS' | ||||||||||||||
+0x04 | 4 | unknown constant 0x00001300 [ignored by game] | ||||||||||||||
+0x08 | 4 | uint32: unknown, appears related to size of this SongSection [ignored by game] | ||||||||||||||
+0x0C | 8 | all 0 [ignored by game] | ||||||||||||||
+0x14 | 16 | all 0 or junk values [ignored by game] | ||||||||||||||
+0x24 | 4 | uint32: battle phase
| ||||||||||||||
+0x28 | 4 | float32: tempo in beats per minute. Only used in the PSP version. This is used to make sure background animations match the beat of the music-- it has no effect on music or gameplay speed. (The PS2 version ignores this, instead using a single tempo for the entire song, specified in ALBUMDEF.TXT.) | ||||||||||||||
+0x2C | 4 | uint32: duration of this SongSection in samples (where 1 sample = 1/48000th of a second) | ||||||||||||||
+0x30 | 4 | always 0 [ignored by game] | ||||||||||||||
+0x34 | 4 | uint32: number of Conditions | ||||||||||||||
+0x38 | ? | Conditions | ||||||||||||||
?+0x00 | 4 | uint32: number of players, always 4 (can be changed safely, though rather pointless) | ||||||||||||||
?+0x04 | 4 | uint32: number of charts per player | ||||||||||||||
?+0x08 | ? | Charts. number of Charts = (number of players) * (number of charts per player). Charts are listed in order by player-- all of Player 1's Charts come first, then all of Player 2's Charts, etc. Note on Players 3 and 4: If there is not a Player 3 participating in the match (i.e. it's single-player or 2-player versus mode), Player 1 gets Player 3's Charts. And if there isn't a Player 4, Player 2 gets Player 4's charts. |
Condition
A Condition determines what to do when the current SongSection ends, perhaps depending on such factors as player energy or randomness.
offset | size | data | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+0x00 | 4 | uint32: condition type
| ||||||||||||||
+0x04 | 4 | float32: condition argument. Used with condition types 1, 2, and 3. | ||||||||||||||
+0x08 | 4 | int32: True effect. This is invoked if the condition above is True. This value has different effects depending on its value. If True effect is less than 0:
If True effect is 0 or greater:
| ||||||||||||||
+0x0C | 4 | int32: False effect. Same as above, but invoked if the condition above is False. |
Chart
Each Chart contains a trace line, phrase bars, and guard marks, defining the lines and button presses the player must follow. Note: whenever "samples" are mentioned here, 1 sample is equal to 1/48000th of a second.
offset | size | data |
---|---|---|
+0x00 | 4 | Magic stamp, always 'CHCH' |
+0x04 | 4 | unknown constant 0x00001300 [ignored by game] |
+0x08 | 4 | uint32: size of this chart in bytes - 44 [ignored by game] |
+0x0C | 4 | always 0 [ignored by game] |
+0x10 | 4 | always 0, game crashes if this value is changed |
+0x14 | 16 | all 0 or junk [ignored by game] |
+0x24 | 4 | uint32: start time of this Chart in samples (relative to whenever the SongSection starts playing) |
+0x28 | 4 | uint32: end time of this Chart in samples. (Not sure if it's actually used for anything, though-- messing with this value causes no visible differences.) |
+0x2C | 4 | number of Trace Line fragments (must be at least 1) |
+0x30 | ? | Trace Line fragments |
?+0x00 | 4 | number of Phrase fragments |
?+0x04 | ? | Phrase fragments |
?+0x00 | 4 | number of Guard fragments |
?+0x04 | ? | Guard fragments |
?+0x08 | 4 | always 0 [ignored by game] |
Trace Line fragment
Trace Line fragments join to form a Trace Line. Every Chart must contain at least 1 Trace Line fragment or else the game will crash. To make this single Trace Line fragment invisible, give it a duration of 1 sample.
offset | size | data |
---|---|---|
+0x00 | 4 | int32: start time in samples, relative to Chart's start time. (Negative start times are not tolerated well-- in one attempt, the Trace Line was invisible until it reached a fragment with a positive start time.) |
+0x04 | 4 | uint32: duration in samples. (The duration should match the difference between this fragment's and the next fragment's start times.) |
+0x08 | 4 | float32: angle in radians, opposite of how it appears in-game. (e.g. an angle pi/4 radians is supposed to be up-right, but this will make the Trace Line approach from down-left.) |
+0x0C | 4 | uint32: curve, always 0 or 1. If it's 0, this fragment will go straight until the next fragment. If it's 1, this fragment will gradually curve between its own angle and that of the next fragment. |
Phrase fragment
Each Phrase Bar that appears on the Trace Line is made of one or more Phrase fragments. Phrase fragments are also used to show the charging and attacks made by computer-controlled players.
A single Trace Line fragment can contain multiple Phrase fragments, but a single Phrase fragment should not span multiple Trace Line fragments. If a Phrase Bar needs to span multiple Trace Line fragments, the bar should be split into multiple Phrase fragments.
offset | size | data |
---|---|---|
+0x00 | 4 | int32: start time in samples, relative to Chart's start time. (Negative start times seem to be tolerated okay, even though they're never used in the game.) |
+0x04 | 4 | uint32: duration in samples. (If this fragment is connected to the next one, duration should be equal to the difference between their start times.) |
+0x08 | 4 | uint32: Phrase Bar start, always 0 or 1. If it's 1, this Phrase fragment begins with an Attack Point, a circle that the player must hit. This should be set to 0 only if this fragment is connected to the previous one, otherwise the game will almost certainly crash. |
+0x0C | 4 | uint32: Phrase Bar end, always 0 or 1. If it's 1, this Phrase fragment is terminated by a rounded end. This should be set to 0 only if this fragment is connected to the next one, otherwise the game could crash. |
+0x10 | 4 | uint32: character animation, always 0, 1, or 2. A playable character has up to 3 possible animations when playing a Phrase Bar-- this value chooses which of those animations to use. (A value greater than 2 causes the phrase fragment to disappear so that it can't be played.) |
+0x14 | 4 | probably junk [ignored by game] |
+0x18 | 4 | probably junk [ignored by game] |
+0x1C | 4 | probably junk [ignored by game] |
Guard fragment
Each Guard fragment creates a button icon that the player must dodge.
offset | size | data |
---|---|---|
+0x00 | 4 | int32: start time in samples, relative to Chart's start time. The game always uses negative start times, but positive start times also seem to work. |
+0x00 | 4 | uint32: guard button
Below, their directions are shown: 3 ^ 0 2 -> [] O 1 X |
+0x00 | 4 | always 0 [ignored by game] |
+0x00 | 4 | always 0 [ignored by game] |
Player Energy/Damage Factors
These values control the players' energy and how much is gained or lost during different battle phases.
offset | size | data |
---|---|---|
+0x00 | 4 | uint32: always 20 (0x14) |
+0x04 | 32 | Player 1 Intro factors (see table below) |
+0x24 | 32 | Player 1 Charge factors |
+0x44 | 32 | Player 1 Battle factors |
+0x64 | 32 | Player 1 Harmony factors |
+0x84 | 32 | Player 1 End factors |
+0xA4 | 32 | Player 2 Intro factors |
+0xC4 | 32 | Player 2 Charge factors |
+0xE4 | 32 | Player 2 Battle factors |
+0x104 | 32 | Player 2 Harmony factors |
+0x124 | 32 | Player 2 End factors |
+0x144 | 160 | all of Player 3's factors, probably unused in PSP |
+0x1E4 | 160 | all of Player 4's factors, probably unused in PSP |
Each set of factors goes like is as follows. Values can be made negative to have the opposite effect.
offset | size | data |
---|---|---|
+0x00 | 4 | float32: starting energy (1.0 = full energy) |
+0x04 | 4 | float32: Charge: energy gained (initial button press) |
+0x08 | 4 | float32: Attack: damage to other player (initial button press, and also after button release?) |
+0x0C | 4 | float32: Guard: energy gained (used in multiplayer) |
+0x10 | 4 | float32: Attack: damage taken on miss |
+0x14 | 4 | float32: Guard: damage taken on miss |
+0x18 | 4 | float32: Charge: energy gained (after button release) |
+0x1C | 4 | float32: Attack: damage to other player (after button release) |
Note: In the PSP version (and maybe PS2 version, haven't checked yet), each battle phase only uses certain factors. For example, only Intro uses starting energy, End ignores any damage done to Player 1, etc. Unfortunately, this means no damaging your enemy during the Charge phase or anything like that.