@ryohey/wavelet
Advanced tools
Comparing version 0.3.2 to 0.3.3
@@ -11,2 +11,3 @@ import { ImmediateEvent, MIDIEventBody, SynthEvent } from "../SynthEvent"; | ||
processScheduledEvents(): void; | ||
private removeProcessedEvents; | ||
handleImmediateEvent(e: ImmediateEvent): void; | ||
@@ -13,0 +14,0 @@ handleDelayableEvent(e: MIDIEventBody): void; |
@@ -32,4 +32,12 @@ import { MIDIControlEvents } from "midifile-ts"; | ||
} | ||
arrayRemove(this.scheduledEvents, (e) => e.isProcessed); | ||
this.removeProcessedEvents(); | ||
} | ||
removeProcessedEvents() { | ||
for (let i = this.scheduledEvents.length - 1; i >= 0; i--) { | ||
const ev = this.scheduledEvents[i]; | ||
if (ev.isProcessed) { | ||
this.scheduledEvents.splice(i, 1); | ||
} | ||
} | ||
} | ||
handleImmediateEvent(e) { | ||
@@ -160,10 +168,2 @@ switch (e.type) { | ||
} | ||
function arrayRemove(arr, test) { | ||
for (let i = arr.length - 1; i >= 0; i--) { | ||
const ev = arr[i]; | ||
if (test(ev)) { | ||
arr.splice(i, 1); | ||
} | ||
} | ||
} | ||
//# sourceMappingURL=SynthEventHandler.js.map |
@@ -144,3 +144,4 @@ import { logger } from "./logger"; | ||
for (let key in state.oscillators) { | ||
for (const oscillator of state.oscillators[key]) { | ||
for (let i = state.oscillators[key].length - 1; i >= 0; i--) { | ||
const oscillator = state.oscillators[key][i]; | ||
oscillator.speed = Math.pow(2, state.pitchBend / 12); | ||
@@ -151,4 +152,6 @@ oscillator.volume = state.volume * state.expression; | ||
oscillator.process([outputs[0][0], outputs[0][1]]); | ||
if (!oscillator.isPlaying) { | ||
state.oscillators[key].splice(i, 1); | ||
} | ||
} | ||
state.oscillators[key] = state.oscillators[key]?.filter((osc) => osc.isPlaying); | ||
} | ||
@@ -155,0 +158,0 @@ } |
@@ -8,3 +8,2 @@ import { SampleData } from "../SynthEvent"; | ||
private isHold; | ||
private isLooping; | ||
private baseSpeed; | ||
@@ -11,0 +10,0 @@ private readonly envelope; |
@@ -9,6 +9,5 @@ import { AmplitudeEnvelope } from "./AmplitudeEnvelope"; | ||
isHold = false; | ||
isLooping = false; | ||
baseSpeed = 1; | ||
envelope; | ||
pitchLFO; | ||
pitchLFO = new LFO(); | ||
speed = 1; | ||
@@ -27,3 +26,2 @@ // 0 to 1 | ||
this.envelope = new AmplitudeEnvelope(sample.amplitudeEnvelope); | ||
this.pitchLFO = new LFO(); | ||
} | ||
@@ -33,3 +31,2 @@ noteOn(pitch, velocity) { | ||
this._isPlaying = true; | ||
this.isLooping = this.sample.loop !== null; | ||
this.sampleIndex = this.sample.sampleStart; | ||
@@ -70,5 +67,3 @@ this.baseSpeed = Math.pow(2, ((pitch - this.sample.pitch) / 12) * this.sample.scaleTuning); | ||
let loopIndex = null; | ||
if (this.sample.loop !== null && | ||
advancedIndex >= this.sample.loop.end && | ||
this.isLooping) { | ||
if (this.sample.loop !== null && advancedIndex >= this.sample.loop.end) { | ||
loopIndex = | ||
@@ -75,0 +70,0 @@ this.sample.loop.start + (advancedIndex - Math.floor(advancedIndex)); |
@@ -47,90 +47,2 @@ (function () { | ||
var dist = {}; | ||
Object.defineProperty(dist, '__esModule', { value: true }); | ||
var MIDIChannelEvents = { | ||
noteOff: 0x08, | ||
noteOn: 0x09, | ||
noteAftertouch: 0x0a, | ||
controller: 0x0b, | ||
programChange: 0x0c, | ||
channelAftertouch: 0x0d, | ||
pitchBend: 0x0e, | ||
}; | ||
var MIDIControlEventNames = [ | ||
"Bank Select", | ||
"Modulation", | ||
"Breath Controller", | ||
"Foot Pedal", | ||
"Portamento Time", | ||
"Data Entry", | ||
"Volume", | ||
"Balance", | ||
"Pan", | ||
"Expression", | ||
"Effect Control 1", | ||
"Effect Control 2", | ||
"Undefined", | ||
"Undefined", | ||
"General Purpose Slider 1", | ||
"General Purpose Slider 2", | ||
"General Purpose Slider 3", | ||
"Knob 2 General Purpose Slider 4", | ||
"Knob 3", | ||
"Knob 4", | ||
"Bank Select", | ||
"Modulation Wheel", | ||
"Breath controller", | ||
"Foot Pedal", | ||
"Portamento Time", | ||
"Data Entry", | ||
"Volume", | ||
"Balance", | ||
"Pan position", | ||
"Expression", | ||
"Effect Control 1", | ||
"Effect Control 2", | ||
"Hold Pedal", | ||
"Portamento", | ||
"Sustenuto Pedal", | ||
"Soft Pedal", | ||
"Legato Pedal", | ||
"Hold 2 Pedal", | ||
"Sound Variation", | ||
"Resonance", | ||
"Sound Release Time", | ||
"Sound Attack Time", | ||
"Frequency Cutoff", | ||
"Sound Control 6", | ||
"Sound Control 7", | ||
"Sound Control 8", | ||
"Sound Control 9", | ||
"Sound Control 10", | ||
"Decay", | ||
"High Pass Filter Frequency", | ||
"General Purpose Button 3", | ||
"General Purpose Button 4", | ||
"Reverb Level", | ||
"Tremolo Level", | ||
"Chorus Level", | ||
"Detune", | ||
"Phaser Level", | ||
"Data Button Increment", | ||
"Data Button Decrement", | ||
"NRPN (LSB)", | ||
"NRPN (MSB)", | ||
"RPN (LSB)", | ||
"RPN (MSB)", | ||
"All Sound Off", | ||
"All Controllers Off", | ||
"Local Keyboard", | ||
"All Notes Off", | ||
"Omni Mode Off", | ||
"Omni Mode On", | ||
"Mono Operation", | ||
"Poly Operation", | ||
]; | ||
var MIDIControlEvents = { | ||
@@ -212,457 +124,2 @@ MSB_BANK: 0x00, | ||
var MIDIMetaEventNames = { | ||
0x00: "sequenceNumber", | ||
0x01: "text", | ||
0x02: "copyrightNotice", | ||
0x03: "trackName", | ||
0x04: "instrumentName", | ||
0x05: "lyrics", | ||
0x06: "marker", | ||
0x07: "cuePoint", | ||
0x20: "midiChannelPrefix", | ||
0x21: "portPrefix", | ||
0x2f: "endOfTrack", | ||
0x51: "setTempo", | ||
0x54: "smpteOffset", | ||
0x58: "timeSignature", | ||
0x59: "keySignature", | ||
0x7f: "sequencerSpecific", | ||
}; | ||
var MIDIMetaEvents = { | ||
sequenceNumber: 0x00, | ||
text: 0x01, | ||
copyrightNotice: 0x02, | ||
trackName: 0x03, | ||
instrumentName: 0x04, | ||
lyrics: 0x05, | ||
marker: 0x06, | ||
cuePoint: 0x07, | ||
midiChannelPrefix: 0x20, | ||
portPrefix: 0x21, | ||
endOfTrack: 0x2f, | ||
setTempo: 0x51, | ||
smpteOffset: 0x54, | ||
timeSignature: 0x58, | ||
keySignature: 0x59, | ||
sequencerSpecific: 0x7f, | ||
}; | ||
function deserialize(stream, lastEventTypeByte, setLastEventTypeByte) { | ||
var deltaTime = stream.readVarInt(); | ||
var eventTypeByte = stream.readInt8(); | ||
if ((eventTypeByte & 0xf0) === 0xf0) { | ||
/* system / meta event */ | ||
if (eventTypeByte === 0xff) { | ||
/* meta event */ | ||
var type = "meta"; | ||
var subtypeByte = stream.readInt8(); | ||
var length = stream.readVarInt(); | ||
switch (subtypeByte) { | ||
case MIDIMetaEvents.sequenceNumber: | ||
if (length !== 2) | ||
throw new Error("Expected length for sequenceNumber event is 2, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "sequenceNumber", | ||
number: stream.readInt16(), | ||
}; | ||
case MIDIMetaEvents.text: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "text", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.copyrightNotice: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "copyrightNotice", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.trackName: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "trackName", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.instrumentName: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "instrumentName", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.lyrics: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "lyrics", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.marker: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "marker", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.cuePoint: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "cuePoint", | ||
text: stream.readStr(length), | ||
}; | ||
case MIDIMetaEvents.midiChannelPrefix: | ||
if (length !== 1) | ||
throw new Error("Expected length for midiChannelPrefix event is 1, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "midiChannelPrefix", | ||
value: stream.readInt8(), | ||
}; | ||
case MIDIMetaEvents.portPrefix: | ||
if (length !== 1) | ||
throw new Error("Expected length for midiChannelPrefix event is 1, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "portPrefix", | ||
port: stream.readInt8(), | ||
}; | ||
case MIDIMetaEvents.endOfTrack: | ||
if (length !== 0) | ||
throw new Error("Expected length for endOfTrack event is 0, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "endOfTrack", | ||
}; | ||
case MIDIMetaEvents.setTempo: | ||
if (length !== 3) | ||
throw new Error("Expected length for setTempo event is 3, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "setTempo", | ||
microsecondsPerBeat: (stream.readInt8() << 16) + | ||
(stream.readInt8() << 8) + | ||
stream.readInt8(), | ||
}; | ||
case MIDIMetaEvents.smpteOffset: { | ||
if (length !== 5) | ||
throw new Error("Expected length for smpteOffset event is 5, got " + length); | ||
var hourByte = stream.readInt8(); | ||
var table = { | ||
0x00: 24, | ||
0x20: 25, | ||
0x40: 29, | ||
0x60: 30, | ||
}; | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "smpteOffset", | ||
frameRate: table[hourByte & 0x60], | ||
hour: hourByte & 0x1f, | ||
min: stream.readInt8(), | ||
sec: stream.readInt8(), | ||
frame: stream.readInt8(), | ||
subframe: stream.readInt8(), | ||
}; | ||
} | ||
case MIDIMetaEvents.timeSignature: | ||
if (length !== 4) | ||
throw new Error("Expected length for timeSignature event is 4, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "timeSignature", | ||
numerator: stream.readInt8(), | ||
denominator: Math.pow(2, stream.readInt8()), | ||
metronome: stream.readInt8(), | ||
thirtyseconds: stream.readInt8(), | ||
}; | ||
case MIDIMetaEvents.keySignature: | ||
if (length !== 2) | ||
throw new Error("Expected length for keySignature event is 2, got " + length); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "keySignature", | ||
key: stream.readInt8(true), | ||
scale: stream.readInt8(), | ||
}; | ||
case MIDIMetaEvents.sequencerSpecific: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "sequencerSpecific", | ||
data: stream.read(length), | ||
}; | ||
default: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
subtype: "unknown", | ||
data: stream.read(length), | ||
}; | ||
} | ||
} | ||
else if (eventTypeByte === 0xf0) { | ||
var length = stream.readVarInt(); | ||
return { | ||
deltaTime: deltaTime, | ||
type: "sysEx", | ||
data: stream.read(length), | ||
}; | ||
} | ||
else if (eventTypeByte === 0xf7) { | ||
var length = stream.readVarInt(); | ||
return { | ||
deltaTime: deltaTime, | ||
type: "dividedSysEx", | ||
data: stream.read(length), | ||
}; | ||
} | ||
else { | ||
throw new Error("Unrecognised MIDI event type byte: " + eventTypeByte); | ||
} | ||
} | ||
else { | ||
/* channel event */ | ||
var param1 = void 0; | ||
if ((eventTypeByte & 0x80) === 0) { | ||
/* running status - reuse lastEventTypeByte as the event type. | ||
eventTypeByte is actually the first parameter | ||
*/ | ||
param1 = eventTypeByte; | ||
eventTypeByte = lastEventTypeByte; | ||
} | ||
else { | ||
param1 = stream.readInt8(); | ||
setLastEventTypeByte(eventTypeByte); | ||
} | ||
var eventType = eventTypeByte >> 4; | ||
var channel = eventTypeByte & 0x0f; | ||
var type = "channel"; | ||
switch (eventType) { | ||
case MIDIChannelEvents.noteOff: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "noteOff", | ||
noteNumber: param1, | ||
velocity: stream.readInt8(), | ||
}; | ||
case MIDIChannelEvents.noteOn: { | ||
var velocity = stream.readInt8(); | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: velocity === 0 ? "noteOff" : "noteOn", | ||
noteNumber: param1, | ||
velocity: velocity, | ||
}; | ||
} | ||
case MIDIChannelEvents.noteAftertouch: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "noteAftertouch", | ||
noteNumber: param1, | ||
amount: stream.readInt8(), | ||
}; | ||
case MIDIChannelEvents.controller: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "controller", | ||
controllerType: param1, | ||
value: stream.readInt8(), | ||
}; | ||
case MIDIChannelEvents.programChange: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "programChange", | ||
value: param1, | ||
}; | ||
case MIDIChannelEvents.channelAftertouch: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "channelAftertouch", | ||
amount: param1, | ||
}; | ||
case MIDIChannelEvents.pitchBend: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "pitchBend", | ||
value: param1 + (stream.readInt8() << 7), | ||
}; | ||
default: | ||
return { | ||
deltaTime: deltaTime, | ||
type: type, | ||
channel: channel, | ||
subtype: "unknown", | ||
data: stream.readInt8(), | ||
}; | ||
} | ||
} | ||
} | ||
/* Wrapper for accessing strings through sequential reads */ | ||
var Stream = /** @class */ (function () { | ||
function Stream(buf) { | ||
this.position = 0; | ||
if (buf instanceof DataView) { | ||
this.buf = buf; | ||
} | ||
else if (buf instanceof ArrayBuffer) { | ||
this.buf = new DataView(buf); | ||
} | ||
else if (buf instanceof Array) { | ||
this.buf = new DataView(new Uint8Array(buf).buffer); | ||
} | ||
else if (buf instanceof Uint8Array) { | ||
this.buf = new DataView(buf.buffer); | ||
} | ||
else { | ||
throw new Error("not supported type: " + typeof buf); | ||
} | ||
} | ||
Stream.prototype.readByte = function () { | ||
return this.buf.getUint8(this.position++); | ||
}; | ||
Stream.prototype.readStr = function (length) { | ||
return this.read(length) | ||
.map(function (e) { return String.fromCharCode(e); }) | ||
.join(""); | ||
}; | ||
Stream.prototype.read = function (length) { | ||
var result = []; | ||
for (var index = 0; index < length; index++) { | ||
result.push(this.readByte()); | ||
} | ||
return result; | ||
}; | ||
/* read a big-endian 32-bit integer */ | ||
Stream.prototype.readInt32 = function () { | ||
var result = this.buf.getInt32(this.position, false); | ||
this.position += 4; | ||
return result; | ||
}; | ||
/* read a big-endian 16-bit integer */ | ||
Stream.prototype.readInt16 = function () { | ||
var result = this.buf.getInt16(this.position, false); | ||
this.position += 2; | ||
return result; | ||
}; | ||
/* read an 8-bit integer */ | ||
Stream.prototype.readInt8 = function (signed) { | ||
if (signed === void 0) { signed = false; } | ||
if (signed) { | ||
return this.buf.getInt8(this.position++); | ||
} | ||
else { | ||
return this.readByte(); | ||
} | ||
}; | ||
Stream.prototype.eof = function () { | ||
return this.position >= this.buf.byteLength; | ||
}; | ||
/* read a MIDI-style variable-length integer | ||
(big-endian value in groups of 7 bits, | ||
with top bit set to signify that another byte follows) | ||
*/ | ||
Stream.prototype.readVarInt = function () { | ||
var result = 0; | ||
for (;;) { | ||
var b = this.readInt8(); | ||
if (b & 0x80) { | ||
result += b & 0x7f; | ||
result <<= 7; | ||
} | ||
else { | ||
/* b is the last byte */ | ||
return result + b; | ||
} | ||
} | ||
}; | ||
return Stream; | ||
}()); | ||
/* | ||
class to parse the .mid file format | ||
(depends on stream.js) | ||
*/ | ||
function read(data) { | ||
function readChunk(stream) { | ||
var id = stream.readStr(4); | ||
var length = stream.readInt32(); | ||
return { | ||
id: id, | ||
length: length, | ||
data: stream.read(length), | ||
}; | ||
} | ||
var stream = new Stream(data); | ||
var headerChunk = readChunk(stream); | ||
if (headerChunk.id !== "MThd" || headerChunk.length !== 6) { | ||
throw new Error("Bad .mid file - header not found"); | ||
} | ||
var headerStream = new Stream(headerChunk.data); | ||
var formatType = headerStream.readInt16(); | ||
var trackCount = headerStream.readInt16(); | ||
var timeDivision = headerStream.readInt16(); | ||
var ticksPerBeat; | ||
if (timeDivision & 0x8000) { | ||
throw new Error("Expressing time division in SMTPE frames is not supported yet"); | ||
} | ||
else { | ||
ticksPerBeat = timeDivision; | ||
} | ||
var header = { | ||
formatType: formatType, | ||
trackCount: trackCount, | ||
ticksPerBeat: ticksPerBeat, | ||
}; | ||
var lastEventTypeByte; | ||
function readEvent(stream) { | ||
return deserialize(stream, lastEventTypeByte, function (byte) { return (lastEventTypeByte = byte); }); | ||
} | ||
var tracks = []; | ||
for (var i = 0; i < header.trackCount; i++) { | ||
tracks[i] = []; | ||
var trackChunk = readChunk(stream); | ||
if (trackChunk.id !== "MTrk") { | ||
throw new Error("Unexpected chunk - expected MTrk, got " + trackChunk.id); | ||
} | ||
var trackStream = new Stream(trackChunk.data); | ||
while (!trackStream.eof()) { | ||
var event = readEvent(trackStream); | ||
tracks[i].push(event); | ||
} | ||
} | ||
return { | ||
header: header, | ||
tracks: tracks, | ||
}; | ||
} | ||
function toCharCodes(str) { | ||
@@ -676,171 +133,3 @@ var bytes = []; | ||
// variable-length quantity | ||
function toVLQ(intNum) { | ||
var v = intNum; | ||
var r = [v & 0x7f]; | ||
while (true) { | ||
v >>= 7; | ||
if (v === 0) { | ||
break; | ||
} | ||
r.unshift(0x80 + (v & 0x7f)); | ||
} | ||
return r; | ||
} | ||
function serialize(e, includeDeltaTime) { | ||
if (includeDeltaTime === void 0) { includeDeltaTime = true; } | ||
var bytes = []; | ||
function add(data) { | ||
if (Array.isArray(data)) { | ||
data.forEach(add); | ||
} | ||
else { | ||
if (!Number.isInteger(data)) { | ||
throw new Error("\"" + data + "\" is not integer"); | ||
} | ||
bytes.push(data); | ||
} | ||
} | ||
if (includeDeltaTime) { | ||
add(toVLQ(e.deltaTime)); | ||
} | ||
function addNumbers(list) { | ||
add(list.length); | ||
list.forEach(function (v) { return add(v); }); | ||
} | ||
function addText(text) { | ||
add(text.length); | ||
add(toCharCodes(text)); | ||
} | ||
switch (e.type) { | ||
case "meta": { | ||
var subtypeCode = MIDIMetaEvents[e.subtype]; | ||
if (subtypeCode === undefined) { | ||
return []; | ||
} | ||
add(0xff); // type | ||
add(subtypeCode); // subtype | ||
switch (e.subtype) { | ||
case "sequenceNumber": | ||
add(e.number); | ||
break; | ||
case "text": | ||
addText(e.text); | ||
break; | ||
case "copyrightNotice": | ||
addText(e.text); | ||
break; | ||
case "trackName": | ||
addText(e.text); | ||
break; | ||
case "instrumentName": | ||
addText(e.text); | ||
break; | ||
case "lyrics": | ||
addText(e.text); | ||
break; | ||
case "marker": | ||
addText(e.text); | ||
break; | ||
case "cuePoint": | ||
addText(e.text); | ||
break; | ||
case "midiChannelPrefix": | ||
addNumbers([e.value]); | ||
break; | ||
case "portPrefix": | ||
addNumbers([e.port]); | ||
break; | ||
case "endOfTrack": | ||
add(0); | ||
break; | ||
case "setTempo": { | ||
var t = e.microsecondsPerBeat; | ||
addNumbers([(t >> 16) & 0xff, (t >> 8) & 0xff, t & 0xff]); | ||
break; | ||
} | ||
case "smpteOffset": { | ||
console.warn("not implemented yet"); | ||
break; | ||
} | ||
case "timeSignature": { | ||
addNumbers([ | ||
e.numerator, | ||
Math.log2(e.denominator), | ||
e.metronome, | ||
e.thirtyseconds, | ||
]); | ||
break; | ||
} | ||
case "keySignature": { | ||
addNumbers([e.key, e.scale]); | ||
break; | ||
} | ||
case "sequencerSpecific": | ||
addNumbers(e.data); | ||
break; | ||
case "unknown": | ||
addNumbers(e.data); | ||
break; | ||
} | ||
break; | ||
} | ||
case "sysEx": | ||
add(0xf0); | ||
addNumbers(e.data); | ||
break; | ||
case "dividedSysEx": | ||
add(0xf7); | ||
addNumbers(e.data); | ||
break; | ||
case "channel": { | ||
var subtypeCode = MIDIChannelEvents[e.subtype]; | ||
if (subtypeCode === undefined) { | ||
return []; | ||
} | ||
add((subtypeCode << 4) + e.channel); // subtype + channel | ||
switch (e.subtype) { | ||
case "noteOff": { | ||
add(e.noteNumber); | ||
add(e.velocity); | ||
break; | ||
} | ||
case "noteOn": { | ||
add(e.noteNumber); | ||
add(e.velocity); | ||
break; | ||
} | ||
case "noteAftertouch": { | ||
add(e.noteNumber); | ||
add(e.amount); | ||
break; | ||
} | ||
case "controller": { | ||
add(e.controllerType); | ||
add(e.value); | ||
break; | ||
} | ||
case "programChange": | ||
add(e.value); | ||
break; | ||
case "channelAftertouch": | ||
add(e.amount); | ||
break; | ||
case "pitchBend": { | ||
add(e.value & 0x7f); | ||
add((e.value >> 7) & 0x7f); | ||
break; | ||
} | ||
case "unknown": | ||
add(e.data); | ||
break; | ||
} | ||
break; | ||
} | ||
} | ||
return bytes; | ||
} | ||
var Buffer = /** @class */ (function () { | ||
/** @class */ ((function () { | ||
function Buffer() { | ||
@@ -889,41 +178,4 @@ this.data = []; | ||
return Buffer; | ||
}()); | ||
})()); | ||
//https://sites.google.com/site/yyagisite/material/smfspec#format | ||
function write(tracks, ticksPerBeat) { | ||
if (ticksPerBeat === void 0) { ticksPerBeat = 480; } | ||
var buf = new Buffer(); | ||
// header chunk | ||
buf.writeChunk("MThd", function (it) { | ||
it.writeInt16(1); // formatType | ||
it.writeInt16(tracks.length); // trackCount | ||
it.writeInt16(ticksPerBeat); // timeDivision | ||
}); | ||
var _loop_1 = function (track) { | ||
buf.writeChunk("MTrk", function (it) { | ||
for (var _i = 0, track_1 = track; _i < track_1.length; _i++) { | ||
var event = track_1[_i]; | ||
it.writeBytes(serialize(event)); | ||
} | ||
}); | ||
}; | ||
// track chunk | ||
for (var _i = 0, tracks_1 = tracks; _i < tracks_1.length; _i++) { | ||
var track = tracks_1[_i]; | ||
_loop_1(track); | ||
} | ||
return buf.toBytes(); | ||
} | ||
dist.MIDIChannelEvents = MIDIChannelEvents; | ||
dist.MIDIControlEventNames = MIDIControlEventNames; | ||
var MIDIControlEvents_1 = dist.MIDIControlEvents = MIDIControlEvents; | ||
dist.MIDIMetaEventNames = MIDIMetaEventNames; | ||
dist.MIDIMetaEvents = MIDIMetaEvents; | ||
dist.Stream = Stream; | ||
dist.deserialize = deserialize; | ||
dist.read = read; | ||
dist.serialize = serialize; | ||
dist.write = write; | ||
class SynthEventHandler { | ||
@@ -958,4 +210,12 @@ processor; | ||
} | ||
arrayRemove(this.scheduledEvents, (e) => e.isProcessed); | ||
this.removeProcessedEvents(); | ||
} | ||
removeProcessedEvents() { | ||
for (let i = this.scheduledEvents.length - 1; i >= 0; i--) { | ||
const ev = this.scheduledEvents[i]; | ||
if (ev.isProcessed) { | ||
this.scheduledEvents.splice(i, 1); | ||
} | ||
} | ||
} | ||
handleImmediateEvent(e) { | ||
@@ -987,8 +247,8 @@ switch (e.type) { | ||
switch (e.controllerType) { | ||
case MIDIControlEvents_1.NONREG_PARM_NUM_MSB: | ||
case MIDIControlEvents_1.NONREG_PARM_NUM_LSB: // NRPN LSB | ||
case MIDIControlEvents.NONREG_PARM_NUM_MSB: | ||
case MIDIControlEvents.NONREG_PARM_NUM_LSB: // NRPN LSB | ||
// Delete the rpn for do not send NRPN data events | ||
delete this.rpnEvents[e.channel]; | ||
break; | ||
case MIDIControlEvents_1.REGIST_PARM_NUM_MSB: { | ||
case MIDIControlEvents.REGIST_PARM_NUM_MSB: { | ||
if (e.value === 127) { | ||
@@ -1005,3 +265,3 @@ delete this.rpnEvents[e.channel]; | ||
} | ||
case MIDIControlEvents_1.REGIST_PARM_NUM_LSB: { | ||
case MIDIControlEvents.REGIST_PARM_NUM_LSB: { | ||
if (e.value === 127) { | ||
@@ -1018,3 +278,3 @@ delete this.rpnEvents[e.channel]; | ||
} | ||
case MIDIControlEvents_1.MSB_DATA_ENTRY: { | ||
case MIDIControlEvents.MSB_DATA_ENTRY: { | ||
const rpn = { | ||
@@ -1032,3 +292,3 @@ ...this.rpnEvents[e.channel], | ||
} | ||
case MIDIControlEvents_1.LSB_DATA_ENTRY: { | ||
case MIDIControlEvents.LSB_DATA_ENTRY: { | ||
this.rpnEvents[e.channel] = { | ||
@@ -1041,25 +301,25 @@ ...this.rpnEvents[e.channel], | ||
} | ||
case MIDIControlEvents_1.MSB_MAIN_VOLUME: | ||
case MIDIControlEvents.MSB_MAIN_VOLUME: | ||
this.processor.setMainVolume(e.channel, e.value); | ||
break; | ||
case MIDIControlEvents_1.MSB_EXPRESSION: | ||
case MIDIControlEvents.MSB_EXPRESSION: | ||
this.processor.expression(e.channel, e.value); | ||
break; | ||
case MIDIControlEvents_1.ALL_SOUNDS_OFF: | ||
case MIDIControlEvents.ALL_SOUNDS_OFF: | ||
this.removeScheduledEvents(e.channel); | ||
this.processor.allSoundsOff(e.channel); | ||
break; | ||
case MIDIControlEvents_1.SUSTAIN: | ||
case MIDIControlEvents.SUSTAIN: | ||
this.processor.hold(e.channel, e.value); | ||
break; | ||
case MIDIControlEvents_1.MSB_PAN: | ||
case MIDIControlEvents.MSB_PAN: | ||
this.processor.setPan(e.channel, e.value); | ||
break; | ||
case MIDIControlEvents_1.MSB_MODWHEEL: | ||
case MIDIControlEvents.MSB_MODWHEEL: | ||
this.processor.modulation(e.channel, e.value); | ||
break; | ||
case MIDIControlEvents_1.MSB_BANK: | ||
case MIDIControlEvents.MSB_BANK: | ||
this.bankSelectMSB[e.channel] = e.value; | ||
break; | ||
case MIDIControlEvents_1.LSB_BANK: { | ||
case MIDIControlEvents.LSB_BANK: { | ||
const msb = this.bankSelectMSB[e.channel]; | ||
@@ -1072,3 +332,3 @@ if (msb !== undefined) { | ||
} | ||
case MIDIControlEvents_1.RESET_CONTROLLERS: | ||
case MIDIControlEvents.RESET_CONTROLLERS: | ||
this.processor.resetChannel(e.channel); | ||
@@ -1092,10 +352,2 @@ break; | ||
} | ||
function arrayRemove(arr, test) { | ||
for (let i = arr.length - 1; i >= 0; i--) { | ||
const ev = arr[i]; | ||
if (test(ev)) { | ||
arr.splice(i, 1); | ||
} | ||
} | ||
} | ||
@@ -1216,6 +468,5 @@ var EnvelopePhase; | ||
isHold = false; | ||
isLooping = false; | ||
baseSpeed = 1; | ||
envelope; | ||
pitchLFO; | ||
pitchLFO = new LFO(); | ||
speed = 1; | ||
@@ -1234,3 +485,2 @@ // 0 to 1 | ||
this.envelope = new AmplitudeEnvelope(sample.amplitudeEnvelope); | ||
this.pitchLFO = new LFO(); | ||
} | ||
@@ -1240,3 +490,2 @@ noteOn(pitch, velocity) { | ||
this._isPlaying = true; | ||
this.isLooping = this.sample.loop !== null; | ||
this.sampleIndex = this.sample.sampleStart; | ||
@@ -1277,5 +526,3 @@ this.baseSpeed = Math.pow(2, ((pitch - this.sample.pitch) / 12) * this.sample.scaleTuning); | ||
let loopIndex = null; | ||
if (this.sample.loop !== null && | ||
advancedIndex >= this.sample.loop.end && | ||
this.isLooping) { | ||
if (this.sample.loop !== null && advancedIndex >= this.sample.loop.end) { | ||
loopIndex = | ||
@@ -1456,3 +703,4 @@ this.sample.loop.start + (advancedIndex - Math.floor(advancedIndex)); | ||
for (let key in state.oscillators) { | ||
for (const oscillator of state.oscillators[key]) { | ||
for (let i = state.oscillators[key].length - 1; i >= 0; i--) { | ||
const oscillator = state.oscillators[key][i]; | ||
oscillator.speed = Math.pow(2, state.pitchBend / 12); | ||
@@ -1463,4 +711,6 @@ oscillator.volume = state.volume * state.expression; | ||
oscillator.process([outputs[0][0], outputs[0][1]]); | ||
if (!oscillator.isPlaying) { | ||
state.oscillators[key].splice(i, 1); | ||
} | ||
} | ||
state.oscillators[key] = state.oscillators[key]?.filter((osc) => osc.isPlaying); | ||
} | ||
@@ -1467,0 +717,0 @@ } |
@@ -11,2 +11,3 @@ import { ImmediateEvent, MIDIEventBody, SynthEvent } from "../SynthEvent"; | ||
processScheduledEvents(): void; | ||
private removeProcessedEvents; | ||
handleImmediateEvent(e: ImmediateEvent): void; | ||
@@ -13,0 +14,0 @@ handleDelayableEvent(e: MIDIEventBody): void; |
@@ -8,3 +8,2 @@ import { SampleData } from "../SynthEvent"; | ||
private isHold; | ||
private isLooping; | ||
private baseSpeed; | ||
@@ -11,0 +10,0 @@ private readonly envelope; |
{ | ||
"name": "@ryohey/wavelet", | ||
"version": "0.3.2", | ||
"version": "0.3.3", | ||
"description": "A wavetable synthesizer that never stops the UI thread created by AudioWorklet.", | ||
@@ -15,3 +15,3 @@ "main": "dist/index.js", | ||
"@ryohey/sf2parser": "^1.2.0", | ||
"midifile-ts": "^1.3.2" | ||
"midifile-ts": "^1.4.0" | ||
}, | ||
@@ -18,0 +18,0 @@ "devDependencies": { |
@@ -54,5 +54,15 @@ import { ControllerEvent, MIDIControlEvents } from "midifile-ts" | ||
} | ||
arrayRemove(this.scheduledEvents, (e) => e.isProcessed) | ||
this.removeProcessedEvents() | ||
} | ||
private removeProcessedEvents() { | ||
for (let i = this.scheduledEvents.length - 1; i >= 0; i--) { | ||
const ev = this.scheduledEvents[i] | ||
if (ev.isProcessed) { | ||
this.scheduledEvents.splice(i, 1) | ||
} | ||
} | ||
} | ||
handleImmediateEvent(e: ImmediateEvent) { | ||
@@ -194,10 +204,1 @@ switch (e.type) { | ||
} | ||
function arrayRemove<T>(arr: T[], test: (e: T) => boolean) { | ||
for (let i = arr.length - 1; i >= 0; i--) { | ||
const ev = arr[i] | ||
if (test(ev)) { | ||
arr.splice(i, 1) | ||
} | ||
} | ||
} |
@@ -206,3 +206,5 @@ import { SampleData, SynthEvent } from "../SynthEvent" | ||
for (let key in state.oscillators) { | ||
for (const oscillator of state.oscillators[key]) { | ||
for (let i = state.oscillators[key].length - 1; i >= 0; i--) { | ||
const oscillator = state.oscillators[key][i] | ||
oscillator.speed = Math.pow(2, state.pitchBend / 12) | ||
@@ -213,7 +215,7 @@ oscillator.volume = state.volume * state.expression | ||
oscillator.process([outputs[0][0], outputs[0][1]]) | ||
if (!oscillator.isPlaying) { | ||
state.oscillators[key].splice(i, 1) | ||
} | ||
} | ||
state.oscillators[key] = state.oscillators[key]?.filter( | ||
(osc) => osc.isPlaying | ||
) | ||
} | ||
@@ -220,0 +222,0 @@ } |
@@ -11,6 +11,5 @@ import { SampleData } from "../SynthEvent" | ||
private isHold = false | ||
private isLooping = false | ||
private baseSpeed = 1 | ||
private readonly envelope: AmplitudeEnvelope | ||
private readonly pitchLFO: LFO | ||
private readonly pitchLFO = new LFO() | ||
@@ -34,3 +33,2 @@ speed = 1 | ||
this.envelope = new AmplitudeEnvelope(sample.amplitudeEnvelope) | ||
this.pitchLFO = new LFO() | ||
} | ||
@@ -41,3 +39,2 @@ | ||
this._isPlaying = true | ||
this.isLooping = this.sample.loop !== null | ||
this.sampleIndex = this.sample.sampleStart | ||
@@ -93,7 +90,3 @@ this.baseSpeed = Math.pow( | ||
if ( | ||
this.sample.loop !== null && | ||
advancedIndex >= this.sample.loop.end && | ||
this.isLooping | ||
) { | ||
if (this.sample.loop !== null && advancedIndex >= this.sample.loop.end) { | ||
loopIndex = | ||
@@ -100,0 +93,0 @@ this.sample.loop.start + (advancedIndex - Math.floor(advancedIndex)) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
365203
3427
Updatedmidifile-ts@^1.4.0