NESDev and Strangulation Records messageboards
Forum Index | FAQ | New User | Login | Search

Previous ThreadView All ThreadsNext Thread*Show in Threaded Mode


SubjectDMC Saw and Square without hogging CPU new  
Posted byblargg
Posted on11/24/03 12:33 PM
From IP199.170.89.44  



A recent post about DMC waveform output put me up to the challenge. I don't have a NES development system to try it on real hardware, so I'd love to find out if it works (perhaps with minor adjustments). I wrote a short web page with illustrations, asm demo code and mp3s of its output when running on an NSF player that handles DMC interrupts:

http://www.slack.net/~ant/nes-emu/dmc_waves.html





SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byMemblers
Posted on11/24/03 9:46 PM
From IP68.58.99.218  



Great trick! I knew the DMC is good at playing an angled waveform (like a triangle), but it just didn't occur to me that setting $4011 back to the top could make a sawtooth wave. It sounds really good.

One thing you'll need to do to make it work on an NES is write $C0 to $4017 to select the DMC channel as the IRQ source.

That 'JSR vbl' might be unsafe since 'vbl' returns with an RTI. And you'd better push/pull the X register there too, since it's in use. But that's minor stuff anyways, the interesting part of the program looks like it works. :-)

I only wish it could play lower notes. Why isn't a value of 0 used in the period table? But hey, I'll take whatever I can get, heheh.




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byblargg
Posted on11/25/03 06:31 AM
From IP199.170.89.189  



One thing you'll need to do to make it work on an NES is write $C0 to $4017 to select the DMC channel as the IRQ source.

I haven't seen this documented in NESSOUND.txt. I know about $4017.6 needing to be set to enable frame IRQ. Does this also mask off DMC IRQs?

That 'JSR vbl' might be unsafe since 'vbl' returns with an RTI. And you'd better push/pull the X register there too, since it's in use.

Yep. I am somewhat confused as to how NSFs are played on real NES hardware, as their "play" routine (vbl) uses a regular RTS and doesn't save/restore anything. The only way to play them seems to be to write a wrapper which saves registers, calls the play routine, then restores registers and does an rti. I pretty much assumed that this would be added to the asm I wrote, and would call vbl.

I've noticed that some NSF players set the IRQ inhibit bit before calling the play routine, but never restore its previous setting. I have a feeling that many NSF players won't even handle this DMC trick.

I only wish it could play lower notes.

It can! The example of using multiple IRQs showed doubling of the wave's period (thus dropping an octave). This can be taken further. For demonstration, I modified the Tetris song player to use the saw for the low part, and lowered it by another octave (so it's really low now).

tetris_low.mp3 (188K)

tetris_low_saw.mp3 (188K) saw part only

This can be set in the asm demo by changing the value reloaded into irq_count. For example, this wave is spread across three IRQs (and can have a maximum amplitude of $30):

  dec   irq_count   ; reset wave every N IRQs
bne mid_wave
lda #3 ; N ** increase this value
sta irq_count
lda volume ; pcm dac = volume
sta $4011
mid_wave:

load $30 into DAC load $30 into DAC
_ _
| |_ | |_
| |_ | |_
| |_ |
| |_ |
| |_ |
| |_ |
| |_ delay |
| |______ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ delay |
| |______ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ delay |
____| |_______|
IRQ IRQ IRQ

For the Tetris song, 8 IRQs are used per wave period, but it's not kept at max volume, so most of the time it's at 0. This seems to reduce bass a bit. I tried lessening the slope per DMC sample by using a non-zero value (i.e. $00 gives -16, $10 gives -12, $22 gives -8, etc.) but then when it was silent it was still toggling and resulted in an audible high pitch. This could be avoided by switching to an zero DMC sample once the wave hit the bottom, but I wasn't interested in dealing with that complexity yet.

Why isn't a value of 0 used in the period table?

It was just a quick hack and another octave of note values wouldn't fit, so I just trimmed at the octave point. I'm going to try to incorporate a much wider range, as it seems this is subtle enough that I should show how it's done.

