Create midiHelp() function

This commit is contained in:
2020-03-14 19:40:22 +01:00
parent 769e9bf936
commit afe21e8565
3 changed files with 74 additions and 1 deletions

View File

@@ -2,12 +2,15 @@ package io.smnp.ext
import io.smnp.environment.Environment
import io.smnp.ext.function.MidiFunction
import io.smnp.ext.function.MidiHelpFunction
import io.smnp.ext.midi.MidiSequencer
import org.pf4j.Extension
@Extension
class MidiModule : NativeModuleProvider("smnp.audio.midi") {
override fun functions() = listOf(MidiFunction())
override fun functions() = listOf(MidiFunction(), MidiHelpFunction())
override fun dependencies() = listOf("smnp.music")
override fun onModuleLoad(environment: Environment) {
MidiSequencer.init()

View File

@@ -0,0 +1,67 @@
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.data.entity.Note
import io.smnp.data.enumeration.Pitch
import io.smnp.error.CustomException
import io.smnp.ext.midi.MidiSequencer
import io.smnp.type.enumeration.DataType.*
import io.smnp.type.matcher.Matcher.Companion.ofType
import io.smnp.type.matcher.Matcher.Companion.optional
import io.smnp.type.model.Value
class MidiHelpFunction : Function("midiHelp") {
override fun define(new: FunctionDefinitionTool) {
new function simple(ofType(STRING)) body { _, (command) ->
val cmd = command.value as String
when (cmd.toLowerCase()) {
"instruments" -> MidiSequencer.instruments.forEachIndexed { index, instrument -> println("$index: $instrument") }
else -> throw CustomException("Unknown command '$cmd' - available commands: 'instruments', '<instrumentId>'")
}
Value.void()
}
new function simple(
ofType(INT),
optional(ofType(INT)),
optional(ofType(NOTE)),
optional(ofType(NOTE)),
optional(ofType(INT))
) body { environment, args ->
val instrument = args[0].value as Int
val bpm = args.getOrNull(1)?.value as Int? ?: 120
val begin = args.getOrNull(2) ?: Value.note(Note(Pitch.C, 0, 4, false))
val end = args.getOrNull(3) ?: Value.note(Note(Pitch.H, 5, 4, false))
val channel = args.getOrNull(4)?.value as Int? ?: 1
if(channel > 16) {
throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded")
}
val notes = Value.list(
listOf(Value.string("i:$instrument")) + environment.invokeFunction(
"range",
listOf(begin, end)
).value as List<Value>
).unwrap() as List<Any>
println(MidiSequencer.instruments[instrument])
println("Channel: $channel")
println("BPM: $bpm")
println("Range: ${begin.value} - ${end.value}")
notes.forEachIndexed { index, it ->
if (index > 0) {
println(it)
MidiSequencer.playChannels(mapOf(channel to listOf(listOf("i:$instrument", it))), mapOf("bpm" to bpm))
Thread.sleep(100)
}
}
Value.void()
}
}
}

View File

@@ -25,6 +25,9 @@ object MidiSequencer {
const val ZERO = 0x00
}
val instruments: List<String>
get() = MidiSystem.getSynthesizer().availableInstruments.map { it.toString() }
fun playChannels(channels: Map<Int, List<List<Any>>>, config: Map<String, Any>) {
val sequence = Sequence(Sequence.PPQ, PPQ)