Create smnp.audio.mic module
This commit is contained in:
11
app/src/main/resources/presets/mic.mus
Normal file
11
app/src/main/resources/presets/mic.mus
Normal 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
0
modules/mic/build.gradle
Normal file
7
modules/mic/gradle.properties
Normal file
7
modules/mic/gradle.properties
Normal file
@@ -0,0 +1,7 @@
|
||||
version=0.0.1
|
||||
|
||||
pluginVersion=0.1
|
||||
pluginId=smnp.audio.mic
|
||||
pluginClass=
|
||||
pluginProvider=Bartłomiej Pluta
|
||||
pluginDependencies=
|
||||
10
modules/mic/src/main/kotlin/io/smnp/ext/MicrophoneModule.kt
Normal file
10
modules/mic/src/main/kotlin/io/smnp/ext/MicrophoneModule.kt
Normal 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())
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,5 @@ include 'modules:text'
|
||||
include 'modules:midi'
|
||||
include 'modules:music'
|
||||
include 'modules:math'
|
||||
include 'modules:mic'
|
||||
include 'modules:music-tools'
|
||||
Reference in New Issue
Block a user