Giter Site home page Giter Site logo

jzz-midi-smf's Introduction

JZZ-midi-SMF

Standard MIDI Files: read / write / play
(MIDI 1.0 and MIDI 2.0)

Node.js Firefox Chrome Opera Safari Internet Explorer Edge
npm npm build Coverage Status Try jzz-midi-smf on RunKit

Install

npm install jzz-midi-smf --save
or yarn add jzz-midi-smf
or get the full development version and minified scripts from GitHub

Usage

Plain HTML
<script src="JZZ.js"></script>
<script src="JZZ.midi.SMF.js"></script>
//...
CDN (jsdelivr)
<script src="https://cdn.jsdelivr.net/npm/jzz"></script>
<script src="https://cdn.jsdelivr.net/npm/jzz-midi-smf"></script>
//...
CDN (unpkg)
<script src="https://unpkg.com/jzz"></script>
<script src="https://unpkg.com/jzz-midi-smf"></script>
//...
CommonJS
var JZZ = require('jzz');
require('jzz-midi-smf')(JZZ);
//...
TypeScript / ES6
import { JZZ } from 'jzz';
import { SMF } from 'jzz-midi-smf';
SMF(JZZ);
//...
AMD
require(['JZZ', 'JZZ.midi.SMF'], function(JZZ, dummy) {
  // ...
});

MIDI files

Supported file formats: .mid, .kar, .rmi

Please check the API Reference !

Playing MIDI file
var midiout = JZZ().openMidiOut();
var data = require('fs').readFileSync('file.mid', 'binary');
// data can be String, Buffer, ArrayBuffer, Uint8Array or Int8Array
var smf = new JZZ.MIDI.SMF(data);
var player = smf.player();
player.connect(midiout);
player.play();
//...
player.speed(0.5); // play twice slower
Viewing the contents of MIDI file
console.log(smf.toString());
Validating MIDI file
var warn = smf.validate();
if (warn) console.log(warn);
Creating MIDI file from scratch
var smf = new JZZ.MIDI.SMF(0, 96); // type 0, 96 ticks per quarter note
var trk = new JZZ.MIDI.SMF.MTrk();
smf.push(trk);
// add contents:
trk.add(0, JZZ.MIDI.smfSeqName('This is a sequence name'))
   .add(0, JZZ.MIDI.smfBPM(90)) // tempo 90 bpm
   .add(96, JZZ.MIDI.noteOn(0, 'C6', 127))
   .add(96, JZZ.MIDI.noteOn(0, 'Eb6', 127))
   .add(96, JZZ.MIDI.noteOn(0, 'G6', 127))
   .add(192, JZZ.MIDI.noteOff(0, 'C6'))
   .add(192, JZZ.MIDI.noteOff(0, 'Eb6'))
   .add(192, JZZ.MIDI.noteOff(0, 'G6'))
   .add(288, JZZ.MIDI.smfEndOfTrack());
// or an alternative way:
trk.smfSeqName('This is a sequence name').smfBPM(90).tick(96)
   .noteOn(0, 'C6', 127).noteOn(0, 'Eb6', 127).noteOn(0, 'G6', 127)
   .tick(96).noteOff(0, 'C6').noteOff(0, 'Eb6').noteOff(0, 'G6')
   .tick(96).smfEndOfTrack();
// or even shorter:
trk.smfSeqName('This is a sequence name').smfBPM(90).tick(96)
   .ch(0).note('C6', 127, 96).note('Eb6', 127, 96).note('G6', 127, 96)
   .tick(192).smfEndOfTrack();
Exporting MIDI file data as JSON or any custom format

One easy thing to remember: SMF is an Array of Tracks and Track is an Array of MIDI events:

for (var i = 0; i < smf.length; i++) {
  for (var j = 0; j < smf[i].length; j++) {
    console.log('track:', i, 'tick:', smf[i][j].tt, smf[i][j].toString());
    // or do whatever else with the message
  }
}
Transposing MIDI file
for (var i = 0; i < smf.length; i++) {
  if (smf[i] instanceof JZZ.MIDI.SMF.MTrk) {
    for (var j = 0; j < smf[i].length; j++) {
      var note = smf[i][j].getNote();
      if (typeof note != 'undefined') {
        if (smf[i][j].getChannel() != 9) { // skip the percussion channel
          smf[i][j].setNote(note + 12);    // transpose one octave up
        }
      }
    }
  }
}
Getting the info
var player = smf.player();
var dump = smf.dump();
console.log('Type:', player.type());
console.log('Number of tracks:', player.tracks());
console.log('Size:', dump.length, 'bytes');
console.log('Duration:', player.duration(), 'ticks');
console.log('Total time:', player.durationMS(), 'milliseconds');
Saving MIDI file
require('fs').writeFileSync('out.mid', smf.dump(), 'binary');

