简体   繁体   中英

Python IMA ADPCM codec

I am developing small streaming audio app, audiochat client. Server uses IMA ADPCM audio codec, framerate 8000, 256 bytes frame size.

I'm using algoritm described here
Refernce compressed sound available here

The quality of decoded sound is poor, and coded sound don't recognising by server as corrected ima adpcm sound.

Please help me to find problem in my code.

# -*-  coding: Utf-8 -*-t
import wave, struct


indexTable=[
            -1, -1, -1, -1, 2, 4, 6, 8,
            -1, -1, -1, -1, 2, 4, 6, 8
            ] 

stepsizeTable=[
              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,   130,   143,
              157,   173,   190,   209,   230,   253,   279,   307,
              337,   371,   408,   449,   494,   544,   598,   658,
              724,   796,   876,   963,  1060,  1166,  1282,  1411,
              1552,  1707,  1878,  2066,  2272,  2499,  2749,  3024,
              3327,  3660,  4026,  4428,  4871,  5358,  5894,  6484,
              7132,  7845,  8630,  9493, 10442, 11487, 12635, 13899,
              15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
              32767
              ] 



def pcm2adpcm(frame): #frame - 1024 Bytes uncompressed

    indexcode = 0
    stepsizecode = 7
    global indexTable
    global stepsizeTable 
    predictedSample = 0
    lstres=list()
    for i in range(0,len(frame)): # Taking bytes
        if (i+1)%2==0:
            binsample=frame[i-1:i+1:]

            originalsample=struct.unpack('h',binsample)[0] # To signed int
            difference = originalsample-predictedSample 
            if difference>=0: 
                newSampleCode=0
            else:
                newSampleCode=8
                difference=-difference
            mask=4
            tempStepsize=stepsizecode 
            for i in range(0,3):
                if difference>=tempStepsize:
                    newSampleCode|=mask
                    difference-=tempStepsize
                tempStepsize>>=1
                mask>>=1
            lstres.append(newSampleCode)
            difference=0
            if newSampleCode&4:
                difference+=stepsizecode 
            if newSampleCode&2:
                difference+=stepsizecode>>1
            if newSampleCode&1:
                difference+=stepsizecode>>2
            difference+=stepsizecode>>3
            if newSampleCode&8:
                difference=-difference
            predictedSample+=difference 
            if predictedSample>32767:
                predictedSample=32767
            if predictedSample<-32767:
                predictedSample=-32767
            indexcode+=indexTable[newSampleCode]
            if indexcode<0:
                indexcode=0
            elif indexcode>88:
                indexcode=88
            stepsizecode=stepsizeTable[indexcode]
    resultBinary=''
    for i in range(0,len(lstres)):
        if (i+1)%2==0:
            #print lstres[i], lstres[i-1], (lstres[i]<<4)|lstres[i-1]
            resultBinary+=chr((lstres[i]<<4)|lstres[i-1])

    return resultBinary

def adpcm2pcm(frame): #frame - 256 Bytes compressed
    index = 0
    stepsize  = 7
    global indexTable
    global stepsizeTable
    newSample = 0


    resultBinary=''

    for i in range(0,len(frame)): # Taking bytes

            binsample=frame[i]

            originalsample=ord(frame[i]) # 
            secoundsample=originalsample>>4 # Secound 4 bit sample
            firstsample=(secoundsample<<4)^originalsample # first 4 bit sample
            lst=[firstsample,secoundsample] # To list

            for originalsample in lst: 

                difference=0

                if originalsample & 4:
                    difference+=stepsize 

                if originalsample & 2:
                    difference+=stepsize >> 1

                if originalsample & 1:
                    difference+=stepsize >> 2  

                difference+=stepsize >> 3

                if originalsample & 8:
                    difference=-difference




                newSample+=difference

                if newSample>32767:
                    newSample=32767

                elif newSample<-32767:
                    newSample=-32767



                resultBinary+=struct.pack('h',newSample) 


                index+=indexTable[originalsample]
                if index<0:
                    index = 0
                elif index>88:
                    index = 88
                stepsize=stepsizeTable[index]


    return resultBinary

if __name__ == '__main__':

    #===========================================================================
    # fout=wave.open('res.wav', 'wb')
    # fout.setnchannels(1)
    # fout.setsampwidth(2)
    # fout.setframerate(8000)
    # f=open('1.wav','rb')
    # f.seek(60)
    # for i in range (0,153):
    #    out=adpcm2pcm(f.read(256))
    #    fout.writeframesraw(out)
    # fout.close()
    #===========================================================================

    f=open('1.wav','rb')
    header=f.read(60)
    foutcompr=open('resCompr.wav','wb')
    foutcompr.write(header)
    fout=wave.open('res.wav', 'rb')
    n=0
    while n<fout.getnframes():
        foutcompr.write(pcm2adpcm(fout.readframes(512)))
        n+=512
    foutcompr.close()

    print "finish"

I can see one problem:

elif indexcode>88:
    indexcode=88
stepsizecode=stepsizeTable[indexcode]

should be:

elif indexcode>88:
    indexcode=88
    stepsizecode=stepsizeTable[indexcode]

That's a pretty significant difference.

Aside from that I would try generating a sine test tone, running that through the algorithm and examining the result. I'd also try to rule out any issues with the conversion between bytes and shorts.

Also, the documentation gives some test vectors that you could use to step through with a debugger.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM