or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants.mdindex.mdmessage-forwarding.mdmessage-processing.mdmidi-input.mdmidi-output.mdnote-processing.mdutilities.mdwebmidi-interface.md

utilities.mddocs/

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

```