SYX files

All calls are almost identical to those for the SMF files:
var data = require('fs').readFileSync('file.syx', 'binary');
var syx = new JZZ.MIDI.SYX(data);
syx.send([0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7]);
syx.sxMasterVolumeF(0.5);
var player = syx.player();
player.connect(midiout);
player.play();
require('fs').writeFileSync('out.syx', syx.dump(), 'binary');

MIDI 2.0 Clips

Playing MIDI 2.0 clip
var midiout = JZZ().openMidiOut();
var data = require('fs').readFileSync('file.midi2', 'binary');
var clip = new JZZ.MIDI.Clip(data);
var player = clip.player();
// since the majority of today's MIDI devices only support MIDI 1.0,
// we can use a converter:
var conv = JZZ.M2M1();
conv.connect(midiout);
player.connect(conv);
player.play();
Creating MIDI 2.0 clip from scratch
var clip = new JZZ.MIDI.Clip();
clip.gr(0).ch(0).noteOn('C5').tick(96).noteOff('C5');
require('fs').writeFileSync('out.midi2', clip.dump(), 'binary');
Most of other calls - same as above
var player = clip.player();
var dump = clip.dump();
console.log(clip.toString());
console.log('Size:', dump.length, 'bytes');
console.log('Duration:', player.duration(), 'ticks');
console.log('Total time:', player.durationMS(), 'milliseconds');

Live DEMOs (source code included)

Read MIDI file - from file, URL, Base64
Write MIDI file - create MIDI file from scratch
MIDI Player - various ways to play MIDI file
Karaoke - playing MIDI files in .kar format

By popular demand

Boilerplate code for bulk MIDI file editing
const fs = require('fs');
const JZZ = require('jzz');
require('jzz-midi-smf')(JZZ);

if (process.argv.length != 4) {
  console.log('Usage: node ' + process.argv[1] + ' <input.mid> <output.mid>');
  process.exit(1);
}

var old_midi = new JZZ.MIDI.SMF(fs.readFileSync(process.argv[2], 'binary'));
var new_midi = new JZZ.MIDI.SMF(old_midi); // copy all settings from the old file
new_midi.length = 0; // remove all tracks

for (var i = 0; i < old_midi.length; i++) {
  var old_track = old_midi[i];
  if (!(old_track instanceof JZZ.MIDI.SMF.MTrk)) continue;
  var new_track = new JZZ.MIDI.SMF.MTrk();
  new_midi.push(new_track);
  for (var j = 0; j < old_track.length; j++) {
    var old_msg = old_track[j];
    var tick = old_msg.tt; // change it if you like, e.g. tick = old_msg.tt / 2;
    if (true) { // add your own condition
      new_track.add(tick, old_msg);
    }
    else if (false) { // add new messages or don't add anything
      var new_msg = JZZ.MIDI.whatever(READ_THE_REFERENCE);
      new_track.add(tick, new_msg);
    }
  }
}
fs.writeFileSync(process.argv[3], new_midi.dump(), 'binary');

See also

Test MIDI Files - these may be useful if you write a MIDI application...

More information

Please visit https://jazz-soft.net for more information.

Thanks for your support!

Stargazers for @jazz-soft/JZZ-midi-SMF

jzz-midi-smf's People

Contributors

jazz-soft avatar pearcemerritt 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

Watchers

 avatar  avatar  avatar  avatar

jzz-midi-smf's Issues

Some other programs cannot find certain tracks

