Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/midi/AlphaSynthMidiFileHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MidiFile } from '@src/midi/MidiFile';
import { MidiUtils } from '@src/midi/MidiUtils';
import { DynamicValue } from '@src/model/DynamicValue';
import { SynthConstants } from '@src/synth/SynthConstants';
import { Midi20PerNotePitchBendEvent } from './Midi20ChannelVoiceEvent';

/**
* This implementation of the {@link IMidiFileHandler}
Expand Down Expand Up @@ -132,6 +133,26 @@ export class AlphaSynthMidiFileHandler implements IMidiFileHandler {
this._midiFile.addEvent(message);
}

public addNoteBend(track: number, tick: number, channel: number, key: number, value: number): void {
if (value >= SynthConstants.MaxPitchWheel) {
value = SynthConstants.MaxPitchWheel;
} else {
value = Math.floor(value);
}

// map midi 1.0 range of 0-16384 (0x4000)
// to midi 2.0 range of 0-4294967296 (0x100000000)
value = value * SynthConstants.MaxPitchWheel20 / SynthConstants.MaxPitchWheel

const message = new Midi20PerNotePitchBendEvent(
tick,
this.makeCommand(MidiEventType.PerNotePitchBend, channel),
key,
value
);
this._midiFile.addEvent(message);
}

public finishTrack(track: number, tick: number): void {
const message: MetaDataEvent = new MetaDataEvent(tick, 0xff, MetaEventType.EndOfTrack, new Uint8Array(0));
this._midiFile.addEvent(message);
Expand Down
12 changes: 12 additions & 0 deletions src/midi/IMidiFileHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ export interface IMidiFileHandler {
*/
addTempo(tick: number, tempo: number): void;

/**
* Add a bend specific to a note to the generated midi file.
* The note does not need to be started, if this event is signaled, the next time a note
* on this channel and key is played it will be affected. The note bend is cleared on a note-off for this key.
* @param track The midi track on which the bend should change.
* @param tick The midi ticks when the bend should change.
* @param channel The midi channel on which the bend should change.
* @param channel The key of the note that should be affected by the bend.
* @param value The new bend for the selected note.
*/
addNoteBend(track: number, tick: number, channel: number, key: number, value: number): void;

/**
* Add a bend to the generated midi file.
* @param track The midi track on which the bend should change.
Expand Down
37 changes: 37 additions & 0 deletions src/midi/Midi20ChannelVoiceEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { IWriteable } from '@src/io/IWriteable';
import { MidiEvent } from '@src/midi/MidiEvent';

/*
* Represents a MIDI 2.0 Channel Voice Message.
*/
export class Midi20PerNotePitchBendEvent extends MidiEvent {

public noteKey: number;
public pitch: number;

public constructor(tick: number, status: number, noteKey: number, pitch: number) {
super(tick, status, 0, 0);
this.noteKey = noteKey;
this.pitch = pitch;
}

/**
* Writes the midi event as binary into the given stream.
* @param s The stream to write to.
*/
public writeTo(s: IWriteable): void {
let b: Uint8Array = new Uint8Array([
0x40,
this.message & 0xff,
this.noteKey & 0xff,

0x00 /* reserved */,
/* 32bit pitch integer */
(this.pitch >> 24) & 0xff,
(this.pitch >> 16) & 0xff,
(this.pitch >> 8) & 0xff,
this.pitch & 0xff
]);
s.write(b, 0, b.length);
}
}
6 changes: 6 additions & 0 deletions src/midi/MidiEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { IWriteable } from '@src/io/IWriteable';
* Lists all midi events.
*/
export enum MidiEventType {

/**
* A per note pitch bend. (Midi 2.0)
*/
PerNotePitchBend = 0x60,

/**
* A note is released.
*/
Expand Down
Loading