So anyway, did you try this on real NES hardware? I want to know if it really works or if it's just due to my optimistic interpretation of DMC.txt.





SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byMemblers
Posted on11/25/03 10:40 AM
From IP68.58.99.218  



I don't have the hardware to test it, I know some people who do, though. I'll put this code into a ROM and post it here soon.

Setting D7 of $4017 should be OK from what the docs say, all I know for sure is one of my programs that used the DMC IRQ was working when I set it to $C0.

There would be some variations with exactly when the IRQ code runs, since it will have to wait until the CPU finishes it's current instruction (usually varying between 5 and 2 cycles long). I don't know how noticable that would be, but an idle loop of NOPs might be helpful if that's the case.

Yeah, playing an NSF on NES requires a small bit of control code. All the vector-related stuff must be handled by that. I was able to play an NSF with IRQs on FCEU, but it didn't work on some NSF-only players that I tried.




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byblargg
Posted on11/25/03 2:59 PM
From IP199.170.89.22  



I improved the IRQ handler to simplify frequency calculation and allow octave shifting. Now the number of clock cycles for a single cycle of the saw wave is (DMC period + 23 + 5 * delay) / octave.

I solved the "ringing" problem by deferring execution of the usual VBL code until the next IRQ occurs. The VBL handler just sets a "do frame" flag which the IRQ handler checks (for clarity, this isn't shown in the demo code).

I expanded the song player a bit to play the entire Tetris GB BGM B song, and put the saw on the low part (I had to implement a simple tracker with blocks, commands, and tempo). I updated the mp3s of it:

tetris_gb.mp3 (520K) saw + square

tetris_gb.mp3 (140K) saw only

If you're going to make a ROM, let me get the song player into a format that I can post. It seems like a better demo. (I need to upgrade my assembler and linker to be able to handle setting up the vectors and data for the DMC).

Regarding variations, I figure the average IRQ acknowledgement latency is around 4 cycles, which is included in the formula above (also included is the 7-cycle interrupt handling time). It might be useful to run a test where some code with many different length instructions is in a loop while the saw wave is running.





SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byAnonymous
Posted on11/25/03 4:15 PM
From IP165.173.124.92  



Timings of IRQ generation seem to be different from what would be expected(they occur significantly sooner than when DMC playback finishes).

It would be useful to run some tests to determine the exact timing of DMC IRQ.




SubjectRe: verifying DMC IRQ timing new  
Posted byblargg
Posted on11/25/03 10:41 PM
From IP199.170.89.41  



I agree fully. I've been forming a test in my mind with the most bang-for-the-buck. Run the test code on a real NES and digitize its output for analysis. First, play a square wave of some period for a short time, to provide a precise reference to the NES's clock rate as sampled, so that neither needs to be know. Then play a DMC saw wave as described, using a few delay and period settings. Use DMC sample lengths of 1 ($4013 = 0) and 17 ($4013 = 1), just in case for length 1 it triggers the IRQ immediately. Save a copy of the exact asm used for the test.

Maybe the DMC triggers an IRQ immediately for sample length = 1, meaning the IRQ generation is tied to the fetching of the last byte, rather than the exhaustion of the bit buffer coupled with no more bytes left to fetch. This would be bad, since sample length 17 generates a quite low frequency wave. If the IRQ triggered several bytes sooner than the end, sample length 17 might be reduced to a usable quantity.

Should I write an asm file for a hardware test, that maximizes the value of the test?





SubjectRe: verifying DMC IRQ timing new  
Posted byXodnizel
Posted on11/25/03 11:01 PM
From IP68.86.57.74  



"Should I write an asm file for a hardware test, that maximizes the value of the test?"

Are you referring to data "value" or usefulness "value"? :)

I've posted the formula I use in FCEU before, but here it is again:

IRQ Clock Cycles=(DMA Clock Cycles) - (0x10-($4010 & 0x0F)) * 16 * (Length of sample in bytes)

"DMA Clock Cycles" refers to the number of CPU cycles between DMA(or expected from the outputted playback rate, at least).