Here's my code.
var JZZ=require('jzz'); require('jzz-midi-smf')(JZZ); var smf = new JZZ.MIDI.SMF(0, 96); // type 0, 96 ticks per quarter note var trk = new JZZ.MIDI.SMF.MTrk(); smf.push(trk); // add contents: trk.add(0, JZZ.MIDI.smfSeqName('This is a sequence name')) .add(0, JZZ.MIDI.smfBPM(90)) // tempo 90 bpm .add(96, JZZ.MIDI.noteOn(0, 'D6', 127)) .add(192, JZZ.MIDI.noteOff(0, 'D6')) .add(0, JZZ.MIDI.noteOn(0, 'E6', 127)) .add(96, JZZ.MIDI.noteOff(0, 'E6')) .add(288, JZZ.MIDI.smfEndOfTrack()); var trk1 = new JZZ.MIDI.SMF.MTrk(); trk1.ch(2); smf.push(trk1); trk1.add(0, JZZ.MIDI.smfSeqName('This is another sequence name')) .add(96, JZZ.MIDI.noteOn(0, 'F6', 127)) .add(192, JZZ.MIDI.noteOff(0, 'F6')) .add(0, JZZ.MIDI.noteOn(0, 'G6', 127)) .add(96, JZZ.MIDI.noteOff(0, 'G6')) .add(288, JZZ.MIDI.smfEndOfTrack()); require('fs').writeFileSync('out.mid', smf.dump(), 'binary');

If I open out.mid in MuseScore or in Domino, only the first track opens, which is strange, since Windows Media Player is able to find the other track.

MTrk fails without 'new' keyword

The JZZ.MIDI.SMF reference says an MTrk can be created without new:
Screen Shot 2019-05-19 at 1 38 26 PM

However, I get this error:

/path/to/app/node_modules/jzz-midi-smf/javascript/JZZ.midi.SMF.js:339
      this.push(new Event(0, '\xff\x2f', ''));
           ^

TypeError: this.push is not a function
    at Function.MTrk (/path/to/app/node_modules/jzz-midi-smf/javascript/JZZ.midi.SMF.js:339:12)
    at Object.<anonymous> (/path/to/app/dist/smf_workspace.js:7:24)
...

when I run this code in Node.js:

var JZZ = require('jzz');
require('jzz-midi-smf')(JZZ);

var smf = new JZZ.MIDI.SMF(0, 96); // type 0, 96 ticks per quarter note
var trk = JZZ.MIDI.SMF.MTrk();
smf.push(trk);
// add contents:
trk.smfSeqName('This is a sequence name').smfBPM(90).tick(96)
   .ch(0).note('C6', 127, 96).note('Eb6', 127, 96).note('G6', 127, 96)
   .tick(192).smfEndOfTrack();

var midiout = JZZ().openMidiOut();
var player = smf.player();
player.connect(midiout);
player.play();

JZZ.close();

This code (except for JZZ.close()) is all copied from examples in README.md.

If I change the 5th line from

var trk = JZZ.MIDI.SMF.MTrk();

to

var trk = new JZZ.MIDI.SMF.MTrk();

I hear the C minor chord as expected

smfText at tick(0) does not appear in output

.smfText('@TMary Was A Little Lame') // Karaoke player will recognize this track by the "@T" tag
.tick(0).smfText('\\Ma') // New verse starts with a backslash "\"
.tick(75).smfText('ry ')
.tick(25).smfText('was ')

Can't load any midis.

Here is an example with 0.mid:

/workspace/nodejs-midiplayer/node_modules/jzz/javascript/JZZ.js:1605
  function _throw(x) { throw RangeError('Bad MIDI value: ' + x); }
                             ^

