Files
motif/server/src/server.ts
T
b1rdmania 11c894bd91 Add complete MIDI search and synthesis pipeline
Backend (MVP):
- Express API with /search and /fetch endpoints
- BitMidi and Dongrays search adapters with scoring heuristics
- CORS proxy with disk caching and validation
- Quality assessment and file size limits

Frontend Integration:
- Switch to @tonejs/midi parser for reliable MIDI parsing
- MIDIService for backend API communication
- MotifEngine updated to try real MIDI, fallback to synthetic
- Enhanced error handling and logging

Development:
- Concurrent frontend/backend npm scripts
- Basic project documentation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-17 20:45:40 +00:00

63 lines
1.7 KiB
TypeScript

import express from 'express';
import cors from 'cors';
import { MIDISearchService } from './services/MIDISearchService.js';
import { MIDIFetchService } from './services/MIDIFetchService.js';
const app = express();
const port = process.env.PORT || 3001;
app.use(cors());
app.use(express.json());
const searchService = new MIDISearchService();
const fetchService = new MIDIFetchService();
// Search for MIDI files
app.get('/api/midi/search', async (req, res) => {
try {
const query = req.query.q as string;
if (!query) {
return res.status(400).json({ error: 'Query parameter "q" is required' });
}
console.log(`Searching for: ${query}`);
const results = await searchService.search(query);
res.json({ results, count: results.length });
} catch (error) {
console.error('Search error:', error);
res.status(500).json({ error: 'Search failed' });
}
});
// Fetch and proxy MIDI file
app.get('/api/midi/fetch', 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(`Fetching: ${url}`);
const result = await fetchService.fetch(url);
if (result.success) {
res.setHeader('Content-Type', 'audio/midi');
res.setHeader('Content-Length', result.data!.length);
res.send(result.data);
} else {
res.status(404).json({ error: result.error });
}
} catch (error) {
console.error('Fetch error:', error);
res.status(500).json({ error: 'Fetch failed' });
}
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
app.listen(port, () => {
console.log(`🎵 Motif backend running on port ${port}`);
});