Where "IRQ Clock cycles" is the number of CPU cycles at which time an IRQ is to be generated, after the 0x00->0x10 write to $4015. It is not 100% accurate, though. The playback frequency does seem to affect when the IRQ occurs(the games expect it this way, at least), so this should be factored into any tests that are run.




SubjectRe: verifying DMC IRQ timing new  
Posted byMemblers
Posted on11/26/03 11:07 AM
From IP68.58.99.218  



Here's a binary with that code. It worked on FCEU, but not on a couple other emus I tried.

http://www.parodius.com/~memblers/bmc-test.nes




SubjectRe: verifying DMC IRQ timing new  
Posted byMemblers
Posted on11/27/03 07:25 AM
From IP68.58.99.218  



Here's another test of this:
http://www.parodius.com/~memblers/sawsweep.nes

It runs through 256 different delay amounts inside the IRQ, then starts over with the next DMC frequency, and so on. Pressing left/right changes the number of segments making up the wave (and also resets the delay and DMC freq).

I put a big delay loop in the code also, you can see the highest IRQ delay settings really dig into it. But the CPU usage can be really low with the right settings.





SubjectRe: DMC Saw and Square without hogging CPU  
Posted byAnonymous
Posted on11/27/03 11:09 PM
From IP130.236.154.216  



Nice work Blargg! I've been thinking about trying this for quite some time, but never got to it since I've always thought that tricks like this would give too much distorsion and just sound awful. I'm glad you've proved me wrong! :)

If you wanna hear how it sounds on a PAL NES, check out the wavs I recorded at http://www.student.itn.liu.se/~miciw347/

// Bananmos




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byblargg
Posted on11/28/03 06:52 AM
From IP199.170.89.63  



It looks and sounds as if only the DMC period is affecting the pitch. The slopes of the saws are evenly stepped, with no delays in them, so it seems the fine-tune delay isn't having any effect. My guess is that the IRQ occurs immediately after the first (and only) byte is fetched, and that the retriggering of the DMC is delayed until after all 8 bits of the sample have been played:

    _                                                _
| |_ | |_
| |_ | |_
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
___| |________________|
AB C B C B C B

A: Reset DAC. Start DMC with 1 sample.

B: DMC fetches first and only byte of sample. It invokes IRQ handler
immediately since no *more* samples need to be fetched. IRQ handler runs
delay loop while DMC outputs 8 1-bit samples.

C: IRQ handler's delay loop completes and DMC is set to restart, but this is
deferred since it's already playing. Thus the delay loop has no effect.

B: DMC finishes previous sample. Restart request is noted so it starts
playing a new sample. DMC reads byte. No more bytes, so trigger IRQ. IRQ
handler enters delay loop.

C: Delay loop finishes... etc.

If this is what's happening, it makes fine-tuning of the overall wave period
more tricky. A solution is to insert a larger delay at the end of the wave,
with the DMC still outputting the sample while the delay takes place. This
would use more CPU time but for lower notes would be somewhat reasonable.
The new scheme would work like this:

_ _
| |_ | |_
| |_ | |_
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
| |_ |
___| |________________|
A B C D E

A: Start DMC. Immediate IRQ. Set DMC to start again after current sample finishes.

B: DMC IRQ as it begins second sample. Set DMC to start again after current sample finishes.

C: DMC IRQ as it begins third sample. Delay while DMC finishes

D: DMC finishes sample. Still delaying.

E: Start DMC. Immediate IRQ. Set DMC to start again after current sample finishes.

etc.

In this example, 33% or more CPU would be used for the delay.

I have some other ideas if this is the case. They involve running the DMC with a 17-byte sample to quickly move through some of the samples by setting its period to a higher value for a short time, then setting it back down. This might allow lower CPU usage.

I'm going to modify my NSF player to do what I think the real NES hardware does based on this new data and if it generates similar output, then I'm going to try out some new schemes.





SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byAnonymous
Posted on11/28/03 11:34 AM
From IP130.236.245.71  



I didn't even realized it didn't work. Now that I think about it though, you are most likely right in your theory of the sample IRQ occurring "too early". It just occurred to me that when I added a sample IRQ to Years Behind a few months ago, I think using a sample length of 1 byte triggered an immediate IRQ, because I was not able to use that sample length no matter how slow a pitch I set the DMC too. Another problem that I noticed (which wasn't such a big deal for YB) was that I couldn't get the DMC "in sync". That is, to make it always interrupt at the exact number of clock cycles that have passed after I started playing the sample... it was always a few scanlines off. I tried writing $4017 and some other things to reset its "phase", but it didn't seem to help.

I haven't done any deeper investigation of the DMCs behavior though, just what was needed to make my code work. If you wish to do some deeper analysis of the DMC and write some diagnostic program, I'll be happy to test it on my console for you. I can't guarantee my EPROM emulator will be working any time though. It dies on me quite often, fixing itself after I've examined it with a multimeter without finding any errors... =/

// Bananmos




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byMemblers
Posted on11/28/03 7:41 PM
From IP68.58.99.218  



See if these sound differently, if you can.

http://www.parodius.com/~memblers/sweep1.nes
http://www.parodius.com/~memblers/sweep17.nes
(can't use the URL tag twice, for some reason?)

In these roms, I tried disabling the sample playback (with $4015) before the delay loop begins, and reenabling it afterwards. Would that help? sweep17 tries a 17-byte sample (all 00) just doing the same thing.




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byblargg
Posted on11/28/03 11:30 PM
From IP199.170.89.112  



I looked over DMC.txt again and noticed that it documents the DMC as triggering an interrupt once it has fetched the last byte of the sample, which agrees with the results: If playback mode "10" is chosen, an interrupt will be dispached when the length counter reaches 0 (after the sample is done playing). and The length counter is decremented after every DMA fetch, and when it arrives at 0, the DMC will take action(s) based on the 2 MSB of $4010.

So, it seems that the DMC triggers an IRQ when it starts playing a 1-byte sample, but doesn't check its enable bit ($4015.4) until it's done playing the sample, so another DMC sample can be queued up ahead of time, allowing a delayed IRQ. This prevents the simple delays as I previously thought possible.

I ran the math on a 17-byte sample and it doesn't seem usable. If the DMC is run at maximum frequency (432 clocks per byte), a 17 byte sample yields about 250 Hz.

I studied the idea of using different DMC periods for 1-byte DMC sample segments. Combining up to 5 segments, each using one of the 16 DMC periods, I was able to find resulting frequencies spaced closely enough for 3 or 4 octaves from around 130 Hz to 950 Hz (no delay loops in the IRQs for this). I haven't implemented this yet. I think the saw waves may sound odd from one note to the next due to the different "angles" that will be combined for the return trip back to 0.

Hmmm, an idea does come. How I figured it worked before was that you start the DMC with a 1-byte sample, it plays the entire thing, then invokes an IRQ. It seems to instead invoke the IRQ immediately, but allow queueing of the next IRQ. So in effect an IRQ *can* still be triggered to occur after the sample is done. So the original idea might be possible if the end-of-sample IRQ is triggered in this messy way.

1) Set DAC.

2) Disable IRQ (SEI). Start DMC sample. Clear DMC's IRQ request and queue up another sample after the current one by re-writing to $4015.4. Enable IRQ (CLI).

3) IRQ occurs when current sample has ended, and next (queued) one is starting. Stop DMC immediately ($4015.4 = 0). Run delay loop. Go back to 2 (1 if number of IRQs per wave have been reached).

This might allow the original scheme to work as planned. Membler's modification (sweep1.nes) needs to simply have two writes to the DMC when re-enabling it (first one to start sample, second one to clear immediate IRQ and queue next sample and IRQ). The writes might need to be spaced more. This might not work if the IRQ occurs slightly delayed, in which case the IRQ handler would have to be allowed to be invoked twice in a row each time, where the second time it would only set $4015.4 to 1 and then return immediately.

