стиснення голосу

Чим менше бітрейт потоку даних, тим далі можна його передати. Якщо вийде стиснути голос до 1-2 кБ / с, можна буде спілкуватися на відстані до 25 км (з використанням трансивера CC1125). Давайте спробуємо розробити голосовий кодек самостійно, без використання готових рішень на кшталт codec2.

Як влаштований голос? У ньому можна виділити кілька елементів:

  • голосні звуки
  • приголосні - шумові - вибухові: п, к, т ...
  • приголосні - шумові - фрікатівние / свистячі: с, ш, щ, ф, в ...
  • приголосні - сонорні - тремтячі: р
  • приголосні - сонорні - носові: м, н

Голосні звуки можна розглядати як музичні - це чистий тон + його обертони різної амплітуди. Приголосні звуки - це шумові звуки з різними тембром і сонорні (тон + шум).

Голосні і приголосні здорово розрізняються по своїй інформативності, порівняйте:

Іронія полягає в тому, що голосні звуки дуже легко описати невеликим набором параметрів. У них немає частот, некратних частоті основного тону, тому все опис зводиться до кількох значень: частота основного тону + амплітуди гармонік. Причому частота домінанти повинна бути виміряна точно (з точністю до 16 біт), а ось амплітуди гармонік терплять і дуже сильну децимації - тому кожну амплітуду можна стиснути до 1 байта або навіть полубайта.

Давайте почнемо з голосних, якщо вже їх так легко описати. Я розробляв алгоритм на Python, просто тому що в ньому це реально швидко і просто.

Читання звукового файлу

Я записав звук «а» у власному виконанні та у виконанні дівчини, і зберіг його в сирому вигляді з дікретізаціей 8кГц у вигляді 16-бітних знакових цілих за допомогою Audacity. Зробимо функцію для читання такого файлу:

Я зберігаю тільки 800 відліків, тобто 100мс звуку - на такому відрізку ще можна прийняти сигнал стаціонарним, незмінні. Наступні фрейми потім проаналізуємо черговими проходами алгоритму. Побудуємо осциллограмму отриманого звуку:

стиснення голосу

побудова спектра

Обчислимо перетворення Фур'є для отриманого звуку. Фур'є повертає комплексну амплітуду, з якою можна обчислити амплітуду і фазу. Вухо практично невідчутно до фази, тому ми можемо заощадити половину бітрейта, повністю усунувши її - залишимо тільки амплітуду, обчисливши її функцією abs.

стиснення голосу

Гарний спектр, правда? Збільшимо цікавить нас фрагмент:

стиснення голосу

Добре видно основний тон і його обертони, спектр має періодичну структуру.

Положення кожного піку визначається співвідношенням: freq = samples / period. Абсциса піку дорівнює відношенню довжини фрейму в семплах (в нашому випадку 800) до періоду хвилі.

Правда, є одна проблема: якщо взяти чистий синус з частотою, що не потрапляє в обрану частотну сітку, то після перетворення Фур'є він перетвориться не в дельта-імпульс (одиничний сплеск), а в якусь розмазала фігуру:

Щоб зменшити цей ефект, необхідно застосувати до сигналу так зване «вікно». Я помножу сигнал на вікно Хеннінг.

Червона лінія - спектр вихідного сигналу, зелена - спектр сигналу з вікном Хеннінг:

стиснення голосу

Стало набагато краще: піки виділені сильніше, їх полушіріна менше і в спектрі менше шуму.

побудова кепстра

Тут вже видно все, що нам потрібно, але як програмно знайти піки і їх амплітуди? Проходити звичайним пошуком локального максимуму - невдячна справа: піки можуть бути злегка зміщені, дубльовані, і так ми знайдемо тільки цілу частину періоду, а він може бути дробовим. Як же нам тоді визначити цей період? Тим же способом, як ми визначали періоди в початковому звуковому сигналі, перетворенням Фур'є. Тільки потрібно спочатку логаріфміровать наш спектр, щоб сильніше виділити піки.

стиснення голосу

І застосувати до цього перетворення Фур'є:

стиснення голосу

Те, що ми побудували, називається прикольним словом «кепстра» (Cepstrum) - з назви зрозуміло, що це є чимось на зразок звернення спектра.

Пошук фундаментальної частоти

У ньому нам потрібен тільки перший пік, чиє становище буде в точності так само періоду шуканого основного тону. Ми знайдемо цей пік звичайним пошуком глобального максимуму, обмеживши область пошуку частотами 80..270 Гц, тому що саме в цьому діапазоні лежать основні частоти голосів дорослих людей. У нашому випадку це діапазон періодів 30..100 (8000 / 270..8000 / 80).

У моєму випадку фундаментальна частота дорівнювала 113Гц, а у моєї дівчини - рівно 200 Гц, що добре співвідноситься з цитатою з Вікіпедії:

запис обертонів

Все, тепер можна повернутися до спектру, пройти по всіх гармоникам знайденої основної частоти і записати їх амплітуду. Я трохи розширюю діапазони частот обертонів, щоб знайти суму всього піку (адже піки розмазані через розбіжність сітки частот з основною частотою).

Навіть дев'ята гармоніка має амплітуду, порівнянну з амплітудою основної частоти, тому потрібно записати досить багато обертонів, мінімум 8-10. З іншого боку, нам достатньо обмежитися смугою в 4кГц, вищі гармоніки вже не так потрібні для передачі голосу.

упаковка параметрів

Для опису одного фрейму з голосом (10мс в нашому випадку) потрібно:

  • фундаментальна частота - 2 байта
  • N * амплітуда обертони - N / 2 байт

Зазвичай достатньо не більше 10 обертонів, тобто характеристика займе 2 + 5 = 7 байт. Вихідний фрейм важив 1600 байт, тобто ступінь стиснення складає

230 раз. Але потрібно розуміти, що так ми стиснули тільки голосні звуки, ще залишилися приголосні - які, як на зло, передають куди більше інформації.

Розпакування звуку і порівняння

Разжатие знову переключитись можна було б зробити через зворотне перетворення Фур'є, але зробимо ще простіше - сгенерируем синусоїди потрібних частот і амплітуд, і складемо їх все один з одним.

Відкриємо в Audacity вихідний файл і відновлений, і порівняємо осцилограми:

стиснення голосу

стиснення голосу

Досить схоже. На слух теж схоже, причому 10 гармонік звучать набагато краще, ніж 8.

Схожі статті