0
# Utilities
1
2
The Utilities class provides static helper methods for MIDI data conversion, note processing, and value transformations. These utilities are essential for working with MIDI data in various formats and performing common conversions.
3
4
## Capabilities
5
6
### Note Conversion Methods
7
8
Convert between different note representations and formats.
9
10
```javascript { .api }
11
class Utilities {
12
/**
13
* Convert note identifier to MIDI note number
14
* @param identifier - Note identifier (e.g., "C4", "F#3", "Bb5")
15
* @param octaveOffset - Octave offset to apply (default: 0)
16
* @returns MIDI note number (0-127)
17
*/
18
static toNoteNumber(identifier: string, octaveOffset?: number): number;
19
20
/**
21
* Convert MIDI note number to note identifier
22
* @param number - MIDI note number (0-127)
23
* @param octaveOffset - Octave offset to apply (default: 0)
24
* @returns Note identifier (e.g., "C4", "F#3")
25
*/
26
static toNoteIdentifier(number: number, octaveOffset?: number): string;
27
28
/**
29
* Get detailed note information from number or string
30
* @param value - Note input (string or number)
31
* @returns Object with note details (name, octave, number, etc.)
32
*/
33
static getNoteDetails(value: string | number): {
34
name: string;
35
octave: number;
36
number: number;
37
accidental?: string;
38
};
39
40
/**
41
* Guess MIDI note number from various input formats
42
* @param input - Note input (string, number, Note object)
43
* @param octaveOffset - Octave offset to apply
44
* @returns MIDI note number (0-127)
45
*/
46
static guessNoteNumber(input: any, octaveOffset?: number): number;
47
}
48
```
49
50
**Usage Examples:**
51
52
```javascript
53
import { Utilities } from "webmidi";
54
55
// Convert note names to numbers
56
console.log(Utilities.toNoteNumber("C4")); // 60
57
console.log(Utilities.toNoteNumber("A4")); // 69
58
console.log(Utilities.toNoteNumber("F#3")); // 54
59
console.log(Utilities.toNoteNumber("Bb5")); // 82
60
61
// With octave offset
62
console.log(Utilities.toNoteNumber("C4", 1)); // 72 (C5)
63
console.log(Utilities.toNoteNumber("C4", -1)); // 48 (C3)
64
65
// Convert numbers to note names
66
console.log(Utilities.toNoteIdentifier(60)); // "C4"
67
console.log(Utilities.toNoteIdentifier(69)); // "A4"
68
console.log(Utilities.toNoteIdentifier(54)); // "F#3"
69
70
// Get note details
71
const details = Utilities.getNoteDetails("F#4");
72
console.log(details.name); // "F#"
73
console.log(details.octave); // 4
74
console.log(details.number); // 66
75
console.log(details.accidental); // "#"
76
77
// Guess note number from various inputs
78
console.log(Utilities.guessNoteNumber("C4")); // 60
79
console.log(Utilities.guessNoteNumber(60)); // 60
80
console.log(Utilities.guessNoteNumber("middle C")); // Attempts to parse
81
```
82
83
### Note Object Builders
84
85
Create Note objects and arrays from various inputs.
86
87
```javascript { .api }
88
/**
89
* Build a Note object from input
90
* @param input - Note input (string, number, Note object)
91
* @param options - Note creation options
92
* @returns Note object
93
*/
94
static buildNote(input: any, options?: {
95
duration?: number;
96
attack?: number;
97
release?: number;
98
octaveOffset?: number;
99
}): Note;
100
101
/**
102
* Build array of Note objects from various inputs
103
* @param notes - Note inputs (single note or array)
104
* @param options - Note creation options
105
* @returns Array of Note objects
106
*/
107
static buildNoteArray(notes: any, options?: {
108
duration?: number;
109
attack?: number;
110
release?: number;
111
octaveOffset?: number;
112
}): Note[];
113
```
114
115
**Usage Examples:**
116
117
```javascript
118
// Build single notes
119
const note1 = Utilities.buildNote("C4");
120
const note2 = Utilities.buildNote(60, { attack: 0.8 });
121
const note3 = Utilities.buildNote(existingNote);
122
123
// Build note arrays
124
const chord = Utilities.buildNoteArray(["C4", "E4", "G4"]);
125
const octave = Utilities.buildNoteArray([60, 62, 64, 65, 67, 69, 71, 72]);
126
const withOptions = Utilities.buildNoteArray(["C4", "D4", "E4"], {
127
duration: 1000,
128
attack: 0.7
129
});
130
```
131
132
### Value Conversion Methods
133
134
Convert between different MIDI value formats.
135
136
```javascript { .api }
137
/**
138
* Convert 7-bit MIDI value to float (0-1)
139
* @param value - 7-bit value (0-127)
140
* @returns Float value (0-1)
141
*/
142
static from7bitToFloat(value: number): number;
143
144
/**
145
* Convert float to 7-bit MIDI value
146
* @param value - Float value (0-1)
147
* @returns 7-bit value (0-127)
148
*/
149
static fromFloatTo7Bit(value: number): number;
150
151
/**
152
* Convert MSB/LSB pair to float value
153
* @param msb - Most significant byte (0-127)
154
* @param lsb - Least significant byte (0-127, default: 0)
155
* @returns Float value (0-1)
156
*/
157
static fromMsbLsbToFloat(msb: number, lsb?: number): number;
158
159
/**
160
* Convert float value to MSB/LSB pair
161
* @param value - Float value (0-1)
162
* @returns Object with msb and lsb properties
163
*/
164
static fromFloatToMsbLsb(value: number): {msb: number; lsb: number};
165
```
166
167
**Usage Examples:**
168
169
```javascript
170
// 7-bit conversions
171
console.log(Utilities.from7bitToFloat(0)); // 0
172
console.log(Utilities.from7bitToFloat(64)); // ~0.504
173
console.log(Utilities.from7bitToFloat(127)); // 1
174
175
console.log(Utilities.fromFloatTo7Bit(0)); // 0
176
console.log(Utilities.fromFloatTo7Bit(0.5)); // 63
177
console.log(Utilities.fromFloatTo7Bit(1)); // 127
178
179
// MSB/LSB conversions (for 14-bit values like pitch bend)
180
console.log(Utilities.fromMsbLsbToFloat(64, 0)); // Center position
181
console.log(Utilities.fromMsbLsbToFloat(127, 127)); // Maximum value
182
183
const msbLsb = Utilities.fromFloatToMsbLsb(0.75);
184
console.log(msbLsb.msb); // MSB value
185
console.log(msbLsb.lsb); // LSB value
186
```
187
188
### Number Offset Operations
189
190
Apply offsets to MIDI note numbers with validation.
191
192
```javascript { .api }
193
/**
194
* Apply octave and semitone offsets to a MIDI note number
195
* @param number - Original MIDI note number (0-127)
196
* @param octaveOffset - Octave offset (default: 0)
197
* @param semitoneOffset - Semitone offset (default: 0)
198
* @returns Modified MIDI note number (0-127)
199
*/
200
static offsetNumber(number: number, octaveOffset?: number, semitoneOffset?: number): number;
201
```
202
203
**Usage Examples:**
204
205
```javascript
206
// Apply offsets
207
console.log(Utilities.offsetNumber(60)); // 60 (no change)
208
console.log(Utilities.offsetNumber(60, 1)); // 72 (up one octave)
209
console.log(Utilities.offsetNumber(60, -1)); // 48 (down one octave)
210
console.log(Utilities.offsetNumber(60, 0, 7)); // 67 (up perfect fifth)
211
console.log(Utilities.offsetNumber(60, 1, -5)); // 67 (up octave, down fourth = fifth)
212
213
// Results are clamped to valid MIDI range (0-127)
214
console.log(Utilities.offsetNumber(120, 1)); // 127 (clamped to max)
215
console.log(Utilities.offsetNumber(5, -1)); // 0 (clamped to min)
216
```
217
218
### Channel Processing
219
220
Sanitize and convert channel inputs to proper formats.
221
222
```javascript { .api }
223
/**
224
* Sanitize channel input to array of valid channel numbers (1-16)
225
* @param channel - Channel input (number, string, or array)
226
* @returns Array of channel numbers (1-16)
227
*/
228
static sanitizeChannels(channel: number | string | number[] | "all"): number[];
229
```
230
231
**Usage Examples:**
232
233
```javascript
234
// Single channel
235
console.log(Utilities.sanitizeChannels(1)); // [1]
236
console.log(Utilities.sanitizeChannels("5")); // [5]
237
238
// Multiple channels
239
console.log(Utilities.sanitizeChannels([1, 3, 5])); // [1, 3, 5]
240
241
// All channels
242
console.log(Utilities.sanitizeChannels("all")); // [1, 2, 3, ..., 16]
243
console.log(Utilities.sanitizeChannels([])); // [1, 2, 3, ..., 16]
244
245
// Invalid channels are filtered out
246
console.log(Utilities.sanitizeChannels([0, 1, 17])); // [1] (0 and 17 removed)
247
```
248
249
### Time Conversion
250
251
Convert time values to MIDI timestamps.
252
253
```javascript { .api }
254
/**
255
* Convert time value to high-resolution timestamp
256
* @param time - Time value (number, string, or relative)
257
* @returns Timestamp in milliseconds
258
*/
259
static toTimestamp(time?: number | string): number;
260
```
261
262
**Usage Examples:**
263
264
```javascript
265
// Current time
266
console.log(Utilities.toTimestamp()); // Current timestamp
267
268
// Absolute time
269
console.log(Utilities.toTimestamp(1000)); // 1000ms from epoch
270
271
// Relative time (if supported)
272
console.log(Utilities.toTimestamp("+500")); // 500ms from now
273
274
// String parsing
275
console.log(Utilities.toTimestamp("1s")); // 1 second (if supported)
276
```
277
278
### Lookup Utilities
279
280
Find properties and names by values.
281
282
```javascript { .api }
283
/**
284
* Get property name by value in an object
285
* @param object - Object to search
286
* @param value - Value to find
287
* @returns Property name or undefined
288
*/
289
static getPropertyByValue(object: object, value: any): string | undefined;
290
291
/**
292
* Get control change name by CC number
293
* @param number - CC number (0-127)
294
* @returns Control change name
295
*/
296
static getCcNameByNumber(number: number): string;
297
298
/**
299
* Get control change number by name
300
* @param name - CC name
301
* @returns CC number (0-127) or undefined
302
*/
303
static getCcNumberByName(name: string): number | undefined;
304
305
/**
306
* Get channel mode name by number
307
* @param number - Channel mode number
308
* @returns Channel mode name
309
*/
310
static getChannelModeByNumber(number: number): string;
311
```
312
313
**Usage Examples:**
314
315
```javascript
316
// Property lookup
317
const ccMap = { volume: 7, pan: 10, sustain: 64 };
318
console.log(Utilities.getPropertyByValue(ccMap, 7)); // "volume"
319
320
// CC name lookup
321
console.log(Utilities.getCcNameByNumber(1)); // "modulation"
322
console.log(Utilities.getCcNameByNumber(7)); // "volume"
323
console.log(Utilities.getCcNameByNumber(64)); // "sustain"
324
325
// CC number lookup
326
console.log(Utilities.getCcNumberByName("volume")); // 7
327
console.log(Utilities.getCcNumberByName("sustain")); // 64
328
console.log(Utilities.getCcNumberByName("unknown")); // undefined
329
330
// Channel mode lookup
331
console.log(Utilities.getChannelModeByNumber(120)); // "allsoundoff"
332
console.log(Utilities.getChannelModeByNumber(123)); // "allnotesoff"
333
```
334
335
### Environment Detection
336
337
Detect the runtime environment.
338
339
```javascript { .api }
340
/**
341
* Whether running in Node.js environment
342
* @returns True if in Node.js
343
*/
344
static get isNode(): boolean;
345
346
/**
347
* Whether running in browser environment
348
* @returns True if in browser
349
*/
350
static get isBrowser(): boolean;
351
```
352
353
**Usage Examples:**
354
355
```javascript
356
// Environment detection
357
if (Utilities.isNode) {
358
console.log("Running in Node.js");
359
// Use Node.js specific functionality
360
}
361
362
if (Utilities.isBrowser) {
363
console.log("Running in browser");
364
// Use browser specific functionality
365
}
366
367
// Conditional imports/requires
368
const midiAccess = Utilities.isBrowser
369
? navigator.requestMIDIAccess()
370
: require('jzz')();
371
```
372
373
## Common Usage Patterns
374
375
### Note Processing Pipeline
376
377
```javascript
378
function processNoteInput(input, options = {}) {
379
// Sanitize input to note number
380
const noteNumber = Utilities.guessNoteNumber(input);
381
382
// Apply offsets if specified
383
const offsetNote = options.octaveOffset || options.semitoneOffset
384
? Utilities.offsetNumber(noteNumber, options.octaveOffset, options.semitoneOffset)
385
: noteNumber;
386
387
// Convert back to identifier
388
const identifier = Utilities.toNoteIdentifier(offsetNote);
389
390
// Build final Note object
391
return Utilities.buildNote(identifier, options);
392
}
393
394
// Usage
395
const note1 = processNoteInput("C4", { octaveOffset: 1 });
396
const note2 = processNoteInput(60, { semitoneOffset: 7 });
397
```
398
399
### Value Scaling and Conversion
400
401
```javascript
402
function scaleControllerValue(rawValue, targetMin = 0, targetMax = 1) {
403
// Convert to float first
404
const normalized = Utilities.from7bitToFloat(rawValue);
405
406
// Scale to target range
407
return targetMin + (normalized * (targetMax - targetMin));
408
}
409
410
function prepareForMidi(floatValue) {
411
// Clamp to valid range
412
const clamped = Math.max(0, Math.min(1, floatValue));
413
414
// Convert to MIDI format
415
return Utilities.fromFloatTo7Bit(clamped);
416
}
417
418
// Usage
419
const controllerValue = scaleControllerValue(100, 0, 127); // Scale CC to 0-127
420
const midiValue = prepareForMidi(0.75); // Convert 0.75 to MIDI value
421
```
422
423
### Channel Management
424
425
```javascript
426
function distributeToChannels(channels, callback) {
427
const validChannels = Utilities.sanitizeChannels(channels);
428
429
validChannels.forEach(channel => {
430
callback(channel);
431
});
432
}
433
434
// Usage
435
distributeToChannels([1, 3, 5], (channel) => {
436
output.channels[channel - 1].sendProgramChange(1);
437
});
438
439
distributeToChannels("all", (channel) => {
440
output.channels[channel - 1].sendControlChange("volume", 100);
441
});
442
```
443
444
## Types
445
446
```javascript { .api }
447
interface NoteDetails {
448
name: string;
449
octave: number;
450
number: number;
451
accidental?: string;
452
}
453
454
interface MsbLsbValue {
455
msb: number;
456
lsb: number;
457
}
458
459
type ChannelInput = number | string | number[] | "all";
460
type NoteInput = string | number | Note;
461
type TimeInput = number | string;
462
```