How to properly calculate sampled duty cycles for the DPCM?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
How to properly calculate sampled duty cycles for the DPCM?
by on (#219688)
The goal is to get a tone equal to the frequency of E-3.

According to the famitracker wiki, e3 uses a value of $152 for its frequency. According to the formula on the same page, (1789772.727 / 16) / (Frequency register + 1), that'd be a frequency of ~726.368, which according to my synthesizer and this chart is almost an F#. So i know it ought to be wrong already, but i used audacity to generate a duty of that frequency. When i import the duty, loop it, and play it, it plays back as an "almost B" with the frequency set to "15".

What am i doing wrong here? I must've misunderstood something fundamental.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219689)
The values in that table are in hexadecimal. Hexadecimal 152 is decimal 338, and (1789772.727 / 16) / (338 + 1) equals 329.97 Hz. This is a perfect fourth below A440, or obviously an E.

But then the pulse wave is fixed at 16 CPU cycles per period unit. The DPCM channel isn't; it depends on the wave data. The output frequency depends on both the period table index value written to $4000 and the wavelength (number of samples per period) of the waveform in the wave data. How are you generating the wave data?
Re: How to properly calculate sampled duty cycles for the DP
by on (#219690)
Thanks! I can't believe i missed that.

The process so far has been opening Audacity, then in the menus: generate > tone > (enter the frequency), ok.

then snip out one perfect duty, export it as .wav, and import into famitracker. Even with the new frequency, it yields a B.

If i add several duties in a string (which seems a little wasteful?), i do get the intended frequency but with a looping stutter. It also looks more lite a triform than a square in the oscilloscope view and sounds the part.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219698)
FrankenGraphics wrote:
then snip out one perfect duty, export it as .wav, and import into famitracker. Even with the new frequency, it yields a B.

If i add several duties in a string (which seems a little wasteful?), i do get the intended frequency but with a looping stutter.

Looping is tricky with DPCM because the length register requires all waves to be 128 * n + 8 samples long. Practically, you need to use a 136-sample loop (which gives the key of B major), a 264-sample loop (which requires tuning everything else up 50 cents or a quarter tone), or an unlooped wave with several periods (which is what Sunsoft games do).

FrankenGraphics wrote:
It also looks more lite a triform than a square in the oscilloscope view and sounds the part.

That's slope overload, one of the hard-to-avoid characteristics of delta modulation.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219700)
Oh i see. So the sample rate would hypothetically need to be higher and/or the dynamic width of the waveform narrower for the slewed slopes to have less impact on something as abrupt as a square, since we can only increment/decrement one unit at a time.

In this case, i'm using E-3 and F-3 (so only two notes) for a quiet drone which the rest plays against. Or that's the idea, currently makeshifted with the mmc5 extension. I guess the sunsoft method is best for notes with decay, for the same reason i get the stutter when looping. Maybe detuning the whole composition as a setup phase would work best here, even if it may result in discomfort between different songs.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219702)
Would you be willing to post your module publicly so that one of us can try to show you how to replicate using the DPCM channel the drone that you have made using an expansion chip?

If you prefer real-time interaction, there's a channel for that in the FamiTracker users' Discord server. There's an invite link in the Famicompo Pico announcement.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219704)
Here's the file. :) Not a full length song, but something. The drone is on mmc5 pulse 1.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219721)
An incredibly limited solution is to use a 0×16+1 byte sample to avoid the detuning to B major. Now you have a C major scale mapped to pitches 0-7 (8 continues with D' but then 9 gives you an F')
Re: How to properly calculate sampled duty cycles for the DP
by on (#219735)
That's pretty nifty, za909! Especially as there's plenty of popular modes that share notes with C major.

Progress!
By transposing the song 1 semitone down, i got enough notes to harmonize with the B major of a 17 bytes long sample, even if it needs to take a few byways. Thanks both, i believe this will work great. :)

Here's the same short loop but with with the mentioned changes.
Attachment:
roman_chapelDPCM.ftm [7.07 KiB]
Downloaded 256 times


If anyone is wondering, i'm planning to use famitrackers' driver as a secondary driver separate to the actual game, to be used in its own bank for menus, game over, etc. Then keep a leaner engine for when there's competing action. It warrants making sure nothing important is left in the RAM space the both drivers use and try to keep it overlapped between them, but should be fine.

At first i thought it was a little extravagant, but then i remembered that it isn't without its precursor. Metroid has a separate driver in each level data bank, even if they're the same and simpler.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219739)
If you wanted it to be closer in tune, you could replace Famitracker's A440-based tuning table with one that more closely matches the DPCM's accidental 16/17 detuning of A440 system. Well, in this case, 16/17 + 100 cents, since the 16/17 is already being approximated by a semitone shift.

If you want to make something that works in both NTSC and PAL you'd need separate tuning tables, though Famitracker's driver does have that.

There's an example tune I made a long time ago to demonstrate this, including a script to generate the tuning table:
http://famitracker.com/forum/posts.php?id=3424

There's an old thread on the topic of the apparently intended tuning of the DPCM frequencies, and also how they're bad at their goal, especially on PAL where two of the chosen frequencies seem to be off-by-one:
http://forums.nesdev.com/viewtopic.php?f=6&t=5473

Optimizing the tuning to match the very imprecise DPCM frequencies might be splitting a rather frizzy hair, though. There will be detuning no matter what while doing this, but replacing the tuning tables will at least centre that detuning.

