Create smnp.audio.mic module

This commit is contained in:
2020-03-17 11:29:01 +01:00
parent 165e572203
commit ec6eeadfa8
10 changed files with 149 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
import smnp.audio.mic;
import smnp.io;
import smnp.collection;
import smnp.system;
if(__param__.containsKey("help")) {
println("Display microphone level in real time in order to check and adjust noise and silence thresholds in wait() function");
exit(1);
}
micLevel();

0
modules/mic/build.gradle Normal file
View File

View File

@@ -0,0 +1,7 @@
version=0.0.1
pluginVersion=0.1
pluginId=smnp.audio.mic
pluginClass=
pluginProvider=Bartłomiej Pluta
pluginDependencies=

View File

@@ -0,0 +1,10 @@
package io.smnp.ext
import io.smnp.ext.function.MicLevelFunction
import io.smnp.ext.function.WaitFunction
import org.pf4j.Extension
@Extension
class MicrophoneModule : NativeModuleProvider("smnp.audio.mic") {
override fun functions() = listOf(WaitFunction(), MicLevelFunction())
}

View File

@@ -0,0 +1,17 @@
package io.smnp.ext.function
import io.smnp.callable.function.Function
import io.smnp.callable.function.FunctionDefinitionTool
import io.smnp.callable.signature.Signature.Companion.simple
import io.smnp.ext.mic.TestMicrophoneLevelLoop
import io.smnp.type.model.Value
class MicLevelFunction : Function("micLevel") {
override fun define(new: FunctionDefinitionTool) {
new function simple() body { _, _ ->
val printer = TestMicrophoneLevelLoop()
printer.run()
Value.void()
}
}
}

View File

@@ -0,0 +1,19 @@
package io.smnp.ext.function
import io.smnp.callable.function.Function
import io.smnp.callable.function.FunctionDefinitionTool
import io.smnp.callable.signature.Signature.Companion.simple
import io.smnp.ext.mic.SoundListenerLoop
import io.smnp.type.enumeration.DataType.INT
import io.smnp.type.matcher.Matcher.Companion.ofType
import io.smnp.type.model.Value
class WaitFunction : Function("wait") {
override fun define(new: FunctionDefinitionTool) {
new function simple(ofType(INT), ofType(INT)) body { _, (inThreshold, outThreshold) ->
val loop = SoundListenerLoop(inThreshold.value as Int, outThreshold.value as Int)
loop.run()
Value.void()
}
}
}

View File

@@ -0,0 +1,47 @@
package io.smnp.ext.mic
import io.smnp.error.CustomException
import javax.sound.sampled.AudioFormat
import javax.sound.sampled.AudioSystem
import javax.sound.sampled.DataLine
import javax.sound.sampled.TargetDataLine
import kotlin.math.pow
abstract class MicrophoneLevelLoop {
protected abstract fun run(micRmsLevel: Int): Boolean
fun run() {
val format = AudioFormat(44100F, 8, 1, true, false)
val info = DataLine.Info(TargetDataLine::class.java, format)
if (!AudioSystem.isLineSupported(info)) {
throw CustomException("The audio system target line is not supported")
}
val line = AudioSystem.getLine(info) as TargetDataLine
line.open(format)
line.start()
val bytes = ByteArray(line.bufferSize / 5)
while (true) {
line.read(bytes, 0, bytes.size)
if(!run(calculateRms(bytes))) {
break
}
Thread.sleep(10)
}
line.stop()
line.close()
}
private fun calculateRms(audioData: ByteArray): Int {
val sum = audioData.map { it.toLong() }.sum()
val avg = sum / audioData.size.toDouble()
val sumMeanSquare = audioData.map { it.toDouble() }.map { (it - avg).pow(2.0) }.reduce { acc, n -> acc + n }
val averageMeanSquare = sumMeanSquare / audioData.size
return (averageMeanSquare.pow(0.5)).toInt()
}
}

View File

@@ -0,0 +1,18 @@
package io.smnp.ext.mic
class SoundListenerLoop(private val inThreshold: Int, private val outThreshold: Int) : MicrophoneLevelLoop() {
private var noiseReached = false
private var silenceReached = false;
override fun run(micRmsLevel: Int): Boolean {
if(micRmsLevel > inThreshold) {
noiseReached = true
}
if(noiseReached && micRmsLevel < outThreshold) {
silenceReached = true
}
return !(noiseReached && silenceReached)
}
}

View File

@@ -0,0 +1,19 @@
package io.smnp.ext.mic
import kotlin.math.min
class TestMicrophoneLevelLoop : MicrophoneLevelLoop() {
private val MAX_WIDTH = 70
override fun run(micRmsLevel: Int): Boolean {
System.out.printf("\rMicrophone level: [${micRmsLevel.toString().padStart(4)}] [")
val bar = min(micRmsLevel, MAX_WIDTH)
repeat(bar) { print("#") }
repeat(MAX_WIDTH - bar) { print(".") }
print("]${if(micRmsLevel > MAX_WIDTH) "*" else " "}")
return true
}
}

View File

@@ -12,4 +12,5 @@ include 'modules:text'
include 'modules:midi'
include 'modules:music'
include 'modules:math'
include 'modules:mic'
include 'modules:music-tools'