Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,23 @@ just call `player.pause()` to pause or `player.load()` to load a new MIDI file.
Returns `true` if `destroy()` has been called on the player. Returns `false`
otherwise.

### `player.render()`

Renders the loaded MIDI file to audio data. Returns an array of `Float32Array`s
containing the raw left and right sample data for the entire song. The
`render()` method should only be called once the MIDI file and soundfonts have
been loaded:

```
player.on("loaded", function() {
const arrays = player.render()
console.log(arrays)
})
```

Note: the uncompressed sample data can consume a lot of memory, depending on
the length of the song.

### `player.on('error', (err) => {})`

This event fires if a fatal error occurs in the player, including if a MIDI file
Expand Down
39 changes: 39 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class Timidity extends EventEmitter {
this._songPtr = songPtr
this._lib._mid_song_start(this._songPtr)
debugVerbose('Song and instruments are loaded')
this.emit('loaded')
}

_getMissingInstruments (songPtr, missingCount) {
Expand Down Expand Up @@ -258,6 +259,44 @@ class Timidity extends EventEmitter {
}
}

render () {
const songLength = this._lib._mid_song_get_total_time(this._songPtr) / 1000
const buffSize = songLength * SAMPLE_RATE
const _array = new Int16Array(BUFFER_SIZE * 2)
const arrays = [new Float32Array(buffSize), new Float32Array(buffSize)]
let sampleCount = -1
let lastSample = 0

while (sampleCount) {
const byteCount = this._lib._mid_song_read_wave(
this._songPtr,
this._bufferPtr,
BUFFER_SIZE * BYTES_PER_SAMPLE
)
sampleCount = byteCount / BYTES_PER_SAMPLE

if (byteCount) {
_array.set(
this._lib.HEAP16.subarray(this._bufferPtr / 2, (this._bufferPtr + byteCount) / 2)
)

for (let i = 0; i < sampleCount; i++) {
arrays[0][i + lastSample] = _array[i * 2] / 0x7FFF
arrays[1][i + lastSample] = _array[i * 2 + 1] / 0x7FFF
}
lastSample = lastSample + sampleCount
this.emit('progress', lastSample, buffSize)
}
}

// reset in case the user wants to play
this.seek(0)
this.pause()
this._lib._mid_song_start(this._songPtr)

return arrays
}

_onAudioProcess (event) {
const sampleCount = (this._songPtr && this._playing)
? this._readMidiData()
Expand Down