Dn-Programming-Core-Management / Dn-FamiTracker

modifications and improvements for 0CC-FamiTracker (based on j0CC-FamiTracker 0.6.3)
Other
386 stars 23 forks source link

Instrument data size being more restricted #266

Open Gumball2415 opened 8 months ago

Gumball2415 commented 8 months ago

No, there's a new issue. "Chopin Barcarolle in F-sharp major Op. 60 (VRC6+MMC5).0cc" can no longer export at all. This is what happens:


* Multiple expansion chips enabled
Building music data...
* Sequences used: 16 (1091 bytes)
* Instruments used: 26 (236 bytes)
* DPCM samples used: 0 (0 bytes)
* Grooves used: 0 (1 bytes)
* Song 0: 117 frames (2574 bytes), 942 patterns (23294 bytes)

Originally posted by @DermotMacFlann in https://github.com/Dn-Programming-Core-Management/Dn-FamiTracker/issues/256#issuecomment-1969189938

DermotMacFlann commented 8 months ago

Gumball2415 commented in the other issue thread that this issue is common for chiptunes using the Namco 163 chip with too many enabled channels, but unusual for a chiptune like this that doesn't use N163 at all. This particular chiptune (included in multichip bug and fix.zip) still successfully exported under 0CC-FamiTracker, and successfully exported a file (even with a playback glitch) in Dn-FamiTracker 0.5.0.2. So though I'm not all that familiar with the source code, and I don't know 6502 ASM anyway, it would seem to me that this chiptune was perhaps just under a certain data storage limit before, but now goes over that limit in the 0.5.0.3 bugfix.

I can explain why the insturment data is so big. I design simulated piano instruments with a realistic halflife fade contour like in a real piano note's vibration. The contour at volume 15 is 98 ticks long, and goes: 15 15 15 14 14 13 13 13 12 12 11 11 11 10 10 10 10 9 9 9 8 8 8 8 8 7 7 7 7 6 6 6 6 6 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0. The problem is, if I use just this contour as one instrument and use FamiTracker volume controls, then every piano note will be 98 ticks long before fading, lingering unnaturally at volume 1 near the end of quieter notes until it reaches 0, because of the way FamiTracker has always calculated volume adjustment given two non-zero volume values. I need the fade to actually reach 0 when the fractional volume is less than 1, so I rendered separate halflife fade contours for all 15 note volumes, and use each of those separate instruments by individually tailored volume instead of using the volume control for just one instrument. That's an 98 tick contour for volume 15, 95 ticks for 14, 93 ticks for 13, 90 ticks for 12...and you get the idea. This has been no problem for other piano chiptunes, but Chopin's Barcarolle was always a hefty piano piece, often played up to ten minutes long, and even using only 32 rows per pattern at a tempo that's often F0A (10 ticks per row), that can still add up in a chiptune.

Here's the export comments from 0CC-FamiTracker:

And the export comments from the otherwise buggy Dn-FamiTracker 0.5.0.2 export:

I've sometimes wished a FamiTracker port could support different volume adjustment modes per chiptune, or perhaps per instrument, or both. Mode A (default, normal FamiTracker behavior): The resulting volume is 0 only if one of the two input volumes is 0, but otherwise the result is never less than 1. Mode B: If a fractional volume is less than 1, it will round down as 0 and never artificially stay at 1. If this mode were available, I could potentially just use a single piano instrument with real volume controls. Mode C: Calculate volumes with subtraction, with 0 as the minimum result. I see behavior like this when studying some existing video game chiptunes, like Mega Man 3.

Gumball2415 commented 8 months ago

inconsistent volume behavior is described in #107

Gumball2415 commented 8 months ago

all the sizes seems to match up until the error from previous versions, this is quite suspicious to me and might not have something to do with volume macro size at all

Gumball2415 commented 8 months ago

Issue #191 (comment)

DermotMacFlann commented 8 months ago

If there's insufficient space for both the driver and the instrument data in a single ROM bank, and the original impetus of having so many such large volume macros for different piano note volumes is to force a fractional volume of less than 1 to actually sound like 0 instead of being artificially kept at 1, then this problem could be fixed outright by allowing fading behavior to be toggled by song and/or track and/or instrument, so that a chiptune can be resequenced so a single piano instrument at volume 15 can be safely used at lower volumes while fading to 0 when expected. Having special volume macros for 15 different volumes of one instrument was always something of an anti-pattern anyway, and ought to be discouraged. I say "by song and/or by track and/or by instrument", because I've noticed this behavior even extends to the Axx effect, where A01 from a volume of 15 goes: 14 14 14 14 14 14 14 14 13 13 13 13 13 13 13 13 12 12 12 12 12 12 12 12 11 11 11 11 11 11 11 11 10 10 10 10 10 10 10 10 9 9 9 9 9 9 9 9 8 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 6 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0. Notice how much longer A01 lingers at volume 1 than the other volumes before reaching 0. I'm assuming A01 progression would be at 1 for only half the time if such a toggle was enabled. I'm guessing any toggle control more specific than song-level or instrument-level might require supporting a new effect in the effect column, and there may not be enough perceived usefulness in such a control to justify more specific dynamic toggling.

