Cleanup
This commit is contained in:
@@ -8,7 +8,6 @@ import kotlin.math.PI
|
|||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
const val PI2 = PI * 2
|
const val PI2 = PI * 2
|
||||||
const val NOTE_LENGTH = 2500
|
|
||||||
|
|
||||||
@ExperimentalJsExport
|
@ExperimentalJsExport
|
||||||
@JsExport
|
@JsExport
|
||||||
@@ -60,9 +59,9 @@ object WorkletProcessor {
|
|||||||
|
|
||||||
for (sample in 0 until samples) {
|
for (sample in 0 until samples) {
|
||||||
var value = sin(offset * PI2) +
|
var value = sin(offset * PI2) +
|
||||||
sin(offset * 2 * PI2) * 0.5 +
|
sin(offset * 2 * PI2) * 0.6 +
|
||||||
sin(offset * 3 * PI2) * 0.25 +
|
sin(offset * 3 * PI2) * 0.4 +
|
||||||
sin(offset * 4 * PI2) * 0.15
|
sin(offset * 4 * PI2) * 0.3
|
||||||
offset += delta
|
offset += delta
|
||||||
|
|
||||||
// new note every NOTE_LENGTH samples
|
// new note every NOTE_LENGTH samples
|
||||||
|
|||||||
@@ -1,162 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import kotlinx.browser.window
|
|
||||||
import org.w3c.dom.MessageEvent
|
|
||||||
import org.w3c.dom.MessagePort
|
|
||||||
import org.w3c.dom.url.URL
|
|
||||||
import org.w3c.files.Blob
|
|
||||||
import org.w3c.files.FilePropertyBag
|
|
||||||
|
|
||||||
enum class WorkletState {
|
|
||||||
INIT,
|
|
||||||
LOADING,
|
|
||||||
LOADED,
|
|
||||||
READY
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AudioWorklet(
|
|
||||||
val jsCodeFile: String,
|
|
||||||
val kotlinCodeFile: String
|
|
||||||
) {
|
|
||||||
var audioContext: dynamic = null
|
|
||||||
var state = WorkletState.INIT
|
|
||||||
var processingCode: Blob? = null
|
|
||||||
var sampleRate: Int = 44100
|
|
||||||
var audioWorkletMessagePort: MessagePort? = null
|
|
||||||
|
|
||||||
abstract fun createNode(audioContext: dynamic): dynamic
|
|
||||||
|
|
||||||
abstract fun onAudioWorkletMessage(message: MessageEvent)
|
|
||||||
|
|
||||||
abstract fun onCodeLoaded()
|
|
||||||
|
|
||||||
fun loadCode() {
|
|
||||||
// hack
|
|
||||||
// concat kotlin js and note-processor.js because
|
|
||||||
// audio worklet es6 is not supported in kotlin yet
|
|
||||||
state = WorkletState.LOADING
|
|
||||||
|
|
||||||
window.fetch(jsCodeFile).then { daResponse ->
|
|
||||||
if (daResponse.ok) {
|
|
||||||
daResponse.text().then { daText ->
|
|
||||||
window.fetch(kotlinCodeFile).then { npResponse ->
|
|
||||||
if (npResponse.ok) {
|
|
||||||
npResponse.text().then { npText ->
|
|
||||||
processingCode = Blob(
|
|
||||||
arrayOf(daText, npText),
|
|
||||||
FilePropertyBag(type = "application/javascript")
|
|
||||||
)
|
|
||||||
|
|
||||||
state = WorkletState.LOADED
|
|
||||||
|
|
||||||
println("Loaded $this code")
|
|
||||||
|
|
||||||
onCodeLoaded()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createContext(callback: () -> Unit) {
|
|
||||||
js("window.AudioContext = window.AudioContext || window.webkitAudioContext")
|
|
||||||
|
|
||||||
audioContext = js("new window.AudioContext()")
|
|
||||||
sampleRate = audioContext.sampleRate as Int
|
|
||||||
|
|
||||||
check(state == WorkletState.LOADED) {
|
|
||||||
"Can not createContext when code is not yet loaded, call loadCode first"
|
|
||||||
}
|
|
||||||
|
|
||||||
val module = audioContext.audioWorklet.addModule(
|
|
||||||
URL.createObjectURL(processingCode!!)
|
|
||||||
)
|
|
||||||
|
|
||||||
module.then {
|
|
||||||
val node: dynamic = createNode(audioContext)
|
|
||||||
|
|
||||||
node.connect(audioContext.destination)
|
|
||||||
|
|
||||||
node.port.onmessage = ::onAudioWorkletMessage
|
|
||||||
|
|
||||||
audioWorkletMessagePort = node.port as? MessagePort
|
|
||||||
|
|
||||||
state = WorkletState.READY
|
|
||||||
|
|
||||||
//postBatchedRequests()
|
|
||||||
|
|
||||||
callback()
|
|
||||||
|
|
||||||
"dynamic"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isResumed(): Boolean = audioContext?.state == "running"
|
|
||||||
|
|
||||||
fun resume() {
|
|
||||||
check(state == WorkletState.READY) {
|
|
||||||
"Unable to resume, state is not READY [$state]"
|
|
||||||
}
|
|
||||||
|
|
||||||
audioContext?.resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fun postRequest(request: WorkerRequest) {
|
|
||||||
batchedRequests.add(request)
|
|
||||||
|
|
||||||
postBatchedRequests()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun postBatchedRequests() {
|
|
||||||
val port = audioWorkletMessagePort
|
|
||||||
|
|
||||||
if (port != null) {
|
|
||||||
for (request in batchedRequests) {
|
|
||||||
val message = when (serializer) {
|
|
||||||
is StringFormat -> {
|
|
||||||
serializer.encodeToString(WorkerRequest.serializer(), request)
|
|
||||||
}
|
|
||||||
|
|
||||||
is BinaryFormat -> {
|
|
||||||
serializer.encodeToByteArray(WorkerRequest.serializer(), request)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
error("Unknown serializer format ${serializer::class.simpleName}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
port.postMessage(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
batchedRequests.clear()
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
object AudioWorkletHandler : AudioWorklet(
|
|
||||||
"static/worklet-processor.js",
|
|
||||||
"static/audio-worklet.js"
|
|
||||||
) {
|
|
||||||
|
|
||||||
override fun createNode(audioContext: dynamic): dynamic = js(
|
|
||||||
// worklet-processor as defined in de javascript:
|
|
||||||
// registerProcessor('worklet-processor', WorkletProcessor);
|
|
||||||
"new AudioWorkletNode(audioContext, 'worklet-processor', { numberOfInputs: 0, outputChannelCount: [2] })"
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun onAudioWorkletMessage(message: MessageEvent) {
|
|
||||||
console.log("Received message from audio worklet: ", message)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCodeLoaded() {
|
|
||||||
println("Audio worklet code is loaded.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
audioWorkletMessagePort?.postMessage("start")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -19,14 +19,10 @@ fun main() {
|
|||||||
}, "")
|
}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
print("get noteLength")
|
|
||||||
document.getElementById("noteLength")?.also {
|
document.getElementById("noteLength")?.also {
|
||||||
println("Set noteLength event")
|
|
||||||
it.addEventListener("change", {
|
it.addEventListener("change", {
|
||||||
println("Set noteLength 1")
|
|
||||||
val target = it.target
|
val target = it.target
|
||||||
if (target is HTMLInputElement) {
|
if (target is HTMLInputElement) {
|
||||||
println("Set noteLength 2")
|
|
||||||
AudioWorkletHandler.setNoteLength(target.value.toInt())
|
AudioWorkletHandler.setNoteLength(target.value.toInt())
|
||||||
}
|
}
|
||||||
}, "")
|
}, "")
|
||||||
|
|||||||
Reference in New Issue
Block a user