Neotron-Compute / Neotron-Pico-BIOS

BIOS for the Neotron Pico
GNU General Public License v3.0
11 stars 5 forks source link

Set up codec for playing audio #86

Closed thejpster closed 9 months ago

thejpster commented 11 months ago

Sets up the TLV320AIC23B CODEC with some default volume levels, and for 48 kHz 16-bit I2S mode with a 12 MHz crystal.

Also plays a short audio sample. We should probably take that out and wire up the BIOS sample playback API to a ring buffer that is played using DMA.

thejpster commented 11 months ago

Thoughts on sample playback.

  1. We need sample format conversion: e.g. from 8-bit signed to 16-bit signed, or from stereo to mono.
  2. We have a lot of CPU power at hand.
  3. PIO FIFO write functions like write_u16_replicated() are perfect for converting one 16-bit mono sample into a stereo pair of 16-bit samples.
  4. You can raise an interrupt when the PIO FIFO has space in it.
  5. At 48,000 samples per second and a typical VGA line-rate of 31,500 lines per second, we only need to produce between 1 and 2 samples per line.
  6. We should feed the PIO TX FIFO with null samples if there's nothing else to do, so the CODEC clocks remain running.

Idea:

  1. Maintain a ring-buffer containing 1024 16-bit stereo samples (i.e. 1024 32-bit words, i.e. 4096 bytes). This is about 25% more than the 800 stereo samples per 60 Hz frame we will usually clock out.
  2. Let the OS add to the buffer, via the common API, incrementing some write pointer. Do format conversion at this point for simplicity. Optionally save format conversion until the TX interrupt, allowing us to store more samples in our RAM buffer.
  3. Let a PIO TX "FIFO not full" interrupt drain the buffer, incrementing some read pointer. Do sample conversion in this IRQ.
  4. If the buffer underflows, send the PIO TX FIFO the value 0x00000000. This is mid-rail with 16-bit signed data and should cause the CODEC to detect silence and go to sleep.
  5. Add a 'wait for frame tick' API so the application can sleep until the start of frame and then generate a frame's worth of samples in one go.
thejpster commented 10 months ago

Todo: Put FLASH_OS back to what it was, and work out precisely how much RAM we need to allocate for globals.