Cleanup
This commit is contained in:
@@ -8,7 +8,6 @@ import kotlin.math.PI
|
||||
import kotlin.math.sin
|
||||
|
||||
const val PI2 = PI * 2
|
||||
const val NOTE_LENGTH = 2500
|
||||
|
||||
@ExperimentalJsExport
|
||||
@JsExport
|
||||
@@ -60,9 +59,9 @@ object WorkletProcessor {
|
||||
|
||||
for (sample in 0 until samples) {
|
||||
var value = sin(offset * PI2) +
|
||||
sin(offset * 2 * PI2) * 0.5 +
|
||||
sin(offset * 3 * PI2) * 0.25 +
|
||||
sin(offset * 4 * PI2) * 0.15
|
||||
sin(offset * 2 * PI2) * 0.6 +
|
||||
sin(offset * 3 * PI2) * 0.4 +
|
||||
sin(offset * 4 * PI2) * 0.3
|
||||
offset += delta
|
||||
|
||||
// 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 {
|
||||
println("Set noteLength event")
|
||||
it.addEventListener("change", {
|
||||
println("Set noteLength 1")
|
||||
val target = it.target
|
||||
if (target is HTMLInputElement) {
|
||||
println("Set noteLength 2")
|
||||
AudioWorkletHandler.setNoteLength(target.value.toInt())
|
||||
}
|
||||
}, "")
|
||||
|
||||
Reference in New Issue
Block a user