The FamiTracker volume mixing table seems to be: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 0 1 1 1 1 1 1 1 2 2 2 2 3 3 3 4 0 1 1 1 1 1 2 2 2 3 3 3 4 4 4 5 0 1 1 1 1 2 2 2 3 3 4 4 4 5 5 6 0 1 1 1 1 2 2 3 3 4 4 5 5 6 6 7 0 1 1 1 2 2 3 3 4 4 5 5 6 6 7 8 0 1 1 1 2 3 3 4 4 5 6 6 7 7 8 9 0 1 1 2 2 3 4 4 5 6 6 7 8 8 9 A 0 1 1 2 2 3 4 5 5 6 7 8 8 9 A B 0 1 1 2 3 4 4 5 6 7 8 8 9 A B C 0 1 1 2 3 4 5 6 6 7 8 9 A B C D 0 1 1 2 3 4 5 6 7 8 9 A B C D E 0 1 2 3 4 5 6 7 8 9 A B C D E F

With a early fade-to-0 toggle, it could be this: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 2 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 4 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 0 0 0 1 1 2 2 2 3 3 4 4 4 5 5 6 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 8 0 0 1 1 2 3 3 4 4 5 6 6 7 7 8 9 0 0 1 2 2 3 4 4 5 6 6 7 8 8 9 A 0 0 1 2 2 3 4 5 5 6 7 8 8 9 A B 0 0 1 2 3 4 4 5 6 7 8 8 9 A B C 0 0 1 2 3 4 5 6 6 7 8 9 A B C D 0 0 1 2 3 4 5 6 7 8 9 A B C D E 0 1 2 3 4 5 6 7 8 9 A B C D E F

So depending on such a toggle, the table slots marked with a dash would be either 1 or 0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ ‒ 1 0 ‒ ‒ ‒ ‒ ‒ ‒ ‒ 1 1 1 1 1 1 1 2 0 ‒ ‒ ‒ ‒ 1 1 1 1 1 2 2 2 2 2 3 0 ‒ ‒ ‒ 1 1 1 1 2 2 2 2 3 3 3 4 0 ‒ ‒ 1 1 1 2 2 2 3 3 3 4 4 4 5 0 ‒ ‒ 1 1 2 2 2 3 3 4 4 4 5 5 6 0 ‒ ‒ 1 1 2 2 3 3 4 4 5 5 6 6 7 0 ‒ 1 1 2 2 3 3 4 4 5 5 6 6 7 8 0 ‒ 1 1 2 3 3 4 4 5 6 6 7 7 8 9 0 ‒ 1 2 2 3 4 4 5 6 6 7 8 8 9 A 0 ‒ 1 2 2 3 4 5 5 6 7 8 8 9 A B 0 ‒ 1 2 3 4 4 5 6 7 8 8 9 A B C 0 ‒ 1 2 3 4 5 6 6 7 8 9 A B C D 0 ‒ 1 2 3 4 5 6 7 8 9 A B C D E 0 1 2 3 4 5 6 7 8 9 A B C D E F

I'm not entirely sure how the driver calculates volume transition, but the 1-or-0 values all predictably occur when two non-zero volumes (each between 1 and 15 inclusive) mix to a fractional value that would round down to 0 that is otherwise being kept at 1.

An alternative is to actually support half-life volume fades as an option at the specification level instead of externally calculating half-life fade macros (them which is what I currently do). But considering how they're calculated (with floating point fractional multiplication), I'm guessing that may be impractical for 6502 architecture which IIRC has no native hardware support for multiplication or division, let alone something as relatively computationally expensive as floating point math.

Gumball2415 commented 8 months ago

Dn (all the way back to vanilla) uses a 256 byte LUT for all volume calculations. This alone does not account for the new size offset of the driver.

DermotMacFlann commented 8 months ago

No, I'm not saying it does account for it. I'm saying that my problem (so many extra volume macros) can go away if I'm allowed to use a mode that allows volume macros to fade to 0 when naturally expected. Then I can edit my project to store one instrument volume macro and safely use it at lower note volumes.

Here's an edit of my problematic Chopin Barcarolle chiptune that now uses 2 instruments instead of 32, and a single volume macro table instead of 16, and it exports properly in the Dn-FamiTracker 0.5.0.3 special build: Chopin Barcarolle in F-sharp major Op. 60 (VRC6+MMC5) (volume simplified).zip However, in this edit, the quieter piano notes are all sustaining at volume 1 longer than they naturally would, and no sustained uncut note is shorter than 97 ticks.