My main complaint about the DPCM freqs is not actually that they made the mistake with loop lengths that adds an extra byte, but that it has so few octaves that are in tune with each other, so that looped or not you can't even count on that to be in tune, whether or not you adjust your other tuning tables.


BTW the one game that used looped 17-byte DPCM for a pitched instrument (The Immortal, Rob Hubbard) just took the "one semitone down is close enough to 16/17" approach:
https://www.youtube.com/watch?v=iXcnA_4OnkQ

(...also you can use longer looped samples, each length has a different detuning based on that +1 byte. 32/33, 48/49, etc.)
Re: How to properly calculate sampled duty cycles for the DP
by on (#219742)
A few years ago I sat down and made DPCM triangle waves for every integer divisor (edit: except divisors that are multiples of 16. Those can't be represented, because there are no integers m, n just that 2·m=16·n+1 ). They're not too big, and they help compensate for the DPCM's stupid tuning table.

viewtopic.php?p=154032#p154032
Re: How to properly calculate sampled duty cycles for the DP
by on (#219779)
Lidnariq, these samples might prove invaluable to me. :beer:
After trying them on, building more a quite well rounded instrument with a decent tri volume in under or about 1k seems very doable, which isn't all that costly. Some ranges and some few notes will have to go, but that's not too much of a problem.

A side effect: The longer samples, if not looped, can act as short notes.
And all samples can be used as note stops in the same way.
Silencing a looped note will make a hard pop, so they're best for drones as-is, but just playing a one-shot sample won't pop.

rainwarrior wrote:
BTW the one game that used looped 17-byte DPCM for a pitched instrument (The Immortal, Rob Hubbard) just took the "one semitone down is close enough to 16/17" approach

Cool to hear a song from the commercial era to use it!

I'm not too worried about some of the notes being a little honkey tonk (though some of the upper notes in my sample are unusable of course), as long as they don't play solo. The beating swell of the detune can sometimes act complementary, especially for the delta artifacts which go in and out. But the detuning can also get old quickly, so lidnariqs triangle library will be useful in that regard too.


Something i found interesting is that there seems to be some cancellation based, airy movement happening in between the alias noises of both the tri channel and the DPCM, presumably because the delta artifacts' phases clash asynchronously. You can control how much by using samples with more or less evident artifacts. It sort of reminds me of a rotary electric organ.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219788)
FrankenGraphics wrote:
Silencing a looped note will make a hard pop, so they're best for drones as-is, but just playing a one-shot sample won't pop.

In Famitracker, use the === note release instead of --- note cut. The former just halts the sound, the latter has an implicit return to 0, I think? (If I'm remembering correctly... at any rate a halt is technically possible and should not pop any worse than the triangle channel does when halted vs silenced. There may have been a workaround of playing a 'null' sample instead of note cut back before release was implemented?)

If not looping a sample, you are not really limited to integer divisions like this, you can use any pitch at all for that.

Re: timbre and volume variation, there's a lot of redundancy in the set, and if you pick samples with divisions that are close to each other they should be closer in sound as well. My quick script made no effort to do this, it was just taking whatever was specified last, I think, which probably always favours the highest divisor.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219790)
When I tried making melodic waves on the DPCM channel I just resorted to medium-length triangle recordings that I then looped using Y commands.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219792)
rainwarrior wrote:
If not looping a sample, you are not really limited to integer divisions like this, you can use any pitch at all for that.
Yeah, that. The loops are really only important if you want looped/chip samples.

Quote:
Re: timbre and volume variation, there's a lot of redundancy in the set, and if you pick samples with divisions that are close to each other they should be closer in sound as well. My quick script made no effort to do this, it was just taking whatever was specified last, I think, which probably always favours the highest divisor.
One thought that occurs to me now is that one could use an unbalanced waveform. Since this would rail to 0 or 126, it would allow a combination of triangle volume control as well as DPCM triangleish (somewhere between a conventional triangle wave and a pulse width wave) wave control.

Of course, you'd need separate samples for every combination of DPCM volume, triangle volume, and DPCM divisor wanted... would consume a lot of bytes awfully quick.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219797)
lidnariq wrote:
rainwarrior wrote:
If not looping a sample, you are not really limited to integer divisions like this, you can use any pitch at all for that.
Yeah, that. The loops are really only important if you want looped/chip samples.

Granted. Though i meant was that if you happen to use looped samples anyway*, you also may get some short notes this way as a side bonus. A lot less useful than i thought now that rainwarrior taught me the use of the == stop. That makes their use limited to sub-step note lengths, percussive addons, staccato gaps and the like.

*I think the main reason to go for tonal loops is to conserve space.

rainwarrior wrote:
[...]a lot of redundancy in the set, and if you pick samples with divisions that are close to each other they should be closer in sound as well


Yeah, it's quite doable to organize them as a few somewhat different sounding voices by grouping if you'd want to, or just focus on one characteristic that works for the song/songs.

I spent a lot of yesterday messing about with the samples. At first i looked at bytes per non-overlapping note as a sort of value, but then came to prioritize that all samples would be within a couple of hundred bytes. + for the 'value' to work best, you kind of need to know what notes you're going to use.
Re: How to properly calculate sampled duty cycles for the DP
by on (#219800)
If you are going for conserving space it is indeed the best solution, especially when you want to simultaneously do something unusual for an NES game. I once wrote a demo song that tries to sound "advanced" while only using the base hardware features, including a looped DPCM waveform made from an FM bass guitar patch.