ADPCM compression - Petr - 01-19-2025
Some WAV formats use (but there are really very few of them) ADPCM compression. And since its implementation is not too complicated, I tried it. So what's the point here:
If you want to slightly reduce the sound in WAV format, you have these options:
1) Reduce the bit depth (so instead of a 32-bit WAV file you use an 8-bit one) - the sound is slightly worse, but on cheap speakers you won't notice the difference. But it's not Hi-fi anymore. The space saving is fourfold.
2) Use mono instead of stereo. You'll lose the sound depth. This will reduce the sound in WAV format by half.
3) Reduce the sound refresh rate - so instead of 44100 records per minute you'll use only 22050, or 11025. This is a drastic loss of sound samples and it's very audible. The ratio of the original and new sizes is given by the ratio of discarded samples (if you go from 44100 to 22050, you get half the size, etc.)
4) You use a better form of data recording with minimal signal difference.
This is an example. ADPCM simply calculates the difference between two consecutive samples and records only this difference. The step it uses to do this is divided into 8 levels (because an 8-bit signal has 256 levels and ADPCM uses 4-bit notation to save space). The maximum value with a sign of 8 can fit into a 4-bit notation (one bit indicates whether it is a positive or negative value). In this way, sound can be stored with minimal loss of quality in half the file size. This compression cause small noise in signal.
The first example shows a function on an array of numbers and does not require any music file:
Code: (Select All)
' ADPCM compression and decompression in QB64
' ----------------------------------------------------------
' This example uses 4-bit quantization for ADPCM compression
Dim originalSamples(0 To 9) As Single
Dim compressedData(0 To 9) As Integer
Dim decompressedSamples(0 To 9) As Single
'Original signal values
originalSamples(0) = 0
originalSamples(1) = 10
originalSamples(2) = 20
originalSamples(3) = 35
originalSamples(4) = 25
originalSamples(5) = 10
originalSamples(6) = 25
originalSamples(7) = 15
originalSamples(8) = 5
originalSamples(9) = 0
Print "Original Values:"
For i = 0 To 9
Print Using "###.##"; originalSamples(i);
Next
Print
' Compression (ADPCM)
Dim predicted As Single
Dim difference As Single
predicted = 0 ' first prediction
For i = 0 To 9
difference = originalSamples(i) - predicted
compressedData(i) = Quantize(difference) ' Kvantování rozdílu
predicted = predicted + Dequantize(compressedData(i)) ' Aktualizace predikce
Next
Print "Compressed Data (4 bite): "
For i = 0 To 9
Print compressedData(i);
Next
Print
' Decompressing process
predicted = 0 ' First prediciton
For i = 0 To 9
decompressedSamples(i) = predicted + Dequantize(compressedData(i))
predicted = decompressedSamples(i)
Next
Print "Decompressed Samples:"
For i = 0 To 9
Print Using "###.##"; decompressedSamples(i);
Next
End
' Difference quantization function
Function Quantize (difference As Single)
Q = Int(difference / 5) ' Quentization step 5
If Q > 7 Then Q = 7 ' limit to 4 bite
If Q < -8 Then Q = -8
Quantize = Q
End Function
' Difference dequantization function
Function Dequantize (quantizedDifference As Integer)
Dequantize = quantizedDifference * 5 ' The reverse process of quantization
End Function
The second example shows the use on real audio (change the MP3 to another MP3 in stereo on line 20)
The result is the sound so as it would sound if written in 4 bits. Note the small background noise, which is an quantization bug of the original, because this program does not have floating compression.
This program actually saves an 8 bit stereo WAV file with the original sample rate, but in 4 bits. In this case only to memory, it does not save anything to the hard disk.
Code: (Select All)
' ADPCM compression and decompression in QB64 for an 8-bit audio signal
' -----------------------------------
' This example uses 4-bit quantization for ADPCM compression of an audio signal in the range 0 to 255.
_Title "ADPCM compression in QB4PE"
Screen _NewImage(100, 24, 0)
Dim originalSamplesL(0 To 9) As Integer
Dim compressedDataL(0 To 9) As Integer
Dim decompressedSamplesL(0 To 9) As Integer
Dim originalSamplesR(0 To 9) As Integer
Dim compressedDataR(0 To 9) As Integer
Dim decompressedSamplesR(0 To 9) As Integer
Dim m As _MEM, Snd As Long
Snd = _SndOpen("A.mp3")
m = _MemSound(Snd, 0)
Locate 1
Do Until a& >= m.SIZE
j = 0
'load music samples
For i = 0 To 9
originalSamplesL(i) = 128 + (_MemGet(m, m.OFFSET + a&, Single) * 127)
originalSamplesR(i) = 128 + (_MemGet(m, m.OFFSET + a& + 4, Single) * 127)
a& = a& + 8
If a& >= m.SIZE Then Exit Do
Next i
' Compression (ADPCM)
ReDim predicted As Single
ReDim difference As Single
predictedL = 128
predictedR = 128 ' Initial assumption (mean value for 8-bit range)
For i = 0 To 9
differenceL = originalSamplesL(i) - predictedL
differenceR = originalSamplesR(i) - predictedR
compressedDataL(i) = Quantize(differenceL) ' Difference quantization
compressedDataR(i) = Quantize(differenceR)
predictedL = predictedL + Dequantize(compressedDataL(i)) ' Update prediction
predictedR = predictedR + Dequantize(compressedDataR(i)) ' Update prediction
'Range verification for prediction
If predictedL < 0 Then predictedL = 0
If predictedL > 255 Then predictedL = 255
If predictedR < 0 Then predictedR = 0
If predictedR > 255 Then predictedR = 255
Next
Print
Print "Original sound samples (0-255) (Left):"
For i = 0 To 9
Print Using "####"; originalSamplesL(i);
Next
Print
Print "Original sound samples (0-255) (Right):"
For i = 0 To 9
Print Using "####"; originalSamplesR(i);
Next
Print
Print "Compressed data (4bite):"
For i = 0 To 9
Print compressedDataL(i);
Print compressedDataR(i);
Next
Print
' Decompresing process
predictedL = 128 'Initial assumption (mean value for 8-bit range)
predictedR = 128
For i = 0 To 9
decompressedSamplesL(i) = predictedL + Dequantize(compressedDataL(i))
decompressedSamplesR(i) = predictedR + Dequantize(compressedDataR(i))
' Range verification for reconstructed samples
If decompressedSamplesL(i) < 0 Then decompressedSamplesL(i) = 0
If decompressedSamplesL(i) > 255 Then decompressedSamplesL(i) = 255
If decompressedSamplesR(i) < 0 Then decompressedSamplesR(i) = 0
If decompressedSamplesR(i) > 255 Then decompressedSamplesR(i) = 255
predictedL = decompressedSamplesL(i)
predictedR = decompressedSamplesR(i)
Next
Print
Print "Decompressed samples (0-255) Left:"
For i = 0 To 9
Print Using "####"; decompressedSamplesL(i);
Next
Print
Print "Decompressed samples (0-255) Right:"
For i = 0 To 9
Print Using "####"; decompressedSamplesR(i);
Next
For i = 0 To 9
L = (decompressedSamplesL(i) - 128) / 128
R = (decompressedSamplesR(i) - 128) / 128
_SndRaw L, R
Next i
Do Until _SndRawLen < .1
_Display
_Limit 20
Loop
Loop
End
' Difference quantization function
Function Quantize# (difference As Single)
Dim Q As Integer
Q = Int(difference / 8) ' Quantization step 8 for 8-bit signal
If Q > 7 Then Q = 7 ' limit to 4 bites
If Q < -8 Then Q = -8
Quantize# = Q
End Function
' Function for dequantizing the difference
Function Dequantize (quantizedDifference As Integer)
Dequantize = quantizedDifference * 8 ' The reverse process of quantization
End Function
|