me again with a soundoutput question

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
me again with a soundoutput question
by on (#1069)
Disch give me a framework to work with sound, well i dont know why he mentions a "getsquare1out" func. that ruturns a value greater than a byte. I thought the value of the output is the 4 bit (depending of decay) of envolpe register.

Which is the output do i have to get? its my first time programming sound and pcm and i dont know very much. Can somebody help me?

Thanks in advance.

by on (#1072)
Well I suppose you don't need a getsquare1out function... I was just showing the concept.

Anyway... at any given cycle, a square channel is outputting 0-F... which can be found by the following conditions:

- If the length counter is disabling the channel -- output is 0
- If the sweep unit is disabling the channel -- output is 0
- If the duty cycle is in "negative" state -- output is 0
- else, output is the current volume level (0-F)

So with the very simplest implimentation, you could check to see what the channel is outputting every ~40.58 cycles and output that to your sound buffer.


To give you a visual idea.... assuming the channel is active (length counter and sweep unit are allowing output).. assume the channel volume is set to A... and assume a 50% duty cycle... with $028 as the 11-bit written wavelength... and assuming a samplerate of 44100... your square output might look something like this:

A A A A A A A A 0 0 0 0 0 0 0 0 A A A A A A A A 0 0 0 0 0 0 0 0 ... etc

that constant on/off cycling is done by the duty cycle -- it being off at those times is what produces the Square shape of the waveform.
apu
by on (#1076)
so, it seems im not emulating it too bad. Im writing the channels envolope value to the sound buffer, if its "0" or the channel is silenced i write "128" (no sound), and if its not "0" i write the envelope.
Is that right?

by on (#1077)
He (Disch) works with unsigned samples, I would say the 'nostalgic side'. ;)
On my side, read - if the channel is disabled by any reason, the output is obviously zero; otherwise, it can be +Value or -Value.

There's 2 sample sizes: 8-bit and 16-bit (umm... yeah). If you choose the 8-bit form, then values are -128 up to +127; else, the 16-bit assumes -32768 up to +32767 (signed int). You're the judge - there's no right choice.
Re: apu
by on (#1079)
Anes wrote:
so, it seems im not emulating it too bad. Im writing the channels envolope value to the sound buffer,


yes... but only under those conditions I listed. Writing all A's will produce silence... just like writing all 0's. The whole point is to have alternating positive output and zero... this produces the waveform. Without it you won't be playing anything.


Quote:
if its "0" or the channel is silenced i write "128" (no sound), and if its not "0" i write the envelope.
Is that right?


Well... I'm giving you signed numbers (not unsigned, Fx3 ;) ). You need unsigned if you are outputting 8-bit sound in windows... so just XOR your output sample with 0x80 to make the conversion.

so if your output is 0... you'd write 0x80 to your sound buffer -- this would be the "center line" on an oscillator. And if you're outputting A... you'd write 0x8A to your sound buffer.

by on (#1082)
In other words:

For 8-bit output:
Code:
sample = value ^ 0x80;


For 16-bit output:
Code:
sample = value ^ 0x8000;
square wave
by on (#1095)
but, suppose i have sqrout func. that check if the channel is silencied, if silenced returns 080H, if its not ruturn Value XOR 080H.
So the func. can return 3 types: -silenced 80H, - not silenced XOR 80H and silenced again (silence that is not returned by a silence lencounter and negative value of duty cycle).

Havin this ruturns values does not deformate the wave?

I hope i could explain well..

by on (#1109)
Don't do that. It'll make it harder to mix channels later

Keep everything signed -- ie: 0 = silenced, greater than zero = output.

Have your square out function return 0 if the channel is silenced... or 0-F if the channel is on (depending on the duty cycle and volume).

Before you output this sample to your audio buffer... you can convert it to unsigned by very simply doing:

sample ^= 0x80;

Do not put that $80 in the square out function of you'll probably just have to take it out later (like when you want to mix the other square's output with this one... or mix in the triangle and other channels)


Probably should look something like:

Code:
sample = 0;
sample += Square1Out();

sample ^= 0x80;
WriteSampleToAudioBuffer( sample );


Square 1 out should NOT be returning these insane high values (alternating 0x80 and 0 would be painfully loud with 8-bit audio). Use the volume level of the channel as it is. If it's too quiet... multiply 'sample' by 2 or something before you output it to the buffer.

Your square 1 out should probably just be returning a value between 0 and F.

by on (#1111)
As long as your overall audio level never exceeds 0x7F, you should be okay - otherwise, you will experience some wicked clipping as a result.

If you need to output a "centered" waveform, you should output 0 for silence and +/- VOL when the wave is playing. It may not perfectly represent the waveform coming out of a real NES, but it will sound almost exactly the same.
thx
by on (#1114)
thanks!!

by on (#1128)
Quietust wrote:
If you need to output a "centered" waveform, you should output 0 for silence and +/- VOL when the wave is playing. It may not perfectly represent the waveform coming out of a real NES, but it will sound almost exactly the same.

Not with the "Hello" demo that uses the square wave channels as a faux PCM register.

by on (#1129)
I consider that to be an extreme case, extremely unlikely to be actually USED by anyone (since you can just use raw PCM for a much higher quality waveform).