RangeError: Bad MIDI value: MThd`MTrk>ÿ
4-Byte VLQÿhttps://jazz-soft.netÿKThis file has 4-byte VLQ delta times. Technically, it's a valid MIDI file.
ÿYou must hear a C-Major scale.`<@`>@`@@`A@`C@`E@`G@`H@ÿ
Thank you!ÿ/

Another example with a different midi:

/workspace/nodejs-midiplayer/node_modules/jzz/javascript/JZZ.js:1605
  function _throw(x) { throw RangeError('Bad MIDI value: ' + x); }
                             ^

RangeError: Bad MIDI value: MThdàMTrk,WÿÿYúÿQ¢_°yÀ°d

Theres more after that RangeError, but its just a bunch of midi data. I loaded the midi just like the examples have shown, with fs.

How to run?

I am trying to run it using react. But I can't get it started. Can you explain me or share me the hello-world example of this package? And I just want midi file read, play, and change tempo features, so which package should I try? There's a lot on your github. I am so lost. Please help.

MTrk.note does not update length

describe('MTrk.note', function() {
  it('should update the length property of the calling MTrk', function() {
    var trk = new JZZ.MIDI.SMF.MTrk();
    trk = trk.ch(0);
    assert.equal(trk.length, 1);

    trk = trk.note('C4', 127);
    assert.equal(trk.length, 2);
  });
});

The above test fails. It can be found in my branch.

I discovered this while trying to write unit tests for some code in an app I've created that uses MTrk. I don't fully understand how MTrk works and my app is working fine as far as I can see and hear, so perhaps this is expected behavior? But, even if it is, it would be nice to have the length properly reflected on the MTrk object so that my unit tests can validate that program behavior is still correct (e.g. midi "noteOn" events have been added to SMF's, etc.) without having to play audio and use human ears to judge :)

From the digging that I've done, part of the issue may be with this line:

MTrk.prototype.send = function(msg) { this._orig.add(this._tick, msg); };

As far as I can tell: because my code builds SMF's using MTrk.ch and then subsequent Mtrk.note and Mtrk.tick calls, it gets in a situation where the MTrk object is converted into a Chan object but this._orig points at the original MTrk object the Chan was converted from. Then any calls to Chan.note result in calls to Chan.send, which updates this._orig and the two objects' states get out of sync. Had the MTrk not been wrapped by the Chan, this would have been pointing at itself and it wouldn't have mattered if calls were made on this or this._orig.

Uncaught Error: Invalid parameters

I have a bunch of midis that don't want to load for some reason. It seems to be the way they are loaded into SMF, because it loads fine in nodejs using fs. Here's what I load it with:

        let selectedFile = document.getElementById('midi_file_input').files[0];
        let reader = new FileReader();
        reader.onload = function(e) {
            midiPlayer = new JZZ.MIDI.SMF(e.target.result).player();
            midiPlayer.connect(nodemidiport);
            midiPlayer.onEnd = function() {
                alert("Midi finished!");
            }
        };
        reader.readAsArrayBuffer(selectedFile);

"npm run coverage" does not work out of the box

I cloned this project yesterday. To get it up an running today I did: npm i and then tried the scripts in package.json. The first two (test and lint) worked. But when I tried to run coverage I got an error.

I'm guessing it's a simple piece missing from my local set-up that's not accounted for in the script, but I don't know what the expected behavior is, so I thought I'd just open this here for a rainy day.

Error:

$ npm run coverage

> [email protected] coverage /Users/pearcemerritt/dev/JZZ-midi-SMF
> nyc report --reporter=text-lcov | coveralls


/Users/pearcemerritt/dev/JZZ-midi-SMF/node_modules/coveralls/bin/coveralls.js:18
        throw err;
        ^
Bad response: 422 {"message":"Couldn't find a repository matching this job.","error":true}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] coverage: `nyc report --reporter=text-lcov | coveralls`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] coverage script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/pearcemerritt/.npm/_logs/2019-07-09T18_37_44_989Z-debug.log

/Users/pearcemerritt/.npm/_logs/2019-07-09T18_37_44_989Z-debug.log:

0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   '/usr/local/Cellar/node/12.1.0/bin/node',
1 verbose cli   '/usr/local/bin/npm',
1 verbose cli   'run',
1 verbose cli   'coverage'
1 verbose cli ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'precoverage', 'coverage', 'postcoverage' ]
5 info lifecycle [email protected]~precoverage: [email protected]
6 info lifecycle [email protected]~coverage: [email protected]
7 verbose lifecycle [email protected]~coverage: unsafe-perm in lifecycle true
8 verbose lifecycle [email protected]~coverage: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/pearcemerritt/dev/JZZ-midi-SMF/node_modules/.bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/dev/bin:/Users/pearcemerritt/Library/Android/sdk/emulator:/Users/pearcemerritt/Library/Android/sdk/tools:/Users/pearcemerritt/Library/Android/sdk/tools/bin:/Users/pearcemerritt/Library/Android/sdk/platform-tools
9 verbose lifecycle [email protected]~coverage: CWD: /Users/pearcemerritt/dev/JZZ-midi-SMF
10 silly lifecycle [email protected]~coverage: Args: [ '-c', 'nyc report --reporter=text-lcov | coveralls' ]
11 silly lifecycle [email protected]~coverage: Returned: code: 1  signal: null
12 info lifecycle [email protected]~coverage: Failed to exec coverage script
13 verbose stack Error: [email protected] coverage: `nyc report --reporter=text-lcov | coveralls`
13 verbose stack Exit status 1
13 verbose stack     at EventEmitter.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:301:16)
13 verbose stack     at EventEmitter.emit (events.js:196:13)
13 verbose stack     at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
13 verbose stack     at ChildProcess.emit (events.js:196:13)
13 verbose stack     at maybeClose (internal/child_process.js:1000:16)
13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:267:5)
14 verbose pkgid [email protected]
15 verbose cwd /Users/pearcemerritt/dev/JZZ-midi-SMF
16 verbose Darwin 17.7.0
17 verbose argv "/usr/local/Cellar/node/12.1.0/bin/node" "/usr/local/bin/npm" "run" "coverage"
18 verbose node v12.1.0
19 verbose npm  v6.9.0
20 error code ELIFECYCLE
21 error errno 1
22 error [email protected] coverage: `nyc report --reporter=text-lcov | coveralls`
22 error Exit status 1
23 error Failed at the [email protected] coverage script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]

Can't generate drum midi sound

Hello. Thank you for great library. Convenient api makes me happy.
However I can't get drums work.
I added one more track to existing example and tried to setup bass drum and snare.
https://usermanuals.finalemusic.com/SongWriter2012Win/Content/PercussionMaps.htm
Generated file don't play drums sound(windows midi player) however midi notes exists in DAW(reaper).
Also when piano exists instead of vibraphone it doesn't produce sound. I tried using different channels but got stuck.
Please provide example how to make drums sound together with piano.

CODE:

<!DOCTYPE html>
<html>
<head>
<title>Write MIDI File</title>
<script src="https://cdn.jsdelivr.net/npm/jzz"></script>
<script src="https://cdn.jsdelivr.net/npm/jzz-midi-smf"></script>
<!-- https://github.com/jazz-soft/JZZ-midi-GM -->
<script src="https://cdn.jsdelivr.net/npm/jzz-midi-gm"></script>
<!-- <script src="./tracks.js"></script> -->
</head>

<body>
<h1>Write MIDI File</h1>

<div id=out></div>
<!-- <button onClick="playTrack()">Play</button> -->

<script type="module">

// Create a MIDI file. Type 1; 100 clocks per quarter note.
// Normally, it would rather be 96, but 100 makes it easier to count.
var smf = new JZZ.MIDI.SMF(1, 100);

// Add MIDI file tracks:
var trk0 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk0); // First track in Type 1 MIDI file is normally used for tempo changes
var trk1 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk1); // This one will be for the karaoke lyrics
var trk2 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk2); // This one will be for the music
var trk3 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk3); // This one will be for the music

trk0.smfSeqName('Little Lame') // The name of the first track serves as the file title
    .smfBPM(90); // Tempo. Normally set at clock 0, but can be also changed later

trk1.smfSeqName('Lyrics') // The names of other tracks don't have any particular meaning
    .smfText('@TMary Was A Little Lame') // Karaoke player will recognize this track by the "@T" tag
    .tick(100).smfText('\\Ma') // New verse starts with a backslash "\"
    .tick(75).smfText('ry ')
    .tick(25).smfText('was ')
    .tick(50).smfText('a ')
    .tick(50).smfText('lit')
    .tick(50).smfText('tle ')
    .tick(50).smfText('lame,')
    .tick(100).smfText('/Lit') // New line starts with a slash "/"
    .tick(50).smfText('tle ')
    .tick(50).smfText('lame,')
    .tick(100).smfText('/Lit')
    .tick(50).smfText('tle ')
    .tick(50).smfText('lame,')
    .tick(100).smfText('/Ma')
    .tick(75).smfText('ry ')
    .tick(25).smfText('was ')
    .tick(50).smfText('a ')
    .tick(50).smfText('lit')
    .tick(50).smfText('tle ')
    .tick(50).smfText('lame,')
    .tick(50).smfText('/A ')
    .tick(50).smfText('lit')
    .tick(50).smfText('tle ')
    .tick(50).smfText('lame ')
    .tick(50).smfText('was ')
    .tick(50).smfText('she!');
    

trk2.smfSeqName('Music')
    .ch(0) // all subsequent messahes will go to channel 0
    .program(0x0b) // set channel 0 program to vibraphone
    .tick(50).note('E5', 127, 5).note('E6', 127, 20)  // clock: 100, MIDI channel: 0, note: E5, velocity: 127, duration: 50 clocks
    .tick(50).note('D5', 127, 50)  // etc...
    .tick(50).note('C5', 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(50).note('E5',127, 25)
    .tick(50).note(64, 127, 50)   // can also use numerical values for the notes
    .tick(50).note(0x40, 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(100).note('E5', 127, 50)
    .tick(50).note('G5', 127, 50)
    .tick(50).note('G5', 127, 90)
    .tick(100).note('E5', 127, 75)
    .tick(75).note('D5', 127, 25)
    .tick(25).note('C5', 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(50).note('E5', 127, 50)
    .tick(50).note('E5', 127, 50)
    .tick(50).note('E5', 127, 50)
    .tick(75).note('E5', 127, 25)
    .tick(25).note('D5', 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(50).note('E5', 127, 50)
    .tick(50).note('D5', 127, 50)
    .tick(50).note('C5', 127, 190)
    .tick(100).note('E5', 100, 90).note('G5', 100, 90).note('C6', 127, 90)
    .tick(100).smfEndOfTrack(); // otherwise it will end on clock 1690
    
trk3.smfSeqName('drum')
    .ch(0) // all subsequent messahes will go to channel 0
    .program(JZZ.MIDI.programName(0, 127, 0))
    //.program('Standard Drum Kit') 
    .tick(50).note(0x51, 127, 5)  
    .tick(50).note(0x52, 127, 50)  
    .tick(50).note(0x53, 127, 50)
    .tick(50).note(0x54, 127, 50)
    .tick(50).note(36,127, 25)
    .tick(50).note(64, 127, 50)  
    .tick(50).note(0x40, 127, 50)
    .tick(50).note(36, 127, 50)
    .tick(50).note(20, 127, 50)
    .tick(50).note('C2', 127, 50)
    .tick(50).note('D2', 127, 50)
    .tick(50).note(0x50, 127, 50)
    .tick(50).note(0x60, 127, 50)
    .tick(50).note('C2', 127, 90)
    .tick(50).note(36, 127, 50)
    
    .tick(50).note(37, 127, 90)
    
    .tick(75).note(38, 127, 25)
    .tick(25).note(39, 127, 50)
    .tick(50).note('C2', 127, 50)
    .tick(50).note('D2', 127, 50)
    .tick(50).note(38, 127, 50)
    .tick(50).note('D2', 127, 50)
    .tick(75).note('D2', 127, 25)
    .tick(25).note('D2', 127, 50)
    .tick(50).note('D2', 127, 50)
    .tick(50).note('D2', 127, 50)
    .tick(50).note('C2', 127, 50)
    .tick(50).note('C2', 127, 190)
    .tick(50).note('D2', 100, 90)
    .tick(50).note('C2', 127, 190)
    .tick(50).note(40, 127, 50)
    .tick(50).note(41, 127, 50)
    .tick(50).note(42, 127, 190)
    .tick(50).note(43, 100, 90)
    .tick(50).note('C2', 127, 190)
    .tick(50).note('C2', 127, 190)
    .tick(50).note(50, 127, 190)
    .tick(50).note(50, 127, 190)
    
    .tick(100).smfEndOfTrack(); // otherwise it will end on clock 1690

var str = smf.dump(); // MIDI file dumped as a string
var b64 = JZZ.lib.toBase64(str); // convert to base-64 string
var uri = 'data:audio/midi;base64,' + b64; // data URI


// Finally, write it to the document as a link and as an embedded object:
document.getElementById('out').innerHTML = 'New file: <a download=lame.mid href=' + uri + '>DOWNLOAD</a> <embed src=' + uri + ' autostart=true>';
</script>

</body>
</html>

Typescript no exported member 'SMF'

I'm getting an error when I copy paste the example :
Module '"jzz-midi-smf"' has no exported member 'SMF'
image
I did 'import JZZ from "jzz" and that gets live audio working.
I could not get the jzz-midi-smf to work though.

I'm using Typescript/ Nodejs, compiling down in react and phaser and rendering to the browser.
I did notice this one: jazz-soft/JZZ#62
I might be able to help out if there is no quick solution to this.

Need a way to detect beats

I'm trying to make a pattern player (a drum machine) and need a way to switch between patterns in a synchronized manner.

So It would be nice if there was an easy way to detect and act on beats while the player is playing. Something like:

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

would probably do.

Something like player.on('tick', () => {}) might also be usefull, but perhaps to demanding ?

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.