diff --git a/telethon/utils.py b/telethon/utils.py index b3075005..f7509227 100644 --- a/telethon/utils.py +++ b/telethon/utils.py @@ -1141,6 +1141,72 @@ def get_appropriated_part_size(file_size): raise ValueError('File size too large') +def encode_waveform(waveform): + """ + Encodes the input ``bytes`` into a 5-bit byte-string + to be used as a voice note's waveform. See `decode_waveform` + for the reverse operation. + + Example + .. code-block:: python + + chat = ... + file = 'my.ogg' + + # Send 'my.ogg' with a ascending-triangle waveform + client.send_file(chat, file, attributes=[types.DocumentAttributeAudio( + duration=7, + voice=True, + waveform=utils.encode_waveform(bytes(range(2 ** 5)) # 2**5 because 5-bit + )] + + # Send 'my.ogg' with a square waveform + client.send_file(chat, file, attributes=[types.DocumentAttributeAudio( + duration=7, + voice=True, + waveform=utils.encode_waveform(bytes((31, 31, 15, 15, 15, 15, 31, 31)) * 4) + )] + """ + bits_count = len(waveform) * 5 + bytes_count = (bits_count + 7) // 8 + result = bytearray(bytes_count + 1) + + for i in range(len(waveform)): + byte_index, bit_shift = divmod(i * 5, 8) + value = (waveform[i] & 0b00011111) << bit_shift + + or_what = struct.unpack('> bit_shift) & 0b00011111 + + byte_index, bit_shift = divmod(value_count - 1, 8) + if byte_index == len(waveform) - 1: + value = waveform[byte_index] + else: + value = struct.unpack('> bit_shift) & 0b00011111 + return bytes(result) + + class AsyncClassWrapper: def __init__(self, wrapped): self.wrapped = wrapped