draw midi input indicator

This commit is contained in:
Skyler Lehmkuhl 2025-11-06 09:12:48 -05:00
parent 5320e14745
commit e97dc5695f
4 changed files with 94 additions and 0 deletions

View File

@ -74,6 +74,26 @@ impl MidiInputManager {
// Get all available MIDI input ports // Get all available MIDI input ports
let ports = midi_in.ports(); let ports = midi_in.ports();
// Get list of currently available device names
let mut available_devices = Vec::new();
for port in &ports {
if let Ok(port_name) = midi_in.port_name(port) {
available_devices.push(port_name);
}
}
// Remove disconnected devices from our connections list
{
let mut conns = connections.lock().unwrap();
let before_count = conns.len();
conns.retain(|conn| available_devices.contains(&conn.device_name));
let after_count = conns.len();
if before_count != after_count {
println!("MIDI: Removed {} disconnected device(s)", before_count - after_count);
}
}
// Get list of already connected device names // Get list of already connected device names
let connected_devices: Vec<String> = { let connected_devices: Vec<String> = {
let conns = connections.lock().unwrap(); let conns = connections.lock().unwrap();

View File

@ -1306,6 +1306,28 @@ async function handleAudioEvent(event) {
context.pianoRedraw(); context.pianoRedraw();
} }
} }
// Update MIDI activity timestamp
context.lastMidiInputTime = Date.now();
console.log('[NoteOn] Set lastMidiInputTime to:', context.lastMidiInputTime);
// Start animation loop to keep redrawing the MIDI indicator
if (!context.midiIndicatorAnimating) {
context.midiIndicatorAnimating = true;
const animateMidiIndicator = () => {
if (context.timelineWidget && context.timelineWidget.requestRedraw) {
context.timelineWidget.requestRedraw();
}
// Keep animating for 1 second after last MIDI input
const elapsed = Date.now() - context.lastMidiInputTime;
if (elapsed < 1000) {
requestAnimationFrame(animateMidiIndicator);
} else {
context.midiIndicatorAnimating = false;
}
};
requestAnimationFrame(animateMidiIndicator);
}
break; break;
case 'NoteOff': case 'NoteOff':

View File

@ -41,6 +41,8 @@ export let context = {
recordingTrackId: null, recordingTrackId: null,
recordingClipId: null, recordingClipId: null,
playPauseButton: null, // Reference to play/pause button for updating appearance playPauseButton: null, // Reference to play/pause button for updating appearance
// MIDI activity indicator
lastMidiInputTime: 0, // Timestamp (Date.now()) of last MIDI input
}; };
// Application configuration // Application configuration

View File

@ -799,6 +799,56 @@ class TimelineWindowV2 extends Widget {
ctx.fillText(typeText, typeX, y + this.trackHierarchy.trackHeight / 2) ctx.fillText(typeText, typeX, y + this.trackHierarchy.trackHeight / 2)
} }
// Draw MIDI activity indicator for active MIDI track
if (track.type === 'audio' && track.object && track.object.type === 'midi') {
if (this.context && this.context.lastMidiInputTime > 0) {
// Check if this is the selected/active MIDI track
const isActiveMidiTrack = isSelected && track.object && track.object.audioTrackId !== undefined
if (isActiveMidiTrack) {
const elapsed = Date.now() - this.context.lastMidiInputTime
const fadeTime = 1000 // Fade out over 1 second (increased for visibility)
if (elapsed < fadeTime) {
// const mindicatorSize = 12 // Made larger
// const mindicatorX = this.trackHeaderWidth - 35 // Position to the left of buttons
// const mindicatorY = y + this.trackHierarchy.trackHeight / 2
// console.log(`[MIDI mIndicator] Drawing at (${mindicatorX}, ${mindicatorY}) with alpha ${1}`)
// // Draw pulsing circle with border
// ctx.strokeStyle = `rgba(0, 255, 0, ${1})`
// ctx.fillStyle = `rgba(0, 255, 0, ${1 * 0.5})`
// ctx.lineWidth = 2
// ctx.beginPath()
// ctx.arc(mindicatorX, mindicatorY, mindicatorSize / 2, 0, Math.PI * 2)
// ctx.fill()
// ctx.stroke()
const alpha = Math.max(0.2, 1 - (elapsed / fadeTime)) // Minimum alpha of 0.3 for visibility
const indicatorSize = 10
const indicatorX = this.trackHeaderWidth - 35 // Position to the left of buttons
const indicatorY = y + this.trackHierarchy.trackHeight / 2
console.log(`[MIDI Indicator] Drawing at (${indicatorX}, ${indicatorY}) with alpha ${alpha}`)
// Draw pulsing circle with border
ctx.strokeStyle = `rgba(0, 255, 0, ${alpha})`
ctx.fillStyle = `rgba(0, 255, 0, ${alpha})`
ctx.lineWidth = 2
ctx.beginPath()
ctx.arc(indicatorX, indicatorY, indicatorSize / 2, 0, Math.PI * 2)
ctx.fill()
ctx.stroke()
}
}
}
}
// Draw toggle buttons for object/shape/audio/midi tracks (Phase 3) // Draw toggle buttons for object/shape/audio/midi tracks (Phase 3)
if (track.type === 'object' || track.type === 'shape' || track.type === 'audio' || track.type === 'midi') { if (track.type === 'object' || track.type === 'shape' || track.type === 'audio' || track.type === 'midi') {
const buttonSize = 14 const buttonSize = 14