feat: added audio track spectrogram visualization feature

This commit is contained in:
Xiaohan-Tian
2026-05-01 17:44:29 -07:00
parent cd90dc1c99
commit eafb3a4937
15 changed files with 696 additions and 88 deletions
+21
View File
@@ -119,6 +119,27 @@
background: rgba(0, 0, 0, 0.35);
}
.region-spectrogram-btn {
position: absolute;
top: 4px;
left: 4px;
background: rgba(0, 0, 0, 0.25);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 3px;
padding: 2px;
margin: 0;
cursor: pointer;
z-index: 2;
display: inline-flex;
align-items: center;
justify-content: center;
}
.region-spectrogram-btn:hover {
background: rgba(0, 0, 0, 0.35);
}
/* Instrument dropdown specific styles */
.instrument-dropdown .quant-dropdown {
min-width: 80px;
+24
View File
@@ -1,6 +1,7 @@
import React, { useState, useRef, useEffect } from 'react';
import './Region.css';
import { FaPencilAlt } from 'react-icons/fa';
import { MdGraphicEq } from 'react-icons/md';
import type { ResizeAction } from '../interfaces';
import { REGION_CONSTANTS, DEBUG_MODE } from '../../constants';
import { KGMidiRegion } from '../../core/region/KGMidiRegion';
@@ -27,6 +28,8 @@ interface RegionItemProps {
onClick?: (regionId: string) => void;
// Explicit open piano roll action from header pencil icon
onOpenPianoRoll?: (regionId: string) => void;
// Open spectrogram viewer for audio regions
onOpenSpectrogram?: (regionId: string) => void;
// MIDI region data for rendering notes
midiRegion?: KGMidiRegion;
// Audio region data for rendering waveform
@@ -49,6 +52,7 @@ const RegionItem: React.FC<RegionItemProps> = ({
onDragEnd,
onClick,
onOpenPianoRoll,
onOpenSpectrogram,
midiRegion,
audioRegion,
audioBuffer
@@ -576,6 +580,26 @@ const RegionItem: React.FC<RegionItemProps> = ({
<FaPencilAlt size={10} />
</button>
)}
{audioRegion && (
<button
className="region-spectrogram-btn"
title="View melodic spectrogram"
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
if (onOpenSpectrogram) {
onOpenSpectrogram(id);
}
}}
aria-label="View spectrogram"
>
<MdGraphicEq size={10} />
</button>
)}
<canvas ref={canvasRef} />
</div>
</div>
+5
View File
@@ -26,6 +26,7 @@ interface TrackGridItemProps {
onRegionDragEnd?: (regionId: string, finalBarNumber: number, finalTrackIndex: number) => void;
onRegionClick?: (regionId: string) => void;
onOpenPianoRoll?: (regionId: string) => void;
onOpenSpectrogram?: (regionId: string) => void;
allTracks?: KGTrack[]; // Added to access all tracks for drag operations
onKGOneClipDrop?: (e: React.DragEvent<HTMLDivElement>, trackIndex: number) => void;
}
@@ -47,6 +48,7 @@ const TrackGridItem: React.FC<TrackGridItemProps> = ({
onRegionDragEnd,
onRegionClick,
onOpenPianoRoll,
onOpenSpectrogram,
allTracks,
onKGOneClipDrop,
}) => {
@@ -566,6 +568,9 @@ const TrackGridItem: React.FC<TrackGridItemProps> = ({
onRegionClick(regionId);
}
}}
onOpenSpectrogram={audioRegion ? (regionId) => {
onOpenSpectrogram?.(regionId);
} : undefined}
midiRegion={midiRegion}
audioRegion={audioRegion}
audioBuffer={audioBuffer}
+3
View File
@@ -30,6 +30,7 @@ interface TrackGridPanelProps {
onRegionUpdated?: (regionId: string, updates: Partial<RegionUI>, expectedModelUpdates?: { startBeat: number, length: number }) => void;
onRegionClick?: (regionId: string) => void;
onOpenPianoRoll?: (regionId: string) => void;
onOpenSpectrogram?: (regionId: string) => void;
onExternalDropComplete?: (trackIndex: number, regionUI: RegionUI) => void;
}
@@ -46,6 +47,7 @@ const TrackGridPanel: React.FC<TrackGridPanelProps> = ({
onRegionUpdated,
onRegionClick,
onOpenPianoRoll,
onOpenSpectrogram,
onExternalDropComplete,
}) => {
const gridContainerRef = useRef<HTMLDivElement>(null);
@@ -651,6 +653,7 @@ const TrackGridPanel: React.FC<TrackGridPanelProps> = ({
onRegionDragEnd={handleRegionDragEnd}
onRegionClick={handleRegionClick}
onOpenPianoRoll={onOpenPianoRoll}
onOpenSpectrogram={onOpenSpectrogram}
allTracks={tracks}
onKGOneClipDrop={handleExternalDrop}
/>