@konsumer/nuked
v0.0.4
Published
Yamaha OPL2/3 FM synth chip emulator
Maintainers
Readme
This is an OPL (IMF, WLF, RAW, DRO, VGM, VGZ) player for the web (and elswhere) based on opl_plr.js by kvee
The main changes I made are to make it lighter & simpler (and more universal) using wasi-sdk instead of emscripten, and to use AudioWorkletProcessor instead of depracated ScriptProcessor for sound-generation. This performs better, and runs in more places.
installation
You can install in your own project (for bundling with vite, etc) with:
npm i @konsumer/nukedYou can add to the web with:
<script type="importmap">
{
"imports": {
"@konsumer/nuked": "https://esm.run/@konsumer/nuked",
"@konsumer/nuked/nuked-player": "https://esm.run/@konsumer/nuked/nuked-player",
"pako": "https://esm.run/pako"
}
}
</script>Now you can import from these, if your script-tag has type=module. If you want optional VGZ support (and are using the web-component) add pako.
usage
There are a few ways to use it. The easiest is a quick web-component:
<script type="module">
import '@konsumer/nuked/nuked-player'
</script>
<nuked-player src="song.imf"></nuked-player>There are a few functions exported:
// these create a "queue" from various files (as Uint8Array or ArrayBuffer, or whatever)
imf(imfData, (imfRate = 560))
raw(rawData)
dro(droData)
vgm(vgmData, loopRepeat)
// this creates an audio-worklet for playback
createAudioWorklet(audioContext, queue)
// This generates a Uint8Array of bytes foir a WAV-file, and can be used offline
createWave(queue)waav
You can generate a WAV (RIFF, uncompressed) file for use in anyhting else:
// create a queue from a file
const queue = imf(await fetch('mysong.imf').then((r) => r.arrayBuffer()))
// create WAV-bytes from queue
const wav = await createWave(queue)
// create a URL (on web) suitable for a audio-tag
const url = URL.createObjectURL(new Blob([wav], { type: 'audio/wav' }))worklet
AudioWorkletProcessor is a hyper-efficient worker (similar to thread) that will run audio-processing in the background. You can use it like this:
import { imf, createAudioWorklet } from '@konsumer/nuked'
// create an audio-context
const ctx = new AudioContext()
// create a queue from a file
const queue = imf(await fetch('mysong.imf').then((r) => r.arrayBuffer()))
// create a worklet from a queue/context
const opl = await createAudioWorklet(ctx, queue)
// connect it to output
opl.connect(ctx.destination)
// stuff you can do
opl.play()
opl.stop()
opl.pause() // toggle pause-state
opl.seek(4) // in seconds
// respond to time-updates
opl.addEventListener('time', ({ current, total }) => {
console.log({ current, total })
})
// you can also get the time right after parsing it (in case you need time, but can't play it through audio-context)
const total = nuke.getTimeLength(queue)vgz
VGZ is just gzipped VGM. You can parse it in js like this:
import { vgm } as nuke from '@konsumer/nuked'
import pako from 'pako'
const queue = vgm(pako.ungzip(await fetch('mysong.vgz').then(r => r.arrayBuffer())))I do this in nuked-player.js.
plans
I would like to make an offline wav-generator, so you can output a sound-file.
Eventually, I would like to minimize any js host requirements, so it can run in more places like:
And I need to test to make sure it works in other js hosts like:
