Python u-Law(MULAW)波解压缩到原始波信号

时间:2018-04-29 10:48:13

标签: python pcm waveform mu-law

我在过去两周搜索了这个问题,但却无法找到算法或解决方案。我有一些简短的.wav文件,但它有MULAW压缩,python似乎没有wave.py内部可以成功解压缩的功能。所以我自己在python中构建了一个解码器。

我在基本元素中找到了有关MULAW的一些信息:

  1. Wikipedia
  2. A-law u-Law comparison
  3. Some c-esc codec library
  4. 所以我需要一些指导,因为我不知道如何从有符号的短整数到全波信号。这是我迄今为止收集到的最初想法:

    所以从wiki我得到了u-law压缩和解压缩的等式:

    压缩:compression

    解压缩:enter image description here

    因此,通过压缩方程判断,输出似乎限制在-1 {+1的float范围内,并且使用从-32,768到32,767的带符号短整数,因此看起来我需要转换它在特定范围内从 short int float

    现在,说实话,我之前听说过量化,但我不确定是否应该首先尝试去量化然后解压缩或以其他方式,或者即使在这种情况下它是相同的事情......教程/文档可能有点棘手的术语。

    我正在使用的wave文件应包含' A'听起来像语音合成,我可能通过比较一些音频软件和自定义波分析仪中的2个波形来验证成功,但我真的想减少这个过程的试错部分。

    所以我想到的是:

    u = 0xff
    data_chunk = b'\xe7\xe7' # -6169
    data_to_r1 = unpack('h',data_chunk)[0]/0xffff # I suspect this is wrong,
    #                                             # but I don't know what else
    
    u_law = ( -1 if data_chunk<0 else 1 )*( pow( 1+u, abs(data_to_r1)) -1 )/u   
    

    因此,我需要以第一次解压缩第二次量化:第三
    由于我在谷歌上找到的所有内容都是如何阅读.wav PCM调制文件类型,而不是如果出现野外压缩时如何管理它。

3 个答案:

答案 0 :(得分:1)

因此,在搜索谷歌之后,在github中找到了解决方案(参见图)。我搜索了许多算法,发现1在有损压缩的误差范围内。 对于来自30的正值的u法则是&gt; 1和来自-32的负值 - > -1

老实说,我认为这个解决方案已经足够但不完全按照每个方程式,但它现在是最好的解决方案。此代码直接从gcc9108 audio codec

转录为python
def uLaw_d(i8bit):
    bias = 33
    sign = pos = 0
    decoded = 0

    i8bit = ~i8bit
    if i8bit&0x80:
        i8bit &= ~(1<<7)
        sign = -1

    pos = ( (i8bit&0xf0) >> 4 ) + 5
    decoded = ((1 << pos) | ((i8bit & 0x0F) << (pos - 4)) | (1 << (pos - 5))) - bias
    return decoded if sign else ~decoded

def uLaw_e(i16bit):
    MAX = 0x1fff
    BIAS = 33
    mask = 0x1000
    sign = lsb = 0
    pos = 12 

    if i16bit < 0:
        i16bit = -i16bit
        sign = 0x80

    i16bit += BIAS

    if ( i16bit>MAX ): i16bit = MAX 

    for x in reversed(range(pos)):
        if i16bit&mask != mask and pos>=5:
            pos = x
            break

    lsb = ( i16bit>>(pos-4) )&0xf
    return ( ~( sign | ( pos<<4 ) | lsb ) )

通过测试:

print( 'normal :\t{0}\t|\t{0:2X}\t:\t{0:016b}'.format(0xff) )
print( 'encoded:\t{0}\t|\t{0:2X}\t:\t{0:016b}'.format(uLaw_e(0xff)) )
print( 'decoded:\t{0}\t|\t{0:2X}\t:\t{0:016b}'.format(uLaw_d(uLaw_e(0xff))) )

并输出:

normal :    255     |   FF  :   0000000011111111
encoded:    -179    |   -B3 :   -000000010110011
decoded:    263     |   107 :   0000000100000111

正如你可以看到263-255 = 8这是在界限范围内。当我尝试实现G.711中描述的seeemmmm方法时,那个用户Oliver Charlesworth建议我查看,数据中最大值的解码值为-8036,接近uLaw规格的最大值,但我无法对解码函数进行逆向工程,以从维基百科中获取二进制等价函数。

最后,我必须说我目前很失望python库不支持所有类型的压缩算法,因为它不仅仅是人们使用的工具,它也是消费者学习的资源python,因为大多数用于进一步深入代码的数据不易获得或可理解。

编辑

解码数据并通过wave.py写入wav文件后,我成功地成功编写了一个新的原始线性PCM文件。这有效......即使我一开始对此持怀疑态度。

编辑2: ::&gt;你可以在compressions.py

找到真正的解决方案

答案 1 :(得分:1)

我发现这对从numpy数组到ulaw的转换很有帮助。

import audioop

def numpy_audioop_helper(x, xdtype, func, width, ydtype):
    '''helper function for using audioop buffer conversion in numpy'''
    xi = np.asanyarray(x).astype(xdtype)
    if np.any(x != xi):
        xinfo = np.iinfo(xdtype)
        raise ValueError("input must be %s [%d..%d]" % (xdtype, xinfo.min, xinfo.max))
    y = np.frombuffer(func(xi.tobytes(), width), dtype=ydtype)
    return y.reshape(xi.shape)

def audioop_ulaw_compress(x):
    return numpy_audioop_helper(x, np.int16, audioop.lin2ulaw, 2, np.uint8)

def audioop_ulaw_expand(x):
    return numpy_audioop_helper(x, np.uint8, audioop.ulaw2lin, 2, np.int16)

答案 2 :(得分:0)

Python实际上支持开箱即用地解码u-Law:

  

AlertDialog.Builder setIcon(int iconId)

     

将u-LAW编码的声音片段转换为线性编码的声音片段。 u-LAW编码始终使用8位样本,因此宽度   此处仅指输出片段的样本宽度。

https://docs.python.org/3/library/audioop.html#audioop.ulaw2lin