I'm trying to get an idea of the usefulness of this hack. For NSFs, most players handle Namco106, which provides decent saw waves (and 8 of 'em too). Its main use would be to allow playback on real NES hardware. Is this hack something that would be rolled into song players and be useful? I don't know how much effort to put into it. It's lost its "neat hack" status for me, so the only reason to fix it is if it will be put to use (and perhaps just to finish the job on a real NES).

I was thinking of making a NES programmer cartridge similar to the one I made for the SNES a long time ago. For the SNES programmer, I had made a little I/O interface for hacking cartridge static RAM to give me mega stats. At some point I realized that I could put some code into the RAM and execute it by rewiring the ROM's chip select to the RAM. I got this working and wrote a bidirectional 57kbps software-based serial interface for the SNES and loader using the single programmable I/O pin on controller port #2, coupled with a MAX232 RS-232 interface level shifter, for connection to my PC. It loaded my code into the SNES's 128K RAM (for protection, I write-protected the save RAM on the cartridge by disconnecting the write line). Since I'd only be doing audio tests (no graphics) on the NES, I could just take any NES game with some save RAM and rewire the ROM chip select to it. My NES is so old though that I'd need to find a replacement cartridge edge-connector otherwise its unreliability would make debugging difficult. Having this would allow me to map out all the details of NES sound hardware, for perfect emulation (I have a lot of time on my hands).

Bananmos, I'll take you up on your offer for running tests on your PAL NES. I can write some tests which gather a lot of data quickly, to minimize test runs. The samples you made were excellent. E-mail me at blargg@mail.com





SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byMemblers
Posted on12/3/03 10:37 PM
From IP68.58.99.218  



This is a really useful hack, because it's an easy way to get a third channel with volume control. That's far more important than the waveform itself, IMHO. Namco106 is great for NSF format (less useful for Famicom, useless for NES), but when you've got that many extra channels it seems wasteful not to use them, but when you do it sounds less like NES music. :)

I hacked up a version of the ROM so it doesn't use delay loops, it does sound like there's a pretty good amount of frequencies available still (when you vary the segments). Hopefully with some full octaves, but it's still good even without that (listen to Pressure Cooker on Atari 2600 for example, good tune, heheh).




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byblargg
Posted on12/4/03 00:21 AM
From IP199.170.89.178  



Well, now that I made the NES programmer cart I will be able to get this idea working well.

Your mention of volume control being the most useful part of this hack got me thinking about why you said that, then I thought about the triangle channel. I wonder if you could make a volume-controllable triangle with the DMC? It would involve alternating between a $00 and $FF sample for the up and down parts, but I'm not sure how the volume and frequency would be handled independently. Maybe a bunch of looped samples could be used, each of the form $00 $00 ... $00 $55 $55 $FF $FF ... $FF $55 $55 ..., i.e. insert semi-flat sections at the top and bottom, of different lengths for each sample. I'll have to experiment with this too.

Actually, I think that the on-or-off stepped triangle channel with its prominent 32x overtone is the signature of NES music, and its limitations make NES music stand out from others.

Can you post/e-mail the asm source you're currently using? I've been having trouble with the IRQ on real NES hardware.





SubjectRe: DMC Saw and Square without hogging CPU new  
Posted bytepples
Posted on12/4/03 04:32 AM
From IP68.53.188.31  



"I think that the on-or-off stepped triangle channel with its prominent 32x overtone is the signature of NES music"
Almost. Several Game Boy games, such as Tetris loaded the NES triangle waveform ("0123456789ABCDEFFEDCBA9876543210") into tone generator 3's wavetable; in fact, my GBA music engine has it as the default waveform for tone generator 3. The thing that sets NES audio apart from Game Boy audio is the ability to do soft envelopes on the pulse and noise channels. The Game Boy allows for a hardware envelope with an initial volume and a decay rate, but channel 1, 2, or 4's volume can't be changed without starting a new note and incurring an audible click.




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byMemblers
Posted on12/4/03 06:00 AM
From IP68.58.99.218  



