import { MIDDLE_C } from '../../../instrument/notes'; import { heldTempo } from '../../../music/time'; import type { NodeDef } from '../../NodeRegistry'; import { asBoolean, asNumber, asString } from '../../values'; import { detachedPort, exec, fxParamsPort, num, playedBusPort, soundFxPort, withDefault } from '../shared'; import { fxParamsOf, tempoPort } from './PlaySound'; export const PlayNote: NodeDef = { type: 'PlayNote', label: 'Play note', category: 'action', description: 'Plays one note of an instrument asset. "note" is its number as MIDI counts it: 60 is C4, 61 C#4, 72 C5. "velocity" is how hard it is struck, 0 to 1 – it makes the note quieter and is handed to what the instrument does with it. "duration" is how many seconds until the note is released; at 0 it is held until a Stop sound ends it. A note belongs to this object like a sound and stops when the object is destroyed, unless "detached" is on. "params" takes values for the parameters of the instrument from an Instrument parameters node. "fx" sends the note through a sound FX on top of what the instrument does; left empty, the one the instrument names, and None through none. "fx params" takes values for its parameters from a Sound FX parameters node – the two sets stay apart. "voice" is the number of this note, for Set sound FX parameters and Stop sound; 0 where the instrument plays nothing for it. "tempo" is what a Delay in the instrument synced to beats counts by, in quarter notes a minute. "bus" is the bus it is heard on; left empty, the one the instrument names.', inputs: [ exec(), { key: 'instrument', label: 'instrument', type: 'string', field: { key: 'instrument', label: 'Instrument', kind: 'asset', default: '', assetTypes: ['instrument'], }, }, { key: 'note', label: 'note', type: 'number', default: MIDDLE_C, field: { key: 'note', label: 'Note', kind: 'number', default: MIDDLE_C, min: 0, max: 127, step: 1 }, }, withDefault(num('velocity'), 1), withDefault(num('volume'), 1), withDefault(num('duration'), 0), detachedPort(), fxParamsPort('fxParams', 'params'), tempoPort(), { ...soundFxPort(), key: 'soundFx' }, fxParamsPort('soundFxParams'), playedBusPort(), ], outputs: [exec(), num('voice')], params: [], run: (ctx, inputs) => { const instrument = asString(inputs.instrument); const voice = instrument ? ctx.playNote( instrument, asNumber(inputs.note), asNumber(inputs.velocity), asNumber(inputs.volume), asNumber(inputs.duration), asBoolean(inputs.detached), fxParamsOf(inputs.fxParams), heldTempo(asNumber(inputs.tempo)), asString(inputs.soundFx), fxParamsOf(inputs.soundFxParams), asString(inputs.bus), ) : 0; return { next: 'exec', outputs: { voice } }; }, };