jzz

repository·master·Indexed 20 days ago

https://github.com/jazz-soft/jzz

A versatile MIDI library for Node.js and web browsers (version 1.9.6). It supports sending, receiving, and playing MIDI messages, with compatibility for MIDI 2.0 (UMP) and MPE. The library provides a chainable asynchronous API for opening ports, managing MIDI nodes via JZZ.Widget, and converting between MIDI note numbers, frequencies, and note names. It supports multiple engines including webmidi, node, extension, and plugin.

Tokens
9.1K
Snippets
32
Records
44
Agent score
70%

What's inside jzz

  1. How MIDI 2.0 works in JZZ

    master

    JZZ supports MIDI 2.0 via the .MIDI2() adapter. Calling .MIDI2() enables MIDI 2.0 mode for subsequent chained calls, while .MIDI1() resets the mode back to MIDI 1.0.

    Key Concepts:

    • Downstream Nodes: MIDI nodes in a chain do not need special configuration to pass through MIDI 2.0 messages.
    • MIDI 1.0 Helpers in MIDI 2.0 mode: When in MIDI 2.0 mode, most MIDI 1.0 helpers require a group as an additional first parameter. These produce MIDI 1.0 messages wrapped in UMP packages.
    • MIDI 2.0 Helpers: Use specific MIDI 2.0 helpers like .umpNoteOn() for UMP-based messages.
    • State Management: .MIDI2() and .MIDI1() clear default group, channel, SysEx ID, and MPE settings.
    • Defaults: Use .gr(group), .ch(channel), and .sxId(id) to set default values for subsequent calls.
    var first = JZZ.Widget();
    var second = JZZ.Widget();
    
    first
      .send([0x90, 0x3c, 0x7f])       // MIDI 1.0
      .MIDI2()                        // enable MIDI 2.0
      .send([0x20, 0x90, 0x3c, 0x7f]) // MIDI 2.0
      .MIDI1()                        // reset to MIDI 1.0
  2. Install JZZ

    master

    You can install JZZ using npm or yarn. For browser environments, you can use CDNs like jsDelivr or unpkg.

    NPM/Yarn:

    npm install jzz --save
    # or
    yarn add jzz

    Note: If you encounter issues with the midi-test module during installation, you can remove it from your devDependencies using npm remove midi-test --save-dev.

    CDN (jsDelivr):

    <script src="https://cdn.jsdelivr.net/npm/jzz"></script>
    <!-- Or a specific version -->
    <script src="https://cdn.jsdelivr.net/npm/jzz@1.9.6"></script>

    CDN (unpkg):

    <script src="https://unpkg.com/jzz"></script>
    <!-- Or a specific version -->
    <script src="https://unpkg.com/jzz@1.9.6"></script>
    npm install jzz --save
  3. Migrate from web-midi-api to jzz

    master

    The web-midi-api package is deprecated and is maintained only for backward compatibility with older projects. It acts as a redirect to the jzz package. For all new projects, you should install and use jzz directly instead of web-midi-api.

    // If you are using the deprecated package, it simply redirects to jzz:
    module.exports = require('jzz');
  4. Import JZZ in different environments

    master

    JZZ supports multiple module systems depending on your project setup.

    CommonJS (Node.js):

    var JZZ = require('jzz');

    TypeScript / ES6:

    import { JZZ } from 'jzz';

    AMD:

    require(['JZZ'], function(JZZ) {
      //...
    });

    Plain HTML:

    <script src="JZZ.js"></script>
  5. Use Compound MIDI messages (GCH)

    master

    Some MIDI operations require multiple messages to be sent together to achieve a single logical effect. JZZ handles this via Compound Channel Messages (GCH). When you use a GCH helper, it returns an array of MIDI messages that represent the complete operation.

    Common GCH operations include:

    • Modulation/Expression: mod(channel, msb, lsb), expression(channel, msb, lsb).
    • Pitch Bend: pitchBend(channel, msb, lsb).
    • RPN (Registered Parameter Number): Used for advanced controls like rpnPitchBendRange or rpnFineTuning. These often involve a sequence of messages (selecting the RPN, then sending the data).
    • Mode Switching: mode1(), mode2(), etc., which can set a channel to Omni/Mono and Poly/Mono simultaneously.
    // Using a GCH helper to set modulation
    // This returns an array of messages (MSB and LSB)
    const modMessages = MIDI.mod(0, 0x40, 0x00);
    
    // Sending them via a port
    port.send(modMessages);
  6. How JZZ async objects and chaining work

    master

    Most JZZ operations (like opening ports or sending messages) are asynchronous and return a specialized object (extending _R and _J) that supports a thenable interface. This allows you to chain operations using .and(), .or(), and .wait().

    Chaining and Error Handling

    • .and(func): Executes func only if the previous operation succeeded.
    • .or(func): Executes func if the previous operation failed (error handling).
    • .wait(delay): Pauses the chain for a specified number of milliseconds.
    • .then(successCallback, errorCallback): Standard Promise-like syntax for handling the result or an error.

    If an error occurs in the chain, subsequent .and() calls will be skipped, and .or() calls will be triggered.

  7. Initialize JZZ with specific engines

    master

    To initialize the JZZ library, you can pass an options object to the initialization process (internally handled by _initJZZ). You can specify which MIDI engines to attempt to use. Supported engine names include:

    • webmidi: Uses the browser's Web MIDI API.
    • node: Uses the jazz-midi package (requires jazz-midi to be installed in Node.js environments).
    • extension: Uses a Chrome/Web extension interface.
    • plugin: Uses the Jazz-Plugin (ActiveX/NPAPI).
    • none: Disables all engines.

    If you provide an array of names, JZZ will attempt them in order. If you provide a single string, it will be treated as the preferred engine. If no engine is specified, it defaults to attempting all web-based engines.

  8. Initialize JZZ

    master

    To use the JZZ library, call the JZZ function. This returns a promise (thenable) that resolves once the MIDI engine is initialized. The engine type (Node.js, Web MIDI, or Plugin) is determined by the environment and the options passed to the constructor.

    JZZ().then(function(jzz) {
      // JZZ is ready to use
    });
  9. Use asynchronous JZZ API

    master

    In environments that support async/await, you can use await with JZZ() and port methods for cleaner code flow.

    async function playNote() {
      var midi = await JZZ();
      var port = await midi.openMidiOut();
      await port.noteOn(0, 'C5', 127);
      await port.wait(500);
      await port.noteOff(0, 'C5');
      await port.close();
      console.log('done!');
    }
  10. Use the Web MIDI API in Node.js

    master

    To use MIDI functionality in Node.js via this package, you request access using navigator.requestMIDIAccess(). This returns a promise that resolves to a midiAccess object containing inputs and outputs collections.

    Key workflow steps:

    1. Call navigator.requestMIDIAccess().
    2. Access midi.inputs and midi.outputs from the resolved object.
    3. For outputs: Call .open() on a port before calling .send([data]).
    4. For inputs: Assign a function to the port.onmidimessage property to handle incoming MIDI data.
    5. Important: Call navigator.close() when finished to prevent the Node.js process from waiting for MIDI input indefinitely.
    var navigator = require('web-midi-api');
    
    var midi;
    var inputs;
    var outputs;
    
    function onMIDIFailure(msg) {
      console.log('Failed to get MIDI access - ' + msg);
      process.exit(1);
    }
    
    function onMIDISuccess(midiAccess) {
      midi = midiAccess;
      inputs = midi.inputs;
      outputs = midi.outputs;
      
      // Example: Test outputs
      outputs.forEach(function(port) {
        port.open();
        port.send([0x90, 60, 0x7f]); // Note On, Middle C, Max Velocity
      });
    
      // Example: Test inputs
      inputs.forEach(function(port) {
        port.onmidimessage = function(ev) {
          console.log('MIDI Data:', ev.data);
        };
      });
    }
    
    navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);
    
    // To exit cleanly:
    // navigator.close();
  11. Convert between MIDI and Frequency/Names

    master

    The JZZ.MIDI utility provides conversion methods between MIDI note numbers, frequencies, and note names.

    • To Frequency: JZZ.MIDI.freq('A5') or JZZ.MIDI.freq(69)
    • To MIDI Number: JZZ.MIDI.midi(440) or JZZ.MIDI.midi('A5')
    JZZ.MIDI.freq('A5'); // => 440
    JZZ.MIDI.freq(69);   // => 440
    JZZ.MIDI.midi(440);  // => 69
    JZZ.MIDI.midi('A5'); // => 69