Generating a bandlimited (anti-aliased) pulse wave.

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Generating a bandlimited (anti-aliased) pulse wave.
by on (#125038)
I'm trying to combine two band limited sawtooth waves in order to form a square wave. Band-limiting is important, because I want to avoid the harsh sound incurred by aliasing. I'd like to be able to use arbitrary duty cycles with the waveform, specifically the 12.5, 25, 50, 75, that the NES uses. I've researched solutions to this on sites like musicdsp.com, but the introduction of wavetables and the lack of comments in the code makes it very difficult to grasp.

Could anyone provide me with either pseudo code or C code, or point me in the direction of source that accomplishes the above? Ideally, I'd like to understand the whole process, but readable code should be good enough.

I've been stuck on the problem of circumventing the nyquist limit for several months now, and would really appreciate some help.
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125039)
Blargg's code to the rescue?
http://slack.net/~ant/bl-synth/
http://slack.net/~ant/nes-emu/
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125042)
Perfect! That's just what I was looking for.
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125050)
Don't forget http://code.google.com/p/blip-buf/
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125154)
Wow, Blargg himself! I've been reading about your blip project for the last two days.

Currently, I am working on creating an Xcode project with it, to no avail. It seems there's a linker conflict if I place both /player and /sdl_player in the project. It doesn't like multiple main functions.

Have you had any success getting this to work on a Mac?
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125155)
Avoid Blip_Buffer and prefer blip_buf. blip_buf has a more refined interface and better timing accuracy.
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125157)
Ah, that's much easier to work with.

A couple of questions. I'm trying to correlate the period of a wave -- 1/frequency with the system you're using, storing the period as an int. I'm sure this is done as an optimization, only if I target a signal of 440hz (A4), this won't even register, as period would still equal 0. Sorry if this is a newbie question, but some info would be greatly useful.

Also, is there a way to make adjustments to the duty cycle within your library?

Either way, this looks like a great package and I will continue reading up on it tomorrow.
Re: Generating a bandlimited (anti-aliased) pulse wave.
by on (#125159)
See demo_fixed.c, which uses the highest-possible clock rate (for maximum time resolution). So the period of your 440-Hz square wave would be clock_rate/440. To make a square wave you add positive and negative deltas at that period, spaced by half the period (floating-point just for clarity; you'd normally use integer math):
Code:
blip_add_delta( blip, clock_rate/440*0.0, +amplitude );
blip_add_delta( blip, clock_rate/440*0.5, -amplitude );
blip_add_delta( blip, clock_rate/440*1.0, +amplitude );
blip_add_delta( blip, clock_rate/440*1.5, -amplitude );
...


For a different duty, just shift the relative timing of the opposite amplitudes. So this does 25%:
Code:
blip_add_delta( blip, clock_rate/440*0.00, +amplitude );
blip_add_delta( blip, clock_rate/440*0.25, -amplitude );
blip_add_delta( blip, clock_rate/440*1.00, +amplitude );
blip_add_delta( blip, clock_rate/440*1.25, -amplitude );
...


As the documentation describes, you're just creating a normal waveform at a high input clock rate, and this resamples to the output rate. Instead of specifying the amplitude at every sample point, you simply specify the points where it changes relative to the previous.