Пять лет назад на Хабре была опубликована статья «Печать и воспроизведение звука на бумаге» — о системе создания и проигрывания спектрограмм. Затем, полтора года назад Meklon опубликовал квест, в котором такая чёрно-белая логарифмическая спектрограмма стала одним из этапов. По авторскому замыслу, её надо было распечатать на принтере, отсканировать смартфоном с приложением-проигрывателем, и воспользоваться таким образом «надиктованным» паролем.


У меня в тот момент не было в досягаемости ни принтера, ни смартфона, так что меня заинтересовали два аспекта задачи:

  1. Как проще всего расшифровать спектрограмму без дополнительных устройств и без дополнительного софта — желательно, прямо в браузере?
  2. Можно ли её расшифровать вообще без софта — «на глаз»?

(Для тех, кто видит спектрограммы впервые, стоит пояснить, что это график, где по горизонтальной оси идёт время воспроизведения, по вертикальной (она логарифмическая) — частота звука, а степень черноты точки обозначает мощность данной частоты в данный момент времени.)

Готовых скриптов для воспроизведения спектрограмм я не нашёл, хотя для обратного преобразования — звука в спектрограмму — легко* находятся примеры, благодаря тому, что функциональность AnalyserNode.getByteFrequencyData() встроена в Web Audio API. А вот для преобразования массива частот в массив PCM для воспроизведения — не обойтись без реализации в скрипте обратного преобразования Фурье (DFT).
*В первом примере в качестве аудиозаписи для спектрального анализа предлагается фрагмент трека "$\Delta M^{-1}_i = -\alpha\sum_{n=1}^N D_i[n]\left[\sum_{j\in C[i]}F_{ji}[n-1]+F \ ext_i[n^{-1}] \right]$" от Aphex Twin: в качестве секретного послания музыкант встроил в этот трек селфи, проявляющееся на логарифмической спектрограмме. К сожалению, в этом примере спектрограмма отображается линейно, так что лицо получается растянутым вверху и сжатым внизу.
По поводу реализации DFT сразу ясно, что такая «числодробилка» на чистом JavaScript будет работать медленно и печально; к счастью, я обнаружил готовый порт библиотеки FFTW («Fastest Fourier Transform in the West») на asm.js — это форма представления низкоуровневого кода, обычно написанного на Си, которую современные браузеры обещают выполнять со скоростью почти как у скомпилированного в машинный код. Обвязку для FFTW, превращающую чёрно-белое изображение в WAV-файл, я взял из ARSS и собственноручно переписал на JavaScript. ARSS принимает изображения, инвертированные по сравнению с PhonoPaper, и я не стал это менять.

Результатом вы можете полюбоваться на tyomitch.github.io/#meklon.png

Внизу видны повторяющиеся горизонтальные полосы — форманты, по положению которых распознаются гласные. Вверху — вертикальные «всплески», соответствующие шумным согласным: более широкие — щелевым (фрикативным), более узкие — смычным. Сонорным же согласным ([р] и [л]) соответствуют «облака» в средних частотах.



Для того, чтобы можно было поиграть со спектрограммой, я приделал примитивную рисовалку, почти целиком скопированную из туториала по рисованию на canvas. Кнопка «Copy» позволяет перевести изображение в красный канал (он игнорируется синтезатором) и попытаться «обвести» звуки.

Википедия пишет: «Считается, что для характеристики звуков речи достаточно выделения четырёх формант». Обведём форманты F2-F4 (F1 почему-то игнорируется синтезатором), и убедимся, что гласные вполне распознаются:



Затем обведём шумные согласные: аффриката [ч] — это [т], плавно переходящее в [ш]; а звонкое [д] от глухого [т] отличается наличием среднечастотных формант. Теперь уже можно различить цифры «шесть» и «де'ить»:



Добавляем тёмно-серым сонорные согласные: заодно заметим, что [р] немного «приподнимает» гласные форманты, а [л] — наоборот, опускает.



Остались недорисованными только губные согласные [б] и [в], но и без них пароль более-менее ясен.

А можно ли нарисовать звук с чистого листа, не обводя спектрограмму аудиозаписи? Скажу честно, у меня не получилось. Может быть, хотите попробовать сами?

