Волновая декомпрессия Python u-Law (MULAW) в необработанный волновой сигнал
Я погуглил эту проблему за последние 2 недели и не смог найти алгоритм или решение. У меня есть какой-то короткий WAV-файл, но он имеет MULAW-сжатие и Python, похоже, не имеет функции внутри wave.py
это может успешно распаковать его. Поэтому я взял на себя обязательство построить декодер на python.
Я нашел некоторую информацию о MULAW в основных элементах:
Поэтому мне нужно некоторое руководство, так как я не знаю, как приблизиться к переходу от подписанного короткого целого к полноволновому сигналу. Это моя первоначальная мысль из того, что я собрал до сих пор:
Итак, из вики я получил уравнение для сжатия и распаковки по u-закону:
Таким образом, судя по уравнению сжатия, похоже, что выход ограничен 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
Так есть ли какой-то алгоритм или важные шаги, которые мне нужно было бы предпринять в форме первого: декомпрессия, второго: квантование: третьего?
Поскольку все, что я нахожу в Google, это как читать .wav
PCM-модулированный тип файла, а не то, как им управлять, если возникает дикое сжатие.
2 ответа
Итак, после поиска в гугле решение было найдено в 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, но я не смог перепроектировать функцию декодирования, чтобы получить двоичный эквивалент функции из википедии.
Наконец, я должен сказать, что в настоящее время я разочарован тем, что библиотека Python не поддерживает все виды алгоритмов сжатия, так как это не просто инструмент, который используют люди, это также ресурс, на котором потребители учатся, поскольку большая часть данных для дальнейшего погружения в Код не доступен или не понятен.
РЕДАКТИРОВАТЬ
После декодирования данных и записи wav файла через wave.py
мне успешно удалось написать новый сырой линейный файл PCM. Это работает... хотя я сначала был настроен скептически.
РЕДАКТИРОВАТЬ 2:::> вы можете найти реальное решение на compressions.py
Я считаю это полезным для преобразования в / из 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)
Python фактически поддерживает декодирование u-Law из коробки:
audioop.ulaw2lin(fragment, width)
Конвертировать звуковые фрагменты в кодировке u-LAW в линейно кодированные звуковые фрагменты. Кодирование u-LAW всегда использует 8-битные выборки, поэтому ширина относится только к ширине выборки выходного фрагмента.