Skip to content

Алгоритм вычисления пауз

sharkovadarya edited this page Dec 11, 2018 · 3 revisions

Для вычисления пауз производится следующая калибровка: перед началом записи выступления выводится обратный отсчёт, во время которого пользователь молчит, а приложение определяет "уровень тишины".

Входные данные:

  • для определения громкости и тишины/речи одного фрагмента записи: массив целых чисел типа Short, полученный в результате вызова метода read() у экземпляра AudioRecord
  • для определения уровней громкости всей записи: отсортированный по возрастанию список громкостей всех фрагментов записи

Выходные данные:

  • для определения громкости: число типа Double, равное громкости фрагмента
  • для определения уровней громкости всей записи: тройка чисел типа Double, соответствующих минимальной, максимальной и средней громкостям

Как происходит калибровка:

Перед началом записи происходит пятисекундный обратный отсчёт, во время которого пользователь молчит. При этом происходит запись аудио (т.е. естественного шума помещения) в буфер. Вычисляются уровни громкости записи. Рассчитывается т.н. "уровень тишины" как:

(avgLevel + maxLevel) / 2

(avgLevel — средний уровень громкости, maxLevel — максимальный уровень громкости)

Как вычисляется громкость фрагмента:

Метод read() класса AudioRecord записывает целые числа в массив типа ShortArray. Проходим по этому массиву и вычисляем amplitude — среднее квадратическое всех значений . Громкость фрагмента вычисляется как

20 * log10(amplitude).

Но нам удобнее не брать квадратный корень для среднего квадратического, поэтому мы считаем среднее арифметическое суммы квадратов и умножаем не на 20, а на 10.

Псевдокод:

v = 0.0
for (i in 0 to buffer.length)
    v += audioBuffer[i] * audioBuffer[i]
amplitude = v / buffer.length
return if (amplitude > 0) 10 * log10(amplitude) else 0.0

Как определяется тишина

Заводим два счётчика: счётчик фрагментов, являющихся тишиной, и общих счётчик фрагментов.

Полученное значение громкости фрагмента сравнивается с уровнем тишины (выше описано, как он вычисляется). Если оно ниже уровня тишины, фрагмент считается тишиной, иначе речью. Увеличиваем общий счётчик и, если надо, счётчик фрагментов, являющихся тишиной.

Как вычисляется объём пауз:

Объём пауз вычисляется по формуле:

silentFragmentsCounter/totalFragmentsCounter

Псевдокод вычисления объёма пауз:

totalFragmentsCounter = 0
silentFragmentsCounter = 0

while (recording)
    record.read()
    volume = calculateVolume(record)
    volumeLevelsList.add(volume)
    if (volume < silenceLevel)
        silentFragmentsCounter++
    totalFragmentsCounter++

silencePercentage = silentFragmentsCounter / totalFragmentsCounter

volumeLevelsList сортируется и используется для определения минимального, максимального и среднего уровней громкости фрагмента.

Информация по каждому слайду

Аналогичным образом считается информация по каждому слайду (заводятся счётчики silentFragmentsCounterOnSlide и totalFragmentsCounterOnSlide, обнуляющиеся при переходе к следующему слайду).

Для каждого слайда выводятся: суммарная доля пауз, средняя длина паузы, количество пауз с длиной выше средней.

Определение суммарной доли пауз на слайде:

Используется булево поле isPause. Если считается, что сейчас (анализ ведётся по ходу записи) не пауза, и был прочитан фрагмент тишины, начинаем считать, что сейчас пауза, и записываем время начала паузы. Если сейчас пауза и был прочитан фрагмент речи, то начинаем считать, что сейчас не пауза, и сохраняем время, в течение которого длилась пауза. Сохранённые длины пауз используются для вычисления средней длины паузы и определения количества пауз с длиной выше средней.

while (recording)
    ...
    if (fragmentVolume < silenceLevel)
        if (not isPause)
            isPause = true
            pauseStartTime = currentTime
        silentFragmentsCounterOnSlide++
    else if (isPause)
        pausesPerSlide.add(currentTime - pauseStartTime) // list of pause lengths
        isPause = false
Clone this wiki locally