01-20-2025, 09:37 PM
16 bit version - trying ADPCM Microsoft standard...
You would certainly be interested in how 16-bit sound would sound if it were compressed by ADPCM and then decompressed. This program will show you exactly this. How it works. Indeed, the differences between signal samples are also written using 4 bits in this case. But how is that possible, you ask yourself. After all, with normal linear stepping it would be jumping in the signal by a huge 32767 /15 (2184) levels in the signal! That would ruin the sound terribly!
Well, for this purpose Microsoft has developed a table (StepTable) that has 88 steps. The program simply jumps in these 88 positions to the nearest similar step value, which is listed in the table. The maximum jump size in the table is currently limited to 15 bits, in this case one bit is no longer used to determine the sign. Values 0–7 indicate the negative direction (delta 0–7). Values 8–15 indicate the positive direction (delta 0–7). This approach causes the sound to be not completely clean, however the resulting file should be 4x smaller in size than a normal 16bite wav file with similar quality. It is possible (almost certain) that the algorithm can be improved somehow...
Rename MP3 - row 44
You would certainly be interested in how 16-bit sound would sound if it were compressed by ADPCM and then decompressed. This program will show you exactly this. How it works. Indeed, the differences between signal samples are also written using 4 bits in this case. But how is that possible, you ask yourself. After all, with normal linear stepping it would be jumping in the signal by a huge 32767 /15 (2184) levels in the signal! That would ruin the sound terribly!
Well, for this purpose Microsoft has developed a table (StepTable) that has 88 steps. The program simply jumps in these 88 positions to the nearest similar step value, which is listed in the table. The maximum jump size in the table is currently limited to 15 bits, in this case one bit is no longer used to determine the sign. Values 0–7 indicate the negative direction (delta 0–7). Values 8–15 indicate the positive direction (delta 0–7). This approach causes the sound to be not completely clean, however the resulting file should be 4x smaller in size than a normal 16bite wav file with similar quality. It is possible (almost certain) that the algorithm can be improved somehow...
Rename MP3 - row 44
Code: (Select All)
'ADPCM - downsize 16bit file 4x
' Original signal array (16bite value, -32768 to 32767)
Dim originalSignalL(0 To 255) As Integer
Dim originalSignalR(0 To 255) As Integer
' ADPCM Microsoft Step Table
Dim stepTable(0 To 87) As Integer
Data 7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31
Data 34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143
Data 157,173,190,209,230,253,279,307,337,371,408,449,494,544
Data 598,658,724,796,876,963,1059,1164,1278,1403,1539,1687,1849
Data 2025,2217,2426,2653,2899,3166,3456,3769,4107,4471,4863,5285
Data 5737,6222,6741,7296,7889,8521,9195,9912,10674,11483,12341
Data 13250,14213,15231,16307,17444,18644,19909,21243,22648,24127
For i = 0 To 87
Read stepTable(i)
Next i
' Starting values for left and right channel
Dim stepIndexL As Integer, stepIndexR As Integer
Dim currentStepL As Integer, currentStepR As Integer
Dim predictedValueL As Integer, predictedValueR As Integer
stepIndexL = 0
stepIndexR = 0
currentStepL = stepTable(stepIndexL)
currentStepR = stepTable(stepIndexR)
predictedValueL = 0
predictedValueR = 0
' Output compressed data (4 bite to sample)
Dim compressedDataL(0 To 255) As Integer
Dim compressedDataR(0 To 255) As Integer
ReDim FullCompressedL(0) As Integer
ReDim FullCompressedR(0) As Integer
' Arry for decompressed values
Dim decompressedSignalL(0 To 255) As Integer
Dim decompressedSignalR(0 To 255) As Integer
' Load sound from file
Dim m As _MEM, Snd As Long
Snd = _SndOpen("n.mp3")
m = _MemSound(Snd, 0)
Dim a As Long
Do Until a& >= m.SIZE
' Load 256 samples into buffer
predictedValueL = 0
predictedValueR = 0
For i = 0 To 255
If a& >= m.SIZE Then Exit Do
originalSignalL(i) = _MemGet(m, m.OFFSET + a&, Single) * 32768
originalSignalR(i) = _MemGet(m, m.OFFSET + a& + 4, Single) * 32768
a& = a& + 8
Next i
' ADPCM compression for lft and right channel
For i = 1 To UBound(originalSignalL)
' left channel
diffL = originalSignalL(i) - predictedValueL
directionL = 0
If diffL >= 0 Then directionL = 1 Else diffL = -diffL
deltaL = diffL \ currentStepL
If deltaL > 7 Then deltaL = 7
compressedValueL = directionL * 8 + deltaL
compressedDataL(i - 1) = compressedValueL
stepChangeL = (deltaL + 0.5) * currentStepL
If directionL = 0 Then stepChangeL = -stepChangeL
predictedValueL = predictedValueL + stepChangeL
If predictedValueL > 32767 Then predictedValueL = 32767
If predictedValueL < -32768 Then predictedValueL = -32768
decompressedSignalL(i) = predictedValueL
stepIndexL = stepIndexL + deltaL - 4
If stepIndexL < 0 Then stepIndexL = 0
If stepIndexL > 87 Then stepIndexL = 87
currentStepL = stepTable(stepIndexL)
' right channel
diffR = originalSignalR(i) - predictedValueR
directionR = 0
If diffR >= 0 Then directionR = 1 Else diffR = -diffR
deltaR = diffR \ currentStepR
If deltaR > 7 Then deltaR = 7
compressedValueR = directionR * 8 + deltaR
compressedDataR(i - 1) = compressedValueR
stepChangeR = (deltaR + 0.5) * currentStepR
If directionR = 0 Then stepChangeR = -stepChangeR
predictedValueR = predictedValueR + stepChangeR
If predictedValueR > 32767 Then predictedValueR = 32767
If predictedValueR < -32768 Then predictedValueR = -32768
decompressedSignalR(i) = predictedValueR
stepIndexR = stepIndexR + deltaR - 4
If stepIndexR < 0 Then stepIndexR = 0
If stepIndexR > 87 Then stepIndexR = 87
currentStepR = stepTable(stepIndexR)
Print "Current compressed sample value: "; compressedDataR(i); compressedDataL(i); " "
If compresseddataR > 15 Or compressedDataL > 15 Then Print "Compression failure!" 'never printed!
Next i
ReDim signalL(0 To 512) As Integer
ReDim signalR(0 To 512) As Integer
' LowPassFilter decompressedSignalL(), signalL(), 10000, _SndRate
' LowPassFilter decompressedSignalR(), signalR(), 10000, _SndRate
'Play decompressed signal
For i = 0 To UBound(decompressedSignalL)
_SndRaw decompressedSignalL(i) / 32768, decompressedSignalR(i) / 32768
'_SndRaw signalL(i) / 32768, signalR(i) / 32768
Next i
Do Until _SndRawLen < .1
Loop
Loop
_MemFree m
_SndClose Snd
End
Sub LowPassFilter (inputSignal() As Integer, outputSignal() As Integer, cutoffFreq As Single, sampleRate As Single)
Dim kernel(0 To 31) As Single ' Filter coefficients (FIR Window, 32 samples)
Dim sum As Single
Dim normFactor As Single
Dim N As Integer
Dim halfN As Integer
N = UBound(kernel)
halfN = N \ 2
' Creating a low-pass filter (Hamming window)
For i = -halfN To halfN
If i = 0 Then
kernel(i + halfN) = 2 * cutoffFreq / sampleRate
Else
kernel(i + halfN) = Sin(2 * 3.14159 * cutoffFreq * i / sampleRate) / (3.14159 * i)
End If
kernel(i + halfN) = kernel(i + halfN) * (0.54 - 0.46 * Cos(2 * 3.14159 * (i + halfN) / N)) ' Hamming window
Next i
' Normalize kernel
For i = 0 To N
normFactor = normFactor + kernel(i)
Next i
For i = 0 To N
kernel(i) = kernel(i) / normFactor
Next i
' Apply filter to input signal
For i = 0 To UBound(inputSignal)
sum = 0
For j = 0 To N
If i - j >= 0 Then
sum = sum + inputSignal(i - j) * kernel(j)
End If
Next j
outputSignal(i) = Int(sum)
Next i
End Sub

