jombo23 / N64-Tools

N64 Tools
The Unlicense
239 stars 113 forks source link

EAD SoundBank Missing Fine-Tuning (And Additional Debug Output Required) #46

Open L-Spiro opened 1 year ago

L-Spiro commented 1 year ago

I am trying to build the tools myself so that I can add this data to the debug output, but the tools are not possible to build thanks to the issue I reported (#45). If there is a way around that I should be able to add this feature myself, but until this I am reporting this as a separate bug.

In EAD games, fine-tuning is ignored—hard-coded to 0x0000—while the base key is determined via a call to ConvertEADGameValueToKeyBase(), which performs the following: BaseKey = round( 60 - log2( x ) * 12 ); This causes the fine-tuning value to be truncated out, which causes many samples in EAD tracks to be off-key. The Float Key and Key Prev/Key/Key Sec values are used to determine both the root key and the fine-tuning value.

Here is how to correctly decode these values using Super Mario 64 Bank 0x25 Percussion 0x29 (Float Key = 0.546910) as an example:

Frac = 0.546910;
RealBase = 60 - log2( Frac ) * 12;  // 70.4474958423231640836092992685735225677490234375, IE base key = 70, fine-tuning = -44.75 cents.
RoundedBase = round( RealBase ); // 70.  This is the final “Key Base” value.
Diff = RealBase - RoundedBase; // 0.4474958423231640836092992685735225677490234375
Cents = -round( (Diff * 100) * 16 ) / 16; // -44.75.
// Fine-tune negation is because increasing the base key lowers the final pitch (and vice-versa) while increasing the fine-tuning increases the final pitch.

Note that EAD games have a much more detailed fine-tuning range than just the standard [-100..100] range of cents so exporting the fine-tuning in cents loses precision, however it would still get the samples extremely close to correct for people who use the DLS files.

For the work I do, I need more accuracy than this, so I would like to just have the raw Float Key/Key Prev/Key/Key Sec values exported to the debug file (as "%.8e" so that all significant digits are printed).

For example, Super Mario 64 Bank 0x25 Instrument 0x0C would look like:

Attack 00000000 Decay 7FFFFFFF Sustain 03E80000 Release FB500000 - 0002 7FBC 0001 7FBC 7FBC 72F6 FFFF 0000 003C3CD0 - 0.2048596590757
…
Attack 00000000 Decay 7FFFFFFF Sustain 03E80000 Release FB500000 - 0002 7FBC 0001 7FBC 7FBC 72F6 FFFF 0000 003C3CD0 - 0.2170408964157
…
Attack 00000000 Decay 7FFFFFFF Sustain 03E80000 Release FB500000 - 0002 7FBC 0001 7FBC 7FBC 72F6 FFFF 0000 003C3CD0 - 0.2806159853935

And Super Mario 64 Bank 0x25 Percussion 0x29 would look like: Attack 00000000 Decay 7FFFFFFF Sustain 03E80000 Release F06DAFB6 - 0002 7FBC 0001 7FBC 7FBC 72F6 FFFF 0000 - 0.546909570694

I included some extra digits in my examples but the idea should be clear: Print the floats with at least 8 significant digits so as to be lossless.

SubDrag commented 1 year ago

Seems like you have it building, feel free to submit a merge request to solve this.