Wednesday, October 21, 2026

Sound generation

        With the graphics engine coming along well, I turned to the second major task this FPGA would need to do: audio generation. The typical method to get audio out of a retrocomputer project like this would be to use something like a AY-3-8910 sound synthesis chip, but I didn’t have any of those on hand and wanted to try making my own audio generator from scratch. The preferred method with modern sound generation is to just play back digitized sound clips, but I didn’t have enough block RAM left over on the FPGA for that, and it would put too much load on the external CPU anyway. Instead, I decided that I wanted to implement a fairly standard wavetable synthesis system, inspired by the AY-3-8910, the Commodore SID, and other classic sound generators.

      Those early classic sound chips were generally good for 3 channels of sound at most, with completely separate sound generation circuitry for each channel. I decided for a more ambitious design, a synthesizer capable of handing up to 16 channels simultaneously. To avoid having to have an unreasonable amount of logic for each channel, the audio engine would operate serially, cycling through the 16 channels and performing all the math required for each one at a time.

Audio engine block diagram

        The audio engine starts with a memory interface block, which loads all of the registers required for a channel from the audio control RAM. Each channel has an associated 32 byte section of the control ram, which is loaded into temporary registers which control the audio engine. After the required math has been run for that channel, 9 bytes will be written back to the audio RAM, containing data that needs to be updated with each cycle. As all 16 channels are processed, right and left channel output values are added to a cumulative sum, which is then sent to the I2S audio output block after all 16 channels are done. The entire cycle repeats on a 48khz clock.

        Each channel starts with a 24 bit phase register, which is updated by a 24 bit frequency control register to set the note frequency. 24 bits of frequency control allows a wide range of frequencies for each channel, giving a maximum frequency of 12mhz and a minimum of somewhere around 1/700hz. Being able to go to frequencies that low might seem pointless, but I wanted the channels to be also used as low-frequency oscillators for cross-channel modulation purposes. It also allows a full 9 octave note range with good precision.

        There is a cross-channel modulation function, which allows each channel's frequency, amplitude, or duty cycle to be adjusted by the output from another channel. This allows the user to set up complex effects such as sirens, warbling sounds, randomly varying notes, rising/falling noise to simulate waves or wind, etc., all without the external CPU having to do anything other than the initial register configuration. The resulting system has a lot of flexibility, and the 16 channels give a lot of spare channels to use as oscillators.

        Each channel can be set to output random noise, square waves, triangle/saw waves, sine waves, or one of four custom waveforms. The triangle/saw tooth wave generation logic supports smoothly transition between falling sawtooth, triangle, and rising sawtooth waves with a bit of clever math. The noise, square, triangle and saw waves are generated mathematically on the fly, while the sine wave and custom waveforms are stored in small lookup tables in memory. Each channel also has an independent ADSR envelope generator, which optionally shapes the volume output for each channel’s audio output.

        The left and right channel outputs from each channel are all summed together, and then output on an I2S port after all 16 channels have been updated. An external amplifier takes the I2S input and drives a speaker. I had originally experimented with a R2R DAC, but it didn’t work well. The I2S amp seems to be a cleaner solution anyway.

Devkits now with added I2S amp and speaker.
(and also a USB hub, 8 digit LED display, and battery backed RTC chip) 

        While I am not an audio expert by any means, the resulting sound synthesis seems good to me. Quite capable of generating the types of sound effects that you’d get out of a mid 80’s game system. I am sure that someone with more musical aptitude than I could do a lot with this audio generator.

No comments:

Post a Comment