Implement complete search results + dual player UI

Backend Enhancements:
- Add ParsedMIDIInfo with track analysis and quality issues
- New /api/midi/parse endpoint for MIDI metadata extraction
- Enhanced MIDIService with parseMIDI method

MIDI Preview Player:
- Complete MIDIPlayer class with polyphonic playback
- Basic oscillator mapping (bass=square, mid=triangle, high=sine)
- Lookahead scheduling with proper cleanup
- Automatic stopping when MIDI ends

New UI Flow:
1. Search → Results table with metadata
2. Select MIDI → Shows parsed info (duration, tracks, tempo)
3. Dual transport: Preview Original vs Generate Motif
4. Try Next Result button for easy A/B testing

Search Results Table:
- Title, source, confidence bar, duration, track count
- Quality issues display (short duration, few notes, etc.)
- Auto-select best result, manual selection available
- Visual confidence bars and issue warnings

This makes the project feel "real" - you can now:
- See exactly what MIDI was found
- Verify it's the right song via preview
- Compare original vs procedural synthesis
- Easily try different results

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
b1rdmania
2025-12-17 21:04:29 +00:00
parent 2d4c748d4c
commit 177e8fbed3
8 changed files with 731 additions and 36 deletions
+25
View File
@@ -2,6 +2,7 @@ import express from 'express';
import cors from 'cors';
import { MIDISearchService } from './services/MIDISearchService.js';
import { MIDIFetchService } from './services/MIDIFetchService.js';
import { MIDIParseService } from './services/MIDIParseService.js';
const app = express();
const port = process.env.PORT || 3001;
@@ -11,6 +12,7 @@ app.use(express.json());
const searchService = new MIDISearchService();
const fetchService = new MIDIFetchService();
const parseService = new MIDIParseService();
// Search for MIDI files
app.get('/api/midi/search', async (req, res) => {
@@ -53,6 +55,29 @@ app.get('/api/midi/fetch', async (req, res) => {
}
});
// Parse MIDI metadata
app.get('/api/midi/parse', async (req, res) => {
try {
const url = req.query.u as string;
if (!url) {
return res.status(400).json({ error: 'URL parameter "u" is required' });
}
console.log(`Parsing MIDI metadata: ${url}`);
const result = await fetchService.fetch(url);
if (result.success && result.data) {
const metadata = parseService.parseMIDI(result.data);
res.json(metadata);
} else {
res.status(404).json({ error: result.error || 'Failed to fetch MIDI' });
}
} catch (error) {
console.error('Parse error:', error);
res.status(500).json({ error: 'Parse failed' });
}
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });