nesdev.comhttps://forums.nesdev.com/ DPCM playback rate does really correlate with note freqshttps://forums.nesdev.com/viewtopic.php?f=6&t=5473 Page 2 of 3

 Author: bucky o'hare [ Fri Apr 06, 2012 9:21 pm ] Post subject: Sorry for the bump, but there's good discussion here and I'd rather not clutter up the board with a closely-related topic. I was wondering if someone can answer this question: I'm curious about﻿ the gaps in the scale when downtuning. Know of any reasons it was designed that way? How would you explain to a layperson what a "timer system" is, and why there are larger gaps up at the higher pitches? Is there a reason it starts off with a major scale and then eventually starts taking bigger leaps?

 Author: rainwarrior [ Fri Apr 06, 2012 11:19 pm ] Post subject: Well, there are some decisions in the 2A03 design that are extremely arbitrary. Take a look at the possible length counter values, for instance: http://wiki.nesdev.com/w/index.php/APU_Length_Counter. I don't think there's really a good explanation for the DPCM frequencies. I think they're just frequencies somebody at Nintendo thought might be useful.

 Author: tepples [ Sat Apr 07, 2012 5:30 am ] Post subject: My wild guess about the larger gaps at the higher pitches is that there is less precision in the sample periods once it goes that high.

 Author: Jarhmander [ Thu Apr 12, 2012 6:41 pm ] Post subject: Tepples' totally right. Here my GNU Octave code (can work in Matlab with few modifications): Code:0; % if you want to put in a m filefunction hz = midi2freq(note)  hz = 440 * 2 .^((note - 69) / 12);endnesfreq = 1.7897725e6;dmcperiods = [0x36; 0x48; 0x54; 0x6A; 0x80; 0x8E; 0xA0; 0xBE; 0xD6; 0xE2; 0xFE; 0x11E; 0x140; 0x154; 0x17C; 0x1AC];notes = [12*12; 11*12+7; 11*12+4; 11*12; 10*12+9; 10*12+7; 10*12+5; 10*12+2; 10*12; 9*12+11; 9*12+9; 9*12+7; 9*12+5; 9*12+4; 9*12+2; 9*12];most_tuned_dmcperiods = round(nesfreq ./ midi2freq(notes));fprintf("difference between original DMC periods and the most tuned possible DMC periods:\n")disp( most_tuned_dmcperiods - dmcperiods)Output:Code:difference between original DMC periods and the most tuned possible DMC periods:  -1  -1   1   1  -1   1   0   0   0   0   0  -1   0  -1   1   0As you can see, they didn't get the most tuned possible values, but they're very close to it. And if you change the 'round' by 'floor' (simple truncation) it outputs:Code:difference between original DMC periods and the most tuned possible DMC periods:  -1  -1   0   0  -1   0   0   0  -1   0   0  -1   0  -1   0  -1 which shows that it is even closer to that algorithm.

 Author: tepples [ Fri Apr 13, 2012 7:14 am ] Post subject: Notice that all the values in dmcperiods are even. This means the counter is probably triggered by the APU clock, which is half the CPU clock. (Quietust traced the circuit, and it turned out that pulse, noise, and DMC period dividers are clocked by the APU clock.) So what happens when you round most_tuned_dmcperiods to the nearest even period? I don't know Octave, so I have no idea whether the following is working syntax: Code:most_tuned_dmcperiods = 2 * round(nesfreq ./ (2 * midi2freq(notes))); And there's an exact formula for nesfreq: 315000000/176

 Author: Jarhmander [ Fri Apr 13, 2012 6:45 pm ] Post subject: You know Tepples, Octave is really like Matlab, with just less restrictions on the language and of course, Octave is not backed with powerful toolboxes; nevertheless, you should apt-get installthat, and also some useful packages like octave-control and octave-signal. And yeah, you're right again: Code:0; % if you want to put in a m filefunction hz = midi2freq(note)   hz = 440 * 2 .^((note - 69) / 12); end nesfreq = 315000000 / 176; dmcperiods = [0x36; 0x48; 0x54; 0x6A; 0x80; 0x8E; 0xA0; 0xBE; 0xD6; 0xE2; 0xFE; 0x11E; 0x140; 0x154; 0x17C; 0x1AC]; notes = [12*12; 11*12+7; 11*12+4; 11*12; 10*12+9; 10*12+7; 10*12+5; 10*12+2; 10*12; 9*12+11; 9*12+9; 9*12+7; 9*12+5; 9*12+4; 9*12+2; 9*12]; most_tuned_dmcperiods = 2 * round(nesfreq ./ (2 * midi2freq(notes))); fprintf("difference between original DMC periods and the most tuned possible DMC periods:\n") disp( most_tuned_dmcperiods - dmcperiods) Output:Code:difference between original DMC periods and the most tuned possible DMC periods:   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0 So now it's apparent that it really correlate with notes, no doubts. That wasn't random at all.

 Author: rainwarrior [ Sat Apr 14, 2012 12:57 am ] Post subject: So what about the "gaps" after the first several chromatic pitches? How many cents off are they? (Would the best case for the skipped pitches be really bad?)

 Author: Jarhmander [ Sat Apr 14, 2012 8:32 am ] Post subject: Data is posted on the (old) 2A03.org forums, but since it has proved instable, I'll post the results here, and recalc them to be sure, posting at the same time my GNU Octave code to get that data, so anyone can verify how the result was obtained. Code:0; % if you want to put in a m filefunction hz = midi2freq(note)   hz = 440 * 2 .^((note - 69) / 12); end % an helperfunction notestruct = make_notestruct(octave, scale, cents)  notestruct = struct("octave", octave, "scale", scale, "cents", cents);end% note that it can output an invalid MIDI notes (values outside 0~127)% as well as non integer values.function midinote = freq2midi(freq)  midinote = log2(freq ./ 440) .* 12 + 69;endfunction notestruct = midi2notestruct(midinote)  closestnote = round(midinote);  oct_offs    = floor(closestnote/12);  closestnote = closestnote - oct_offs*12;  octave      = oct_offs - 1;  scale       = closestnote;  cents       = (midinote - oct_offs*12 - scale) * 100;  notestruct = make_notestruct(octave, scale, cents);endfunction str = scale2disp(scale)   scaledisp = ["C";"C#";"D";"D#";"E";"F";"F#";"G";"G#";"A";"A#";"B"];   str = scaledisp(scale+1);endnesfreq = 315000000 / 176; dmcperiods = [0x36; 0x48; 0x54; 0x6A; 0x80; 0x8E; 0xA0; 0xBE; 0xD6; 0xE2; 0xFE; 0x11E; 0x140; 0x154; 0x17C; 0x1AC]; dmcfreqs = nesfreq ./ dmcperiods;dmcmidi = freq2midi(dmcfreqs);dmcnotes = midi2notestruct(dmcmidi);fprintf("DMC period  octave     scale   cents\n");fprintf("-----------------------------------------\n");for i=1:length(dmcperiods)  fprintf("0x%03X       %2d        %2s       %+2.6g\n", dmcperiods(i), ...                                                        dmcnotes.octave(i), ...                                                        scale2disp(dmcnotes.scale)(i), ...                                                        dmcnotes.cents(i));endResults:Code:DMC period  octave     scale   cents-----------------------------------------0x036       11         C       -17.88270x048       10         G       -15.92770x054       10         E       +17.20140x06A       10         C       +14.47780x080        9         A       -12.01770x08E        9         G       +8.285760x0A0        9         F       +1.668590x0BE        9         D       +4.155580x0D6        9         C       -1.778080x0E2        8         B       +3.767550x0FE        8         A       +1.560680x11E        8         G       -3.86330x140        8         F       +1.668590x154        8         E       -3.286820x17C        8         D       +4.155580x1AC        8         C       -1.77808

 Author: rainwarrior [ Sat Apr 14, 2012 1:29 pm ] Post subject: I don't have octave, but I wrote a similar python program to answer the question I was asking. What I wanted to know was what are the best-fit values that could have been used for any given note. http://rainwarrior.ca/projects/nes/dpcm_freqs.py Code:DMC   Octave   Note   Cents        -----------------------------------0x002 16       A      -12.017693340x004 15       A      -12.017693340x006 15       D      -13.972694210x008 14       A      -12.017693340x00A 14       F      +1.668592790x00C 14       D      -13.972694210x00E 13       B      +19.156400190x010 13       A      -12.017693340x012 13       G      -15.927695070x014 13       F      +1.668592790x016 13       D#     +36.664364290x018 13       D      -13.972694210x01A 13       C      +47.454644890x01C 12       B      +19.156400190x01E 12       A#     -0.286408070x020 12       A      -12.017693340x022 12       G#     -16.973102840x024 12       G      -15.927695070x026 12       F#     -9.530709470x028 12       F      +1.668592790x02A 12       E      +17.201399320x02C 12       D#     +36.664364290x030 12       D      -13.972694210x032 12       C#     +15.354878930x036 12       C      -17.88269594   *****0x038 11       B      +19.156400190x03C 11       A#     -0.286408070x040 11       A      -12.017693340x044 11       G#     -16.973102840x048 11       G      -15.92769507   *****0x04C 11       F#     -9.530709470x050 11       F      +1.668592790x054 11       E      +17.20139932   *****0x05A 11       D#     -2.241408940x060 11       D      -13.972694210x064 11       C#     +15.354878930x06A 11       C      +14.47776118   *****0x072 10       B      -11.485710340x078 10       A#     -0.286408070x080 10       A      -12.01769334   *****0x086 10       G#     +8.675278110x08E 10       G      +8.28576325    *****0x098 10       F#     -9.530709470x0A0 10       F      +1.66859279    *****0x0AA 10       E      -3.286816710x0B4 10       D#     -2.241408940x0BE 10       D      +4.15557666    *****0x0CA 10       C#     -1.871472640x0D6 10       C      -1.77807702    *****0x0E2 9        B      +3.76755176    *****0x0F0 9        A#     -0.286408070x0FE 9        A      +1.56068253    *****0x10E 9        G#     -4.196409800x11E 9        G      -3.86329747    *****0x12E 9        F#     +1.896619470x140 9        F      +1.66859279    *****0x154 9        E      -3.28681671    *****0x168 9        D#     -2.241408940x17C 9        D      +4.15557666    *****0x194 9        C#     -1.871472640x1AC 9        C      -1.77807702    *****0x1C4 8        B      +3.767551760x1E0 8        A#     -0.286408070x1FC 8        A      +1.56068253----------------------------------- Does it shed any light on why they picked the particular notes they did? I dunno, by this the choices still look kinda arbitrary to me.

 Author: lidnariq [ Sat Apr 14, 2012 3:20 pm ] Post subject: Musically the note choice makes a fair amount of sense- The entire Ionian octave at the bottom. Most of the next octave, missing the 3rd and 7th scale degrees The major triad of the next octave up The root scale degree at top. Because any desired detune and transposition can be encoded when the sample is made, this allows any song to play notes over most of two octaves in Ionian or Dorian modes. Is it be as good as a fully programmable divisor as on the triangle and pulse wave channels? Obviously not. Would other decisions that only used 4 bits for specifying period make more sense? Yes; I think including one octave of a full chromatic scale at plus a few higher notes would probably have been a better design. But I think this is far more explicable than the restrictions on noise frequency or the duplicate pulse duty (1/4 and 3/4 have the same sound).

 Author: rainwarrior [ Sat Apr 14, 2012 6:09 pm ] Post subject: You can build large samples at any frequency, at whichever samplerate from the table is good for you, but interestingly it doesn't seem to be based around doing that kind of thing. In that sort of situation it would be more useful to keep your samplerates in tune with each other, rather than trying to keep them in tune with an arbitrary standard like A440 (which is clearly in use here). Note that only the lowest two Cs are exactly an octave apart; the rest are jittered up and down trying to match to A440 rather than matching each other. It's not particularly good for short looped samples either, since the sample length is 16n+1 bytes. A 1 byte sample would be too quiet to be useful. If it was an even 16, with 16 bytes you could make a decent DPCM triangle 3-7 octaves down from the frequencies mentioned, and play it all over that major scale. However, it's 17 bytes, which detunes it by 16/17... which kind of makes the scale mostly pointless (unless you want to tune your square/triangle at A=414hz). Kinda seems like it's not intended for that either. The only place I've seen this tried was in Rob Hubbard's The Immortal, which used a 17 byte bass, but doesn't really bother to compensate for the 16/17 detune, just kinda uses it sparingly, and accompanies it with vibrato generally. 16/17 is most of a semitone off, so it's still close enough to be usable. (So for example, in track 2 he uses DPCM pitch 2, an E frequency, to play a tone close enough to E-flat to be acceptable.) Honestly I think they're rather poorly chosen for any purpose. Sunsoft tried to make do with them, and they do an okay job, but you'll notice their basslines jump in octaves all the time and they bottom and top of the octave really never sound in tune with each other. They just live with the approximation. Note that they for the most part don't use the low samplerates where that pre-fab major scale resides, because they'd sound too muddy at such a low samplerate anyway. They're forced to use the more poorly tuned higher ones, and do the tuning via multiple samples. If you ask what my guess is, the designer originally presumed sample lengths wouldn't have the +1, and designed the scale for short looped samples in an A440 tuning. After the first octave, just chose arbitrary pitches; F and G are good because they're in the middle but also an important scale note, I guess trying to space out the higher frequencies so there are more to work with? Other ones are just haphazardly chosen, in my opinion. Maybe they were chosen early on, intended for a different purpose, and then as a feature it was de-emphasized later on in the design process and it didn't ever get a rework.

 Author: lidnariq [ Sat Apr 14, 2012 6:40 pm ] Post subject: Sure; they evidently knew just enough to make decisions for the audio hardware that are correct at first glimpse and inadequate when a person who knows more about the situation looks at it. See also: the looped noise mode's interactions with the restrictions on noise rate.

 Author: tepples [ Sat Apr 14, 2012 7:28 pm ] Post subject: At least on the Game Boy, looped noise makes acceptable C, D, F, and G# in each octave, which allows for passable covers of the Super Mario Bros. 2 and the end of "Wish" by Nine Inch Nails (which uses a D, C, G#, F descending scale).

 Author: rainwarrior [ Sat Apr 14, 2012 7:55 pm ] Post subject: On a whim I decided I would try to make an in-tune 17-byte looped DPCM sample. Or, well, at least as in tune as is possible on the NES. http://rainwarrior.ca/projects/nes/lately_tuned.nsf So, this is a short tune with a 17-byte looped DPCM sample. It makes sure to use all 16 possible pitches. The pitch tables used for the other channels have been custom built with A-flat = 440hz * 16 / 17, to compensate for the detune due to sample length. As you can hear, for the high notes especially, the DPCM really doesn't have a lot of resolution to get pitches accurate anyway. I'm bent over as far as I can to try and sound in-tune with the DPCM's chosen scale, and even with this the results aren't particularly magical. The NES has never really been an instrument for precision tuning anyway, I suppose, but if I did this correctly, this is a best-case example for DPCM tuning.

 Author: rainwarrior [ Sat Apr 14, 2012 9:59 pm ] Post subject: Just to point out how bad this tuning scheme actually is, check out the four Cs: Code:0x036 12       C      -17.882695940x06A 11       C      +14.477761180x0D6 10       C      -1.778077020x1AC 9        C      -1.77807702 Note that 0x036 and 0x06A are a total of 31 cents apart, because one rounds up and the other down! This is almost comic. You cannot use the DPCM's pitches to play an in-tune octave, except between the lowest two (which are the least likely to be used since the samplerate is so low down there). It would have been much better to just forget about trying to hit the A440 scale and make these power of 2 multiples of each other. Sunsoft games could have had much nicer tuning in their basslines. Also, Tepples, I'd be interested in hearing that GB Wish cover, if you have a link.

 Page 2 of 3 All times are UTC - 7 hours Powered by phpBB® Forum Software © phpBB Grouphttp://www.phpbb.com/