|
|
import { generatorTypes } from "./generator.js"; |
|
|
import { midiControllers } from "../../midi_parser/midi_message.js"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const modulatorSources = { |
|
|
noController: 0, |
|
|
noteOnVelocity: 2, |
|
|
noteOnKeyNum: 3, |
|
|
polyPressure: 10, |
|
|
channelPressure: 13, |
|
|
pitchWheel: 14, |
|
|
pitchWheelRange: 16, |
|
|
link: 127 |
|
|
|
|
|
}; |
|
|
export const modulatorCurveTypes = { |
|
|
linear: 0, |
|
|
concave: 1, |
|
|
convex: 2, |
|
|
switch: 3 |
|
|
}; |
|
|
|
|
|
export class Modulator |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
currentValue = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sourceEnum; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
secondarySourceEnum; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modulatorDestination; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transformAmount; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transformType; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(srcEnum, secSrcEnum, destination, amount, transformType) |
|
|
{ |
|
|
this.sourceEnum = srcEnum; |
|
|
this.modulatorDestination = destination; |
|
|
this.secondarySourceEnum = secSrcEnum; |
|
|
this.transformAmount = amount; |
|
|
this.transformType = transformType; |
|
|
|
|
|
|
|
|
if (this.modulatorDestination > 58) |
|
|
{ |
|
|
this.modulatorDestination = generatorTypes.INVALID; |
|
|
} |
|
|
|
|
|
|
|
|
this.sourcePolarity = this.sourceEnum >> 9 & 1; |
|
|
this.sourceDirection = this.sourceEnum >> 8 & 1; |
|
|
this.sourceUsesCC = this.sourceEnum >> 7 & 1; |
|
|
this.sourceIndex = this.sourceEnum & 127; |
|
|
this.sourceCurveType = this.sourceEnum >> 10 & 3; |
|
|
|
|
|
|
|
|
this.secSrcPolarity = this.secondarySourceEnum >> 9 & 1; |
|
|
this.secSrcDirection = this.secondarySourceEnum >> 8 & 1; |
|
|
this.secSrcUsesCC = this.secondarySourceEnum >> 7 & 1; |
|
|
this.secSrcIndex = this.secondarySourceEnum & 127; |
|
|
this.secSrcCurveType = this.secondarySourceEnum >> 10 & 3; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.isEffectModulator = |
|
|
( |
|
|
this.sourceEnum === 0x00DB |
|
|
|| this.sourceEnum === 0x00DD |
|
|
) |
|
|
&& this.secondarySourceEnum === 0x0 |
|
|
&& ( |
|
|
this.modulatorDestination === generatorTypes.reverbEffectsSend |
|
|
|| this.modulatorDestination === generatorTypes.chorusEffectsSend |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static copy(modulator) |
|
|
{ |
|
|
return new Modulator( |
|
|
modulator.sourceEnum, |
|
|
modulator.secondarySourceEnum, |
|
|
modulator.modulatorDestination, |
|
|
modulator.transformAmount, |
|
|
modulator.transformType |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static isIdentical(mod1, mod2, checkAmount = false) |
|
|
{ |
|
|
return (mod1.sourceEnum === mod2.sourceEnum) |
|
|
&& (mod1.modulatorDestination === mod2.modulatorDestination) |
|
|
&& (mod1.secondarySourceEnum === mod2.secondarySourceEnum) |
|
|
&& (mod1.transformType === mod2.transformType) |
|
|
&& (!checkAmount || (mod1.transformAmount === mod2.transformAmount)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static debugString(mod) |
|
|
{ |
|
|
function getKeyByValue(object, value) |
|
|
{ |
|
|
return Object.keys(object).find(key => object[key] === value); |
|
|
} |
|
|
|
|
|
let sourceString = getKeyByValue(modulatorCurveTypes, mod.sourceCurveType); |
|
|
sourceString += mod.sourcePolarity === 0 ? " unipolar " : " bipolar "; |
|
|
sourceString += mod.sourceDirection === 0 ? "forwards " : "backwards "; |
|
|
if (mod.sourceUsesCC) |
|
|
{ |
|
|
sourceString += getKeyByValue(midiControllers, mod.sourceIndex); |
|
|
} |
|
|
else |
|
|
{ |
|
|
sourceString += getKeyByValue(modulatorSources, mod.sourceIndex); |
|
|
} |
|
|
|
|
|
let secSrcString = getKeyByValue(modulatorCurveTypes, mod.secSrcCurveType); |
|
|
secSrcString += mod.secSrcPolarity === 0 ? " unipolar " : " bipolar "; |
|
|
secSrcString += mod.secSrcCurveType === 0 ? "forwards " : "backwards "; |
|
|
if (mod.secSrcUsesCC) |
|
|
{ |
|
|
secSrcString += getKeyByValue(midiControllers, mod.secSrcIndex); |
|
|
} |
|
|
else |
|
|
{ |
|
|
secSrcString += getKeyByValue(modulatorSources, mod.secSrcIndex); |
|
|
} |
|
|
return `Modulator: |
|
|
Source: ${sourceString} |
|
|
Secondary source: ${secSrcString} |
|
|
Destination: ${getKeyByValue(generatorTypes, mod.modulatorDestination)} |
|
|
Trasform amount: ${mod.transformAmount} |
|
|
Transform type: ${mod.transformType} |
|
|
\n\n`; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sumTransform(modulator) |
|
|
{ |
|
|
return new Modulator( |
|
|
this.sourceEnum, |
|
|
this.secondarySourceEnum, |
|
|
this.modulatorDestination, |
|
|
this.transformAmount + modulator.transformAmount, |
|
|
this.transformType |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
export const DEFAULT_ATTENUATION_MOD_AMOUNT = 960; |
|
|
export const DEFAULT_ATTENUATION_MOD_CURVE_TYPE = modulatorCurveTypes.concave; |
|
|
|
|
|
export function getModSourceEnum(curveType, polarity, direction, isCC, index) |
|
|
{ |
|
|
return (curveType << 10) | (polarity << 9) | (direction << 8) | (isCC << 7) | index; |
|
|
} |
|
|
|
|
|
const soundFontModulators = [ |
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
DEFAULT_ATTENUATION_MOD_CURVE_TYPE, |
|
|
0, |
|
|
1, |
|
|
0, |
|
|
modulatorSources.noteOnVelocity |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.initialAttenuation, |
|
|
DEFAULT_ATTENUATION_MOD_AMOUNT, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator(0x0081, 0x0, generatorTypes.vibLfoToPitch, 50, 0), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
DEFAULT_ATTENUATION_MOD_CURVE_TYPE, |
|
|
0, |
|
|
1, |
|
|
1, |
|
|
midiControllers.mainVolume |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.initialAttenuation, |
|
|
DEFAULT_ATTENUATION_MOD_AMOUNT, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator(0x000D, 0x0, generatorTypes.vibLfoToPitch, 50, 0), |
|
|
|
|
|
|
|
|
new Modulator(0x020E, 0x0010, generatorTypes.fineTune, 12700, 0), |
|
|
|
|
|
|
|
|
|
|
|
new Modulator(0x028A, 0x0, generatorTypes.pan, 500, 0), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
DEFAULT_ATTENUATION_MOD_CURVE_TYPE, |
|
|
0, |
|
|
1, |
|
|
1, |
|
|
midiControllers.expressionController |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.initialAttenuation, |
|
|
DEFAULT_ATTENUATION_MOD_AMOUNT, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator(0x00DB, 0x0, generatorTypes.reverbEffectsSend, 200, 0), |
|
|
|
|
|
|
|
|
new Modulator(0x00DD, 0x0, generatorTypes.chorusEffectsSend, 200, 0) |
|
|
]; |
|
|
|
|
|
const customModulators = [ |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum(modulatorCurveTypes.linear, 0, 0, 0, modulatorSources.polyPressure), |
|
|
0x0, |
|
|
generatorTypes.vibLfoToPitch, |
|
|
50, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
modulatorCurveTypes.linear, |
|
|
0, |
|
|
0, |
|
|
1, |
|
|
midiControllers.tremoloDepth |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.modLfoToVolume, |
|
|
24, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
modulatorCurveTypes.convex, |
|
|
1, |
|
|
0, |
|
|
1, |
|
|
midiControllers.attackTime |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.attackVolEnv, |
|
|
6000, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
modulatorCurveTypes.linear, |
|
|
1, |
|
|
0, |
|
|
1, |
|
|
midiControllers.releaseTime |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.releaseVolEnv, |
|
|
3600, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
modulatorCurveTypes.linear, |
|
|
1, |
|
|
0, |
|
|
1, |
|
|
midiControllers.brightness |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.initialFilterFc, |
|
|
6000, |
|
|
0 |
|
|
), |
|
|
|
|
|
|
|
|
new Modulator( |
|
|
getModSourceEnum( |
|
|
modulatorCurveTypes.linear, |
|
|
1, |
|
|
0, |
|
|
1, |
|
|
midiControllers.filterResonance |
|
|
), |
|
|
0x0, |
|
|
generatorTypes.initialFilterQ, |
|
|
250, |
|
|
0 |
|
|
) |
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const defaultModulators = soundFontModulators.concat(customModulators); |