The $4011 register does have some volume control over the triangle and noise channels. The only game that uses it that I know of is Star Tropics 2.

Here's the main part of the source:
http://www.parodius.com/~memblers/bmc.asm




SubjectRe: DMC Saw and Square without hogging CPU new  
Posted byDisch
Posted on12/4/03 08:19 AM
From IP66.127.105.177  



It also plays a significant role in Just Breed. Most notably track 6. The triangle is too loud if the $4011 thing isn't accounted for (sort of dominates the song).

I dont think Just Breed changes 4011 like Star Tropics 2 does... though...




SubjectFinally works on NES hardware! new  
Posted byblargg
Posted on12/4/03 09:35 AM
From IP199.170.89.94  



I finally got the saw wave working on real NES hardware!

tetris_works.mp3

I had to figure out aspects of the DMC beyond what is documented in DMC.txt. Basically the DMC has a sample byte output section which is *always running* and is never reset. Every 8 bit cycles it either fetches a new sample byte, if the DMC is still playing, or it fetches nothing and then waits 8 cycles without disturbing the DAC value. At the start of *each* bit cycle, the current DMC period ($4011 bits 0-3) is used to initialize the length of the cycle.

I demonstrated this to myself by writing a simple program which repeatedly started the DMC playing and immediately set the DAC to a mid-range value. Examining the output sound revealed varying delays before the DMC sample started playing. The delay never got above the length of one DMC sample byte at the current period.

Practical effects of these conclusions:

1) If IRQ generation is enabled, it will occur when the last byte of the sample is fetched, thus it will occur 8 sample bits *before* the end of the sample.

2) When the DMC is started, it might be up to 8 cycles before the sample starts playing, since the sample output section might be in the middle of a sample byte/silence.

This means that the DMC can't be used as a delayed IRQ generator with very high accuracy. The lowest latency from DMC initiation to actual start can be obtained by keeping the DMC at its highest frequency ($4010 = $0F) when it's not in use, yielding a maximum latency of 432 clock cycles.

I don't think NSF players need to mind this detail, unless they want to emulate this saw wave hack properly :)

I had to use the solution I mentioned a few posts ago of using a different DMC period for each segment of an entire wave cycle. One nice benefit of the above limitations is that there are *no* delay loops, thus CPU usage is fairly low. About 250 cycles are used for one saw wave period, so a 500 Hz saw wave takes about 125000 CPU cycles per second, or 7% CPU time. Another benefit is that other interrupts won't interfere with the saw wave frequency, keeping the sound clean. Here are several saw waves of different frequency, recorded from NES hardware running this scheme:



Even though the shape of the wave is (slightly) different for each note, they sound about the same. This was my concern when I had mentioned this idea a few days ago.

This method seems to be literally the only way to do this without using a lot of CPU time. The only improvement to this scheme I can think of is changing the DMC frequency of individual sample bit cycles, rather than every DMC sample byte (i.e. every 8 sample bit cycles). This would require a delay loop in the IRQ handler, and precise timing to wait until a single sample bit has played.

I plan on updating the web page and posting the source to the Tetris music player.





SubjectRe: Finally works on NES hardware! new  
Posted bytepples
Posted on12/4/03 4:21 PM
From IP68.53.188.31  



tepples loads Tetris 1.1 (J) into VisualBoyAdvance and plays with its sound channel muting functions

Actually, the Game Boy Tetris tune doesn't use channel 3. Instead, it uses channels 1 and 2, the pulse wave channels that are present in both the Game Boy and NES, at duty 25%.




SubjectRe: Finally works on NES hardware! new  
Posted byblargg
Posted on12/5/03 00:21 AM
From IP199.170.89.35  



Several Game Boy games, such as Tetris loaded the NES triangle waveform ("0123456789ABCDEFFEDCBA9876543210") into tone generator 3's wavetable; in fact, my GBA music engine has it as the default waveform for tone generator 3. The thing that sets NES audio apart from Game Boy audio is the ability to do soft envelopes on the pulse and noise channels.

