Dn-Programming-Core-Management / Dn-FamiTracker

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

Remove "Cut sub-volume" option, make volume levels match between tracker and NSF export #107

Open nyanpasu64 opened 2 years ago

nyanpasu64 commented 2 years ago

Turns out that channel volume has 128 possible values, only 16 of which are exposed to the user, and the rest are only achievable through Axy (volume slide). Search for VOL_COLUMN_SHIFT in the source code.

A01 takes somewhere around 128 frames to bring a full-volume channel to volume 0.

I think that channel volume 0 produces volume 0x00, and F produces 0x78 (which the A01 effect instantly brings down to volume E). But not specifying a volume at all produces 0x7F (which the A01 effect takes 7 frames to bring down to volume E)! See https://github.com/Dn-Programming-Core-Management/Dn-FamiTracker/blob/master/Source/ChannelHandler.cpp. But why are there m_iDefaultVolume and m_iVolume and m_iNewVolume and m_iNoteVolume?!

Sadly this extra volume precision is wasted. The FDS has 5-bit chip volume, but FamiTracker ignores half of them even with Axy, only using odd chip volumes unless you use an instrument with a finer volume envelope.

How does Axy (mis)behave?

I wrote two test modules which apply A01 (decrease channel volume by 1 per frame) to an empty 2A03 and FDS instrument, and an attenuated 5B instrument, then watched Dn-FT's register view and NSFPlay's "Keyboard/Track Information" window. "a01.dnm" has an empty volume column (internal volume $7F), and "a01 volume F.dnm" has volume F in each channel (reducing the channel volume to $78) (cut sub-volume.zip). Results:

NSF export:

FamiTracker, "Cut sub-volume" program option unchecked (by default):

FamiTracker, "Cut sub-volume" checked:

Note that AF0 can achieve internal volume 7F, which is unattainable through the volume column alone (which results in volume 78).

In tracker, the VRC6 saw channel also never reaches volume 0 (even with "cut sub-volume" checked). In nsfplay, the channel "keys off" (despite volume remaining nonzero) and goes silent.

Making the behavior consistent

The option for "Cut sub-volume" should be removed (or made module-specific if people actually use it). Either the tracker should be changed to assume it's turned off, or the tracker and driver should both be changed to assume it's turned on (in 2A03 and/or 5B).

To make FDS behavior consistent, either the program needs to change to treat FDS A0y as volume 0, or the driver needs to change to treat it as volume 1.

Honestly it's sad how "empty volume" and "AF0" can get "louder than F", the 2A03 spends twice as long on volume 1 as 2 and up, and the FDS can only have half-precision volume fades with Axy (and sufficiently loud VRC6 saw has even less than that).

Is it too late to change these? I don't want to figure out the complexity of redesigning FT's volume system (either replacing or tacking a new mode onto the existing code). But assuming I did, it might be okay to change the volume levels of previous FDS/VRC6 modules by ±1, if this is explicitly mentioned in the changelog.

DermotMacFlann commented 6 months ago

I discussed something similar here. This should be a toggle, specific to a song, or to an instrument, or maybe togglable in the effect column.

I also observed the behavior nyanpasu64 mentioned in regards to A0x fading. Specifically, the fades behave like this, each starting at volume F (15): A0F: DB975310 A0E: DB9864210 A0D: DBA8653210 A0C: DCA9764310 A0B: DCA98654210 A0A: DCBA87653210 A09: DCBA98764321.0 A08: EDCBA9876543210 A07: EDCBA98.7654321..0 A06: EDC.BA9.876.543.21.0 A05: ED.CB.A.98.76.5.43.21..0 A04: E.D.C.B.A.9.8.7.6.5.4.3.2.1..0 A03: E.D..C..B.A..9..8.7..6..5.4..3..2.1....0 A02: E...D...C...B...A...9...8...7...6...5...4...3...2...1......0 A01: E.......D.......C.......B.......A.......9.......8.......7.......6.......5.......4.......3.......2.......1..............0 And, yes, it spends twice as much time on 1 as on the other volumes.

This seems related to the behavior of the relative volume table: 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 Notice how much of the empty space in the table is filled with 1, right next to a single row and a single column of 0. In fact, the relative volume of any two non-zero volume values will always yield 1. This is because relative volume always rounds down, unless it's between 0 and 1, in which case it rounds up. This ensures that instrument volume macros are heard all the way through at any volume, but it can be inappropriate, say, for instruments designed to use a halflife fade, like for this piano instrument I rendered: 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 At volume 15, this volume progression sounds natural. But at lowers volumes, the note lingers at volume 1 for an unnaturally long time before reaching 0. When I make piano chiptunes, instead of using a single piano instrument, I design 15 for each non-zero volume, and use one of them at maximum volume. But this balloons the instrument data you have to store, which is part of why my interest in Instrument data size being more restricted #266 overlaps with this issue. My large piano chiptunes all exported properly in 0CC-FamiTracker, but the larger driver size for Dn-FamiTracker means there's no longer enough space in one ROM bank to store both the driver and instrument samples, at least for one of my piano chiptunes. I'm not ready to switch fully to Dn-FamiTracker until every chiptune I successfully exported in 0CC-FamiTracker will export an equally valid file in Dn-FamiTracker.

Here's what that relative volume table looks like when the volumes between 0 and 1 are actually allowed to round down to 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 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 here is the same table, with those non-zero less-than-one entries marked with dashes instead: 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 can see that there are times where rounding up to 1 may be desirable. But there are plenty of other situations where rounding down to 0 is more appropriate. This needs to be configurable at least per song, and preferably per instrument.