@konsumer/nuked
Version:
Yamaha OPL2/3 FM synth chip emulator
131 lines (89 loc) • 3.69 kB
Markdown
This is an OPL (IMF, WLF, RAW, DRO, VGM, VGZ) player for the web (and elswhere) based on [opl_plr.js by kvee](http://software.kvee.cz/)
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:
```sh
npm i @konsumer/nuked
```
You can add to the web with:
```html
<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:
```html
<script type="module">
import '@konsumer/nuked/nuked-player'
</script>
<nuked-player src="song.imf"></nuked-player>
```
There are a few functions exported:
```js
// 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)
```
You can generate a WAV (RIFF, uncompressed) file for use in anyhting else:
```js
// 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' }))
```
[](https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletProcessor) is a hyper-efficient worker (similar to thread) that will run audio-processing in the background. You can use it like this:
```js
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 is just gzipped VGM. You can parse it in js like this:
```js
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](docs/nuked-player.js).
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:
- [null0](https://github.com/notnullgames/null0)
- [null-units](https://github.com/konsumer/null-units)
And I need to test to make sure it works in other js hosts like:
- [web-audio-api](https://github.com/ircam-ismm/node-web-audio-api)