APU: volume and... envelope? ^^;;;

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
APU: volume and... envelope? ^^;;;
by on (#235997)
As you can see from the question, I don't know much about the APU. After reading the wiki regarding for the register content for volume, I came more confused than before I looked at it :lol:

Maybe if I explain what I want to do, it will be easier to know if what I'm looking at is the right information. On a Jukebox screen, I want to show the current volume of each channel. The Famitracker/famitone combo driver that I'm using is buffering the values of each register so it should be easy to access but I don't know what to extract and what to show because of the volume/constant/envelope explained in the wiki.

My question is, what value should I extract from the register of each channel to show the current volume? I guess there must be a special case for triangle/dpcm since you cannot control it, so I need to figure out how it work to show a visualization of it.

Once I understand how to extract the values it should be easy to display them.

Thank you in advance for some basic information on the subject.
Re: APU: volume and... envelope? ^^;;;
by on (#235999)
Most likely for the thing you're working on you don't have to worry about envelope mode. Just use the current 4-bit constant volume.

Envelope isn't supported by Famitracker. Mostly only used by old games. It's kind of a badly implemented hardware feature, always has to start at full volume and does a simple linear fade to 0. Using constant volume with per-frame control is much more versatile.
Re: APU: volume and... envelope? ^^;;;
by on (#236028)
I see. I wouldn't have known just by looking at the wiki ^^;;; I was going to test first with the 4 bits only so it seems my instinct was right.

As for DPCM/Triangle, since there is no volume, what would be the best way to know if something is playing? I will check their registers and see if I can guess something out of it.

Thanks again!
Re: APU: volume and... envelope? ^^;;;
by on (#236036)
Maybe Off topic:
In my audio engine, I like the hardware envelope as a way to apply a simple articulation at the beginning of notes, especially since it doesn't use as much memory/cycles as my software envelope. It depends on how I want things to sound. I think it's also really good for sound effects. It gives a nice 'pingy' arcadey sound. Just my 2 cents.
Re: APU: volume and... envelope? ^^;;;
by on (#236043)
Banshaku wrote:
As for DPCM/Triangle, since there is no volume, what would be the best way to know if something is playing?

DPCM is easy, you can just read $4015 and check bit 4.

Triangle there are a few different ways to silence. Which one is used depends on the engine. You can write 0 to $4008 to halt it with the "linear counter" at the next quarter-frame tick. You can write $4015 to disable it (not usually preferable because writing to $4015 has the potential to interfere with other channels, esp. DPCM). You can let the "length counter" run out. You can write 0 to the frequency registers to produce a pitch too high to be heard. I think the first method ($4008) is probably the one most often used?
Re: APU: volume and... envelope? ^^;;;
by on (#236049)
@gravelstudios

Yes, it was offtopic since I'm not making an engine but just trying to read the status of channel in an existing engine :lol:

@rainwarrior

DPCM is quite easy, thanks! For the triangle, well, I don't know how famitracker does it so the pointers you gave should be a good start. Time to look inside the driver source code, I guess :D

edit:

I looked inside the code and inside apu.s, it set 4008 to 0 at "@KillTriangle", so I guess 0 means off for the triangle then.
Re: APU: volume and... envelope? ^^;;;
by on (#236058)
Sorry for the double post, just to say that it worked.

What I do, for other people that may want to do the same thing with famitracker.
- use the buffered value of the registers. If your version doesn't, just buffer them inside apu.s
- Square 1/2/noise: use the lower 4 bits of $4000, $4004, $400C
- triangle: check it $4008 value. If 0 then off else, something is playing
- DPCM: check status of value written to $4015. If bit 4 is set (or if all channel are on, if equal $1F) then DPCM is playing

That's it and it is working. My only thing left to do, which is not related to volume, is to check if famitracker driver allowed to pause music or not. For now I don't see the flag so either I removed it when restructuring code (duh) or there is no such thing. It's not that much of an important feature but would like to add it.
Re: APU: volume and... envelope? ^^;;;
by on (#236175)
Try writing $80 to $4008 instead of 0. That's the most common way to mute the Triangle I think (depending on the engine), and that's how I do it in my sound engine. It should mute it at once. No idea if it works with Famitracker though.

The wiki suggests to write 0 to $4008, something to $400B and then something with bit 7 set to $4017 though. Sounds complicated.
Re: APU: volume and... envelope? ^^;;;
by on (#236180)
Pokun wrote:
Try writing $80 to $4008 instead of 0. That's the most common way to mute the Triangle I think (depending on the engine), and that's how I do it in my sound engine. It should mute it at once. No idea if it works with Famitracker though.

The wiki suggests to write 0 to $4008, something to $400B and then something with bit 7 set to $4017 though. Sounds complicated.

I guess you're referring to the bottom of this page.
To $4008: $80 or $00 doesn't matter. The high bit controls whether it will count down, but you're setting its reload value either way. The actual silence happens once the frame sequence reloads it.

To $400B: I think the linear counter reload won't apply until after a $400B write? At least that's what a few emulators seem to implement. My memory is a bit hazy on this one. Weirdly my music engine might neglect writing $400B, but I don't recall this being a problem? Memory is hazy here, I'm kinda confused about this.

To $4017: This will clock the frame sequencer immediately, causing an instant silence instead of up to a 1/4 frame delay for the next clock whenever the frame sequence silences the triangle. If you want to eliminate that delay, this is necessary, though if you're using envelopes or other frame sequence stuff it will interfere with those. I'd personally say the delay is slight enough not to be a problem, but if you want an immediate halt this how to do it.
Re: APU: volume and... envelope? ^^;;;
by on (#236185)
I see, I read somewhere that bit 7 must be set to silence Triangle right away. Seems that was wrong. The reason I write $80 might be because I don't use the internal length counter, so I have no reason the clear the Length Counter Halt Flag (although I'm not sure if that matters when muting). I'm sure I learned that from Nerdy Nights sound tutorial.

Yeah not using $400B and $4017 when muting the Triangle have never really created any audible problems for me. Seems just making the sound engine unnecessarily complicated unless you really need them for some reason. I think that bottom part of the wiki is new BTW. At least I don't remember reading it before.
Re: APU: volume and... envelope? ^^;;;
by on (#236187)
@Pokun

Since the values comes from the famitracker driver, the only way to change it would be to change how the driver works, which is not the goal of this post but just refresh each frame on the screen (volume bars) what is happening in each channel. No modification is required.

From the last few people, it seems people don't know if the driver does have a pause function or not. I will recheck the original version (Shiru's combo driver is based on 4.6) and see if such code existed, seems the only way. If not, I will just remove the button on the screen.
Re: APU: volume and... envelope? ^^;;;
by on (#236189)
Oh, I did not see that question.

No, Famitracker doesn't have a pause feature.

Usually the way I've implemented one is to set $4015 to 0 on pause. Then to unpause, set $4015 to $0F.

This isn't a complete solution, though, because the channels don't fully turn back on until the high frequency register is written ($4003, $4007, etc.) which reloads their length counter. To get that to work, I needed to find where Famitracker stores a cached value for those registers and invalidate it (i.e. set the value to $FF) so that on the next frame it is guaranteed to rewrite those registers.

The reason there's a cached value for those is because writing to e.g. $4003 resets phase and causes a pop sound, so it's normal to avoid writing to that register unless the value has actually changed. There's probably some CMP right next to the code that stores to $4003, that should tell you where the value is cached.
Re: APU: volume and... envelope? ^^;;;
by on (#236192)
I see, so it doesn't exist, like I was suspecting for a while. Thanks for confirming.

With what you said, I may be able to implement it quite fast. I don't understand the part that writing 0 to 4015 would stop the driver. It would stop the hardware channels, yes, but for the driver, I'm not aware because of lack of knowledge of how it works.

Still, what you just said gives me a lot of useful information on how to implement it so I will just test it and see how it goes then.

Thanks for the information!
Re: APU: volume and... envelope? ^^;;;
by on (#236195)
Well you stop the driver by not calling its play routine every frame while you're paused.
Re: APU: volume and... envelope? ^^;;;
by on (#236197)
I was able to implement a quick pause flag with the current existing one and was able to restart it without modifying the play routine in nmi but depending on how the song is made, it causes on resume some channel to not be playing at all until some specific parameter reset it (i.e. the volume bars are still shown but no sound comes out).

I guess it may not be easy to smoothly return from pause and may not be that necessary anyway so for this project I think I will skip it until I understand more about the driver. It may be possible to do it more smoothly, it just my knowledge of the driver is lacking and my goal is not to learn famitracker innards to, someday.
Re: APU: volume and... envelope? ^^;;;
by on (#236206)
I don't know if it matters but in my pause routine I first silence all channels by clearing the volume setting in $4000, $4004, $400C and the mute setting in $4008 for the Triangle. $4015 is only used for DMC, the other APU channels are always enabled. Then I toggle a play flag (like the opposite of a pause flag as it's not only used for pausing) which skips the entire play routine each frame if cleared. Unpausing is simply done by calling the pause routine again toggling the play flag on again. The play routine is designed to set the appropriate volume each frame so there is no need to unmute the channels again. It might not be entirely perfect, but I have not noticed anything strange doing it this way as long as the channels are properly muted upon pausing. Failing to mute causes some small but noticeable audible glitches. But again this all depends on how the driver is designed.

Not sure if toggling the play flag is the best way though as if it fails for some reason the game might loose track of the flag's state and pause when it's supposed to unpause and vice versa. I might change that and have separate pause and unpause routines that guarantees the state of the flag, or you may have to read the state of the flag each time you use pause.
Re: APU: volume and... envelope? ^^;;;
by on (#236208)
The famitracker drivers clears its value, like you said, at $4000, $4004 and $400C when the music is stopped so my current issue is not related about that unfortunately. Thank you for the idea ;)

I think the reason is more related to the music format itself. For example, in a tracked song, you can start an effect/note that will be active for multiple frames. When you pause, you just stopped in the middle an active note/event, which means when you unpause it, it cannot continue unless it knew the state, somehow, when it was stopped and re-trigger it at that exact moment. I wouldn't be surprised if instruments that contains effects, if stopped in the middle of playing, won't continue because of that too, which would be why that some notes are not playing (effect was stopped) but the volumes are still applied to a stopped effect/note, which is my current issue.

I will live with it, not a big issue in my case. It would have just been a nice option in the jukebox but it's not a deal breaker.
Re: APU: volume and... envelope? ^^;;;
by on (#236209)
My sound driver Pently pauses music as Pokun describes. When pently_stop_music clears the "music playing" flag, the following happens:


Setting the flag back to a nonzero value (jsr pently_resume_music) causes the musical time and envelope generation to pick up exactly where they left off.

This approach works well on a PSG or wavetable with full software envelopes, such as those in the 2A03, MMC5, Sunsoft 5B (aka AY-3-8910 or YM2149F SSG), VRC6, or Namco 163. If software envelopes weren't available, such as on the Game Boy or a few Famicom expansion synths, it would need to wait for the next ADSR segment and resume the note from there.
Re: APU: volume and... envelope? ^^;;;
by on (#236212)
Yeah setting volume to 0 for squares/noise is probably better than clearing $4015 like I suggested, esp. if the driver is normally updating volume every frame.

Banshaku wrote:
I think the reason is more related to the music format itself. For example, in a tracked song, you can start an effect/note that will be active for multiple frames. When you pause, you just stopped in the middle an active note/event, which means when you unpause it, it cannot continue unless it knew the state, somehow, when it was stopped and re-trigger it at that exact moment. I wouldn't be surprised if instruments that contains effects, if stopped in the middle of playing, won't continue because of that too, which would be why that some notes are not playing (effect was stopped) but the volumes are still applied to a stopped effect/note, which is my current issue.

I'm pretty sure this is just the length counter issue I mentioned above. Until the cached value for $4003/4007 etc. changes it won't reload the length counter that got cleared by writing 0 to $4015, and the channel won't turn back on. Probably the zero volume technique is easier, since you don't have to go looking for the cache variables, but that was how I'd always done it in the past.
Re: APU: volume and... envelope? ^^;;;
by on (#236234)
I see, then I guess it worth giving it a try before giving up on it for now. I will just backup the volumes, set them to zero then pause the engine. When unpaused, put back the previous values and see how it goes.

What about 4003/4007, do they still need to be set to $FF to avoid popping? That part should be easy to test so I will know right away if it does has an impact (popping sound and other issues).
Re: APU: volume and... envelope? ^^;;;
by on (#236235)
Banshaku wrote:
I see, then I guess it worth giving it a try before giving up on it for now. I will just backup the volumes, set them to zero then pause the engine. When unpaused, put back the previous values and see how it goes.

No you shouldn't need to back anything up, that's the point. Volume will get overwritten every active frame anyway.

Banshaku wrote:
What about 4003/4007, do they still need to be set to $FF to avoid popping? That part should be easy to test so I will know right away if it does has an impact (popping sound and other issues).

No you don't write $FF to $4003. Sorry, this is getting like several steps removed from the problem.

If you write 0 to $4015 to silence all the channels, they will not "wake up" until there is some write to $4003, $4007, etc. to reload the length counter. However, sound engines tend to write these registers infrequently because writing it too often makes a bad noise. So... it's typical to have some variable somewhere that stores the last written value to $4003, which is checked before writing it to prevent any unnecessary writes. If you find that variable you can change its value so that on the next frame the engine will think $4003 is not up to date and take care of waking it up for you.

...and none of that needs to be done if you didn't write 0 to $4015. If you used the volume technique, then there's nothing to wake up.
Re: APU: volume and... envelope? ^^;;;
by on (#236237)
From my questions, you already figured out that I don't know much about the APU and try to guess about possible issues or how to do it (that's a programmer's habit, I guess ^^;;;).

Thank you for clarifying about $4003/$4007, I really appreciate it. This is one more reason I'm not touching the APU for now since I have no idea what I'm doing :lol:

Will test the volume without any backup or anything. Quite a simple approach and like it.

edit:

And I always enjoy learning new things. I know more about the APU today!
[solved] APU: volume and... envelope? ^^;;;
by on (#236241)
After testing more with the famitracker driver regarding my last question (pausing the song), there was nothing necessary to be done: the driver allows it, it just that there was not function with the name pause on it :lol:

Basically, if you just change the flag from playing ($01) to stopped ($00), the channels volumes will be set to OFF ($00 or $30 depending on the channel). When you put back the flag to $01, the song continue to play without issues. I was just trying to split hairs for nothing. Since all upper bits of the flag variable are not used, I just added an extra flag to it to know if I asked to pause it or the song finished naturally, which means my pause method knows in which state the driver is and won't try to restart something that was already finished.

Thanks rainwarrior and everyone that helped on the subject, it's now working like I wanted. cool :D
Re: APU: volume and... envelope? ^^;;;
by on (#236304)
Just to follow up on how to silence the triangle:

No, you don't have to write $400B after writing $4008. I think that was written because of a mistaken omission on that page, insinuating that writing $4008 is not sufficient to reload the linear counter. (It is sufficient.)

So really all you need to do is write $80 to $4008 to silence the triangle (and subsequently $FF to $4008 will wake it up). That will leave the counters halted too, which is probably what you want. Most people would not want to use the linear/length counter feature. The 1/4 frame delay is real, but kind of innocuous.


(I wrote a test ROM just to be sure, before making corrections to the wiki page.)
Re: APU: volume and... envelope? ^^;;;
by on (#236315)
I see. Thank you for the extra information. Right now this is what the famitracker driver does and it has no impact so far:

Code:
noMusic:
   lda #$30         ;mute channels when music does not play
   sta BUF_4000
   sta BUF_4004
   sta BUF_400C
   lda #$00
   sta BUF_4008


it could be specific to the Shiru's Famitracker/Famitone combo but I would need to dig in the original code to confirm though.

For now, I had no issue when I set back to play the flag. For some reason, it writes $00 instead of $80. I guess I need to learn more about the meaning of the values before talking more on the subject ^^;;;
Re: APU: volume and... envelope? ^^;;;
by on (#236413)
Is that your code or is it part of Famitracker? Bit 7 of $4008 is used to disable the hardware length counter for the Triangle (0=enabled, 1=disabled). Since most sound engines (not sure about Famitracker) doesn't use the hardware length counter and instead controls note lengths in software (by muting the Triangle when the note is supposed to be finished playing and unmuting when the next note comes), that flag is always set in such sound engines. Therefore $80 is used for muting and $FF for unmuting instead of $00 and $7F. It's the same reason the Squares and Noise are muted by writing $30 to $4000/$4004/$400C instead of $00 so that the hardware length counter and hardware envelope both are kept disabled at all times. By manipulating the volume over several frames, more advanced software envelopes can be created than the single hardware one (which is just a simple linear fade to 0 as Rainwarrior said).



Thanks Rainwarrior for confirming that writing $80 to $4008 is sufficient to silence Triangle, and for fixing the wiki.
Re: APU: volume and... envelope? ^^;;;
by on (#236421)
Good question. It either:

- was in famitracker
- was in famitracker/famitone combo

Not sure which one. Since I know nothing about sound engines, I didn't add that part and it was taken "as-is". For now, there is no ill effects and it has always worked well. Maybe the famitone engine for sfx uses it? I guess not since it should be using famitracker data. Hmmm..

I will try to find the origin of this code give a follow-up about it. Thanks for mentioning it!

edit:

I just confirm the origin of the code and it came from the famitracker/famitone neslib combo example. I will update it to $80 and test if it goes well.
Re: APU: volume and... envelope? ^^;;;
by on (#236453)
I think there is still some use for the linear counter, even in an all-software environment because it lets you do something that software would normally be unable to do, which is to play those very short triangle bursts. Since my sound engine rewrites all three triangle registers every frame I have full control of the duration, but I can also, at any time, set the linear counter to something that takes less than one frame, producing some unusual distorted sounds. Basically I treat $4008 as a triangle "duty cycle" selector, where $00-$02 produce distorted tones and anything above $03 is a normal triangle wave.
Re: APU: volume and... envelope? ^^;;;
by on (#236454)
za909 wrote:
I think there is still some use for the linear counter, even in an all-software environment because it lets you do something that software would normally be unable to do, which is to play those very short triangle bursts. Since my sound engine rewrites all three triangle registers every frame I have full control of the duration, but I can also, at any time, set the linear counter to something that takes less than one frame, producing some unusual distorted sounds. Basically I treat $4008 as a triangle "duty cycle" selector, where $00-$02 produce distorted tones and anything above $03 is a normal triangle wave.

Well, this could be done in software, but only if your sound engine runs more than once per frame, which is impractical except on specific mappers. Interesting effects, by the way !
Re: APU: volume and... envelope? ^^;;;
by on (#236486)
Yeah I think it might be a good idea to add commands to a sound engine that allows the composer to change some registers arbitrarily in order to allow some advanced stuff not normally allowed by the sound data format.

Cool effects indeed! :)
Re: APU: volume and... envelope? ^^;;;
by on (#236490)
Technically, if you buffer all the values before they are sent to the registers, you could do all kind of effects on it (this is how the famitracker/famitone combo work, famitone is added after famitracker song is done).
Re: APU: volume and... envelope? ^^;;;
by on (#236492)
Some Sunsoft games used short triangle bursts like za909 posted. The croaking frogs in Gimmick!, or some sound effects in Fester's Quest, etc. I think Metroid also used it for the "bubble" sound in the Tourian area music.

It's not very common, though. Famitracker never supported it (though I dunno about the 0CC forks).

Pokun wrote:
Yeah I think it might be a good idea to add commands to a sound engine that allows the composer to change some registers arbitrarily in order to allow some advanced stuff not normally allowed by the sound data format.

I think PPMCK/MML allowed this kind of thing.
Re: APU: volume and... envelope? ^^;;;
by on (#236513)
Yeah I think PPMCK even allows the composer to program their own assembly routines in order to do stuff not allowed by the MML.

And yeah buffering the APU registers is very useful anyhow to minimize writes to them to once per frame. Nerdy Nights teaches that too.
Re: APU: volume and... envelope? ^^;;;
by on (#236514)
I guess it's a question of whether to buffer all four channels before writing any or to calculate each channel to a buffer, write out the buffer, and proceed to the next channel. I don't know how other drivers work, but Pently does the latter, placing the buffer in three bytes of zero page.
Re: APU: volume and... envelope? ^^;;;
by on (#236519)
Famitracker doesn't buffer them in the original driver: it was only done in the famitracker/famitone sfx combo to allow famitone to overwrite a channel when sfx are required, thus mixing them.
Re: APU: volume and... envelope? ^^;;;
by on (#236579)
rainwarrior wrote:
Some Sunsoft games used short triangle bursts like za909 posted. The croaking frogs in Gimmick!, or some sound effects in Fester's Quest, etc. I think Metroid also used it for the "bubble" sound in the Tourian area music.

It's not very common, though. Famitracker never supported it (though I dunno about the 0CC forks).

Pokun wrote:
Yeah I think it might be a good idea to add commands to a sound engine that allows the composer to change some registers arbitrarily in order to allow some advanced stuff not normally allowed by the sound data format.

I think PPMCK/MML allowed this kind of thing.

Yes It allows that. It's the y command. You can poke a value anywhere, you can even crash the sound engine if you want.

10 years ago (holy crap, really?), I did an example of a croaking sound in MML. What's funny is that I had to make the y command in the noise channel, because this channel is processed after the triangle channel and it allows me to override what was written into $4008.

Neil Baldwin made something interesting with buffered writes to the APU (again, 10 years ago!): putting into a ring buffer, and using that ring buffer as an echo buffer. It makes very realistic one-channel echos. http://dutycyclegenerator.com/#EchoDemo