From ff45e7e479902ad45b9dce20b7be9e59680ea0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Fri, 20 Mar 2020 19:41:03 +0100 Subject: [PATCH] Overload synth() and wave() functions --- .../config/{MapConfig.kt => ConfigMap.kt} | 4 ++-- ...{MapConfigSchema.kt => ConfigMapSchema.kt} | 10 ++++----- .../io/smnp/ext/function/MidiFunction.kt | 10 ++++----- .../io/smnp/ext/function/MidiHelpFunction.kt | 4 ++-- .../src/main/kotlin/io/smnp/ext/midi/Midi.kt | 8 +++---- .../io/smnp/ext/function/SynthFunction.kt | 22 +++++++++++++++++++ .../io/smnp/ext/function/WaveFunction.kt | 9 +++++++- .../io/smnp/ext/synth/AdsrEnvelopeFactory.kt | 4 ++-- .../io/smnp/ext/synth/EnvelopeFactory.kt | 4 ++-- .../kotlin/io/smnp/ext/synth/WaveCompiler.kt | 4 ++-- 10 files changed, 54 insertions(+), 25 deletions(-) rename api/src/main/kotlin/io/smnp/util/config/{MapConfig.kt => ConfigMap.kt} (85%) rename api/src/main/kotlin/io/smnp/util/config/{MapConfigSchema.kt => ConfigMapSchema.kt} (83%) diff --git a/api/src/main/kotlin/io/smnp/util/config/MapConfig.kt b/api/src/main/kotlin/io/smnp/util/config/ConfigMap.kt similarity index 85% rename from api/src/main/kotlin/io/smnp/util/config/MapConfig.kt rename to api/src/main/kotlin/io/smnp/util/config/ConfigMap.kt index 366c785..d78ad71 100644 --- a/api/src/main/kotlin/io/smnp/util/config/MapConfig.kt +++ b/api/src/main/kotlin/io/smnp/util/config/ConfigMap.kt @@ -3,7 +3,7 @@ package io.smnp.util.config import io.smnp.error.ShouldNeverReachThisLineException import io.smnp.type.model.Value -class MapConfig(private val map: Map) { +class ConfigMap(private val map: Map) { private val raw by lazy { map.map { (key, value) -> key.unwrap() to value }.toMap() as Map } operator fun get(key: String): Value { @@ -19,6 +19,6 @@ class MapConfig(private val map: Map) { } companion object { - val EMPTY = MapConfig(emptyMap()) + val EMPTY = ConfigMap(emptyMap()) } } \ No newline at end of file diff --git a/api/src/main/kotlin/io/smnp/util/config/MapConfigSchema.kt b/api/src/main/kotlin/io/smnp/util/config/ConfigMapSchema.kt similarity index 83% rename from api/src/main/kotlin/io/smnp/util/config/MapConfigSchema.kt rename to api/src/main/kotlin/io/smnp/util/config/ConfigMapSchema.kt index 3523190..9c00e22 100644 --- a/api/src/main/kotlin/io/smnp/util/config/MapConfigSchema.kt +++ b/api/src/main/kotlin/io/smnp/util/config/ConfigMapSchema.kt @@ -5,25 +5,25 @@ import io.smnp.type.enumeration.DataType import io.smnp.type.matcher.Matcher import io.smnp.type.model.Value -class MapConfigSchema { +class ConfigMapSchema { private data class Parameter(val matcher: Matcher, val required: Boolean, val default: Value) private val parameters = mutableMapOf() - fun required(name: String, matcher: Matcher): MapConfigSchema { + fun required(name: String, matcher: Matcher): ConfigMapSchema { parameters[name] = Parameter(matcher, true, Value.void()) return this } - fun optional(name: String, matcher: Matcher, default: Value = Value.void()): MapConfigSchema { + fun optional(name: String, matcher: Matcher, default: Value = Value.void()): ConfigMapSchema { parameters[name] = Parameter(matcher, false, default) return this } - fun parse(config: Value): MapConfig { + fun parse(config: Value): ConfigMap { val configMap = config.value as Map - return MapConfig(parameters.mapNotNull { (name, parameter) -> + return ConfigMap(parameters.mapNotNull { (name, parameter) -> val value = configMap[Value.string(name)] ?: if (parameter.required) throw CustomException("The '$name' parameter of ${parameter.matcher} is required") else parameter.default diff --git a/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiFunction.kt b/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiFunction.kt index 4392e26..328f1b5 100644 --- a/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiFunction.kt +++ b/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiFunction.kt @@ -13,12 +13,12 @@ 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 +import io.smnp.util.config.ConfigMap +import io.smnp.util.config.ConfigMapSchema class MidiFunction : Function("midi") { - private val schema = MapConfigSchema() + private val schema = ConfigMapSchema() .optional("bpm", ofType(INT), Value.int(120)) .optional("ppq", ofType(INT)) .optional("output", ofType(STRING)) @@ -47,7 +47,7 @@ class MidiFunction : Function("midi") { throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded") } - Midi.with(MapConfig.EMPTY).play(unwrappedLines) + Midi.with(ConfigMap.EMPTY).play(unwrappedLines) Value.void() } @@ -74,7 +74,7 @@ class MidiFunction : Function("midi") { throw CustomException("MIDI standard supports max to 16 channels and that number has been exceeded") } - Midi.with(MapConfig.EMPTY).play(unwrappedChannels) + Midi.with(ConfigMap.EMPTY).play(unwrappedChannels) Value.void() } diff --git a/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiHelpFunction.kt b/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiHelpFunction.kt index 444a02d..91a38e6 100644 --- a/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiHelpFunction.kt +++ b/modules/midi/src/main/kotlin/io/smnp/ext/function/MidiHelpFunction.kt @@ -12,7 +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 +import io.smnp.util.config.ConfigMap class MidiHelpFunction : Function("midiHelp") { override fun define(new: FunctionDefinitionTool) { @@ -59,7 +59,7 @@ class MidiHelpFunction : Function("midiHelp") { if (index > 0) { println(it) Midi - .with(MapConfig(mapOf(Value.string("bpm") to Value.int(bpm)))) + .with(ConfigMap(mapOf(Value.string("bpm") to Value.int(bpm)))) .play(mapOf(channel to listOf(listOf("i:$instrument", it)))) Thread.sleep(100) } diff --git a/modules/midi/src/main/kotlin/io/smnp/ext/midi/Midi.kt b/modules/midi/src/main/kotlin/io/smnp/ext/midi/Midi.kt index 364fbfe..b5b1ea5 100644 --- a/modules/midi/src/main/kotlin/io/smnp/ext/midi/Midi.kt +++ b/modules/midi/src/main/kotlin/io/smnp/ext/midi/Midi.kt @@ -1,6 +1,6 @@ package io.smnp.ext.midi -import io.smnp.util.config.MapConfig +import io.smnp.util.config.ConfigMap import java.io.File import javax.sound.midi.MidiSystem import javax.sound.midi.Sequence @@ -28,11 +28,11 @@ object Midi { sequencer.stop() } - fun with(config: MapConfig): SequenceExecutor { + fun with(config: ConfigMap): SequenceExecutor { return SequenceExecutor(sequencer, config) } - class SequenceExecutor(private val sequencer: Sequencer, private val config: MapConfig) { + class SequenceExecutor(private val sequencer: Sequencer, private val config: ConfigMap) { fun play(lines: List>) { val sequence = Sequence(Sequence.PPQ, config.getUnwrappedOrDefault("ppq", DEFAULT_PPQ)) provideCompiler(config).compileLines(lines, sequence) @@ -40,7 +40,7 @@ object Midi { writeToFile(sequence) } - private fun provideCompiler(config: MapConfig): SequenceCompiler = + private fun provideCompiler(config: ConfigMap): SequenceCompiler = if (config.containsKey("ppq")) PpqSequenceCompiler() else DefaultSequenceCompiler() diff --git a/modules/synth/src/main/kotlin/io/smnp/ext/function/SynthFunction.kt b/modules/synth/src/main/kotlin/io/smnp/ext/function/SynthFunction.kt index 3445959..3e83614 100644 --- a/modules/synth/src/main/kotlin/io/smnp/ext/function/SynthFunction.kt +++ b/modules/synth/src/main/kotlin/io/smnp/ext/function/SynthFunction.kt @@ -2,19 +2,41 @@ package io.smnp.ext.function import io.smnp.callable.function.Function import io.smnp.callable.function.FunctionDefinitionTool +import io.smnp.callable.signature.Signature import io.smnp.callable.signature.Signature.Companion.simple import io.smnp.ext.synth.Synthesizer import io.smnp.ext.synth.Wave +import io.smnp.ext.synth.WaveCompiler +import io.smnp.type.enumeration.DataType import io.smnp.type.enumeration.DataType.INT +import io.smnp.type.matcher.Matcher import io.smnp.type.matcher.Matcher.Companion.listOf import io.smnp.type.model.Value class SynthFunction : Function("synth") { + override fun define(new: FunctionDefinitionTool) { new function simple(listOf(INT)) body { _, (wave) -> val bytes = (wave.value as List).map { (it.value as Int).toByte() }.toByteArray() Synthesizer.synth(Wave(bytes)) Value.void() } + + new function Signature.vararg( + listOf(DataType.NOTE, INT, DataType.STRING), + Matcher.mapOfMatchers(Matcher.ofType(DataType.STRING), Matcher.anyType()) + ) body { _, (config, vararg) -> + val compiler = WaveCompiler(config, Synthesizer.SAMPLING_RATE) + val wave = compiler.compileLines(vararg.unwrapCollections() as List>) + Synthesizer.synth(wave) + Value.void() + } + + new function Signature.vararg(listOf(DataType.NOTE, INT, DataType.STRING)) body { _, (vararg) -> + val compiler = WaveCompiler(Value.map(emptyMap()), Synthesizer.SAMPLING_RATE) + val wave = compiler.compileLines(vararg.unwrapCollections() as List>) + Synthesizer.synth(wave) + Value.void() + } } } \ No newline at end of file diff --git a/modules/synth/src/main/kotlin/io/smnp/ext/function/WaveFunction.kt b/modules/synth/src/main/kotlin/io/smnp/ext/function/WaveFunction.kt index 2f16cbf..f7191b4 100644 --- a/modules/synth/src/main/kotlin/io/smnp/ext/function/WaveFunction.kt +++ b/modules/synth/src/main/kotlin/io/smnp/ext/function/WaveFunction.kt @@ -14,7 +14,6 @@ import io.smnp.type.model.Value class WaveFunction : Function("wave") { - override fun define(new: FunctionDefinitionTool) { new function Signature.vararg( listOf(NOTE, INT, STRING), @@ -26,5 +25,13 @@ class WaveFunction : Function("wave") { Value.list(wave.bytes.map { Value.int(it.toInt()) }.toList()) } + + new function Signature.vararg(listOf(NOTE, INT, STRING)) body { _, (vararg) -> + val compiler = WaveCompiler(Value.map(emptyMap()), Synthesizer.SAMPLING_RATE) + + val wave = compiler.compileLines(vararg.unwrapCollections() as List>) + + Value.list(wave.bytes.map { Value.int(it.toInt()) }.toList()) + } } } \ No newline at end of file diff --git a/modules/synth/src/main/kotlin/io/smnp/ext/synth/AdsrEnvelopeFactory.kt b/modules/synth/src/main/kotlin/io/smnp/ext/synth/AdsrEnvelopeFactory.kt index d1ee4cc..2999b56 100644 --- a/modules/synth/src/main/kotlin/io/smnp/ext/synth/AdsrEnvelopeFactory.kt +++ b/modules/synth/src/main/kotlin/io/smnp/ext/synth/AdsrEnvelopeFactory.kt @@ -3,10 +3,10 @@ package io.smnp.ext.synth import io.smnp.type.enumeration.DataType.FLOAT import io.smnp.type.matcher.Matcher.Companion.ofType import io.smnp.type.model.Value -import io.smnp.util.config.MapConfigSchema +import io.smnp.util.config.ConfigMapSchema object AdsrEnvelopeFactory : EnvelopeFactory { - private val schema = MapConfigSchema() + private val schema = ConfigMapSchema() .required("p1", ofType(FLOAT)) .required("p2", ofType(FLOAT)) .required("p3", ofType(FLOAT)) diff --git a/modules/synth/src/main/kotlin/io/smnp/ext/synth/EnvelopeFactory.kt b/modules/synth/src/main/kotlin/io/smnp/ext/synth/EnvelopeFactory.kt index 45a8650..c330963 100644 --- a/modules/synth/src/main/kotlin/io/smnp/ext/synth/EnvelopeFactory.kt +++ b/modules/synth/src/main/kotlin/io/smnp/ext/synth/EnvelopeFactory.kt @@ -4,13 +4,13 @@ import io.smnp.error.CustomException import io.smnp.type.enumeration.DataType import io.smnp.type.matcher.Matcher import io.smnp.type.model.Value -import io.smnp.util.config.MapConfigSchema +import io.smnp.util.config.ConfigMapSchema interface EnvelopeFactory { fun createEnvelope(config: Value): Envelope companion object { - private val schema = MapConfigSchema() + private val schema = ConfigMapSchema() .required("name", Matcher.ofType(DataType.STRING)) private val factories = mapOf( diff --git a/modules/synth/src/main/kotlin/io/smnp/ext/synth/WaveCompiler.kt b/modules/synth/src/main/kotlin/io/smnp/ext/synth/WaveCompiler.kt index 1461961..dac6ded 100644 --- a/modules/synth/src/main/kotlin/io/smnp/ext/synth/WaveCompiler.kt +++ b/modules/synth/src/main/kotlin/io/smnp/ext/synth/WaveCompiler.kt @@ -7,12 +7,12 @@ import io.smnp.math.Fraction import io.smnp.type.enumeration.DataType import io.smnp.type.matcher.Matcher import io.smnp.type.model.Value -import io.smnp.util.config.MapConfigSchema +import io.smnp.util.config.ConfigMapSchema import kotlin.math.pow class WaveCompiler(config: Value, private val samplingRate: Double) { private val semitone = 2.0.pow(1.0 / 12.0) - private val schema = MapConfigSchema() + private val schema = ConfigMapSchema() .optional("bpm", Matcher.ofType(DataType.INT), Value.int(120)) .optional( "overtones", Matcher.listOf(DataType.FLOAT), Value.list(