Волновая декомпрессия Python u-Law (MULAW) в необработанный волновой сигнал - PullRequest
0 голосов
/ 29 апреля 2018

Я погуглил эту проблему за последние 2 недели и не смог найти алгоритм или решение. У меня есть какой-то короткий WAV-файл, но он имеет MULAW-сжатие, и Python, похоже, не имеет функции внутри wave.py, которая может успешно распаковать его. Поэтому я взял на себя обязательство построить декодер на python.

Я нашел некоторую информацию о MULAW в основных элементах:

  1. Википедия
  2. Сравнение по закону А-закона
  3. Некоторая библиотека кодеков c-esc

Так что мне нужно некоторое руководство, так как я не знаю, как приблизиться к переходу от подписанного короткого целого к полноволновому сигналу. Это моя первоначальная мысль из того, что я собрал до сих пор:


Итак, из вики я получил уравнение для сжатия и распаковки по закону:

сжатие: compression

декомпрессия: enter image description here

Таким образом, судя по уравнению сжатия, получается, что вывод ограничен диапазоном float от -1 до +1 и со знаком короткого целого числа от –32 768 до 32 767, так что, похоже, мне нужно преобразовать его из short int до float в определенном диапазоне.

Теперь, если честно, я раньше слышал о квантовании, но я не уверен, стоит ли сначала пытаться деквантовать, а затем декомпрессировать, или другим способом, или даже если в этом случае это то же самое. ... учебники / документация могут быть немного хитрыми с терминологией.

Предполагается, что звуковой файл, с которым я работаю, содержит звук «А», подобный синтезу речи. Вероятно, я смог бы убедиться в успехе, сравнив две формы сигнала в некотором программном обеспечении для звука и в специальном анализаторе волн, но мне бы очень хотелось уменьшить количество проб и ошибок. раздел этого процесса.

Итак, что я имел в виду:

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   

Итак, есть ли какой-то алгоритм или важные шаги, которые мне нужно предпринять в форме first : декомпрессия , second : квантование : третий ?
Поскольку все, что я нахожу в Google, - это как читать тип файла с .wav PCM-модуляцией, а не как управлять им, если возникает дикое сжатие.

Ответы [ 3 ]

0 голосов
/ 31 июля 2018

Python фактически поддерживает декодирование u-Law из коробки:

audioop.ulaw2lin(fragment, width)

Преобразование звуковых фрагментов в кодировке u-LAW в линейно кодированные звуковые фрагменты. Кодирование u-LAW всегда использует 8-битные отсчеты, поэтому ширина здесь относится только к ширине выборки выходного фрагмента.

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

0 голосов
/ 09 июля 2019

Я считаю это полезным для преобразования в / из ulaw с массивами numpy.

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)
0 голосов
/ 02 мая 2018

Итак, после поиска в Google решение было найдено в github (см. Рисунок). Я искал много алгоритмов и нашел 1, который находится в пределах ошибки для сжатия с потерями. Что по закону для положительных значений от 30 -> 1 и для отрицательных значений от -32 -> -1

Если честно, я думаю, что это решение является адекватным, но не вполне для каждого уравнения, скажем так, но пока это лучшее решение. Этот код транскрибируется на python непосредственно с аудиокодека gcc9108

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, что в пределах границ. Когда я попытался реализовать метод seeemmmm, описанный в G.711 , этот добрый пользователь Оливер Чарльзуорт предложил мне взглянуть, декодированное значение для максимума в данных было -8036, что близко к максимуму uLaw spec, но я не смог перепроектировать функцию декодирования, чтобы получить двоичный эквивалент функции из википедии.

Наконец, я должен сказать, что в настоящее время я разочарован тем, что библиотека python не поддерживает все виды алгоритмов сжатия, так как это не просто инструмент, который используют люди, это также ресурс, который потребители изучают, поскольку большая часть данных для Дальнейшее погружение в код не всегда доступно или не понятно.


РЕДАКТИРОВАТЬ

После декодирования данных и записи wav-файла через wave.py мне успешно удалось записать новый необработанный линейный файл PCM. Это работает ... хотя я сначала был настроен скептически.


РЕДАКТИРОВАТЬ 2: ::> вы можете найти реальное решение на compressions.py


...