dan-rodrigues / ics-adpcm

Programmable multichannel ADPCM decoder for FPGA

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

verilator-tests action status symbiyosys-tests action status

ics-adpcm

This is a programmable IMA-ADPCM decoder / mixer. It can be configured with up to 16 ADPCM channels (or "voices") with independent volumes and playback rates. Sample data is loaded from a shared 16MByte address space. The output mix is signed 16bit stereo PCM.

The aim is to minimize resource use and support slower, low power devices such as the Lattice iCE40 UP5K (logic cost is about 1000LCs, or less than 20%).

Design goals

  • Minimize resource use
    • Register files are implemented in a way that can be inferred as block RAMs instead of using FFs. On iCE40, 2x 512byte RAMs are used.
    • Only one multiplier is used. On iCE40 UP5K, 1 "DSP Block" is used.
  • Favor fmax over performance
    • One target for this project is >35MHz on an UP5K
    • Other device shouldn't have much trouble meeting timing at >100MHz

Features

  • Playback of up to 16 concurrent, independently configurable ADPCM channels.
  • ADPCM data loaded from a shared 16MByte address space using a ready/valid interface to also support slower memories i.e. flash.
  • Per-channel signed 8bit stereo volume control.
  • Per-channel Q4.12 16bit playback rate. This gives a maximum playback rate of approx. 16.0 the output rate and a minimum of (1/4096 = 0.0002).

Limitations

  • No hard filters / EG / interpolators. The channel registers can be modified during playback which allows an external gateware / soft CPU to emulate some of these effects.
  • ADPCM decoding is always enabled. LPCM for cleaner single-cycle waveforms may be an optional extra later. High playback rates help mask the shortcomings of ADPCM here but isn't ideal.
  • ADPCM start/end/loop addresses must be 1kbyte aligned.

Prerequisites

ADPCM encoding

The IMA-ADPCM data used is compatible with what ffmpeg generates with the following command:

ffmpeg -i input.wav -ac 1 -f s16le -acodec adpcm_ima_wav output.adpcm

ffmpeg can be used to encode samples for playback but depending on the source material, a lookahead encoder such as adpcm-xq may produce better results. The expected header, which ffmpeg creates by default, is:

  • 2 bytes: Initial predictor
  • 2 bytes: Initial step index (high byte ignored)

The block size in 4bit nybbles can be configured using the ADPCM_BLOCK_SIZE but the default is to use what the above encoders (and many others) default to, which is 1kbyte.

Usage

PCM memory

IMA-ADPCM encoded data is read using the ports prefixed with pcm_. pcm_read_address and pcm_address_valid are used for reading and the module will wait indefinitely for pcm_data_ready to be asserted with valid data on pcm_read_data. The address is 16bit, not 8bit, the LSB shouldn't be disregarded.

Channel registers

Channels are configured using the ports prefixed with ch_write_. During a write, the inputs must be held stable until ch_write_ready is asserted. ch_write_ready is asserted for one cycle only. Writes take at least 2 cycles but potentially more if there is contention during a write. ch_write_byte_mask can be used to do 8bit writes on the lower/upper bits of the VOLUMES register but can be set to 2'b11 if this isn't needed.

Each channel has 8x 16bit registers arranged in an array-of-structs layout in a register file. Only 6 of the 8 regsiters of each channel are used but the 2 unused ones remain as padding.

The start address for each channel is (channel_id * 8 + offset).

START, END and LOOP are effectively 1kbyte block indexes since all addresses are 1kbyte aligned. All addresses must point to the start of an ADPCM block header.

Offset Name Width Description
0 START 14 PCM memory start address
1 FLAGS 1 FLAGS[0]: Enables automatic looping once END is reached. Playback ends otherwise.
2 END 14 PCM memory end address. This isn't inclusive so the block this points to isn't played, so this should be set to address of (final block + 1). Playback stops unless FLAGS[0] is set to enable automatic looping.
3 LOOP 14 PCM memory loop address. If FLAGS[0] is set and END is reached, playback restarts from this address. This value must be >= START && < END.
4 VOLUMES 16 8bit signed volumes. High 8bits is R, low 8bits is L.
5 PITCH 16 Playback rate. Q4.12 fixed point value, so 0x1000 is a playback rate of 1.0. If the output rate is 44.1KHz, PITCH = (0x1000 * 0.5) = 0x800 would play the sample at (44.1KHz * 0.5 = 22.05KHz).

Global registers

Channels are started and stopped using a separate interface using ports prefixed with gb_write_. There is 1 bit per configured channel, so the width of these registers depends on the value of the CHANNELS parameter. These registers serve as the key-on / key-off control.

gb_write_busy is asserted immediately after a write to these registers and remains asserted until the write is committed. Attempting a write while busy will overwrite the previously staged value. Writes are commited once per OUTPUT_INTERVAL cycles. The busy flag is also asserted on reset to mute all channels.

Offset Name Description
0 PLAY Channels with a corresponding bit set to 1 will (re)start playback. All 0 bits are ignored.
1 STOP Channels with a corresponding bit set to 1 will stop playback. All 0 bits are ignored.

Status registers

status_read_address and status_read_data can be used to read certain channel state. May be useful if the module is driven by a CPU.

Offset Name Description
0 PLAYING Channels with a corresponding bit are currently playing.
1 ENDED Channels with a corresponding bit set have ended playback. The bit remains set until playback is started again.
2 BUSY BUSY[0] outputs the value of gb_write_busy. All other bits are undefined.

Other flags

These may be useful if the module is driven by an FSM rather than a CPU:

  • gb_playing outputs the value of PLAYING.
  • gb_ended outputs the value of ENDED.

Audio output

Signed 16bit stereo output is updated once per OUTPUT_INTERVAL cycles. output_valid is asserted for 1 cycle at which point output_l / output_r have valid data to be registered. The outputs are undefined at all other times.

Tests

  • The /sim directory contains Verilator-driven tests that assert that the ADPCM decoding and PCM output work as exepcted for different test cases. Note git-lfs is required to checkout the test reference files.
  • The /formal directory contains SymbiYosys-driven tests for parts of the control interface. The PCM decoding / mixing / output is ignored which is covered by the above tests instead.

Demo

The /demo directory contains a ULX3S project that allows the user to play different notes with a switchable sample bank. It also includes a simple tracker for automatic playback.

About

Programmable multichannel ADPCM decoder for FPGA

License:MIT License


Languages

Language:Verilog 98.0%Language:Shell 2.0%