// Node type definitions for the audio node graph editor // Each node type defines its inputs, outputs, parameters, and HTML template /** * Signal types for node ports * These match the backend SignalType enum */ export const SignalType = { AUDIO: 'audio', // Blue circles MIDI: 'midi', // Green squares CV: 'cv' // Orange diamonds }; /** * Node category for organization in the palette */ export const NodeCategory = { INPUT: 'input', GENERATOR: 'generator', EFFECT: 'effect', UTILITY: 'utility', OUTPUT: 'output' }; /** * Get CSS class for a port based on its signal type */ export function getPortClass(signalType) { return `connector-${signalType}`; } /** * Node type catalog * Maps node type names to their definitions */ export const nodeTypes = { Oscillator: { name: 'Oscillator', category: NodeCategory.GENERATOR, description: 'Oscillator with multiple waveforms and CV modulation', inputs: [ { name: 'V/Oct', type: SignalType.CV, index: 0 }, { name: 'FM', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'Audio', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'frequency', label: 'Frequency', min: 20, max: 20000, default: 440, unit: 'Hz' }, { id: 1, name: 'amplitude', label: 'Amplitude', min: 0, max: 1, default: 0.5, unit: '' }, { id: 2, name: 'waveform', label: 'Waveform', min: 0, max: 3, default: 0, unit: '' } ], getHTML: (nodeId) => `
Oscillator
` }, Gain: { name: 'Gain', category: NodeCategory.UTILITY, description: 'VCA (voltage-controlled amplifier) - CV multiplies gain', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 }, { name: 'CV', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'gain', label: 'Gain', min: 0, max: 2, default: 1, unit: 'x' } ], getHTML: (nodeId) => `
Gain
` }, Mixer: { name: 'Mixer', category: NodeCategory.UTILITY, description: 'Mix up to 4 audio inputs with independent gain controls', inputs: [ { name: 'Input 1', type: SignalType.AUDIO, index: 0 }, { name: 'Input 2', type: SignalType.AUDIO, index: 1 }, { name: 'Input 3', type: SignalType.AUDIO, index: 2 }, { name: 'Input 4', type: SignalType.AUDIO, index: 3 } ], outputs: [ { name: 'Mixed Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'gain1', label: 'Gain 1', min: 0, max: 2, default: 1, unit: 'x' }, { id: 1, name: 'gain2', label: 'Gain 2', min: 0, max: 2, default: 1, unit: 'x' }, { id: 2, name: 'gain3', label: 'Gain 3', min: 0, max: 2, default: 1, unit: 'x' }, { id: 3, name: 'gain4', label: 'Gain 4', min: 0, max: 2, default: 1, unit: 'x' } ], getHTML: (nodeId) => `
Mixer
` }, Filter: { name: 'Filter', category: NodeCategory.EFFECT, description: 'Biquad filter with lowpass/highpass modes', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 }, { name: 'Cutoff CV', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'cutoff', label: 'Cutoff', min: 20, max: 20000, default: 1000, unit: 'Hz' }, { id: 1, name: 'resonance', label: 'Resonance', min: 0.1, max: 10, default: 0.707, unit: 'Q' }, { id: 2, name: 'type', label: 'Type', min: 0, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
Filter
` }, ADSR: { name: 'ADSR', category: NodeCategory.UTILITY, description: 'Attack-Decay-Sustain-Release envelope generator', inputs: [ { name: 'Gate', type: SignalType.CV, index: 0 } ], outputs: [ { name: 'Envelope', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'attack', label: 'Attack', min: 0.001, max: 5, default: 0.01, unit: 's' }, { id: 1, name: 'decay', label: 'Decay', min: 0.001, max: 5, default: 0.1, unit: 's' }, { id: 2, name: 'sustain', label: 'Sustain', min: 0, max: 1, default: 0.7, unit: '' }, { id: 3, name: 'release', label: 'Release', min: 0.001, max: 5, default: 0.2, unit: 's' } ], getHTML: (nodeId) => `
ADSR
` }, MidiInput: { name: 'MidiInput', category: NodeCategory.INPUT, description: 'MIDI input - receives MIDI events from track', inputs: [], outputs: [ { name: 'MIDI Out', type: SignalType.MIDI, index: 0 } ], parameters: [], getHTML: (nodeId) => `
MIDI Input
Receives MIDI from track
` }, MidiToCV: { name: 'MidiToCV', category: NodeCategory.UTILITY, description: 'Convert MIDI notes to CV signals', inputs: [ { name: 'MIDI In', type: SignalType.MIDI, index: 0 } ], outputs: [ { name: 'V/Oct', type: SignalType.CV, index: 0 }, { name: 'Gate', type: SignalType.CV, index: 1 }, { name: 'Velocity', type: SignalType.CV, index: 2 } ], parameters: [], getHTML: (nodeId) => `
MIDI→CV
Converts MIDI to CV signals
` }, AudioToCV: { name: 'AudioToCV', category: NodeCategory.UTILITY, description: 'Envelope follower - converts audio amplitude to CV', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'attack', label: 'Attack', min: 0.001, max: 1.0, default: 0.01, unit: 's' }, { id: 1, name: 'release', label: 'Release', min: 0.001, max: 1.0, default: 0.1, unit: 's' } ], getHTML: (nodeId) => `
Audio→CV
` }, Oscilloscope: { name: 'Oscilloscope', category: NodeCategory.UTILITY, description: 'Visual audio signal monitor (pass-through)', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 }, { name: 'V/oct', type: SignalType.CV, index: 1 }, { name: 'CV In', type: SignalType.CV, index: 2 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'time_scale', label: 'Time Scale', min: 10, max: 1000, default: 100, unit: 'ms' }, { id: 1, name: 'trigger_mode', label: 'Trigger', min: 0, max: 3, default: 0, unit: '' }, { id: 2, name: 'trigger_level', label: 'Trigger Level', min: -1, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
Oscilloscope
` }, VoiceAllocator: { name: 'VoiceAllocator', category: NodeCategory.UTILITY, description: 'Polyphonic voice allocator - creates N instances of internal graph', inputs: [ { name: 'MIDI In', type: SignalType.MIDI, index: 0 } ], outputs: [ { name: 'Mixed Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'voices', label: 'Voices', min: 1, max: 16, default: 8, unit: '' } ], getHTML: (nodeId) => `
Voice Allocator
Double-click to edit
` }, AudioInput: { name: 'AudioInput', category: NodeCategory.INPUT, description: 'Audio track clip input - receives audio from timeline clips', inputs: [], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [], getHTML: (nodeId) => `
Audio Input
Audio from clips
` }, AudioOutput: { name: 'AudioOutput', category: NodeCategory.OUTPUT, description: 'Final audio output', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [], getHTML: (nodeId) => `
Audio Output
Final output to speakers
` }, TemplateInput: { name: 'TemplateInput', category: NodeCategory.INPUT, description: 'VoiceAllocator template input - receives MIDI for one voice', inputs: [], outputs: [ { name: 'MIDI Out', type: SignalType.MIDI, index: 0 } ], parameters: [], getHTML: (nodeId) => `
Template Input
MIDI for one voice
` }, TemplateOutput: { name: 'TemplateOutput', category: NodeCategory.OUTPUT, description: 'VoiceAllocator template output - sends audio to voice mixer', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [], parameters: [], getHTML: (nodeId) => `
Template Output
Audio to mixer
` }, LFO: { name: 'LFO', category: NodeCategory.UTILITY, description: 'Low frequency oscillator for modulation', inputs: [], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'frequency', label: 'Frequency', min: 0.01, max: 20, default: 1.0, unit: 'Hz' }, { id: 1, name: 'amplitude', label: 'Amplitude', min: 0, max: 1, default: 1.0, unit: '' }, { id: 2, name: 'waveform', label: 'Waveform', min: 0, max: 4, default: 0, unit: '' }, { id: 3, name: 'phase', label: 'Phase', min: 0, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
LFO
` }, NoiseGenerator: { name: 'NoiseGenerator', category: NodeCategory.GENERATOR, description: 'White and pink noise generator', inputs: [], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'amplitude', label: 'Amplitude', min: 0, max: 1, default: 0.5, unit: '' }, { id: 1, name: 'color', label: 'Color', min: 0, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
Noise
` }, Splitter: { name: 'Splitter', category: NodeCategory.UTILITY, description: 'Split audio signal to multiple outputs for parallel routing', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Out 1', type: SignalType.AUDIO, index: 0 }, { name: 'Out 2', type: SignalType.AUDIO, index: 1 }, { name: 'Out 3', type: SignalType.AUDIO, index: 2 }, { name: 'Out 4', type: SignalType.AUDIO, index: 3 } ], parameters: [], getHTML: (nodeId) => `
Splitter
1→4 split
` }, Pan: { name: 'Pan', category: NodeCategory.UTILITY, description: 'Stereo panning with CV modulation', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 }, { name: 'Pan CV', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'pan', label: 'Pan', min: -1, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
Pan
` }, Delay: { name: 'Delay', category: NodeCategory.EFFECT, description: 'Stereo delay with feedback', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'delay_time', label: 'Delay Time', min: 0.001, max: 2.0, default: 0.5, unit: 's' }, { id: 1, name: 'feedback', label: 'Feedback', min: 0, max: 0.95, default: 0.5, unit: '' }, { id: 2, name: 'wet_dry', label: 'Wet/Dry', min: 0, max: 1, default: 0.5, unit: '' } ], getHTML: (nodeId) => `
Delay
` }, Reverb: { name: 'Reverb', category: NodeCategory.EFFECT, description: 'Schroeder reverb with room size and damping', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'room_size', label: 'Room Size', min: 0, max: 1, default: 0.5, unit: '' }, { id: 1, name: 'damping', label: 'Damping', min: 0, max: 1, default: 0.5, unit: '' }, { id: 2, name: 'wet_dry', label: 'Wet/Dry', min: 0, max: 1, default: 0.3, unit: '' } ], getHTML: (nodeId) => `
Reverb
` }, Chorus: { name: 'Chorus', category: NodeCategory.EFFECT, description: 'Chorus effect with modulated delay', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'rate', label: 'Rate', min: 0.1, max: 5.0, default: 1.0, unit: 'Hz' }, { id: 1, name: 'depth', label: 'Depth', min: 0, max: 1, default: 0.5, unit: '' }, { id: 2, name: 'wet_dry', label: 'Wet/Dry', min: 0, max: 1, default: 0.5, unit: '' } ], getHTML: (nodeId) => `
Chorus
` }, Flanger: { name: 'Flanger', category: NodeCategory.EFFECT, description: 'Flanger effect with feedback', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'rate', label: 'Rate', min: 0.1, max: 10.0, default: 0.5, unit: 'Hz' }, { id: 1, name: 'depth', label: 'Depth', min: 0, max: 1, default: 0.7, unit: '' }, { id: 2, name: 'feedback', label: 'Feedback', min: -0.95, max: 0.95, default: 0.5, unit: '' }, { id: 3, name: 'wet_dry', label: 'Wet/Dry', min: 0, max: 1, default: 0.5, unit: '' } ], getHTML: (nodeId) => `
Flanger
` }, FMSynth: { name: 'FM Synth', category: NodeCategory.GENERATOR, description: '4-operator FM synthesizer', inputs: [ { name: 'V/Oct', type: SignalType.CV, index: 0 }, { name: 'Gate', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'algorithm', label: 'Algorithm', min: 0, max: 3, default: 0, unit: '' }, { id: 1, name: 'op1_ratio', label: 'Op1 Ratio', min: 0.25, max: 16, default: 1.0, unit: '' }, { id: 2, name: 'op1_level', label: 'Op1 Level', min: 0, max: 1, default: 1.0, unit: '' }, { id: 3, name: 'op2_ratio', label: 'Op2 Ratio', min: 0.25, max: 16, default: 2.0, unit: '' }, { id: 4, name: 'op2_level', label: 'Op2 Level', min: 0, max: 1, default: 0.8, unit: '' }, { id: 5, name: 'op3_ratio', label: 'Op3 Ratio', min: 0.25, max: 16, default: 3.0, unit: '' }, { id: 6, name: 'op3_level', label: 'Op3 Level', min: 0, max: 1, default: 0.6, unit: '' }, { id: 7, name: 'op4_ratio', label: 'Op4 Ratio', min: 0.25, max: 16, default: 4.0, unit: '' }, { id: 8, name: 'op4_level', label: 'Op4 Level', min: 0, max: 1, default: 0.4, unit: '' } ], getHTML: (nodeId) => `
FM Synth
Operator 1
Operator 2
Operator 3
Operator 4
` }, WavetableOscillator: { name: 'Wavetable', category: NodeCategory.GENERATOR, description: 'Wavetable oscillator with preset waveforms', inputs: [ { name: 'V/Oct', type: SignalType.CV, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'wavetable', label: 'Wavetable', min: 0, max: 7, default: 0, unit: '' }, { id: 1, name: 'fine_tune', label: 'Fine Tune', min: -1, max: 1, default: 0, unit: '' }, { id: 2, name: 'position', label: 'Position', min: 0, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
Wavetable
` }, SimpleSampler: { name: 'Sampler', category: NodeCategory.GENERATOR, description: 'Simple sample playback with pitch shifting', inputs: [ { name: 'V/Oct', type: SignalType.CV, index: 0 }, { name: 'Gate', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'gain', label: 'Gain', min: 0, max: 2, default: 1.0, unit: '' }, { id: 1, name: 'loop', label: 'Loop', min: 0, max: 1, default: 0, unit: '' }, { id: 2, name: 'pitch_shift', label: 'Pitch Shift', min: -12, max: 12, default: 0, unit: 'semi' } ], getHTML: (nodeId) => `
Sampler
No sample loaded
` }, MultiSampler: { name: 'Multi Sampler', category: NodeCategory.GENERATOR, description: 'Multi-sample instrument with velocity layers and key zones', inputs: [ { name: 'MIDI In', type: SignalType.MIDI, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'gain', label: 'Gain', min: 0, max: 2, default: 1.0, unit: '' }, { id: 1, name: 'attack', label: 'Attack', min: 0.001, max: 1, default: 0.01, unit: 's' }, { id: 2, name: 'release', label: 'Release', min: 0.01, max: 5, default: 0.1, unit: 's' }, { id: 3, name: 'transpose', label: 'Transpose', min: -24, max: 24, default: 0, unit: 'semi' } ], getHTML: (nodeId) => `
Multi Sampler
File Range Root Vel
No layers loaded
` }, Compressor: { name: 'Compressor', category: NodeCategory.EFFECT, description: 'Dynamic range compressor with soft-knee', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'threshold', label: 'Threshold', min: -60, max: 0, default: -20, unit: 'dB' }, { id: 1, name: 'ratio', label: 'Ratio', min: 1, max: 20, default: 4, unit: ':1' }, { id: 2, name: 'attack', label: 'Attack', min: 0.1, max: 100, default: 5, unit: 'ms' }, { id: 3, name: 'release', label: 'Release', min: 10, max: 1000, default: 100, unit: 'ms' }, { id: 4, name: 'makeup_gain', label: 'Makeup Gain', min: 0, max: 20, default: 0, unit: 'dB' }, { id: 5, name: 'knee', label: 'Knee', min: 0, max: 12, default: 6, unit: 'dB' } ], getHTML: (nodeId) => `
Compressor
` }, Limiter: { name: 'Limiter', category: NodeCategory.EFFECT, description: 'Peak limiter with ceiling control', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'threshold', label: 'Threshold', min: -60, max: 0, default: -10, unit: 'dB' }, { id: 1, name: 'release', label: 'Release', min: 10, max: 1000, default: 50, unit: 'ms' }, { id: 2, name: 'ceiling', label: 'Ceiling', min: -20, max: 0, default: 0, unit: 'dB' } ], getHTML: (nodeId) => `
Limiter
` }, Distortion: { name: 'Distortion', category: NodeCategory.EFFECT, description: 'Waveshaping distortion with multiple algorithms', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'drive', label: 'Drive', min: 0.01, max: 20, default: 1, unit: '' }, { id: 1, name: 'type', label: 'Type', min: 0, max: 3, default: 0, unit: '' }, { id: 2, name: 'tone', label: 'Tone', min: 0, max: 1, default: 0.7, unit: '' }, { id: 3, name: 'mix', label: 'Mix', min: 0, max: 1, default: 1, unit: '' } ], getHTML: (nodeId) => `
Distortion
` }, Constant: { name: 'Constant', category: NodeCategory.UTILITY, description: 'Constant CV source - outputs a fixed voltage', inputs: [], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'value', label: 'Value', min: -10, max: 10, default: 0, unit: '' } ], getHTML: (nodeId) => `
Constant
` }, AutomationInput: { name: 'AutomationInput', category: NodeCategory.UTILITY, description: 'Timeline automation - outputs CV signal controlled by timeline curves', inputs: [], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [], getHTML: (nodeId) => `
Automation
Timeline-based automation
Not connected
Edit curves in timeline
` }, Math: { name: 'Math', category: NodeCategory.UTILITY, description: 'Mathematical and logical operations on CV signals', inputs: [ { name: 'CV In A', type: SignalType.CV, index: 0 }, { name: 'CV In B', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'operation', label: 'Operation', min: 0, max: 13, default: 0, unit: '' } ], getHTML: (nodeId) => `
Math
` }, Quantizer: { name: 'Quantizer', category: NodeCategory.UTILITY, description: 'Quantize CV to musical scales', inputs: [ { name: 'CV In', type: SignalType.CV, index: 0 } ], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 }, { name: 'Gate Out', type: SignalType.CV, index: 1 } ], parameters: [ { id: 0, name: 'scale', label: 'Scale', min: 0, max: 10, default: 0, unit: '' }, { id: 1, name: 'root', label: 'Root', min: 0, max: 11, default: 0, unit: '' } ], getHTML: (nodeId) => `
Quantizer
` }, SlewLimiter: { name: 'SlewLimiter', category: NodeCategory.UTILITY, description: 'Limit rate of change for portamento/glide effects', inputs: [ { name: 'CV In', type: SignalType.CV, index: 0 } ], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'rise_time', label: 'Rise Time', min: 0, max: 5, default: 0.01, unit: 's' }, { id: 1, name: 'fall_time', label: 'Fall Time', min: 0, max: 5, default: 0.01, unit: 's' } ], getHTML: (nodeId) => `
Slew Limiter
` }, EQ: { name: 'EQ', category: NodeCategory.EFFECT, description: '3-band parametric EQ', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'low_freq', label: 'Low Freq', min: 20, max: 500, default: 100, unit: 'Hz' }, { id: 1, name: 'low_gain', label: 'Low Gain', min: -24, max: 24, default: 0, unit: 'dB' }, { id: 2, name: 'mid_freq', label: 'Mid Freq', min: 200, max: 5000, default: 1000, unit: 'Hz' }, { id: 3, name: 'mid_gain', label: 'Mid Gain', min: -24, max: 24, default: 0, unit: 'dB' }, { id: 4, name: 'mid_q', label: 'Mid Q', min: 0.1, max: 10, default: 0.707, unit: '' }, { id: 5, name: 'high_freq', label: 'High Freq', min: 2000, max: 20000, default: 8000, unit: 'Hz' }, { id: 6, name: 'high_gain', label: 'High Gain', min: -24, max: 24, default: 0, unit: 'dB' } ], getHTML: (nodeId) => `
EQ
Low Band
Mid Band
High Band
` }, SampleHold: { name: 'Sample & Hold', category: NodeCategory.UTILITY, description: 'Samples CV input when gate signal goes high', inputs: [ { name: 'CV In', type: SignalType.CV, index: 0 }, { name: 'Gate In', type: SignalType.CV, index: 1 } ], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [], getHTML: (nodeId) => `
Sample & Hold
Samples CV input
on gate rising edge
` }, BpmDetector: { name: 'BPM Detector', category: NodeCategory.UTILITY, description: 'Detects tempo from audio and outputs BPM as CV', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'BPM CV', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'smoothing', label: 'Smoothing', min: 0.0, max: 1.0, default: 0.9, unit: '' } ], getHTML: (nodeId) => `
BPM Detector
Analyzes incoming audio and outputs detected BPM as CV signal
` }, EnvelopeFollower: { name: 'Envelope Follower', category: NodeCategory.UTILITY, description: 'Extracts amplitude envelope from audio signal', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'CV Out', type: SignalType.CV, index: 0 } ], parameters: [ { id: 0, name: 'attack', label: 'Attack', min: 0.001, max: 1.0, default: 0.01, unit: 's' }, { id: 1, name: 'release', label: 'Release', min: 0.001, max: 1.0, default: 0.1, unit: 's' } ], getHTML: (nodeId) => `
Envelope Follower
` }, RingModulator: { name: 'Ring Modulator', category: NodeCategory.EFFECT, description: 'Multiplies carrier and modulator for metallic timbres', inputs: [ { name: 'Carrier', type: SignalType.AUDIO, index: 0 }, { name: 'Modulator', type: SignalType.AUDIO, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'mix', label: 'Mix', min: 0.0, max: 1.0, default: 1.0, unit: '' } ], getHTML: (nodeId) => `
Ring Modulator
` }, Phaser: { name: 'Phaser', category: NodeCategory.EFFECT, description: 'Sweeping all-pass filters for phase shifting effect', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'rate', label: 'Rate', min: 0.1, max: 10.0, default: 0.5, unit: 'Hz' }, { id: 1, name: 'depth', label: 'Depth', min: 0.0, max: 1.0, default: 0.7, unit: '' }, { id: 2, name: 'stages', label: 'Stages', min: 2, max: 8, default: 6, unit: '' }, { id: 3, name: 'feedback', label: 'Feedback', min: -0.95, max: 0.95, default: 0.5, unit: '' }, { id: 4, name: 'wetdry', label: 'Wet/Dry', min: 0.0, max: 1.0, default: 0.5, unit: '' }, { id: 5, name: 'sync', label: 'Sync to BPM', min: 0, max: 1, default: 0, unit: '' } ], getHTML: (nodeId) => `
Phaser
` }, BitCrusher: { name: 'Bit Crusher', category: NodeCategory.EFFECT, description: 'Lo-fi effect via bit depth and sample rate reduction', inputs: [ { name: 'Audio In', type: SignalType.AUDIO, index: 0 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'bitdepth', label: 'Bit Depth', min: 1, max: 16, default: 8, unit: 'bits' }, { id: 1, name: 'samplerate', label: 'Sample Rate', min: 100, max: 48000, default: 8000, unit: 'Hz' }, { id: 2, name: 'mix', label: 'Mix', min: 0.0, max: 1.0, default: 1.0, unit: '' } ], getHTML: (nodeId) => `
Bit Crusher
` }, Vocoder: { name: 'Vocoder', category: NodeCategory.EFFECT, description: 'Multi-band vocoder - modulator controls carrier spectrum', inputs: [ { name: 'Modulator', type: SignalType.AUDIO, index: 0 }, { name: 'Carrier', type: SignalType.AUDIO, index: 1 } ], outputs: [ { name: 'Audio Out', type: SignalType.AUDIO, index: 0 } ], parameters: [ { id: 0, name: 'bands', label: 'Bands', min: 8, max: 32, default: 16, unit: '' }, { id: 1, name: 'attack', label: 'Attack', min: 0.001, max: 0.1, default: 0.01, unit: 's' }, { id: 2, name: 'release', label: 'Release', min: 0.001, max: 1.0, default: 0.05, unit: 's' }, { id: 3, name: 'mix', label: 'Mix', min: 0.0, max: 1.0, default: 1.0, unit: '' } ], getHTML: (nodeId) => `
Vocoder
` } }; /** * Get all node types in a specific category */ export function getNodesByCategory(category) { return Object.entries(nodeTypes) .filter(([_, def]) => def.category === category) .map(([type, def]) => ({ type, ...def })); } /** * Get all categories that have nodes */ export function getCategories() { const categories = new Set(); Object.values(nodeTypes).forEach(def => categories.add(def.category)); return Array.from(categories); }