feat: add sequencer, piano roll modules with pre-composed chiptune melody

Add step sequencer (16-step with note/gate editing) and piano roll
(canvas-based MIDI editor with draw/erase tools). Includes a Megaman-style
melody in C minor. Chiptune preset now uses piano roll instead of keyboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jose Luis
2026-03-21 01:30:03 +01:00
parent 4a003f2af2
commit 65a89e2b59
7 changed files with 647 additions and 23 deletions

View File

@@ -5,6 +5,8 @@ import { updateParam } from '../engine/audioEngine.js';
import Knob from './Knob.jsx';
import ScopeDisplay from './ScopeDisplay.jsx';
import KeyboardWidget from './KeyboardWidget.jsx';
import SequencerWidget from './SequencerWidget.jsx';
import PianoRollWidget from './PianoRollWidget.jsx';
export default function ModuleNode({ mod, zoom, onStartConnect, onPortPosition }) {
const def = getModuleDef(mod.type);
@@ -65,7 +67,11 @@ export default function ModuleNode({ mod, zoom, onStartConnect, onPortPosition }
return (
<div
className={`module ${isSelected ? 'selected' : ''}`}
style={{ left: mod.x * zoom, top: mod.y * zoom, transform: `scale(${zoom})`, transformOrigin: 'top left' }}
style={{
left: mod.x * zoom, top: mod.y * zoom,
transform: `scale(${zoom})`, transformOrigin: 'top left',
...(mod.type === 'pianoroll' ? { width: 520 } : mod.type === 'sequencer' ? { width: 310 } : {}),
}}
data-module-id={mod.id}
onPointerDown={(e) => {
// Don't deselect when clicking inside a module
@@ -142,6 +148,12 @@ export default function ModuleNode({ mod, zoom, onStartConnect, onPortPosition }
{/* Keyboard widget */}
{mod.type === 'keyboard' && <KeyboardWidget moduleId={mod.id} />}
{/* Sequencer widget */}
{mod.type === 'sequencer' && <SequencerWidget moduleId={mod.id} />}
{/* Piano Roll widget */}
{mod.type === 'pianoroll' && <PianoRollWidget moduleId={mod.id} />}
{/* Output ports */}
{def.outputs.map(port => (
<div key={port.name} className="port-row output">