Skip to content

Commit 7b5f8f3

Browse files
committed
Reinstating the sequencer!
Didn’t take much time to bring back the circular sequencer from previous coding efforts in this project.
1 parent 23f966e commit 7b5f8f3

7 files changed

Lines changed: 2188 additions & 21 deletions

app/app-controller-browser.js

Lines changed: 147 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class EnhancedPatternApp {
3434
// Initialize core components
3535
this.database = new PatternDatabase();
3636
this.explorer = new SystematicExplorer();
37+
this.sequencer = null;
3738

3839
// Application state
3940
this.currentPattern = null;
@@ -44,6 +45,7 @@ class EnhancedPatternApp {
4445
// Initialize the application
4546
this.setupEventListeners();
4647
this.initialize();
48+
this.initializeSequencer();
4749

4850
console.log('✅ Enhanced Pattern Application initialized successfully');
4951
}
@@ -56,7 +58,8 @@ class EnhancedPatternApp {
5658
'MathUtils', 'RegularPolygonGenerator', 'EuclideanGenerator',
5759
'PerfectBalanceAnalyzer', 'PatternAnalyzer', 'CenterOfGravityCalculator',
5860
'AdvancedPatternCombiner', 'UnifiedPatternParser', 'PatternConverter',
59-
'SystematicExplorer', 'PatternDatabase', 'UIComponents', 'AppConfig'
61+
'SystematicExplorer', 'PatternDatabase', 'UIComponents', 'AppConfig',
62+
'SequencerController', 'SequencerIntegration'
6063
];
6164

6265
const missingClasses = requiredClasses.filter(className =>
@@ -87,6 +90,94 @@ class EnhancedPatternApp {
8790
console.log('🎯 Application initialization complete');
8891
}
8992

93+
/**
94+
* Initialize the sequencer controller
95+
*/
96+
async initializeSequencer() {
97+
try {
98+
console.log('🎵 Initializing sequencer...');
99+
100+
// Create sequencer controller
101+
this.sequencer = new SequencerController('patternSequencerCanvas', 'balanceSection', {
102+
autoPlay: false,
103+
defaultTempo: 120,
104+
defaultVolume: 0.5,
105+
enableAudio: true,
106+
enableVisual: true
107+
});
108+
109+
// Setup sequencer event listeners
110+
this.setupSequencerEvents();
111+
112+
console.log('✅ Sequencer initialized successfully');
113+
114+
} catch (error) {
115+
console.error('❌ Failed to initialize sequencer:', error);
116+
// Continue without sequencer if initialization fails
117+
this.sequencer = null;
118+
}
119+
}
120+
121+
/**
122+
* Setup sequencer event listeners
123+
*/
124+
setupSequencerEvents() {
125+
if (!this.sequencer) return;
126+
127+
// Sequencer control buttons
128+
const playBtn = document.getElementById('sequencerPlayBtn');
129+
const pauseBtn = document.getElementById('sequencerPauseBtn');
130+
const stopBtn = document.getElementById('sequencerStopBtn');
131+
const tempoSlider = document.getElementById('sequencerTempoSlider');
132+
const volumeSlider = document.getElementById('sequencerVolumeSlider');
133+
const tempoDisplay = document.getElementById('sequencerTempoDisplay');
134+
const volumeDisplay = document.getElementById('sequencerVolumeDisplay');
135+
const statusDisplay = document.getElementById('sequencerStatus');
136+
137+
if (playBtn) {
138+
playBtn.addEventListener('click', () => this.sequencer.play());
139+
}
140+
141+
if (pauseBtn) {
142+
pauseBtn.addEventListener('click', () => this.sequencer.pause());
143+
}
144+
145+
if (stopBtn) {
146+
stopBtn.addEventListener('click', () => this.sequencer.stop());
147+
}
148+
149+
if (tempoSlider && tempoDisplay) {
150+
tempoSlider.addEventListener('input', (e) => {
151+
const tempo = parseInt(e.target.value);
152+
this.sequencer.setTempo(tempo);
153+
tempoDisplay.textContent = tempo;
154+
});
155+
}
156+
157+
if (volumeSlider && volumeDisplay) {
158+
volumeSlider.addEventListener('input', (e) => {
159+
const volume = parseInt(e.target.value) / 100;
160+
this.sequencer.updateAudioSettings({ volume });
161+
volumeDisplay.textContent = `${e.target.value}%`;
162+
});
163+
}
164+
165+
// Listen for sequencer events
166+
this.sequencer.on('onPlaybackChange', (data) => {
167+
if (statusDisplay) {
168+
statusDisplay.textContent = data.isPlaying ? 'Playing' :
169+
data.isPaused ? 'Paused' : 'Ready';
170+
}
171+
});
172+
173+
this.sequencer.on('onError', (error) => {
174+
console.error('Sequencer error:', error);
175+
if (statusDisplay) {
176+
statusDisplay.textContent = 'Error';
177+
}
178+
});
179+
}
180+
90181
/**
91182
* Setup all event listeners for the application
92183
*/
@@ -319,7 +410,7 @@ class EnhancedPatternApp {
319410
// Show and populate balance section
320411
const balanceSection = document.getElementById('balanceSection');
321412
if (balanceSection) {
322-
balanceSection.style.display = 'flex';
413+
balanceSection.style.display = 'grid';
323414

324415
const balanceInfo = balanceSection.querySelector('.balance-info-compact');
325416
const balanceViz = balanceSection.querySelector('.balance-visualization-large');
@@ -347,14 +438,30 @@ class EnhancedPatternApp {
347438
<strong>Milne's Formula:</strong> |∑(e^(i2πkⱼ/n))| / onsets = ${analysis.balanceAnalysis.normalizedMagnitude.toFixed(6)}
348439
</div>
349440
</div>
441+
<div class="analysis-box cog-box" style="margin-top: 8px;">
442+
<div class="analysis-box-header">
443+
<span class="analysis-box-icon">🎯</span>
444+
<span class="analysis-box-title">Center of Gravity</span>
445+
</div>
446+
<div class="analysis-box-content">
447+
<div class="cog-distance-value">
448+
Distance: ${analysis.cogAnalysis?.distance?.toFixed(4) || 'N/A'}
449+
</div>
450+
<div class="cog-angle-value">
451+
Angle: ${analysis.cogAnalysis?.angle?.toFixed(1) || 'N/A'}°
452+
</div>
453+
<div class="cog-description">
454+
${analysis.cogAnalysis?.distance < 0.1 ? '🎯 Geometrically Centered' : 'Pattern analysis'}
455+
</div>
456+
</div>
457+
</div>
350458
`;
351459
}
352-
353-
if (balanceViz) {
354-
balanceViz.innerHTML = UIComponents.renderCogVisualization(analysis.cogAnalysis, analysis.stepCount);
355-
}
356460
}
357461

462+
// Load pattern into sequencer
463+
this.loadPatternIntoSequencer(pattern, analysis);
464+
358465
} catch (error) {
359466
console.error('❌ Analysis display error:', error);
360467

@@ -439,6 +546,12 @@ class EnhancedPatternApp {
439546
const balanceAnalysis = PerfectBalanceAnalyzer.calculateBalance(pattern.steps, pattern.stepCount);
440547
const cogAnalysis = CenterOfGravityCalculator.calculateCenterOfGravity(pattern.steps);
441548

549+
console.log('🔍 Analysis generated:', {
550+
balanceAnalysis: balanceAnalysis ? 'OK' : 'MISSING',
551+
cogAnalysis: cogAnalysis ? 'OK' : 'MISSING',
552+
cogProperties: cogAnalysis ? Object.keys(cogAnalysis) : 'N/A'
553+
});
554+
442555
return {
443556
title: 'Mathematical Pattern Analysis',
444557
patternOutputItems: patternOutputItems,
@@ -1287,6 +1400,34 @@ ${perfectBalancePatterns.map((pattern, index) => {
12871400
this.updateDatabaseStats();
12881401
}
12891402
}
1403+
1404+
/**
1405+
* Load pattern into sequencer for playback and visualization
1406+
*/
1407+
loadPatternIntoSequencer(pattern, analysis) {
1408+
if (!this.sequencer) {
1409+
console.warn('⚠️ Sequencer not available');
1410+
return;
1411+
}
1412+
1413+
try {
1414+
// Create sequencer-compatible pattern object
1415+
const sequencerPattern = SequencerIntegration.convertPatternResult(pattern);
1416+
1417+
// Add CoG data for visualization
1418+
if (analysis && analysis.cogAnalysis) {
1419+
sequencerPattern.cogData = analysis.cogAnalysis;
1420+
}
1421+
1422+
// Load pattern into sequencer
1423+
this.sequencer.updatePattern(sequencerPattern);
1424+
1425+
console.log(`🎵 Pattern loaded into sequencer: ${sequencerPattern.name}`);
1426+
1427+
} catch (error) {
1428+
console.error('❌ Failed to load pattern into sequencer:', error);
1429+
}
1430+
}
12901431
}
12911432

12921433
// Export for global access

0 commit comments

Comments
 (0)