• Stars
    star
    139
  • Rank 262,954 (Top 6 %)
  • Language
    Swift
  • License
    MIT License
  • Created almost 8 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simplest MIDI Swift library

WebMIDIKit: Simplest Swift MIDI library

###Want to learn audio synthesis, sound design and how to make cool sounds in an afternoon? Check out Syntorial!

About

What's MIDI

MIDI is a standard governing music software and music device interconnectivity. It lets you make music by sending data between applications and devices.

What's WebMIDI

WebMIDI is a browser API standard that brings the MIDI technology to the web. WebMIDI is minimal, it only describes MIDI port selection, receiving data from input ports and sending data to output ports. WebMIDI is currently implemented in Chrome & Opera. Note that WebMIDI is relatively low level as messages are still represented as sequences of UInt8s (bytes/octets).

What's WebMIDIKit

WebMIDIKit is an implementation of the WebMIDI API for macOS/iOS. On these OS, the native framework for working with MIDI is CoreMIDI. CoreMIDI is old and the API is entirely in C (💩). Using it involves a lot of void pointer casting (💩^9.329), and other unspeakable things. Furthermore, some of the APIs didn't quite survive the transition to Swift and are essentially unusable in Swift (MIDIPacketList APIs, I'm looking at you).

CoreMIDI is also extremely verbose and error prone. Selecting an input port and receiving data from it is ~80 lines of convoluted Swift code. WebMIDIKit let's you do the same thing in 1.

WebMIDIKit is a part of the AudioKit project and will eventually replace AudioKit's MIDI implementation.

Also note that WebMIDIKit adds some APIs which aren't a part of the WebMIDI standard. These are marked as non-standard in the code base.

Usage

Installation

Use Swift Package Manager. Add the following .Package entry into your dependencies.

.Package(url: "https://github.com/adamnemecek/webmidikit", from: "1.0.0")

Check out the sample project.

Selecting an input port and receiving MIDI messages from it

import WebMIDIKit

/// represents the MIDI session
let midi: MIDIAccess = MIDIAccess()

/// prints all MIDI inputs available to the console and asks the user which port they want to select
let inputPort: MIDIInput? = midi.inputs.prompt()

/// Receiving MIDI events 
/// set the input port's onMIDIMessage callback which gets called when the port receives MIDI packets
inputPort?.onMIDIMessage = { (list: UnsafePointer<MIDIPacketList>) in
    for packet in list {
        print("received \(packet)")
    }
}

Selecting an output port and sending MIDI packets to it

/// select an output port
let outputPort: MIDIOutput? = midi.outputs.prompt()

/// send messages to it
outputPort.map {

	/// send a note on message
	/// the bytes are in the normal MIDI message format (https://www.midi.org/specifications/item/table-1-summary-of-midi-message)
	/// i.e. you have to send two events, a note on event and a note off event to play a single note
	/// the format is as follows:
	/// byte0 = message type (0x90 = note on, 0x80 = note off)
	/// byte1 = the note played (0x60 = C8, see http://www.midimountain.com/midi/midi_note_numbers.html)
	/// byte2 = velocity (how loud the note should be 127 (=0x7f) is max, 0 is min)

	let noteOn: [UInt8] = [0x90, 0x60, 0x7f]
	let noteOff: [UInt8] = [0x80, 0x60, 0]

	/// send the note on event
	$0.send(noteOn)

	/// send a note off message 1000 ms (1 second) later
	$0.send(noteOff, offset: 1000)

	/// in WebMIDIKit, you can also chain these
	$0.send(noteOn)
	  .send(noteOff, offset: 1000)
}

If the output port you want to select has a corresponding input port you can also do

let outputPort: MIDIOutput? = midi.output(for: inputPort)

Similarly, you can find an input port for the output port.

let inputPort2: MIDIInput? = midi.input(for: outputPort)

Looping over ports

Port maps are dictionary like collections of MIDIInputs or MIDIOutputs that are indexed with the port's id. As a result, you cannot index into them like you would into an array (the reason for this being that the endpoints can be added and removed so you cannot reference them by their index).

for (id, port) in midi.inputs {
	print(id, port)
}

Creating virtual ports

To create virtual input and output ports, use the the createVirtualVirtualMIDIInput and createVirtualVirtualMIDIOutput functions respectively.

let virtualInput = midi.createVirtualMIDIInput(name: "Virtual input")

let virtualOutput = midi.createVirtualMIDIOutput(name: "Virtual output") { (list: UnsafePointer<MIDIPacketList>) in

}

Installation

Use Swift Package Manager. Add the following .Package entry into your dependencies.

.Package(url: "https://github.com/adamnemecek/webmidikit", from: "1.0.0")

If you are having any build issues, look at the sample project sample project.

Documentation

MIDIAccess

Represents the MIDI session. See spec.

class MIDIAccess {
	/// collections of MIDIInputs and MIDIOutputs currently connected to the computer
	var inputs: MIDIInputMap { get }
	var outputs: MIDIOutputMap { get }

	/// will be called if a port changes either connection state or port state
	var onStateChange: ((MIDIPort) -> ())? = nil { get set }

	init()
	
	/// given an output, tries to find the corresponding input port
	func input(for port: MIDIOutput) -> MIDIInput?
	
	/// given an input, tries to find the corresponding output port
	/// if you send data to the output port returned, the corresponding input port
	/// will receive it (assuming the `onMIDIMessage` is set)
	func output(for port: MIDIInput) -> MIDIOutput?
}

MIDIPort

See spec. Represents the base class of MIDIInput and MIDIOutput.

