Create MapConfigSchema utility function

This commit is contained in:
2020-03-20 17:01:30 +01:00
parent c28ae23774
commit 900d3849f1
11 changed files with 203 additions and 56 deletions

View File

@@ -13,9 +13,17 @@ import io.smnp.type.matcher.Matcher.Companion.listOfMatchers
import io.smnp.type.matcher.Matcher.Companion.mapOfMatchers
import io.smnp.type.matcher.Matcher.Companion.ofType
import io.smnp.type.model.Value
import io.smnp.util.config.MapConfig
import io.smnp.util.config.MapConfigSchema
class MidiFunction : Function("midi") {
private val schema = MapConfigSchema()
.optional("bpm", ofType(INT), Value.int(120))
.optional("ppq", ofType(INT))
.optional("output", ofType(STRING))
.optional("play", ofType(BOOL))
override fun define(new: FunctionDefinitionTool) {
new function vararg(
listOf(NOTE, INT, STRING),
@@ -27,7 +35,7 @@ class MidiFunction : Function("midi") {
throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded")
}
Midi.with(unwrapConfig(config)).play(unwrappedLines)
Midi.with(schema.parse(config)).play(unwrappedLines)
Value.void()
}
@@ -39,7 +47,7 @@ class MidiFunction : Function("midi") {
throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded")
}
Midi.with(emptyMap()).play(unwrappedLines)
Midi.with(MapConfig.EMPTY).play(unwrappedLines)
Value.void()
}
@@ -54,7 +62,7 @@ class MidiFunction : Function("midi") {
throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded")
}
Midi.with(unwrapConfig(config)).play(unwrappedChannels)
Midi.with(schema.parse(config)).play(unwrappedChannels)
Value.void()
}
@@ -66,7 +74,7 @@ class MidiFunction : Function("midi") {
throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded")
}
Midi.with(emptyMap()).play(unwrappedChannels)
Midi.with(MapConfig.EMPTY).play(unwrappedChannels)
Value.void()
}
@@ -76,21 +84,4 @@ class MidiFunction : Function("midi") {
Value.void()
}
}
private fun unwrapConfig(config: Value): Map<String, Any> {
return (config.unwrap() as Map<String, Any>)
.map { (key, value) ->
key to when (key) {
"bpm" -> value as? Int
?: throw CustomException("Invalid parameter type: 'bpm' is supposed to be of int type")
"ppq" -> value as? Int
?: throw CustomException("Invalid parameter type: 'ppq' is supposed to be of int type")
"output" -> value as? String
?: throw CustomException("Invalid parameter type: 'output' is supposed to be of string type")
"play" -> value as? Boolean
?: throw CustomException("Invalid parameter type: 'play' is supposed to be of bool type")
else -> value
}
}.toMap()
}
}

View File

@@ -12,6 +12,7 @@ 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
import io.smnp.util.config.MapConfig
class MidiHelpFunction : Function("midiHelp") {
override fun define(new: FunctionDefinitionTool) {
@@ -58,7 +59,7 @@ class MidiHelpFunction : Function("midiHelp") {
if (index > 0) {
println(it)
Midi
.with(mapOf("bpm" to bpm))
.with(MapConfig(mapOf(Value.string("bpm") to Value.int(bpm))))
.play(mapOf(channel to listOf(listOf("i:$instrument", it))))
Thread.sleep(100)
}

View File

@@ -1,5 +1,6 @@
package io.smnp.ext.midi
import io.smnp.util.config.MapConfig
import java.io.File
import javax.sound.midi.MidiSystem
import javax.sound.midi.Sequence
@@ -7,7 +8,6 @@ import javax.sound.midi.Sequencer
object Midi {
private const val DEFAULT_PPQ = 1000
private const val DEFAULT_BPM = 120
private const val MIDI_FILE_TYPE = 1
private val sequencer = MidiSystem.getSequencer()
private val synthesizer = MidiSystem.getSynthesizer()
@@ -28,38 +28,38 @@ object Midi {
sequencer.stop()
}
fun with(config: Map<String, Any>): SequenceExecutor {
fun with(config: MapConfig): SequenceExecutor {
return SequenceExecutor(sequencer, config)
}
class SequenceExecutor(private val sequencer: Sequencer, private val config: Map<String, Any>) {
class SequenceExecutor(private val sequencer: Sequencer, private val config: MapConfig) {
fun play(lines: List<List<Any>>) {
val sequence = Sequence(Sequence.PPQ, (config.getOrDefault("ppq", DEFAULT_PPQ) as Int))
val sequence = Sequence(Sequence.PPQ, config.getUnwrappedOrDefault("ppq", DEFAULT_PPQ))
provideCompiler(config).compileLines(lines, sequence)
play(sequence)
writeToFile(sequence)
}
private fun provideCompiler(config: Map<String, Any>): SequenceCompiler =
private fun provideCompiler(config: MapConfig): SequenceCompiler =
if (config.containsKey("ppq")) PpqSequenceCompiler()
else DefaultSequenceCompiler()
private fun play(sequence: Sequence) {
(config.getOrDefault("play", true) as Boolean).takeIf { it }?.let {
config.getUnwrappedOrDefault("play", true).takeIf { it }?.let {
playSequence(sequence) {
Midi.sequencer.tempoInBPM = (config.getOrDefault("bpm", DEFAULT_BPM) as Int).toFloat()
sequencer.tempoInBPM = (config["bpm"].value as Int).toFloat()
}
}
}
private fun writeToFile(sequence: Sequence) {
config.getOrDefault("output", null)?.let {
MidiSystem.write(sequence, MIDI_FILE_TYPE, File(it as String))
config.getUnwrappedOrDefault<String?>("output", null)?.let {
MidiSystem.write(sequence, MIDI_FILE_TYPE, File(it))
}
}
fun play(channels: Map<Int, List<List<Any>>>) {
val sequence = Sequence(Sequence.PPQ, (config.getOrDefault("ppq", DEFAULT_PPQ) as Int))
val sequence = Sequence(Sequence.PPQ, config.getUnwrappedOrDefault("ppq", DEFAULT_PPQ))
provideCompiler(config).compileChannels(channels, sequence)
play(sequence)
writeToFile(sequence)