Skip to content

Commit

Permalink
Features/fluidsynth rendered (#5)
Browse files Browse the repository at this point in the history
* initial

* audio processor added

* some changes

* poc impl.

* changed

* testmidi changed

* instrument added

* different track/instruments impl

* note off and velocity impl

* testfiles separated

* setup test build

* missing file added

* mario underworld added

* * buffered rendering impl

* fade out impl

* render is async now
clean up

* velocity exp

* velocity back to lin

* pitch added

* before changing midi parser

* midi parser changed
pithcbend impl

* pitch shifting sound glitches fixed

* CC pan/expr impl

* IMidiEvent refactoring
MidiEventNotification impl.

* * generating d.ts files during deployment

* build script updated

* babel added

* missing file added

* absolute tick position added to event

* package json version updated

* using index.d.ts now

* missing d.ts file added

* ppq was set to public

* fixed: volume, expression, pitch values might not be correct

* package version increased

* forced samplerate in audio context to 44100

* did some polish:
* stop event will be triggered after playback is done
* fadeout time increased
* fixed bug for midi files which have no track id

* package moved to organization

* readme updated

* typo fixed

* volume increased

* missing files added

* webpack setup

* my renderer removed

* fetch samples impl
performCompose called

* soundfont generation complete

* playback is working !

* depecndecy build script added

* removed files readded

* build js-synth step added to CI

* * CI branch added
* player workflow opimized
* license changed to matching to js-synthesizer

* loading speed of smaples improves

* set parcel version fix to 1.12.3 due this bug:
parcel-bundler/parcel#5955

* sfcompose version udpated

* stop handling improved

* dependencies set up as dev dependencies

* download last soundfont hack imp

* sf issues fixed

* * buffer size changable
* repo url changable

* synth rendering using audioworklet

* build process optimized

* jsbuild as dev dependency

* fixed audioworklet version

* * event notification after player play

* prerenders the whole file now

* repo url changed, blocksize changed

* percussion handling changed

* rendering via webworker impl

* webworker block rendering impl

* js-buildsynth replaced by parcel fs

* renderer stop behaviour improved

* renderer block size options changed to rendererBufferSeconds

* jssynth preload optimized

* start/stop behaviour improved

* early stop bug fixed

* test

* test 2

* test 3

* merge saved

Co-authored-by: samba <samba@manjaro>
Co-authored-by: Samba Godschynski <[email protected]>
  • Loading branch information
3 people authored Mar 24, 2021
1 parent 283d085 commit 2f759d3
Show file tree
Hide file tree
Showing 12 changed files with 9,033 additions and 1,205 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ on:
branches:
- main
- feature/*
- features/*
- develop
pull_request:
branches: [ main ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
Expand Down
695 changes: 674 additions & 21 deletions LICENSE

Large diffs are not rendered by default.

17 changes: 3 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
# Just another MIDI player
* instead of triggering note events by a timer, this player prerenders a MIDI file to an [AudioBuffer](https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer). So the result is more precise regarding the timing than other JS MIDI players, but on the other hand the precalculation needs a bit of extra time
* uses [midifile](https://github.com/nfroidure/midifile) for parsing midi data.
* uses [js-synthesizer](https://github.com/jet2jet/js-synthesizer)
* uses [soundfont-server](https://github.com/werckme/soundfont-server)
* uses [midifile](https://github.com/nfroidure/midifile) for parsing midi data.
* used by [werckmeister component](https://github.com/werckme/werckmeister-component)


## Supported MIDI events
* Note On
* Note Off
* CC
* experssion
* panorama
* PC
* Pitch Bend
* Meta Events
* Tempo
8,643 changes: 7,804 additions & 839 deletions package-lock.json

Large diffs are not rendered by default.

30 changes: 20 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@werckmeister/midiplayer",
"version": "1.0.2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
Expand All @@ -10,29 +10,39 @@
"build": "parcel build --no-source-maps src/WerckmeisterMidiPlayer.ts -o index.js",
"dev": "parcel test.html"
},
"staticFiles": {
"staticPath": [
"./node_modules/@werckmeister/sfcompose",
"./node_modules/js-synthesizer/externals/libfluidsynth-2.0.2.js"
],
"watcherGlob": "*.wasm"
},
"repository": {
"type": "git",
"url": "git+https://github.com/werckme/midiplayer.git"
},
"author": "Samba Godschynski",
"license": "MIT",
"license": "GPL-3.0-or-later",
"bugs": {
"url": "https://github.com/werckme/midiplayer/issues"
},
"homepage": "https://github.com/werckme/midiplayer#readme",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-typescript": "^7.10.4",
"@types/lodash": "^4.14.165",
"@werckmeister/sfcompose": "1.0.0-dev-25",
"babel-core": "^6.26.3",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"parcel-plugin-static-files-copy": "^2.5.0",
"typescript": "^4.1.3"
},
"dependencies": {
"@types/lodash": "^4.14.165",
"js-synthbuild": "file:jssynthbuild",
"js-synthesizer": "^1.7.0",
"lodash": "^4.17.20",
"midifile": "^2.0.0",
"babel-core": "^6.26.3",
"babel-polyfill": "^6.26.0"
}
"parcel": "1.12.3",
"parcel-plugin-static-files-copy": "2.5.0",
"typescript": "^4.1.3"
},
"dependencies": {}
}
65 changes: 65 additions & 0 deletions src/FluidSynthWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const RendererIdleTimeMillis = 100;

function getSynth() {
const _synth = new JSSynth.Synthesizer();
_synth.init(_sampleRate);
return _synth;
}

const State = {
stopped: 0,
playing: 1,
stopping: 2
}

const session = {
state: State.stopped
}

function render(sessionId, soundFontBff, midiBuffer, audioBufferLength, inBlockSize) {
session.state = State.playing;
session.sesisonId = sessionId;
const synth = getSynth();
synth.loadSFont(soundFontBff).then(() => {
synth.addSMFDataToPlayer(midiBuffer).then(() => {
synth.playPlayer().then(()=> {
let samplesLeft = audioBufferLength;
function renderBlock() {
if (samplesLeft <= 0 || session.state !== State.playing) {
session.state = State.stopped;
self.postMessage({sessionId, done: true});
return;
}
const blockSize = Math.min(inBlockSize, samplesLeft);
const audioBuffer = [
new Float32Array(blockSize),
new Float32Array(blockSize)
];
synth.render(audioBuffer);
const bffL = audioBuffer[0].buffer;
const bffR = audioBuffer[1].buffer;
const samplePos = audioBufferLength - samplesLeft;
const lastBlock = (samplesLeft - blockSize) <= 0;
self.postMessage({bffL, bffR, blockSize, samplePos, lastBlock, sessionId}, [bffL, bffR]);
samplesLeft -= blockSize;
setTimeout(renderBlock, RendererIdleTimeMillis); // aka. sleep
}
renderBlock();
});
});
});
}

self.onmessage = function (msg) {
if(msg.data.stop && session.state === State.playing) {
session.state = State.stopping;
return;
}
if (session.state !== State.stopped) {
return;
}
const {soundFont, midiBuffer, audioBufferLength, blockSize, sampleRate, sessionId} = msg.data;
_sampleRate = sampleRate;
render(sessionId, soundFont, midiBuffer, audioBufferLength, blockSize);
}

152 changes: 0 additions & 152 deletions src/Instrument.ts

This file was deleted.

57 changes: 0 additions & 57 deletions src/InstrumentSamples.ts

This file was deleted.

Loading

0 comments on commit 2f759d3

Please sign in to comment.