On the GameBoy, it's optional to have that particular waveform or another. On the NES, either you use the funky triangle wave or you only get two square channels. Rygar, Solomon's Key and Clash at Demonhead come to mind (they use the triangle for sound effects). Most NES tunes use the triangle wave rather than have only two instrument channels, which makes them somewhat distinct from music on other game systems. I think the inclusion of the DMC was also fairly unique for a 1985/1986 system. The dungeon door open sound in Zelda was always a novelty back in the day.

I wonder if this DMC saw wave hack would have made a significant difference in NES music 14 years ago. Then again, 7% CPU usage is probably too costly for many games.

Actually, the Game Boy Tetris tune doesn't use channel 3. Instead, it uses channels 1 and 2, the pulse wave channels that are present in both the Game Boy and NES, at duty 25%.

I agree, but playing the song with pulse waves for both voices wouldn't have demonstrated the DMC saw wave hack very well :). As for the tune, it was the simplest of the 30 or so I had transcribed by ear into my old Game Music program. I'm thinking of making another demo using three square wave channels (the DMC will provide one) to play the title theme from Blasto!, on the TI 99/4A. I'd use Tunnels of Doom but it only has two voices.

I think I could get a decent DMC-based triangle wave by simply mirroring the saw components shown a few posts ago. I would use the same set of DMC periods for each segment, but use a sample of $FF instead of $00 for the rising part.





SubjectRe: Finally works on NES hardware! new  
Posted bytepples
Posted on12/5/03 01:30 AM
From IP68.53.188.31  



"Then again, 7% CPU usage is probably too costly for many games."
Darn right, especially during vblank.




SubjectRe: Finally works on NES hardware! new  
Posted byMemblers
Posted on12/6/03 01:32 AM
From IP68.58.99.218  



We could stop it from interrupting any PPU writes with SEI and CLI. It might sound OK, unless there's a lot of writes.

But using sprite-DMA may be a problem, it ties the CPU up for 512 cycles. I don't think it would be interruptable. There might be a valid reason to use the $2004 register for once, heheh.




SubjectRe: Finally works on NES hardware! new  
Posted byblargg
Posted on12/6/03 10:46 PM
From IP199.170.89.108  



I updated the DMC saw waves page and added 6502 asm source to play a saw scale using the DMC.

Unfortunately I didn't do as thorough a job of documenting the final technique as I did for the original idea, but I did preserve the old page with its ASCII diagrams. I appreciate the feedback and testing that others have provided.

I'd like to complete this and move on. I still want to make the song player source available, calculate the DMC period tables for PAL NES hardware (and have it tested on a PAL NES), and perhaps put up the C++ source for program I wrote to calculate the DMC period combinations for each note. After that I think it will be documented sufficiently that others can continue development from where I've left off, assuming the hack has any practical use.





SubjectRe: Finally works on NES hardware! new  
Posted byblargg
Posted on12/7/03 09:27 AM
From IP199.170.89.70  



I made (supposed) NES-format ROMs of the saw scale demo and song player (links to .NES ROMs), but don't have any emulators handy to verify their operation. The saw scale demo should work on a PAL NES; a short WAV recording of the first few notes of output would be useful for verifying this.

From what little documentation of PAL DMC frequencies I have, there seem to be no significant adjustments needed for the saw-wave tables. I might generate a set of tables that has equal error for PAL and NTSC machines, rather than favoring NTSC as I currently do.





SubjectRe: Finally works on NES hardware! new  
Posted byMemblers
Posted on12/7/03 10:33 PM
From IP68.58.99.218  



Yep, I believe you wouldn't need to adjust the DMC playback rates.

I tried a few emulators. As before, only FCEUltra played the saw (out of tune, though).

This hack kicks ass. If I use this sometime, I'll call it "blargg modulation", if you don't mind.




Previous ThreadView All ThreadsNext Thread*Show in Threaded Mode
Jump to

Memblers' homepage             Contact Me

Forums powered by WWWThreads Demo