If I may have a suggestion: AICA should be addressing samples, not bytes. Change it and most of your code will become universal - as only the actual fetch from memory will have to convert sample number to data address.

As for ADPCM - this approach will never work. It might for non-looped samples when the sound pitch matches the sound's own, but that's about it. I'm not so sure current skipping is correct for 16-bit cases as well. Things to note:
- ADPCM always starts with lowest nible, then moves to high, then to next byte
- If the sound pitch is changed, the step will not be one. ADPCM decoder still needs to refresh it's internal state for _every_ sample on it's way to current one. That also means you need to implement proper skipping for step < 1 - this will be easier if you follow my first suggestion.
- I understand you're doing interpolation between two consecutive samples. Be careful with that on ADPCM. I'd disable it for now for those samples.
- And there's the loop processing smile But one thing at a time.