Code Monkey home page Code Monkey logo

timidity's Introduction

timidity

travis npm downloads javascript style guide

Play MIDI files in the browser w/ Web Audio, WebAssembly, and libtimidity

Play MIDI files in a browser with a simple API.

Demo

This package is used on BitMidi.com, the wayback machine for old-school MIDI files! Check out some examples here:

Install

npm install timidity

Features

  • Lightweight โ€“ Just 23 KB of JavaScript and 22 KB of lazy-loaded WebAssembly
  • Simple โ€“ No bells and whistles. Just what is needed to play MIDI files.
  • Works with the FreePats General MIDI soundset.

Usage

const Timidity = require('timidity')

const player = new Timidity()
player.load('/my-file.mid')
player.play()

player.on('playing', () => {
  console.log(player.duration) // => 351.521
})

Easier Usage

If you just want to play MIDI files in the browser and don't need a JavaScript API interface, consider using the bg-sound package, which supports this much simpler usage:

<script src="bg-sound.min.js"></script>
<bg-sound src="sound.mid"></bg-sound>

API

player = new Timidity([baseUrl])

Create a new MIDI player.

Optionally, provide a baseUrl to customize where the player will look for the lazy-loaded WebAssembly file libtimidity.wasm and the FreePats General MIDI soundset files. The default baseUrl is /.

For example, here is how to mount the necessary files at / with the express server:

const timidityPath = path.dirname(require.resolve('timidity'))
app.use(express.static(timidityPath))

const freepatsPath = path.dirname(require.resolve('freepats'))
app.use(express.static(freepatsPath))

player.load(urlOrBuf)

This function loads the specified MIDI file urlOrBuf, which is a string path to the MIDI file or a Uint8Array which contains the MIDI file data.

This should be the first function called on a new Timidity instance.

player.play()

Plays the currently loaded MIDI file.

player.pause()

Pauses the currently loaded MIDI file.

player.seek(seconds)

Seeks to a specified time in the MIDI file.

If the player is paused when the function is called, it will remain paused. If the function is called from another state (playing, etc.), the player will continue playing.

player.duration

Returns the duration in seconds (number) of the currently playing MIDI file. Note that duration will return 0 until the file is loaded, which normally happens just before the playing event.

player.currentTime

Returns the elapsed time in seconds since the MIDI file started playing.

player.destroy()

Destroys the entire player instance, stops the current MIDI file from playing, cleans up all resources.

Note: It's best to reuse the same player instance for as long as possible. It is not recommended to call player.destroy() to stop or change MIDI files. Rather, just call player.pause() to pause or player.load() to load a new MIDI file.

player.destroyed

Returns true if destroy() has been called on the player. Returns false otherwise.

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

This event fires if a fatal error occurs in the player, including if a MIDI file is unable to be played.

player.on('timeupdate', (seconds) => {})

This event fires when the time indicated by the currentTime property has been updated.

player.on('unstarted', () => {})

This event fires when a new MIDI file is being loaded.

player.on('ended', () => {})

This event fires when a MIDI file has played until the end.

player.on('playing', () => {})

This event fires when a MIDI file starts playing.

player.on('paused', () => {})

This event fires when a MIDI file is paused.

player.on('buffering', () => {})

This event fires when a MIDI file is loading.

License

Copyright (c) Feross Aboukhadijeh.

timidity's People

Contributors

feross avatar kichikuou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

timidity's Issues

Check URL Error Message

I'm using timidity with a Python program to compose MIDI data (Abjad). The timidity playback is fine, except that I get this error message in the terminal every time a file is compiled:

Check URL type=7 Check URL type=2 Check URL type=1 open url (type=1, name=/usr/local/Cellar/timidity/2.15.0/share/timidity/timidity.cfg) url_file_open(/usr/local/Cellar/timidity/2.15.0/share/timidity/timidity.cfg) mmap - success. size=4625
Would you happen to have any suggestions on how to make the error message go away? Do I need to configure the .cfg file? Speaking of which, how to access the .cfg file on a Mac?

Thank you!

Is the brfs browserify transform not applied in the published build?

