All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.simiacryptus.util.audio.PercentileLoudnessWindowBuffer.kt Maven / Gradle / Ivy

There is a newer version: 1.0.33
Show newest version
@file:Suppress("unused", "MemberVisibilityCanBePrivate")

package com.simiacryptus.util.audio

import org.slf4j.LoggerFactory
import java.util.*

class PercentileLoudnessWindowBuffer(
    inputBuffer: Deque,
    outputBuffer: Deque,
    continueFn: () -> Boolean,
) : LoudnessWindowBuffer(inputBuffer, outputBuffer, continueFn) {


    // Required number of quiet windows
    var quietWindowMax = 3

    // Threshold for quiet windows
    var quietThreshold = 0.25

    // Maximum number of seconds to flush the buffer
    var flushSeconds = 60.0

    // Minimum number of seconds to flush the buffer
    var minSeconds = 1.0

    // List of RMS values currently in the buffer
    val rmsHeap = ArrayList()

    // List of consecutive quiet window percentiles
    val quietWindow = ArrayList()

    override fun shouldOutput(): Boolean {
        val quietPacket = synchronized(outputPacketBuffer) { outputPacketBuffer.takeLast(quietWindowMax).reduce { a, b -> a + b } }
        val loudness = quietPacket.spectralEntropy
        // Binary search the RMS value in the rmsHeap list
        var index = rmsHeap.binarySearch(loudness)
        // If the index is negative, set it to the negative index - 1
        if (index < 0) index = -index - 1
        // Calculate the percentile of the RMS value
        val percentile = index.toDouble() / rmsHeap.size
        // Calculate the minimum buffer size
        val minBufferSize = AudioRecorder.audioFormat.frameRate * AudioRecorder.audioFormat.frameSize * minSeconds
        // If the buffer size is less than the minimum buffer size, add the percentile to the quiet window and add the RMS value to the rmsHeap list
        val sum = synchronized(outputPacketBuffer) { outputPacketBuffer.map { it.size }.sum() }
        if (minBufferSize > sum) {
            // Add the percentile to the quiet window
            quietWindow.add(percentile)
            // Add the RMS value to the rmsHeap list
            rmsHeap.add(loudness)
            // Sort the rmsHeap list
            rmsHeap.sort()
            // Continue to the next iteration of the loop
            return false
        }
        // While the quiet window size is greater than or equal to the quiet window max, remove the first element
        while (quietWindow.size >= quietWindowMax) quietWindow.removeAt(0)
        // While the quiet window is not empty and the maximum value is greater than the quiet threshold, remove the first element
        while (quietWindow.isNotEmpty() && quietWindow.maxOrNull()!! > quietThreshold) quietWindow.removeAt(0)
        // If the percentile is less than the quiet threshold, add the percentile to the quiet window
        if (percentile < quietThreshold) {
            quietWindow.add(percentile)
            // Otherwise, clear the quiet window
        } else {
            quietWindow.clear()
        }
        // Log the RMS value, percentile, and quiet windows
        AudioRecorder.log.debug(
            "Loudness: %.3f, percentile: %.3f, quiet windows=[%s] (%d samples)".format(
                loudness,
                percentile,
                quietWindow.joinToString(", ") { "%.3f".format(it) },
                quietPacket.samples.size
            )
        )
        // Calculate the maximum buffer size
        val maxBufferSize = AudioRecorder.audioFormat.frameRate * AudioRecorder.audioFormat.frameSize * flushSeconds
        // If the buffer size is greater than the maximum buffer size or the quiet window size is greater than or equal to the quiet window max,
        // add the converted raw to wav byte array to the output buffer, reset the buffer, clear the rmsHeap list, and clear the quiet window
        return if (sum > maxBufferSize || quietWindow.size >= quietWindowMax) {
            // Clear the rmsHeap list
            rmsHeap.clear()
            // Clear the quiet window
            quietWindow.clear()
            // Otherwise, add the RMS value to the rmsHeap list and sort it
            true
        } else {
            // Add the RMS value to the rmsHeap list
            rmsHeap.add(loudness)
            // Sort the rmsHeap list
            rmsHeap.sort()
            false
        }
    }

    companion object {
        // Create a Logger instance for the AudioPump class
        val log = LoggerFactory.getLogger(PercentileLoudnessWindowBuffer::class.java)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy