Хорошо, у меня возникла эта проблема с алгоритмом сжатия uLaw с PCM тип файла wav . И вот что я обнаружил, так это то, что дополнение к двум делает своего рода отрицательное значение некоторого двоичного числа , как можно увидеть здесь . И после консультации с wikipedia я счел это верным.
Парень объяснил это тем, что нашел least significant bit
и перевернул все после него. Должен сказать, что все вышеперечисленные решения не сильно мне помогли. Когда я попробовал 0x67ff
, он дал мне какой-то результат вместо -26623
. Теперь решения могли бы сработать, если бы кто-то знал, что least significant bit
сканирует список данных, но я не знал, так как данные в PCM различаются. Итак, вот мой ответ:
max_data = b'\xff\x67' #maximum value i've got from uLaw data chunk to test
def twos_compliment(short_byte): # 2 bytes
short_byte = signedShort(short_byte) # converting binary string to integer from struct.unpack i've just shortened it.
valid_nibble = min([ x*4 for x in range(4) if (short_byte>>(x*4))&0xf ])
bit_shift = valid_nibble + min( [ x for x in [1,2,4,8] if ( ( short_byte>>valid_nibble )&0xf )&x ] )
return (~short_byte)^( 2**bit_shift-1 )
data = 0x67ff
bit4 = '{0:04b}'.format
bit16 = lambda x: ' '.join( map( bit4, reversed([ x&0xf, (x>>4)&0xf, (x>>8)&0xf, (x>>12)&0xf ]) ) )
# print( bit16(0x67ff) , ' : ', bit16( twos_compliment( b'\xff\x67' ) ) )
# print( bit16(0x67f0) , ' : ', bit16( twos_compliment( b'\xf0\x67' ) ) )
# print( bit16(0x6700) , ' : ', bit16( twos_compliment( b'\x00\x67' ) ) )
# print( bit16(0x6000) , ' : ', bit16( twos_compliment( b'\x00\x60' ) ) )
print( data, twos_compliment(max_data) )
Теперь, поскольку код не читается, я проведу вас через эту идею.
## example data, for testing... in general unknown
data = 0x67ff # 26623 or 0110 0111 1111 1111
Это просто любое шестнадцатеричное значение, мне нужно было проверить, чтобы быть уверенным, но в целом это может быть что угодно в диапазоне int . Поэтому, чтобы не зацикливаться на целой связке 65535 значений short integer
, может быть, я решил разделить ее на nibbles (4 бита). Это можно сделать так, если вы раньше не использовали bitwise operators
.
nibble_mask = 0xf # 1111
valid_nibble = []
for x in range(4): #0,1,2,3 aka places of bit value
# for individual bits you could go 1<<x as you will see later
# x*4 is because we are shifting bit places , so 0xFA>>4 = 0xF
# so 0x67ff>>0*4 = 0x67ff
# so 0x67ff>>1*4 = 0x67f
# so 0x67ff>>2*4 = 0x67
# so 0x67ff>>3*4 = 0x6
# and nibble mask just makes it confided to 1 nibble so 0xFA&0xF=0xA
if (data>>(x*4))&nibble_mask: valid_nibble.append(x*4) # to avoid multiplying it with 4 later
Итак, мы ищем least significant bit
, поэтому здесь достаточно min(valid_nibble )
. Здесь мы получили место, где находится первый активный (с установленным битом) клев. Теперь нам просто нужно найти, где в нужном клеве наш первый установленный бит.
bit_shift = min(valid_nibble)
for x in range(4):
# in my example above [1,2,4,8] i did this to spare python calculating
ver_data = data>>min(bit_shift ) # shifting from 0xFABA to lets say 0xFA
ver_data &= nibble_mask # from 0xFA to 0xA
if ver_data&(1<<x):
bit_shift += (1<<x)
break
Теперь мне нужно кое-что прояснить, поскольку видение ~
и ^
может сбить с толку людей, которые к этому не привыкли:
XOR
: ^
: 2 номера необходимы
Эта операция довольно нелогична: для каждых 2 битов она сканирует, если оба равны 1 или 0, это будет 0, для всего остального 1.
0b10110
^0b11100
---------
0b01010
И еще один пример:
0b10110
^0b11111
---------
0b01001
1's complement
: ~
- другой номер не требуется
Эта операция переворачивает каждый бит числа. Это очень похоже на то, что мы ищем, но не оставляет младший значащий бит .
0b10110
~
0b01001
И как мы можем видеть здесь, комплимент 1 такой же, как и полный бит числа XOR.
Теперь, когда мы поняли друг друга, мы получим two's complement
, восстановив все биты до младший значащий бит в в дополнение .
data = ~data # one's complement of data
Это, к сожалению, перевернуло все биты в нашем номере, поэтому нам просто нужно найти способ перевернуть числа, которые мы хотим. Мы можем сделать это с bit_shift
, так как это битовая позиция нашего бита, которую мы должны сохранить. Таким образом, при вычислении количества данных, которое может содержать некоторое количество битов, мы можем сделать это с помощью 2**n
, а для клева мы получаем 16, поскольку мы вычисляем 0 в значениях битов.
2**4 = 16 # in binary 1 0000
Но нам нужны байты после 1
, чтобы мы могли использовать это, чтобы уменьшить значение на 1, и мы можем получить.
2**4 -1 = 15 # in binary 0 1111
Итак, давайте рассмотрим логику в конкретном примере:
0b110110
lsb = 2 # binary 10
~0b110110
----------
0b001001 # here is that 01 we don't like
0b001001
^0b000011 # 2**2 = 4 ; 4-1 = 3 in binary 0b11
---------
0b001010
Я надеюсь, что это помогло бы вам или любому новичку, у которого была такая же проблема, и исследовали их ** поиск решения. Имейте в виду, что этот код, который я написал, является кодом Франкенштейна, поэтому я должен был объяснить это. Это может быть сделано красивее, если кто-то хочет сделать мой код красивым, пожалуйста, будьте моим гостем.