loop station

This commit is contained in:
vadimwit
2026-03-20 01:03:43 +00:00
parent 8cd9b01941
commit f583979b3e
9 changed files with 2600 additions and 25 deletions
+38 -8
View File
@@ -11,8 +11,9 @@ import DebugView from './components/DebugView'
import DrumView from './components/DrumView'
import { NOTES, detectKey, detectTopKeys, matchChordFromChroma, detectRepeatingProgression, getChordTones, getChordCandidates, getNoteHistoryAnalysis } from './lib/theory'
import ChordDetailModal from './components/ChordDetailModal'
import ExplorePanel from './components/ExplorePanel'
import CurrentJamPanel from './components/CurrentJamPanel'
import LoopStation from './components/LoopStation'
import { useLoopEngine } from './services/loopEngine'
import settingIcon from './assets/setting-icon.png'
const DEFAULTS = {
@@ -83,6 +84,23 @@ export default function App() {
const onsetTimestampsRef = useRef([])
const bpmSmoothRef = useRef(null)
// ── Loop station ─────────────────────────────────────────────────────────────
const {
slots,
masterLen,
setStream: loopSetStream,
handleSlotClick,
commitTrim,
cancelRecord,
retrimSlot,
deleteSlot,
setVolume: loopSetVolume,
addSlot: loopAddSlot,
audioCtxRef: loopAudioCtxRef,
masterStartRef: loopMasterStartRef,
masterLenRef: loopMasterLenRef,
} = useLoopEngine(bpm)
// ── Key: auto-detected + optional lock ───────────────────────────────────────
const [keyInfo, setKeyInfo] = useState(null) // auto-detected
const [lockedKey, setLockedKey] = useState(null) // { root, mode } or null
@@ -525,6 +543,7 @@ export default function App() {
setMicError(true)
setIsListening(false)
}}
onStreamReady={loopSetStream}
/>
{micError && (
@@ -535,7 +554,7 @@ export default function App() {
)}
{/* ── Chord detail modal ── */}
<ChordDetailModal chord={selectedChord} onClose={() => setSelectedChord(null)} keyInfo={effectiveKey} chordHistory={chordHistory} />
<ChordDetailModal chord={selectedChord} onClose={() => setSelectedChord(null)} onChordClick={setSelectedChord} keyInfo={effectiveKey} chordHistory={chordHistory} />
{/* ── Progression banner ── */}
<ProgressionBanner
@@ -561,12 +580,6 @@ export default function App() {
</div>
</div>
{/* ── Explore any chord — collapsible ── */}
<ExplorePanel
keyInfo={effectiveKey}
chordHistory={chordHistory}
onChordClick={setSelectedChord}
/>
{/* ── Current jam — collapsible ── */}
<CurrentJamPanel
@@ -576,6 +589,23 @@ export default function App() {
onChordClick={setSelectedChord}
/>
{/* ── Loop station ── */}
<LoopStation
slots={slots}
bpm={bpm}
masterLen={masterLen}
audioCtxRef={loopAudioCtxRef}
masterStartRef={loopMasterStartRef}
masterLenRef={loopMasterLenRef}
onSlotClick={handleSlotClick}
onCommitTrim={commitTrim}
onCancelRecord={cancelRecord}
onRetrim={retrimSlot}
onDelete={deleteSlot}
onVolumeChange={loopSetVolume}
onAddSlot={loopAddSlot}
/>
{/* ── Behind the scenes — collapsible ── */}
<div className="mb-3 bg-panel border border-border rounded-xl overflow-hidden">
<button