Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Reducing noise in 8:2 IMA ADPCM? (Read 5213 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Reducing noise in 8:2 IMA ADPCM?

I'm working on a project that requires ADPCM compression of 8-bit samples to 2-bit. The ADPCM implementation I used is based off the IMA ADPCM algorithm, except adapted to 8-bit samples and 2 bit compression. I already have an encoder and decoder set up, but I've encountered a lot of noise in the conversion.

The project I'm working on is for the Sega Genesis, an old video game system; I want to stream PCM files as level music for a game. However, the Genesis only has 4MB of ROM space, so the audio files need to be compressed by at least a 4:1 ratio. Some of the decompression on the Genesis side is done using a lookup table; calculations in this part can be as complex as necessary, since it'll all be precalculated. The part that is calculated with a table is highlighted red in the decoder source; no complex floating point operations or filters can be done outside of that part in the decoder. (Anything can be changed in the encoder, since the Genesis doesn't handle the encoding.)

Here's the source for both the encoder and decoder (for the computer, not the Genesis). It's in BASIC, so hopefully it'll be pretty easy to understand despite my lack of commenting.

Code: [Select]
Function encodeSample(sample#)
Local code#
Local diff#
Local step_#
Local diffQ#

step_ = stepTable(index)

diff = sample - predSample

If diff >= 0 Then
code = 0
Else
code = 2
diff = -diff
EndIf

diffQ = step_

If diff >= step_ Then
code = code Or 1
diffQ = diffQ + step_
EndIf

If (code And 2) Then
predSample = predSample - diffQ
Else
predSample = predSample + diffQ
EndIf

If predSample > 127 Then predSample = 127
If predSample < -127 Then predSample = -127

index = index + indexTable(code)

If index < 0 Then index = 0
If index > 31 Then index = 31

Return (code And $03)
End Function

Code: [Select]
Function decodeSample(code)[color=#FF0000]
Local step_%
Local diffQ#

step_ = stepTable(index)

diffQ = step_

If (code And 1) Then
diffQ = diffQ + step_
EndIf[/color]

If (code And 2) Then diffQ = -diffQ

predSample = predSample + diffQ

If predSample > 127 Then predSample = 127
If predSample < -127 Then predSample = -127
[color=#FF0000]
index = index + indexTable(code)
If index < 0 Then index = 0
If index > 31 Then index = 31
[/color]

Return predSample
End Function

Also, here's the step table and index table that I'm using:

Code: [Select]
6,7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45
50,55,60,66,73,80,88,97,107,118,127
Code: [Select]
-1,1,-1,1

Finally, here's a sample of what the compression sounds like (it's pretty crappy).

Original File
Compressed File

For comparison, here's a sample of what 8:4 compression sounds like. I'd like to get somewhat near this quality, if possible.
8:4 Compressed File


Any help on this would be greatly appreciated. Note that I'm a newbie to this stuff, so any complex math will probably go right over my head. =P

 

Reducing noise in 8:2 IMA ADPCM?

Reply #1
Unfortunately you can't really get something for nothing. Given that you're sitting at a desired bitrate of about 44kbps, I don't know how much more signal you expect to get out of that stream without heading down the psychoacoustic route, which is probably requires way more signal processing than the poor 68K in the Genesis is capable of. If you're doing the processing on the Z80 sound chip, even less will be possible.

Reducing noise in 8:2 IMA ADPCM?

Reply #2
Unfortunately you can't really get something for nothing. Given that you're sitting at a desired bitrate of about 44kbps, I don't know how much more signal you expect to get out of that stream without heading down the psychoacoustic route, which is probably requires way more signal processing than the poor 68K in the Genesis is capable of. If you're doing the processing on the Z80 sound chip, even less will be possible.


The encoding process isn't being done on the Genesis, and the most important part of the decoding process (which is the part highlighted in red in the decoder source) is precalculated and put in a lookup table. The only part of the decoding that's actually being done on the Genesis side is adding the difference to the predictor and clipping it at -127 or 127. Also, the Z80 (which isn't a sound chip BTW =P) is being used for decoding; right now, the decoder reaches about 22.5KhZ (the Genesis DAC can only play up to 33KhZ without hanging anyway, so that's decent enough for a game), but I'm sure it can be optimized more.

Could you elaborate more on the psychoacoustic route, if possible? How much complex calculations does it require?

Reducing noise in 8:2 IMA ADPCM?

Reply #3
Unfortunately you can't really get something for nothing. Given that you're sitting at a desired bitrate of about 44kbps, I don't know how much more signal you expect to get out of that stream without heading down the psychoacoustic route, which is probably requires way more signal processing than the poor 68K in the Genesis is capable of. If you're doing the processing on the Z80 sound chip, even less will be possible.


The encoding process isn't being done on the Genesis, and the most important part of the decoding process (which is the part highlighted in red in the decoder source) is precalculated and put in a lookup table. The only part of the decoding that's actually being done on the Genesis side is adding the difference to the predictor and clipping it at -127 or 127. Also, the Z80 (which isn't a sound chip BTW =P) is being used for decoding; right now, the decoder reaches about 22.5KhZ (the Genesis DAC can only play up to 33KhZ without hanging anyway, so that's decent enough for a game), but I'm sure it can be optimized more.

Could you elaborate more on the psychoacoustic route, if possible? How much complex calculations does it require?


I would pretty much agree with Canar here, I don't think you can expect much for almost nothing. A simple decoding algorithm like you are using is not going to be able to work magic. Doing 16->4-bit ADPCM is bad enough, going down to 2 bits is a whole new level of pain to the ears I imagine. Based on my past experience with similar problems I could only suggest these things:

1) Low pass filter your source before encoding it. The lower the frequencies being tracked the better ADPCM can keep up with it, high frequency content gives ADPCM fits. Of course you will be taking a fidelity hit here but it is trading off fidelity for noise. On the other hand you might be better off going 8->3 and using lower sampling rates. It's all tradeoffs.

2) IMA ADPCM is pretty bad sounding in the first place. Have you looked into some similar but slightly more complex schemes? You might want to look at the CD-XA compression scheme for example which yields a similar data rate but gives better results. There is more math though as a couple of multiplies and adds are required. Many older video game consoles employed compression schemes for audio based on this kind of algorithm.

3) To save some CPU you can probably pre-clip your input to prevent the overload in the decoded signal that you are needing to clip. This can be as simple as limiting the input to +-100 instead of +-127, or you could decode the signal as you are encoding it and analyze where clipping would occur and then try to shape the waveform to try to avoid it. The time you save clipping could perhaps be put towards a more complex decoding algorithm. However one huge caveat is that with 2-bit encoding I think your error is going to be so large that you will need to pre-clip your input signal to almost nothing.

Anyway, good luck with this, I think you have a real challenge on your hands.