I want an alternative volume fade note where less than 1 actually means 0. A 256 byte LUT table for both modes could still work if all those special 1 entries are changed to 0, like so: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 2 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 4 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 0 0 0 1 1 2 2 2 3 3 4 4 4 5 5 6 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 8 0 0 1 1 2 3 3 4 4 5 6 6 7 7 8 9 0 0 1 2 2 3 4 4 5 6 6 7 8 8 9 A 0 0 1 2 2 3 4 5 5 6 7 8 8 9 A B 0 0 1 2 3 4 4 5 6 7 8 8 9 A B C 0 0 1 2 3 4 5 6 6 7 8 9 A B C D 0 0 1 2 3 4 5 6 7 8 9 A B C D E 0 1 2 3 4 5 6 7 8 9 A B C D E F ..And additional logic is used. In "default" mode (the way volume has worked since vanilla FamiTracker), the algorithm could check if a fetched table volume value is 0. Then, if the X and Y volume input values are both non-zero (values between 1 and 15 inclusive), then a volume value of 1 is used. But in the alternative volume mode I propose, 0 means 0, and note fades to less than 1 will actually be 0.

Another way of encoding it in the driver could be storing that 256-byte table twice, and using one table or the other depending on which mode is used.

DermotMacFlann commented 7 months ago

Wait a minute...256 byte table? This table is only storing nybbles. There's one really elegant way to support both volume fade modes I described with a table of 5-bit values (shown here in hexadecimal): 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x02 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x04 0x00 0x01 0x01 0x01 0x01 0x02 0x02 0x02 0x02 0x02 0x04 0x04 0x04 0x04 0x04 0x06 0x00 0x01 0x01 0x01 0x02 0x02 0x02 0x02 0x04 0x04 0x04 0x04 0x06 0x06 0x06 0x08 0x00 0x01 0x01 0x02 0x02 0x02 0x04 0x04 0x04 0x06 0x06 0x06 0x08 0x08 0x08 0x0A 0x00 0x01 0x01 0x02 0x02 0x04 0x04 0x04 0x06 0x06 0x08 0x08 0x08 0x0A 0x0A 0x0C 0x00 0x01 0x01 0x02 0x02 0x04 0x04 0x06 0x06 0x08 0x08 0x0A 0x0A 0x0C 0x0C 0x0E 0x00 0x01 0x02 0x02 0x04 0x04 0x06 0x06 0x08 0x08 0x0A 0x0A 0x0C 0x0C 0x0E 0x10 0x00 0x01 0x02 0x02 0x04 0x06 0x06 0x08 0x08 0x0A 0x0C 0x0C 0x0E 0x0E 0x10 0x12 0x00 0x01 0x02 0x04 0x04 0x06 0x08 0x08 0x0A 0x0C 0x0C 0x0E 0x10 0x10 0x12 0x14 0x00 0x01 0x02 0x04 0x04 0x06 0x08 0x0A 0x0A 0x0C 0x0E 0x10 0x10 0x12 0x14 0x16 0x00 0x01 0x02 0x04 0x06 0x08 0x08 0x0A 0x0C 0x0E 0x10 0x10 0x12 0x14 0x16 0x18 0x00 0x01 0x02 0x04 0x06 0x08 0x0A 0x0C 0x0C 0x0E 0x10 0x12 0x14 0x16 0x18 0x1A 0x00 0x01 0x02 0x04 0x06 0x08 0x0A 0x0C 0x0E 0x10 0x12 0x14 0x16 0x18 0x1A 0x1C 0x00 0x02 0x04 0x06 0x08 0x0A 0x0C 0x0E 0x10 0x12 0x14 0x16 0x18 0x1A 0x1C 0x1E Now imagine the toggle is a byte value of either 0 or 1, where 1 represents vanilla FamiTracker behavior. To get the volume from the table, add the toggle to the table value, then right-shift the sum by 1 bit. The 0x01 table entries will result in 0 or 1 depending on the toggle, while all other table values are unaffected.

Gumball2415 commented 7 months ago

the driver is slightly bigger than older versions. this means that the instrument size is slightly more restricted.

you can't do anything about this, unless you can refactor the entire driver without adding bugs or reimplement instrument loading with bankswitching.

DermotMacFlann commented 7 months ago

If I recall, aren't DPCM samples already implemented with bankswitching? That couldn't be helped, since they can be so large anyway. I mean, you understand the reasons I needed a lot of instrument data, and how I wouldn't need all that data if there were another option of volume fade behavior. But in the event someone did need that much instrument data, why not support bankswitching for it?

Gumball2415 commented 7 months ago

you are asking for a major rewrite of both the nsf driver and the export code, as this requires a new NSF program architecture. as stated in an earlier statement regarding nsf driver maintenance (#231), this kind of architecture will have to wait until bhop replaces the old driver.

DermotMacFlann commented 7 months ago

I was afraid of that. What about the other idea, involving different volume fade modes for volumes approaching zero? I know this largely concerns my problem, but...it's still my problem.

Gumball2415 commented 7 months ago

for volume related things, see #107