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

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
tineras
Posts: 53
Joined: Mon Jul 05, 2010 7:59 am

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

Post by tineras »

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: Select all

$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!
Last edited by tineras on Mon Sep 12, 2011 3:29 pm, edited 4 times in total.
ReaperSMS
Posts: 174
Joined: Sun Sep 19, 2004 11:07 pm

Post by ReaperSMS »

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.
User avatar
tineras
Posts: 53
Joined: Mon Jul 05, 2010 7:59 am

Post by tineras »

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
ReaperSMS
Posts: 174
Joined: Sun Sep 19, 2004 11:07 pm

Post by ReaperSMS »

What does your sweep code look like?
User avatar
tineras
Posts: 53
Joined: Mon Jul 05, 2010 7:59 am

Post by tineras »

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: Select all

/** 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: Select all

/** $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: Select all

/*** 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
Last edited by tineras on Mon Sep 12, 2011 2:50 pm, edited 4 times in total.
ReaperSMS
Posts: 174
Joined: Sun Sep 19, 2004 11:07 pm

Post by ReaperSMS »

and checkSweepSilence is something along the lines of:

Code: Select all

checkSweepSilence()
{
		if (sweepNegFlag)
				sweepSilence = (period < 8);
		else
				sweepSilence = ((period + (period >> sweepShift)) > 0x7FF);
}
?
User avatar
tineras
Posts: 53
Joined: Mon Jul 05, 2010 7:59 am

Post by tineras »

ReaperSMS wrote:and checkSweepSilence is something along the lines of:

Code: Select all

checkSweepSilence()
{
		if (sweepNegFlag)
				sweepSilence = (period < 8);
		else
				sweepSilence = ((period + (period >> sweepShift)) > 0x7FF);
}
?
I updated the previous post with the checkSweepSilence code.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Post by Near »

Small note:

Code: Select all

if(data & 0x80)  rect1.sweepEnable = true;  else  rect1.sweepEnable = false;
Can be written as:

Code: Select all

rect1.sweepEnable = data & 0x80;
Boolean assign will cast a non-zero value to true (1).
Post Reply