Problem with rectangle (pulse) channel in SMB (RESOLVED)

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Problem with rectangle (pulse) channel in SMB (RESOLVED)
by on (#83762)
UPDATE 2: I resolved this issue by setting the length counter to 0 if the channel is ever set to disabled during the $4015 write.

--------------------------------------------------------

UPDATE: Shortly after typing this, I thought of a possible typo that I could have made. Sure enough, I checked and had a variable in the wrong place. While that fixed a few other sound problems I had, this one still remains, but sounds a little different. I'll upload a new video when I get a chance.

Also, this seems to only happen with blocks when I'm in the underground worlds (like 1-2).

---------------------------------------------------------

I have only implemented the first two channels and am trying to work out all of the kinks before moving on to the other channels. There are certain sounds that are not being silenced during their sweep (as I assume they should be). I silenced the second channel shortly after the video starts. Here is an example:

(incorrect sweep sounds)
http://www.youtube.com/watch?v=mTrhzaMnrC0 (Updated)

(another video to show how other sounds....sound)
http://www.youtube.com/watch?v=fHxJRyJtlpw

The video shows mario jumping and hitting a block (or the fireball hitting the block). The values for the block hit are

Code:
$4000: 0x9E, $4000: 0x93, $4000: 0x3A, $4000: 0x0A
$4000: 0x9E, $4000: 0xBB, $4000: 0x3A, $4000: 0x0A


The constant volume flag is set and the length counter is almost at max still. When I load the last four values shown into the sndtest.nes rom, it plays exactly like it does in the video. This is true for other emulators as well.

My question is... is there something else that should be silencing the channel at that point that I am missing?

Thanks!

by on (#83771)
Aside from $4015 writes...

Sweep sounds a bit slow, do you have the frame sequencer implemented right? It should be clocking twice a frame, so the last set of values should be ticking a new timer period every other frame.

The sweep ought to drop the period below 8 after 38 ticks, or a little under 1.3 seconds, and silence the channel.

by on (#83772)
ReaperSMS wrote:
...Sweep sounds a bit slow, do you have the frame sequencer implemented right? ...


You are right. Now that I have fixed the typo I had, it produces a similar (sweeping upward) sound, but the duration is shorter (and cleaner). However, it is still much longer than it should be and there is still an obvious problem.

I'll re-check the $4015 writes to make sure everything looks correct when I get home. And I'll take another updated video to show the new output.

Thanks

by on (#83778)
What does your sweep code look like?

by on (#83779)
ReaperSMS wrote:
What does your sweep code look like?


Some of my APU code is similar to the MyNES emulator. My sweep function is more or less identical. Below is my sweep function along with my $4001 write code.

Code:
/** SWEEP **/

void APU_rect1::updateSweep()
{
   if(sweepEnable && !sweepSilence)
   {
      if(sweepCount > 0)
      {
         sweepCount--;
      }
      else
      {
         sweepCount = sweepRate;

         if(!sweepNegFlag)   // Sweep Updward
         {
            period += (period >> sweepShift);
         }
         else if(sweepNegFlag)   // Sweep Downward
         {
            period -= (period >> sweepShift) + 1;
         }

         // Check for sweep silence and update frequency
         checkSweepSilence();
      }
   }
   if(sweepReset)
   {
      sweepReset = false;
      sweepCount = sweepRate;
   }
}

Code:
/** $4001 WRITE **/

if(data & 0x80)  rect1.sweepEnable = true;  else  rect1.sweepEnable = false;
rect1.sweepRate = ((data >> 4) & 0x07);
if(data & 0x08)  rect1.sweepNegFlag = true;  else  rect1.sweepNegFlag = false;
rect1.sweepShift = data & 0x07;

if(rect1.sweepShift == 0)
     rect1.sweepEnable = false;

rect1.sweepReset = true;
rect1.checkSweepSilence();

Code:
/*** SWEEP SILENCE ***/

sweepSilence = false;

if(period < 8 || (!sweepNegFlag && period > 0x7FF))
{
   sweepSilence = true;
}
if(!sweepSilence)   // Calculate new samples per period
{
   double freq = 1790000 / 16 / (period + 1);
   samplesPerPeriod = (unsigned int)(samplingRate / freq);
}


Also, I should note that almost every other sound seems correct (music, jumping, going down pipes, getting mushrooms, etc.).

Here is an updated video: http://www.youtube.com/watch?v=mTrhzaMnrC0
And another to compare other sounds: http://www.youtube.com/watch?v=fHxJRyJtlpw

Thanks

by on (#83780)
and checkSweepSilence is something along the lines of:

Code:
checkSweepSilence()
{
      if (sweepNegFlag)
            sweepSilence = (period < 8);
      else
            sweepSilence = ((period + (period >> sweepShift)) > 0x7FF);
}

?

by on (#83781)
ReaperSMS wrote:
and checkSweepSilence is something along the lines of:

Code:
checkSweepSilence()
{
      if (sweepNegFlag)
            sweepSilence = (period < 8);
      else
            sweepSilence = ((period + (period >> sweepShift)) > 0x7FF);
}

?


I updated the previous post with the checkSweepSilence code.

by on (#83786)
Small note:

Code:
if(data & 0x80)  rect1.sweepEnable = true;  else  rect1.sweepEnable = false;


Can be written as:
Code:
rect1.sweepEnable = data & 0x80;


Boolean assign will cast a non-zero value to true (1).