SDRAM Audio playback
From Hamsterworks Wiki!
This FPGA Project was completed in July 2014.
I needed a way to do a bit better testing on my SDRAM controller, and wanted a test bed for my future Audio DSP hacking so I knocked this up. It has a lot of little things all put together such as an FPGA implemented Stereo One Bit DAC, the SDRAM Controller and a quick and dirty RS232 interface.
Once uploaded it will start playing random noise - whatever is in the SDRAM. WARNING - THIS NOISE IS VERY LOUD! DO NOT HAVE YOUR EARBUDS IN!. It is also random, so the energy is distribution is not link 'natural' sounds. You can then send 16-bit stereo audio down the RS232 port at 115200 baud, and they will be written to RAM and replacing the noise with something much nicer, or maybe some death-metal.
To do this process I open up two terminal windows. In the first I run
stty 115200 < /dev/ttyUSB1; od -Ad -x < /dev/ttyUSB1
allowing me to see what is being written, and in the other window I run
dd if=/tmp/NeverGoingToGiveYouUp.raw bs=8k of=/dev/ttyUSB1
to send the data through.
The RAW file was made by 'ripping' a CD track as a WAV file, then stripping off the first 46 bytes, as they are the wave file header. You will need 8MB of audio to completely fill the SDRAM. At 44.1kHz that is about 47 seconds. Sending 8MB down the serial port is very slow, and can take 10 minutes. I might look at loading this out of an SD card sometime.
Future enhancements might be for a wave-based synth perhaps?
It also makes a good test-bench for experimenting with shelf life of data held in SDRAM. If you unplug the board then plug it back most of the data remains!
Sorry but the top level module is called "upsample" as one of the projects I have in mind is using a polyphase filter to convert a stream of 44.1k audio to 48k.
The entire project's source is here:
The only thing that isn't explicitly coded is the FIFO that holds samples before they head out to the DACs.
The design is constrained for a Papilio Pro with the Audio Wing plugged into the CL slot. Unlike a lot of boards the clock rate is 32kHz, so you will need to adjust some constants to get the RX module, memory controller, and sample playback rate to work nicely at a different input clock.
A quick fix for the noise
Where there is the following line:
rd_address <= rd_address+1;
Replace it with:
if rd_address = wr_address then rd_address <= (others => '0'); else rd_address <= rd_address+1; end if;
That will cause it to play only the area of memory that has been written, plus one extra sample. Oh and it doesn't like it if you write more than 8MB. And you will still get bad noise if your data isn't correctly byte-aligned.
Not much of a fix really!