I spent some time last night looking into how feasible it would be to setup timidity as a sort of "codec" for webamp.org. I've tried importing timidity and I'm getting this error in my webpack build:

ERROR in ./node_modules/timidity/index.js
Module not found: Error: Can't resolve 'fs' in '/Users/jeldredge/projects/webamp/node_modules/timidity'
 @ ./node_modules/timidity/index.js 3:11-24
 @ ./js/index.js

Looking at the source I see the comment: // Inlined at build time by 'brfs' browserify transform right above that line.

I'm seeing this in both version 1.0.0 and 1.0.1.

Am I expected to run the brfs browserify transform in my own project?

Any guidance would be appreciated. Thanks for the awesome project. I'm enjoying the JSParty podcast talking about bitmidi!

Tempo and pitch on Windows/Android

Some platforms/systems use a sampleRate of 48000. This results in faster, higher pitched play back. The fix is to use the sampleRate from the audio context:

_loadSong(midiBuf) {
	const optsPtr = this._lib._mid_alloc_options(
		this._audioContext.sampleRate || DEFAULT_SAMPLE_RATE,
		AUDIO_FORMAT,
		NUM_CHANNELS,
		BUFFER_SIZE
	)

Can't resolve 'fs', brfs browserify problem?

I'm having hard time to make this package work, I'm keep getting that fs and a modules are missing, I found similar one in the previous issues but I still can't solve it.
I'm using Nuxtjs SSR/webpack and I have never used the browserify.

Is there any clear way to get it work?

image

I appreciate it and thank you in advance ๐Ÿ™

Very confused about how to use this

Hey. Great package. Yet can't figure out how to use this in the browser. I'm trying browserify with the readme example, but all I'm getting are errors: both async and sync fetching of the wasm failed.

If you can explain a bit more I can PR a better explanation for beginners.

Can't connect to jack audio server when running Timidity

In order to run Guitar Pro 5.2 emulated on wine on Linux I need to run timidity so I can get the audio from the program. I followed instructions from this tutorial but when I run timidity it fails with the following erros:

$  timidity -iA 
connect(2) call to /dev/shm/jack-1000/default/jack_0 failed (err=No such file or directory)
attempt to connect to server failed
Couldn't open output device

Currently I have installed Jack 0.125.0-8 and Timidity++ 2.15.0-2.

Fork with AudioWorklet implementation

Hi, I really like this library, and I have made an attempt to reuse a lot of its bits and create a version that uses AudioWorkletProcessor rather than the very deprecated ScriptProcessorNode. Can be found here.

I need to work on completely copying the api here, with the duration features and events, but it stays pretty close right now otherwise. Most of the original index.js is now bundled into a registerProcessor for the AudioWorkletGlobalScope, and a second interface class MIDIPlayer handles all the messy communication with the worklet, as well as instantiating itself from an async static builder.

Some improvements otherwise include dynamically loading the timidity.cfg file on building the instance, and simply requiring that the pat folders are found in the same place. Also, a built in build system with rollup is now included.

I am not sure there is PR interest/how active this library is, and this is a pretty big set of changes. But let me know! It is right now working pretty well.

Can I use it in node environment.

I tried to run the demo code on readme using node. But I got the following errors.

// timidity_example_1.js
const Timidity = require('timidity')

const player = new Timidity()
player.load('/my-file.mid')
player.play()

player.on('playing', () => {
  console.log(player.duration) // => 351.521
})
D:\code\node\midi>node timidity_example_1.js
D:\code\node\midi\node_modules\timidity\index.js:32
    this._baseUrl = new URL(baseUrl, window.location.origin).href
                                     ^

ReferenceError: window is not defined
    at new Timidity (D:\code\node\midi\node_modules\timidity\index.js:32:38)
    at Object.<anonymous> (D:\code\node\midi\timidity_example_1.js:3:16)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47

Node.js v18.12.1

D:\code\node\midi>

I noticed that the readme.

Play MIDI files in the browser w/ Web Audio, WebAssembly, and libtimidity
Play MIDI files in a browser with a simple API.

Is there any chances that it will support for running in node/deno?

Real-time midi streams support?

Hi @feross,

very nice work with the library.

I was wondering if it provides any features for real-time midi streams support? It seems the original library provides some functions to do so (e.g. mid_istream_open_mem, mid_istream_read).

Thanks,
Francisco

IOS background audio

Hey @feross, I love this plugin, finally i can add midi player to my site.
so far it works for desktop browsers.
However on iphone/ipad, as soon as i switch to a different tab/page, or turn off screen, the audio stopped.
but it seem to work perfectly in your bitmidi.com, even i switch to other app or turn off screen.
Here's my sample code. Is there anything i should do to keep the audio playing in the background ?

test link

const Timidity = require('timidity')
const player = new Timidity()
window.onload = function(){
 document.querySelector("#start_music").addEventListener('click',function(){
     console.log('started.');
     player.load('/bach.mid')
     player.play()
 });
 document.querySelector("#stop_music").addEventListener('click',function(){
     console.log('Stopped.');
     player.pause();
     
 });
}

Integration with Webamp?

Hey! I saw you post about BitMidi in the Changelog Slack (LOVE IT!) and that lead me here. I maintain https://github.com/captbaritone/webamp (https://webamp.org) and having midi support would be very cool. However, the API that you currently expose would probably not be quite what we need. The main thing we would need would be access to the raw audio node (so we can attach the analyzer, EQ, etc).

MIDI support is something we've been asked for before, and I would love to come up with a good way to support non-browser players so that, one day, Timidity could just be one of many such "codecs".

Would this be something that would interest you? Something we could work on together maybe?

I'm happy to discuss here or, if you prefer something more realtime, your welcome to join our Discord: https://discord.gg/wvaaG4

Error when trying to use this in WebPack.

Hi @feross - I know you're very busy so hopefully this won't take much of your time.

When I try to do a simple import * as timidity from "timidity"; and then run that file through webpack I get the following 2 errors:

ERROR in ./node_modules/timidity/libtimidity.wasm
Module not found: Error: Can't resolve 'env' in '/home/chrism/dev/something/node_modules/timidity'
 @ ./node_modules/timidity/libtimidity.wasm
 @ ./node_modules/timidity/index.js
 @ ./src/js/index.js

ERROR in ./node_modules/timidity/libtimidity.wasm
WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
* ./src/js/index.js --> ./node_modules/timidity/index.js --> ./node_modules/timidity/libtimidity.wasm

I'm not a heavy webpack user but maybe you have some pointers as to how I can fix this? Will issue a PR if I get it working.

Error with official example

When I try const Timidity = require('timidity') from the readme, I get Uncaught ReferenceError: require is not defined.

Then I browserify the example from the readme. But then it can't find libtimidity.wasm.

Then I replace

const player = new Timidity()
player.load('/my-file.mid')

by

baseUrl = 'https://bitmidi.com/timidity/'
const player = new Timidity(baseUrl)
player.load('https://bitmidi.com/uploads/16752.mid')

Then I get the warning "The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.".

I click on the webpage (which works after applying browserify to bg-sound). But there's still no sound.

So how exactly can I use timidity?

Noises/Crackling when switching to new MIDI track

I set up MIDI so that Wine can make MIDI work for games.
Each time a track needs to be stopped and switch to a new track (changing levels inside the game, or pressing Next on a MIDI player) there are these noises at the start of the track, like if the buffer is still filling (assumption) Sometimes, the noises last for longer (it seems to get worse if you switch MIDI tracks quicker)

Is this a Buffer Size issue? CPU usage? Pulseaudio buffer different than Timidity buffer?

This issue plagues me from old distributions and it's still happening on new hardware. I must be doing something wrong or missing some essential configuration.
Any tips?
Is there a way for perfectly-matching or synchronizing the Timidity buffer size with the buffer size required for the ALSA/Pulseaudio soundcard to work? Is a mismatch between these two the main suspect?

I even recorded footage on OBS to see if the noises would be recorded by the footage, it's here:
https://www.youtube.com/watch?v=t7Yw9a1OWJQ

Add more instruments

I've noticed while playing this MIDI, the music seems a bit off. Timidity doesn't have enough instruments to play Passport correctly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.