APU Questions

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
APU Questions
by on (#52548)
Hello,
I'm getting back into the APU(one way or another) and am curious about a few things, hoping you can help(yeah you! right there!).

- so i need to know if someone can give a C style algo for generating the waves. I didn't find anything about the square in the docs i've read, but i've read that the triangle is 4-bits wide and behaves like so:
Code:
FEDCBA98765432100123456789ABCDEF
that seems easy enough to create if i have loop that runs at the sample rate i could do this inside:
Code:
int inc=1;                                                      //two global elements
triangle = [-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8]; //outside of the output loop
//...somewhere inside the loop
if(!inc){
    for(i=0;i<15; i++){
        output = triangle[i];
        if(i==15)inc=0;
    }
}else{
    for(i=15;i>0; i--){
        output = triangle[i];
        if(i==0)inc=0;
    }
}

- Now I'm assuming that I can do something infinitely easier for a square, but I don't know the bit-depth or resolution I'm supposed to do it at.

- Same for the noise channel. I can do random no problem, but I don't know if there's a special algorithm to make the randomness accurate to the NES that I should be considering.

Had some more questions, but i forgot them after typing this :p
So anyone have any ideas?
Thanks,
Malik
Re: APU Questions
by on (#52549)
Laserbeak43 wrote:
- Now I'm assuming that I can do something infinitely easier for a square, but I don't know the bit-depth or resolution I'm supposed to do it at.

There are eight segments to the square waveform. Each segment lasts (period_high * 256 + period_low + 1) * 2 CPU cycles. Depending on the duty cycle setting, 1, 2, 4, or 6 of these segments output the channel's current volume; the others output 0.

Quote:
- Same for the noise channel. I can do random no problem, but I don't know if there's a special algorithm to make the randomness accurate to the NES that I should be considering.

Read this article to learn the basic concept.
Re: APU Questions
by on (#52551)
Hah! no one complained!! my triangle must be correct! :)

tepples wrote:
There are eight segments to the square waveform. Each segment lasts (period_high * 256 + period_low + 1) * 2 CPU cycles. Depending on the duty cycle setting, 1, 2, 4, or 6 of these segments output the channel's current volume; the others output 0.

so each CPU cycle is 1.79uSecs? I'm gonna have to do some math to figure out what you've just said. And I might be wrong cause i don't know much about DAC's but what do i do to get perioudHigh*256 out of a 4 bit DAC. Heh, i just don't understand what you're saying all together.
tepples wrote:
Read this article to learn the basic concept.
thanks i'll check that out
Re: APU Questions
by on (#52552)
Laserbeak43 wrote:
Hah! no one complained!! my triangle must be correct! :)

Running the DAC in the range -7 through 8 is good enough for now, but once you implement mixer nonlinearity, you'll need to use 0 through 15.

Quote:
so each CPU cycle is 1.79uSecs? I'm gonna have to do some math to figure out what you've just said.

Each cycle of the NTSC NES CPU is 22/39375000 seconds, or about 558.73 ns. See CPU and APU on the wiki.

by on (#52553)
so it looks like the timer is one of the things i need to learn about? Am i using 4 bits for the square waves too? from what you've said it looks even more than 8 bits.

by on (#52559)
Laserbeak43 wrote:
so it looks like the timer is one of the things i need to learn about? Am i using 4 bits for the square waves too? from what you've said it looks even more than 8 bits.

The DAC is 4-bit, meaning it can be set from 0-15. The period [set in registers 4002/4003 or 4006/4007 for square wave] is what can range from 1 to 2048.

The period is a divider on the 1.79MHz clock. When this period clock ticks (about ~1,790,000/period times-per-second), the next thing that happens is a divide-by-two counter on the square channel. When the divide-by-two counter ticks, THEN the square wave sequencer moves to the next step in the 8-step square-wave sequence. Tepples already pointed out this 8-step sequence is dependent on the square wave's duty-cycle, but really all that it means is you need to sometimes output the "volume" of the channel [the 0-15 DAC setting] and sometimes output 0. All you're really doing to the 8-step sequence by adding the dividers is stretching the sequence out in time. Each 'DAC' or '0' in the 8-step sequence actually lasts for several samples at 44,100KHz. The higher the period, the longer the stretch and the lower the note.

It gets complicated by envelopes and sweep units, but save that for another day.

I found the audio portion very rewarding to do and also the most fun listening to some of the crap sound that I generated whilst doing so.

WRT the noise channel you can gen up the 93- or 32766- bit tables and just roll through them in your sample generating code.

by on (#52560)
NESICIDE wrote:
WRT the noise channel you can gen up the 93- or 32766- bit tables and just roll through them in your sample generating code.

That'll suffice for an early stage emulator like the OP's or perhaps the sort of high-level emulation expected on an emulator designed for a handheld. But the NES might react differently if you play looped noise with short bursts of non-looped noise to switch to a different 93-step pattern. Want me to bang out a test ROM?

by on (#52561)
haha, sure! if you're willing!!
thanks guys. that cleared a lot up btw NESICIDE