Комментарии (13)


  1. DimPal
    04.10.2019 15:21

    Возможно для синтеза речи «на глаз» такая визуализация не самая лучшая. Осмелюсь предположить, что слоги лучше могут быть лучше видны на банальной огибающей громкости. Что касается формант (и причудливое правило поиска четырех формант), то мне это больше напоминает аккорд. Знаете, аккорд в музыке можно записать одной буквой, а гармоник там может быть много, причем в разных октавах по разному. На мой взгляд, если свести гласные к какому-то аналогу музыкальных нот, то будет чуть нагляднее. Только хроматических нот в октаве 12, а для визуализации речи наверно лучше разбить помельче. Тембральный же окрас нужно как то цветами что ли передавать. IMHO подобная визуализация была бы нагляднее.


  1. Quiensabe
    04.10.2019 17:34
    +1

    Очень любопытно!
    Жаль не получается подгрузить свою картинку со спектрограммой, для экспериментов. Пробовал указать ссылку вместо имени файла в ссылке (пример), в редакторе изображение появляется, но воспроизведение не работает, увы.


    1. tyomitch Автор
      04.10.2019 17:57

      Тут сразу две проблемы: во-первых, размер спектрограммы у меня захардкожен (400х225), потому что я боялся, что для больших изображений FFTW не будет успевать отрабатывать «в реальном времени»; во-вторых, правила безопасности запрещают JS-коду, пришедшему с одного домена, работать с данными, пришедшими с другого домена.

      Если хотите поиграть со своими собственными изображениями, то проще всего сохранить мой код (HTML-файл и FFTW.js) на локальный диск, и открывать оттуда. Хрому при этом нужен ещё и флаг --allow-file-access-from-files. Именно так — открывая с локального диска — я свой скрипт и отлаживал.


      1. Quiensabe
        05.10.2019 19:38

        Спасибо! Обязательно попробую.


  1. Meklon
    04.10.2019 18:54

    Круто, спасибо. Помню, что мне приходилось ещё и очень придирчиво выбирать цифры и буквы, чтобы не было разночтений.


    1. tyomitch Автор
      04.10.2019 18:56

      И тем не менее, разночтения были :-D


      1. Meklon
        04.10.2019 19:11

        Я помню)) будем считать, что это было задуманное коварство.


  1. Stiver
    04.10.2019 19:12
    +1

    Звуковиды разрешают глухим говорить по телефону. (с)


  1. TimeCoder
    04.10.2019 21:11
    +1

    Спасибо! Пара вопросов:


    1. Какова ширина окна? Ну в смысле, если по горизонтали время, а вертикали — частоты, мы же не можем построить спектр по одному отчёту сигнала? Как я понимаю, есть скользящее окно (и наверное ещё и домножаемое на оконную функцию Хэмминга), но какова его ширина? Для сигнала 44100 Hz.
    2. Про форманты, можете хотя бы кратко? Просто, я в университете занимался 3й формантой, это было лет 15 назад, и может забыл, но в упор не помню, чтобы в голосе видел 4-ю.


    1. tyomitch Автор
      04.10.2019 22:47

      1. Хороший вопрос! Код DSP я взял из ARSS, не слишком в него вникая — вероятно, именно из-за этого у меня синтезатор игнорирует самые низкие частоты, включая F1. Судя по тому, что в комментариях к генерации фильтра упоминается «Blackman function», то для окна используется именно она, а ширина окна задаётся параметром tbw, в моём случае равным 27 сэмплам. При этом у меня строится не спектр по сигналу, а наоборот, сигнал по спектру; и окно используется только для интерполяции спектра (от 50 пикселей в секунду — к 44100 сэмплам).
      2. Форманта — это просто узкая полоса частот, в которой в какой-то промежуток времени сконцентрировано много энергии. Формант можно выделить очень много (в слове «эс» на КДПВ видно больше десятка), но для анализа речи достаточно первых трёх или четырёх, у остальных просто нет практического применения.


  1. tyomitch Автор
    04.10.2019 22:47

    .


  1. buriy
    05.10.2019 01:07

    А зачем рисовать спектрограмму в логарифмическом виде? Так же ничего не понятно!


  1. FocusReactive
    05.10.2019 14:44

    Интересно! Помню был другой проект, наоборот звук рисовать. Весело pixelscommander.com/interactive-revolution/funkyphone-webaudio-api-music-instrument