Note that you don't construct MIDIPorts nor it's subclasses yourself, you only get them from the MIDIAccess object. Also note that you only ever deal with subclasses or MIDIPort (MIDIInput or MIDIOutput) never MIDIPort itself.

class MIDIPort {

	var id: Int { get }
	var manufacturer: String { get }

	var name: String { get }

	/// .input (for MIDIInput) or .output (for MIDIOutput)
	var type: MIDIPortType { get }

	var version: Int { get }

	/// .connected | .disconnected,
	/// indicates if the port's endpoint is connected or not
	var state: MIDIPortDeviceState { get }

	/// .open | .closed
	var connection: MIDIPortConnectionState { get }

	/// open the port, is called implicitly when MIDIInput's onMIDIMessage is set or MIDIOutputs' send is called
	func open()

	/// closes the port
	func close()
}

MIDIInput

Allows for receiving data send to the port.

See spec.

class MIDIInput: MIDIPort {
	/// set this and it will get called when the port receives messages.
	var onMIDIMessage: ((UnsafePointer<MIDIPacketList>) -> ())? = nil { get set }
}

MIDIOutput

See spec.

class MIDIOutput: MIDIPort {

	/// send data to port, note that unlike the WebMIDI API, 
	/// the last parameter specifies offset from now, when the event should be scheduled (as opposed to absolute timestamp)
	/// the unit remains milliseconds though.
	/// note that right now, WebMIDIKit doesn't support sending multiple packets in the same call, to send multiple packets, you need on call per packet
	func send<S: Sequence>(_ data: S, offset: Timestamp = 0) -> MIDIOutput where S.Iterator.Element == UInt8
	
	// clear all scheduled but yet undelivered midi events
	func clear()
}

More Repositories

1

awesome-metal

A collection of Metal and MetalKit projects and resources. Very much work in progress.
171
star
2

adjoint

Thoughts on adjoint, norm and such.
152
star
3

FScriptAnywhere

F-Script Anywhere for Mac OS X Mavericks (10.9), Yosemite (10.10), El Capitan (10.11)
66
star
4

shadertoy

Rust
30
star
5

femtovg

Rust
24
star
6

zipline

The cd companion utility you've always wanted
Swift
17
star
7

AnvilKit

AnvilKit tames Metal. Very much WIP.
Swift
11
star
8

pgraph

Rust
8
star
9

ScoreFollower

HTML
7
star
10

Arena

Implementation of the Arena data structure in Swift.
Swift
7
star
11

DualQuaternionToolbox

MATLAB
6
star
12

see-mirror

SEE: Simple ECMAScript Engine Mirror
C
6
star
13

avfoundation-rs

Rust
5
star
14

coinductive

5
star
15

juce

Rust bindings for JUCE
C++
4
star
16

WebMIDIKitDemo

Simple Demo of WebMIDIKit
Swift
4
star
17

firmament

Rust
3
star
18

rust_tricks

A collection of some Rust tricks that I discovered the hard way
3
star
19

dq

Dual quaternion implementation in Rust
Rust
3
star
20

KoreMetal

Swift
3
star
21

BitSet

Generic implementation of the fixed sized BitSet data structure. Work-in-progress
Swift
3
star
22

SOFT

C
3
star
23

alchemusica

Mirror of https://osdn.net/projects/alchemusica/
Objective-C
2
star
24

potpack

Rust
2
star
25

graphics_resources

2
star
26

DualFourier

Julia
2
star
27

ColoringByPixel

像素涂色
Swift
1
star
28

Shadertweak

Objective-C
1
star
29

Conference

Swift
1
star
30

Flame

GPU-based Quake lightmapper for Mac OS X.
Swift
1
star
31

SortedArray

Swift
1
star
32

hg_sdf_metal

A Metal port of Mercury's signed distance bound utilities
Metal
1
star
33

PointOfView

Swift
1
star
34

ShapeEdit

Updated Apple sample code
Swift
1
star
35

modern_robotics

Rust port of modern robotics source code (Work in progress)
Rust
1
star
36

adopting.metal.2

Swift
1
star
37

wgpu_rects

Rust
1
star
38

aecombiner

Combine severity codes for AEs - very specific file format
Swift
1
star
39

PlaySoftMIDI

PlaySoftMIDI Apple example in Swift
Swift
1
star
40

SwiftMIDI

Some extensions for using CoreMIDI in swift.
Swift
1
star
41

adamnemecek.github.com

'muh blagh'
JavaScript
1
star
42

PerformingCalculationsOnAGPU

Objective-C
1
star
43

awesome-rust-ecs

1
star
44

adamnemecek.github.io

1
star
45

claerbout

Shell
1
star
46

VTH264Demo

C
1
star
47

adopting.metal.1

1
star
48

qtfm

Mirror of http://qtfm.sourceforce.com/
MATLAB
1
star
49

pathfinder_bug

Rust
1
star
50

GeometricAlgebra

Mirror of code from http://geometricalgebra.net/code.html
Java
1
star
51

awesome-rust-gui

1
star
52

IUEditor

IUEditor
JavaScript
1
star
53

kakao

Rust
1
star
54

raft-swift

Swift
1
star
55

CFArrayEx

Swift wrapper around CFArray
Swift
1
star
56

MetalShaders

We will port iq's WebGL fragment shader one by one from his Shader Toy website
Objective-C
1
star
57

LimitOrderBook

C++
1
star
58

coreml

Rust
1
star
59

AiFinalProject

Ai Final project for Alex Katzfey and Paul Hein
Python
1
star
60

gpuspecs

Rust
1
star