feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
/**
|
2026-04-07 00:41:30 +02:00
|
|
|
* ShapeSeq Projection — 3 global post-chain knobs
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
2026-04-07 00:41:30 +02:00
|
|
|
* Applied after the primitive chain produces a pattern, before the clock plays it.
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
2026-04-07 00:41:30 +02:00
|
|
|
* Knobs:
|
|
|
|
|
* 1. velocityCurve: 'linear' | 'exponential' | 'sCurve'
|
|
|
|
|
* 2. gateThreshold: [0, 1] — global density filter (steps with velocity below threshold are muted)
|
|
|
|
|
* 3. pitchRange: { low: midiNote, high: midiNote } — clamp midiNote to range
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
|
|
|
|
* @module shapeseq/projection
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { clonePattern } from './pattern.js';
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2026-04-07 00:41:30 +02:00
|
|
|
// Constants
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export const VELOCITY_CURVES = ['linear', 'exponential', 'sCurve'];
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Velocity curve math
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
2026-04-07 00:41:30 +02:00
|
|
|
* Apply a velocity curve to a [0,1] value.
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
|
|
|
|
* @param {number} value - Input value in [0,1]
|
2026-04-07 00:41:30 +02:00
|
|
|
* @param {'linear'|'exponential'|'sCurve'} curve
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
* @returns {number} Transformed value in [0,1]
|
|
|
|
|
*/
|
2026-04-07 00:41:30 +02:00
|
|
|
function velocityCurveApply(value, curve) {
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
const v = value < 0 ? 0 : value > 1 ? 1 : value;
|
2026-04-07 00:41:30 +02:00
|
|
|
switch (curve) {
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
case 'exponential':
|
|
|
|
|
return v * v;
|
|
|
|
|
case 'sCurve':
|
|
|
|
|
return (3 - 2 * v) * v * v; // smoothstep: 3v² - 2v³
|
|
|
|
|
case 'linear':
|
|
|
|
|
default:
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-04-07 00:41:30 +02:00
|
|
|
* Fold a MIDI note number into a target range by shifting octaves.
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
2026-04-07 00:41:30 +02:00
|
|
|
* @param {number} note - MIDI note number
|
|
|
|
|
* @param {number} low - Low bound (inclusive)
|
|
|
|
|
* @param {number} high - High bound (inclusive)
|
|
|
|
|
* @returns {number} MIDI note within [low, high]
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*/
|
2026-04-07 00:41:30 +02:00
|
|
|
function octaveFold(note, low, high) {
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
if (high <= low) return low;
|
2026-04-07 00:41:30 +02:00
|
|
|
let n = note | 0;
|
|
|
|
|
while (n < low) n += 12;
|
|
|
|
|
while (n > high) n -= 12;
|
|
|
|
|
// If 12-step folding overshoots (range < 12), clamp
|
|
|
|
|
if (n < low) n = low;
|
|
|
|
|
if (n > high) n = high;
|
|
|
|
|
return n;
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2026-04-07 00:41:30 +02:00
|
|
|
// Public API
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
2026-04-07 00:41:30 +02:00
|
|
|
* Create a projection config with defaults.
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
2026-04-07 00:41:30 +02:00
|
|
|
* @param {Object} [opts]
|
|
|
|
|
* @param {'linear'|'exponential'|'sCurve'} [opts.velocityCurve='linear']
|
|
|
|
|
* @param {number} [opts.gateThreshold=0]
|
|
|
|
|
* @param {{ low?: number, high?: number }} [opts.pitchRange]
|
|
|
|
|
* @returns {{ velocityCurve: string, gateThreshold: number, pitchRange: { low: number, high: number } }}
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*/
|
2026-04-07 00:41:30 +02:00
|
|
|
export function createProjection(opts = {}) {
|
|
|
|
|
return {
|
|
|
|
|
velocityCurve: opts.velocityCurve || 'linear',
|
|
|
|
|
gateThreshold: opts.gateThreshold ?? 0,
|
|
|
|
|
pitchRange: {
|
|
|
|
|
low: opts.pitchRange?.low ?? 0,
|
|
|
|
|
high: opts.pitchRange?.high ?? 127,
|
|
|
|
|
},
|
|
|
|
|
};
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-04-07 00:41:30 +02:00
|
|
|
* Apply projection to a pattern. Returns a new pattern (no mutation).
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
2026-04-07 00:41:30 +02:00
|
|
|
* For each step:
|
|
|
|
|
* 1. Apply velocity curve to step.velocity
|
|
|
|
|
* 2. If step.velocity < gateThreshold, set step.trigger = false
|
|
|
|
|
* 3. If step.midiNote != null, fold into [pitchRange.low, pitchRange.high] by octave
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
*
|
2026-04-07 00:41:30 +02:00
|
|
|
* @param {{ velocityCurve: string, gateThreshold: number, pitchRange: { low: number, high: number } }} config
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
* @param {{ steps: Array, stepCount: number, metadata: Object }} patternDesc
|
|
|
|
|
* @returns {{ steps: Array, stepCount: number, metadata: Object }}
|
|
|
|
|
*/
|
2026-04-07 00:41:30 +02:00
|
|
|
export function applyProjection(config, patternDesc) {
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
const result = clonePattern(patternDesc);
|
|
|
|
|
const steps = result.steps;
|
|
|
|
|
const count = result.stepCount;
|
|
|
|
|
|
|
|
|
|
for (let s = 0; s < count; s++) {
|
|
|
|
|
const step = steps[s];
|
|
|
|
|
|
2026-04-07 00:41:30 +02:00
|
|
|
// 1. Velocity curve
|
|
|
|
|
step.velocity = velocityCurveApply(step.velocity, config.velocityCurve);
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
|
2026-04-07 00:41:30 +02:00
|
|
|
// 2. Gate threshold (uses post-curve velocity)
|
|
|
|
|
if (step.velocity < config.gateThreshold) {
|
|
|
|
|
step.trigger = false;
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-07 00:41:30 +02:00
|
|
|
// 3. Pitch range (octave fold)
|
|
|
|
|
if (step.midiNote != null) {
|
|
|
|
|
step.midiNote = octaveFold(step.midiNote, config.pitchRange.low, config.pitchRange.high);
|
feat(shapeseq): implement Layer 1 modules
Four modules that build on the Layer 0 foundation:
- primitive.js: base class with category system (generator/processor/
timing/converter), param schema validation, boundary enforcement
(clamp/wrap/scaled), symbolic process() interface, state management
for freeze, and applyBoundary() utility for delta control
- clock.js: AudioContext lookahead scheduling (25ms interval, 100ms
window) replacing setTimeout arpeggiator. Reads pattern descriptions
for per-step swing (timeOffset) and ratchet (subdivisions). Emits
seq.noteOn/noteOff/step/loopStart via event bus.
- projection.js: composable transform chain with 5 transforms
(VelocityCurve, GateThreshold, RangeMap, OctaveFolder, StutterMap)
and 3 presets (expressive, percussive, fullRange). Pitch quantization
deliberately excluded (handled by Interval Lock primitive).
- step-viz.js: Canvas2D circular step visualizer with even angular
spacing for any step count. Pitch→radius, velocity→node size,
accent→color. 60fps-friendly with pre-allocated coordinate buffers.
Tap interaction for step toggling.
2026-03-24 01:02:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|