MySafeCode commited on
Commit
7746a56
·
verified ·
1 Parent(s): de8ef86

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +712 -834
index.html CHANGED
@@ -1,846 +1,724 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
 
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SID Chip Tune Studio</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- :root {
15
- --c64-blue: #352879;
16
- --c64-lightblue: #6c5eb5;
17
- --c64-cyan: #00a0a0;
18
- --c64-purple: #a0a0ff;
19
- --c64-pink: #ff00ff;
20
- --c64-yellow: #ffff00;
21
- --c64-orange: #ff7700;
22
- --c64-green: #00ff00;
23
- --c64-red: #ff0000;
24
- --c64-white: #ffffff;
25
- --c64-gray: #7869c4;
26
- --bg-dark: #0a0a0f;
27
- --bg-medium: #1a1a2e;
28
- --bg-light: #16213e;
29
- }
30
-
31
- body {
32
- font-family: 'Courier New', monospace;
33
- background: linear-gradient(135deg, var(--bg-dark) 0%, var(--bg-medium) 100%);
34
- color: var(--c64-white);
35
- min-height: 100vh;
36
- overflow-x: hidden;
37
- position: relative;
38
- }
39
-
40
- body::before {
41
- content: '';
42
- position: fixed;
43
- top: 0;
44
- left: 0;
45
- right: 0;
46
- bottom: 0;
47
- background:
48
- repeating-linear-gradient(
49
- 0deg,
50
- transparent,
51
- transparent 2px,
52
- rgba(0, 160, 160, 0.03) 2px,
53
- rgba(0, 160, 160, 0.03) 4px
54
- );
55
- pointer-events: none;
56
- z-index: 1;
57
- }
58
-
59
- .container {
60
- max-width: 1400px;
61
- margin: 0 auto;
62
- padding: 20px;
63
- position: relative;
64
- z-index: 2;
65
- }
66
-
67
- header {
68
- text-align: center;
69
- padding: 30px 0;
70
- background: linear-gradient(135deg, var(--c64-blue), var(--c64-lightblue));
71
- border-radius: 15px;
72
- margin-bottom: 30px;
73
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
74
- position: relative;
75
- overflow: hidden;
76
- }
77
-
78
- header::before {
79
- content: '';
80
- position: absolute;
81
- top: -50%;
82
- left: -50%;
83
- width: 200%;
84
- height: 200%;
85
- background: repeating-linear-gradient(
86
- 45deg,
87
- transparent,
88
- transparent 10px,
89
- rgba(255, 255, 255, 0.05) 10px,
90
- rgba(255, 255, 255, 0.05) 20px
91
- );
92
- animation: slide 20s linear infinite;
93
- }
94
-
95
- @keyframes slide {
96
- 0% { transform: translate(0, 0); }
97
- 100% { transform: translate(50px, 50px); }
98
- }
99
-
100
- h1 {
101
- font-size: 3em;
102
- text-shadow: 3px 3px 0 var(--c64-purple),
103
- 6px 6px 0 var(--c64-pink),
104
- 9px 9px 20px rgba(0, 0, 0, 0.5);
105
- position: relative;
106
- z-index: 1;
107
- letter-spacing: 5px;
108
- margin-bottom: 10px;
109
- }
110
-
111
- .subtitle {
112
- font-size: 1.2em;
113
- color: var(--c64-yellow);
114
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
115
- position: relative;
116
- z-index: 1;
117
- }
118
-
119
- .credits {
120
- margin-top: 15px;
121
- font-size: 0.9em;
122
- color: var(--c64-cyan);
123
- position: relative;
124
- z-index: 1;
125
- }
126
-
127
- .credits a {
128
- color: var(--c64-yellow);
129
- text-decoration: none;
130
- transition: all 0.3s;
131
- }
132
-
133
- .credits a:hover {
134
- color: var(--c64-orange);
135
- text-shadow: 0 0 10px var(--c64-orange);
136
- }
137
-
138
- .controls {
139
- display: grid;
140
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
141
- gap: 20px;
142
- margin-bottom: 30px;
143
- }
144
-
145
- .control-group {
146
- background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
147
- padding: 20px;
148
- border-radius: 10px;
149
- border: 2px solid var(--c64-cyan);
150
- box-shadow: 0 5px 15px rgba(0, 160, 160, 0.3);
151
- transition: transform 0.3s, box-shadow 0.3s;
152
- }
153
-
154
- .control-group:hover {
155
- transform: translateY(-2px);
156
- box-shadow: 0 8px 25px rgba(0, 160, 160, 0.5);
157
- }
158
-
159
- .control-group h3 {
160
- color: var(--c64-cyan);
161
- margin-bottom: 15px;
162
- font-size: 1.2em;
163
- text-transform: uppercase;
164
- letter-spacing: 2px;
165
- }
166
-
167
- .btn {
168
- background: linear-gradient(135deg, var(--c64-purple), var(--c64-pink));
169
- color: var(--c64-white);
170
- border: none;
171
- padding: 12px 25px;
172
- border-radius: 8px;
173
- font-size: 1em;
174
- font-weight: bold;
175
- cursor: pointer;
176
- transition: all 0.3s;
177
- text-transform: uppercase;
178
- letter-spacing: 1px;
179
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
180
- margin: 5px;
181
- }
182
-
183
- .btn:hover {
184
- transform: translateY(-2px);
185
- box-shadow: 0 6px 20px rgba(255, 0, 255, 0.4);
186
- background: linear-gradient(135deg, var(--c64-pink), var(--c64-purple));
187
- }
188
-
189
- .btn:active {
190
- transform: translateY(0);
191
- }
192
-
193
- .btn.active {
194
- background: linear-gradient(135deg, var(--c64-green), var(--c64-yellow));
195
- box-shadow: 0 0 20px rgba(0, 255, 0, 0.5);
196
- }
197
-
198
- .slider-container {
199
- margin: 10px 0;
200
- }
201
-
202
- .slider-label {
203
- display: flex;
204
- justify-content: space-between;
205
- margin-bottom: 5px;
206
- font-size: 0.9em;
207
- color: var(--c64-yellow);
208
- }
209
-
210
- input[type="range"] {
211
- width: 100%;
212
- height: 8px;
213
- background: linear-gradient(90deg, var(--c64-blue), var(--c64-cyan));
214
- border-radius: 5px;
215
- outline: none;
216
- -webkit-appearance: none;
217
- }
218
-
219
- input[type="range"]::-webkit-slider-thumb {
220
- -webkit-appearance: none;
221
- width: 20px;
222
- height: 20px;
223
- background: var(--c64-yellow);
224
- border-radius: 50%;
225
- cursor: pointer;
226
- box-shadow: 0 0 10px rgba(255, 255, 0, 0.5);
227
- transition: all 0.3s;
228
- }
229
-
230
- input[type="range"]::-webkit-slider-thumb:hover {
231
- background: var(--c64-orange);
232
- box-shadow: 0 0 20px rgba(255, 119, 0, 0.8);
233
- }
234
-
235
- .tracks-container {
236
- background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
237
- border-radius: 15px;
238
- padding: 20px;
239
- border: 3px solid var(--c64-cyan);
240
- box-shadow: 0 10px 30px rgba(0, 160, 160, 0.3);
241
- }
242
-
243
- .tracks-header {
244
- display: grid;
245
- grid-template-columns: 80px repeat(4, 1fr) 100px;
246
- gap: 10px;
247
- margin-bottom: 15px;
248
- padding: 10px;
249
- background: rgba(0, 0, 0, 0.3);
250
- border-radius: 8px;
251
- }
252
-
253
- .header-cell {
254
- color: var(--c64-yellow);
255
- font-weight: bold;
256
- text-align: center;
257
- font-size: 0.9em;
258
- text-transform: uppercase;
259
- letter-spacing: 1px;
260
- }
261
-
262
- .track-row {
263
- display: grid;
264
- grid-template-columns: 80px repeat(4, 1fr) 100px;
265
- gap: 10px;
266
- margin-bottom: 10px;
267
- padding: 10px;
268
- background: rgba(0, 0, 0, 0.2);
269
- border-radius: 8px;
270
- transition: all 0.3s;
271
- align-items: center;
272
- }
273
-
274
- .track-row:hover {
275
- background: rgba(0, 160, 160, 0.1);
276
- transform: translateX(5px);
277
- }
278
-
279
- .track-row.playing {
280
- background: rgba(255, 255, 0, 0.1);
281
- box-shadow: 0 0 15px rgba(255, 255, 0, 0.3);
282
- animation: pulse 0.5s ease-in-out infinite alternate;
283
- }
284
-
285
- @keyframes pulse {
286
- from { opacity: 0.8; }
287
- to { opacity: 1; }
288
- }
289
-
290
- .track-number {
291
- color: var(--c64-cyan);
292
- font-weight: bold;
293
- text-align: center;
294
- font-size: 1.2em;
295
- }
296
-
297
- .instrument-cell {
298
- display: flex;
299
- align-items: center;
300
- justify-content: center;
301
- gap: 5px;
302
- }
303
-
304
- .instrument-indicator {
305
- width: 12px;
306
- height: 12px;
307
- border-radius: 50%;
308
- background: var(--c64-gray);
309
- transition: all 0.3s;
310
- }
311
-
312
- .instrument-indicator.active {
313
- box-shadow: 0 0 10px currentColor;
314
- animation: blink 0.5s ease-in-out infinite;
315
- }
316
-
317
- .instrument-indicator.lead { background: var(--c64-yellow); }
318
- .instrument-indicator.bass { background: var(--c64-red); }
319
- .instrument-indicator.arpeggio { background: var(--c64-green); }
320
- .instrument-indicator.drums { background: var(--c64-purple); }
321
-
322
- @keyframes blink {
323
- 0%, 100% { opacity: 1; }
324
- 50% { opacity: 0.3; }
325
- }
326
-
327
- .track-toggle {
328
- background: var(--c64-blue);
329
- color: var(--c64-white);
330
- border: 2px solid var(--c64-cyan);
331
- padding: 8px 15px;
332
- border-radius: 5px;
333
- cursor: pointer;
334
- transition: all 0.3s;
335
- font-size: 0.9em;
336
- font-weight: bold;
337
- }
338
-
339
- .track-toggle:hover {
340
- background: var(--c64-cyan);
341
- transform: scale(1.05);
342
- }
343
-
344
- .track-toggle.enabled {
345
- background: var(--c64-green);
346
- border-color: var(--c64-yellow);
347
- }
348
-
349
- .visualizer {
350
- margin-top: 30px;
351
- padding: 20px;
352
- background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
353
- border-radius: 15px;
354
- border: 2px solid var(--c64-cyan);
355
- height: 200px;
356
- position: relative;
357
- overflow: hidden;
358
- }
359
-
360
- .visualizer canvas {
361
- width: 100%;
362
- height: 100%;
363
- display: block;
364
- }
365
-
366
- .pattern-display {
367
- position: absolute;
368
- top: 10px;
369
- right: 10px;
370
- background: rgba(0, 0, 0, 0.7);
371
- padding: 10px;
372
- border-radius: 5px;
373
- color: var(--c64-yellow);
374
- font-size: 0.9em;
375
- }
376
-
377
- @media (max-width: 768px) {
378
- h1 { font-size: 2em; }
379
- .tracks-header, .track-row {
380
- grid-template-columns: 60px repeat(4, 1fr) 80px;
381
- font-size: 0.8em;
382
- }
383
- .controls {
384
- grid-template-columns: 1fr;
385
- }
386
- }
387
-
388
- .loading-overlay {
389
- position: fixed;
390
- top: 0;
391
- left: 0;
392
- right: 0;
393
- bottom: 0;
394
- background: rgba(0, 0, 0, 0.9);
395
- display: flex;
396
- align-items: center;
397
- justify-content: center;
398
- z-index: 1000;
399
- opacity: 0;
400
- pointer-events: none;
401
- transition: opacity 0.3s;
402
- }
403
-
404
- .loading-overlay.active {
405
- opacity: 1;
406
- pointer-events: all;
407
- }
408
-
409
- .loading-text {
410
- color: var(--c64-cyan);
411
- font-size: 2em;
412
- animation: flash 0.5s ease-in-out infinite;
413
- }
414
-
415
- @keyframes flash {
416
- 0%, 100% { opacity: 1; }
417
- 50% { opacity: 0.5; }
418
- }
419
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  </head>
 
421
  <body>
422
- <div class="loading-overlay" id="loadingOverlay">
423
- <div class="loading-text">INITIALIZING SID CHIP...</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
  </div>
425
 
426
- <div class="container">
427
- <header>
428
- <h1>🎵 SID CHIP TUNE STUDIO 🎵</h1>
429
- <div class="subtitle">8-Bit Music Synthesizer</div>
430
- <div class="credits">
431
- Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
432
- </div>
433
- </header>
434
-
435
- <div class="controls">
436
- <div class="control-group">
437
- <h3>🎛️ Master Controls</h3>
438
- <button class="btn" id="playBtn" onclick="togglePlay()">▶ PLAY</button>
439
- <button class="btn" id="stopBtn" onclick="stopMusic()">⬛ STOP</button>
440
- <button class="btn" id="randomBtn" onclick="randomizeTracks()">🎲 RANDOM</button>
441
- </div>
442
-
443
- <div class="control-group">
444
- <h3>🎵 Tempo & Volume</h3>
445
- <div class="slider-container">
446
- <div class="slider-label">
447
- <span>BPM</span>
448
- <span id="bpmValue">120</span>
449
- </div>
450
- <input type="range" id="bpmSlider" min="60" max="200" value="120" oninput="updateBPM(this.value)">
451
- </div>
452
- <div class="slider-container">
453
- <div class="slider-label">
454
- <span>Volume</span>
455
- <span id="volumeValue">70%</span>
456
- </div>
457
- <input type="range" id="volumeSlider" min="0" max="100" value="70" oninput="updateVolume(this.value)">
458
- </div>
459
- </div>
460
-
461
- <div class="control-group">
462
- <h3>🎹 Instruments</h3>
463
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 5px;">
464
- <button class="btn" id="leadBtn" onclick="toggleInstrument('lead')">LEAD</button>
465
- <button class="btn" id="bassBtn" onclick="toggleInstrument('bass')">BASS</button>
466
- <button class="btn" id="arpBtn" onclick="toggleInstrument('arpeggio')">ARP</button>
467
- <button class="btn" id="drumBtn" onclick="toggleInstrument('drums')">DRUMS</button>
468
- </div>
469
- </div>
470
  </div>
471
-
472
- <div class="tracks-container">
473
- <div class="tracks-header">
474
- <div class="header-cell">TRACK</div>
475
- <div class="header-cell">LEAD</div>
476
- <div class="header-cell">BASS</div>
477
- <div class="header-cell">ARPEGGIO</div>
478
- <div class="header-cell">DRUMS</div>
479
- <div class="header-cell">ENABLE</div>
480
- </div>
481
- <div id="tracksGrid"></div>
482
  </div>
483
-
484
- <div class="visualizer">
485
- <canvas id="visualizer"></canvas>
486
- <div class="pattern-display">
487
- <div>Pattern: <span id="currentPattern">0</span>/10</div>
488
- <div>Beat: <span id="currentBeat">0</span>/4</div>
489
- </div>
 
 
490
  </div>
 
491
  </div>
492
 
493
- <script>
494
- // Audio Context and Global Variables
495
- let audioContext;
496
- let isPlaying = false;
497
- let currentTrack = 0;
498
- let currentBeat = 0;
499
- let bpm = 120;
500
- let masterVolume = 0.7;
501
- let intervalId;
502
- let analyser;
503
- let dataArray;
504
- let animationId;
505
-
506
- // Instrument states
507
- const instruments = {
508
- lead: true,
509
- bass: true,
510
- arpeggio: true,
511
- drums: true
512
- };
513
-
514
- // Track patterns (10 tracks x 4 instruments x 16 steps)
515
- const tracks = [];
516
- for (let i = 0; i < 10; i++) {
517
- tracks.push({
518
- enabled: true,
519
- lead: generatePattern('lead'),
520
- bass: generatePattern('bass'),
521
- arpeggio: generatePattern('arpeggio'),
522
- drums: generatePattern('drums')
523
- });
524
- }
525
-
526
- // Scales for different instruments
527
- const leadScale = ['C4', 'D4', 'E4', 'G4', 'A4', 'C5', 'D5', 'E5'];
528
- const bassScale = ['C2', 'G2', 'C3', 'G3', 'C4'];
529
- const arpScale = ['C3', 'E3', 'G3', 'C4', 'E4', 'G4'];
530
- const drumNotes = ['C1', 'C#1', 'D1']; // Different drum sounds
531
-
532
- // Note frequencies
533
- const noteFrequencies = {
534
- 'C1': 32.70, 'C#1': 34.65, 'D1': 36.71,
535
- 'C2': 65.41, 'G2': 98.00, 'C3': 130.81, 'G3': 196.00, 'C4': 261.63,
536
- 'C3': 130.81, 'E3': 164.81, 'G3': 196.00, 'C4': 261.63, 'E4': 329.63, 'G4': 392.00,
537
- 'C4': 261.63, 'D4': 293.66, 'E4': 329.63, 'G4': 392.00, 'A4': 440.00,
538
- 'C5': 523.25, 'D5': 587.33, 'E5': 659.25
539
- };
540
-
541
- // Initialize audio context
542
- function initAudio() {
543
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
544
- analyser = audioContext.createAnalyser();
545
- analyser.fftSize = 256;
546
- dataArray = new Uint8Array(analyser.frequencyBinCount);
547
- analyser.connect(audioContext.destination);
548
- }
549
-
550
- // Generate pattern for instrument
551
- function generatePattern(type) {
552
- const pattern = [];
553
- const steps = 16;
554
-
555
- for (let i = 0; i < steps; i++) {
556
- if (Math.random() > 0.3) {
557
- if (type === 'lead') {
558
- pattern.push(leadScale[Math.floor(Math.random() * leadScale.length)]);
559
- } else if (type === 'bass') {
560
- pattern.push(bassScale[Math.floor(Math.random() * bassScale.length)]);
561
- } else if (type === 'arpeggio') {
562
- pattern.push(arpScale[Math.floor(Math.random() * arpScale.length)]);
563
- } else if (type === 'drums') {
564
- pattern.push(drumNotes[Math.floor(Math.random() * drumNotes.length)]);
565
- }
566
- } else {
567
- pattern.push(null);
568
- }
569
- }
570
-
571
- return pattern;
572
- }
573
-
574
- // Create SID-style oscillator
575
- function createSIDOscillator(frequency, type = 'square', volume = 0.3) {
576
- const oscillator = audioContext.createOscillator();
577
- const gainNode = audioContext.createGain();
578
-
579
- // Set waveform type for SID-like sound
580
- if (type === 'lead') {
581
- oscillator.type = 'sawtooth';
582
- gainNode.gain.value = volume * 0.7;
583
- } else if (type === 'bass') {
584
- oscillator.type = 'square';
585
- gainNode.gain.value = volume * 0.8;
586
- } else if (type === 'arpeggio') {
587
- oscillator.type = 'triangle';
588
- gainNode.gain.value = volume * 0.5;
589
- } else if (type === 'drums') {
590
- oscillator.type = 'square';
591
- gainNode.gain.value = volume;
592
- }
593
-
594
- oscillator.frequency.value = frequency;
595
- oscillator.connect(gainNode);
596
- gainNode.connect(analyser);
597
-
598
- return { oscillator, gainNode };
599
- }
600
-
601
- // Play a note
602
- function playNote(frequency, type, duration = 0.1) {
603
- if (!frequency) return;
604
-
605
- const { oscillator, gainNode } = createSIDOscillator(frequency, type, masterVolume);
606
-
607
- oscillator.start();
608
-
609
- // Envelope for SID-like sound
610
- gainNode.gain.setValueAtTime(0, audioContext.currentTime);
611
- gainNode.gain.linearRampToValueAtTime(masterVolume, audioContext.currentTime + 0.01);
612
- gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
613
-
614
- oscillator.stop(audioContext.currentTime + duration);
615
- }
616
-
617
- // Initialize tracks grid
618
- function initTracksGrid() {
619
- const grid = document.getElementById('tracksGrid');
620
- grid.innerHTML = '';
621
-
622
- for (let i = 0; i < 10; i++) {
623
- const row = document.createElement('div');
624
- row.className = 'track-row';
625
- row.id = `track-${i}`;
626
-
627
- row.innerHTML = `
628
- <div class="track-number">${String(i + 1).padStart(2, '0')}</div>
629
- <div class="instrument-cell">
630
- <div class="instrument-indicator lead" id="lead-${i}"></div>
631
- </div>
632
- <div class="instrument-cell">
633
- <div class="instrument-indicator bass" id="bass-${i}"></div>
634
- </div>
635
- <div class="instrument-cell">
636
- <div class="instrument-indicator arpeggio" id="arp-${i}"></div>
637
- </div>
638
- <div class="instrument-cell">
639
- <div class="instrument-indicator drums" id="drums-${i}"></div>
640
- </div>
641
- <button class="track-toggle enabled" onclick="toggleTrack(${i})">ON</button>
642
- `;
643
-
644
- grid.appendChild(row);
645
- }
646
- }
647
-
648
- // Toggle track
649
- function toggleTrack(index) {
650
- tracks[index].enabled = !tracks[index].enabled;
651
- const btn = document.querySelector(`#track-${index} .track-toggle`);
652
- btn.classList.toggle('enabled');
653
- btn.textContent = tracks[index].enabled ? 'ON' : 'OFF';
654
- }
655
-
656
- // Toggle instrument
657
- function toggleInstrument(type) {
658
- instruments[type] = !instruments[type];
659
- const btn = document.getElementById(type === 'arpeggio' ? 'arpBtn' : type + 'Btn');
660
- btn.classList.toggle('active');
661
- }
662
-
663
- // Play sequence
664
- function playSequence() {
665
- const track = tracks[currentTrack];
666
- const row = document.getElementById(`track-${currentTrack}`);
667
-
668
- // Add playing animation
669
- document.querySelectorAll('.track-row').forEach(r => r.classList.remove('playing'));
670
- row.classList.add('playing');
671
-
672
- // Clear previous indicators
673
- document.querySelectorAll('.instrument-indicator').forEach(ind => ind.classList.remove('active'));
674
-
675
- // Play instruments for current beat
676
- if (track.enabled) {
677
- if (instruments.lead && track.lead[currentBeat]) {
678
- playNote(noteFrequencies[track.lead[currentBeat]], 'lead', 0.2);
679
- document.getElementById(`lead-${currentTrack}`).classList.add('active');
680
- }
681
-
682
- if (instruments.bass && track.bass[currentBeat]) {
683
- playNote(noteFrequencies[track.bass[currentBeat]], 'bass', 0.3);
684
- document.getElementById(`bass-${currentTrack}`).classList.add('active');
685
- }
686
-
687
- if (instruments.arpeggio && track.arpeggio[currentBeat]) {
688
- playNote(noteFrequencies[track.arpeggio[currentBeat]], 'arpeggio', 0.15);
689
- document.getElementById(`arp-${currentTrack}`).classList.add('active');
690
- }
691
-
692
- if (instruments.drums && track.drums[currentBeat]) {
693
- playNote(noteFrequencies[track.drums[currentBeat]], 'drums', 0.1);
694
- document.getElementById(`drums-${currentTrack}`).classList.add('active');
695
- }
696
- }
697
-
698
- // Update beat and track
699
- currentBeat++;
700
- if (currentBeat >= 16) {
701
- currentBeat = 0;
702
- currentTrack = (currentTrack + 1) % 10;
703
- }
704
-
705
- // Update display
706
- document.getElementById('currentPattern').textContent = currentTrack + 1;
707
- document.getElementById('currentBeat').textContent = Math.floor(currentBeat / 4) + 1;
708
- }
709
-
710
- // Toggle play
711
- function togglePlay() {
712
- if (!audioContext) {
713
- initAudio();
714
- }
715
-
716
- const btn = document.getElementById('playBtn');
717
-
718
- if (isPlaying) {
719
- isPlaying = false;
720
- clearInterval(intervalId);
721
- btn.textContent = '▶ PLAY';
722
- btn.classList.remove('active');
723
- document.querySelectorAll('.track-row').forEach(r => r.classList.remove('playing'));
724
- } else {
725
- isPlaying = true;
726
- const interval = 60000 / (bpm * 4); // 16th notes
727
- intervalId = setInterval(playSequence, interval);
728
- btn.textContent = '⏸ PAUSE';
729
- btn.classList.add('active');
730
-
731
- // Start visualizer
732
- if (!animationId) {
733
- visualize();
734
- }
735
- }
736
- }
737
-
738
- // Stop music
739
- function stopMusic() {
740
- isPlaying = false;
741
- clearInterval(intervalId);
742
- currentTrack = 0;
743
- currentBeat = 0;
744
- document.getElementById('playBtn').textContent = '▶ PLAY';
745
- document.getElementById('playBtn').classList.remove('active');
746
- document.querySelectorAll('.track-row').forEach(r => r.classList.remove('playing'));
747
- document.querySelectorAll('.instrument-indicator').forEach(ind => ind.classList.remove('active'));
748
- document.getElementById('currentPattern').textContent = '0';
749
- document.getElementById('currentBeat').textContent = '0';
750
- }
751
-
752
- // Update BPM
753
- function updateBPM(value) {
754
- bpm = parseInt(value);
755
- document.getElementById('bpmValue').textContent = bpm;
756
-
757
- if (isPlaying) {
758
- clearInterval(intervalId);
759
- const interval = 60000 / (bpm * 4);
760
- intervalId = setInterval(playSequence, interval);
761
- }
762
- }
763
-
764
- // Update volume
765
- function updateVolume(value) {
766
- masterVolume = value / 100;
767
- document.getElementById('volumeValue').textContent = value + '%';
768
- }
769
-
770
- // Randomize tracks
771
- function randomizeTracks() {
772
- for (let i = 0; i < 10; i++) {
773
- tracks[i].lead = generatePattern('lead');
774
- tracks[i].bass = generatePattern('bass');
775
- tracks[i].arpeggio = generatePattern('arpeggio');
776
- tracks[i].drums = generatePattern('drums');
777
- }
778
-
779
- // Flash animation
780
- const overlay = document.getElementById('loadingOverlay');
781
- overlay.classList.add('active');
782
- setTimeout(() => overlay.classList.remove('active'), 500);
783
- }
784
-
785
- // Visualizer
786
- function visualize() {
787
- const canvas = document.getElementById('visualizer');
788
- const ctx = canvas.getContext('2d');
789
- canvas.width = canvas.offsetWidth;
790
- canvas.height = canvas.offsetHeight;
791
-
792
- function draw() {
793
- animationId = requestAnimationFrame(draw);
794
-
795
- analyser.getByteFrequencyData(dataArray);
796
-
797
- ctx.fillStyle = 'rgba(10, 10, 15, 0.2)';
798
- ctx.fillRect(0, 0, canvas.width, canvas.height);
799
-
800
- const barWidth = (canvas.width / dataArray.length) * 2.5;
801
- let barHeight;
802
- let x = 0;
803
-
804
- for (let i = 0; i < dataArray.length; i++) {
805
- barHeight = (dataArray[i] / 255) * canvas.height;
806
-
807
- const gradient = ctx.createLinearGradient(0, canvas.height, 0, canvas.height - barHeight);
808
- gradient.addColorStop(0, '#352879');
809
- gradient.addColorStop(0.5, '#00a0a0');
810
- gradient.addColorStop(1, '#ffff00');
811
-
812
- ctx.fillStyle = gradient;
813
- ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
814
-
815
- x += barWidth + 1;
816
- }
817
- }
818
-
819
- draw();
820
- }
821
-
822
- // Initialize on load
823
- window.addEventListener('load', () => {
824
- initTracksGrid();
825
-
826
- // Set initial active states
827
- document.getElementById('leadBtn').classList.add('active');
828
- document.getElementById('bassBtn').classList.add('active');
829
- document.getElementById('arpBtn').classList.add('active');
830
- document.getElementById('drumBtn').classList.add('active');
831
-
832
- // Hide loading overlay
833
- setTimeout(() => {
834
- document.getElementById('loadingOverlay').classList.remove('active');
835
- }, 1000);
836
- });
837
-
838
- // Handle visibility change
839
- document.addEventListener('visibilitychange', () => {
840
- if (document.hidden && isPlaying) {
841
- togglePlay();
842
- }
843
- });
844
- </script>
845
- </body>
846
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
+
4
  <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>SID Chip Tune Studio</title>
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ :root {
16
+ --c64-blue: #352879;
17
+ --c64-lightblue: #6c5eb5;
18
+ --c64-cyan: #00a0a0;
19
+ --c64-purple: #a0a0ff;
20
+ --c64-pink: #ff00ff;
21
+ --c64-yellow: #ffff00;
22
+ --c64-orange: #ff7700;
23
+ --c64-green: #00ff00;
24
+ --c64-red: #ff0000;
25
+ --c64-white: #ffffff;
26
+ --c64-gray: #7869c4;
27
+ --bg-dark: #0a0a0f;
28
+ --bg-medium: #1a1a2e;
29
+ --bg-light: #16213e;
30
+ }
31
+
32
+ body {
33
+ font-family: 'Courier New', monospace;
34
+ background: linear-gradient(135deg, var(--bg-dark) 0%, var(--bg-medium) 100%);
35
+ color: var(--c64-white);
36
+ min-height: 100vh;
37
+ overflow-x: hidden;
38
+ position: relative;
39
+ }
40
+
41
+ body::before {
42
+ content: '';
43
+ position: fixed;
44
+ top: 0;
45
+ left: 0;
46
+ right: 0;
47
+ bottom: 0;
48
+ background:
49
+ repeating-linear-gradient(0deg,
50
+ transparent,
51
+ transparent 2px,
52
+ rgba(0, 160, 160, 0.03) 2px,
53
+ rgba(0, 160, 160, 0.03) 4px);
54
+ pointer-events: none;
55
+ z-index: 1;
56
+ }
57
+
58
+ .container {
59
+ max-width: 1400px;
60
+ margin: 0 auto;
61
+ padding: 20px;
62
+ position: relative;
63
+ z-index: 2;
64
+ }
65
+
66
+ header {
67
+ text-align: center;
68
+ padding: 30px 0;
69
+ background: linear-gradient(135deg, var(--c64-blue), var(--c64-lightblue));
70
+ border-radius: 15px;
71
+ margin-bottom: 30px;
72
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
73
+ position: relative;
74
+ overflow: hidden;
75
+ }
76
+
77
+ header::before {
78
+ content: '';
79
+ position: absolute;
80
+ top: -50%;
81
+ left: -50%;
82
+ width: 200%;
83
+ height: 200%;
84
+ background: repeating-linear-gradient(45deg,
85
+ transparent,
86
+ transparent 10px,
87
+ rgba(255, 255, 255, 0.05) 10px,
88
+ rgba(255, 255, 255, 0.05) 20px);
89
+ animation: slide 20s linear infinite;
90
+ }
91
+
92
+ @keyframes slide {
93
+ 0% {
94
+ transform: translate(0, 0);
95
+ }
96
+
97
+ 100% {
98
+ transform: translate(50px, 50px);
99
+ }
100
+ }
101
+
102
+ h1 {
103
+ font-size: 3em;
104
+ text-shadow: 3px 3px 0 var(--c64-purple),
105
+ 6px 6px 0 var(--c64-pink),
106
+ 9px 9px 20px rgba(0, 0, 0, 0.5);
107
+ position: relative;
108
+ z-index: 1;
109
+ letter-spacing: 5px;
110
+ margin-bottom: 10px;
111
+ }
112
+
113
+ .subtitle {
114
+ font-size: 1.2em;
115
+ color: var(--c64-yellow);
116
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
117
+ position: relative;
118
+ z-index: 1;
119
+ }
120
+
121
+ .credits {
122
+ margin-top: 15px;
123
+ font-size: 0.9em;
124
+ color: var(--c64-cyan);
125
+ position: relative;
126
+ z-index: 1;
127
+ }
128
+
129
+ .credits a {
130
+ color: var(--c64-yellow);
131
+ text-decoration: none;
132
+ transition: all 0.3s;
133
+ }
134
+
135
+ .credits a:hover {
136
+ color: var(--c64-orange);
137
+ text-shadow: 0 0 10px var(--c64-orange);
138
+ }
139
+
140
+ .controls {
141
+ display: grid;
142
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
143
+ gap: 20px;
144
+ margin-bottom: 30px;
145
+ }
146
+
147
+ .control-group {
148
+ background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
149
+ padding: 20px;
150
+ border-radius: 10px;
151
+ border: 2px solid var(--c64-cyan);
152
+ box-shadow: 0 5px 15px rgba(0, 160, 160, 0.3);
153
+ transition: transform 0.3s, box-shadow 0.3s;
154
+ }
155
+
156
+ .control-group:hover {
157
+ transform: translateY(-2px);
158
+ box-shadow: 0 8px 25px rgba(0, 160, 160, 0.5);
159
+ }
160
+
161
+ .control-group h3 {
162
+ color: var(--c64-cyan);
163
+ margin-bottom: 15px;
164
+ font-size: 1.2em;
165
+ text-transform: uppercase;
166
+ letter-spacing: 2px;
167
+ }
168
+
169
+ .btn {
170
+ background: linear-gradient(135deg, var(--c64-purple), var(--c64-pink));
171
+ color: var(--c64-white);
172
+ border: none;
173
+ padding: 12px 25px;
174
+ border-radius: 8px;
175
+ font-size: 1em;
176
+ font-weight: bold;
177
+ cursor: pointer;
178
+ transition: all 0.3s;
179
+ text-transform: uppercase;
180
+ letter-spacing: 1px;
181
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
182
+ margin: 5px;
183
+ }
184
+
185
+ .btn:hover {
186
+ transform: translateY(-2px);
187
+ box-shadow: 0 6px 20px rgba(255, 0, 255, 0.4);
188
+ background: linear-gradient(135deg, var(--c64-pink), var(--c64-purple));
189
+ }
190
+
191
+ .btn:active {
192
+ transform: translateY(0);
193
+ }
194
+
195
+ .btn.active {
196
+ background: linear-gradient(135deg, var(--c64-green), var(--c64-yellow));
197
+ box-shadow: 0 0 20px rgba(0, 255, 0, 0.5);
198
+ }
199
+
200
+ .slider-container {
201
+ margin: 10px 0;
202
+ }
203
+
204
+ .slider-label {
205
+ display: flex;
206
+ justify-content: space-between;
207
+ margin-bottom: 5px;
208
+ font-size: 0.9em;
209
+ color: var(--c64-yellow);
210
+ }
211
+
212
+ input[type="range"] {
213
+ width: 100%;
214
+ height: 8px;
215
+ background: linear-gradient(90deg, var(--c64-blue), var(--c64-cyan));
216
+ border-radius: 5px;
217
+ outline: none;
218
+ -webkit-appearance: none;
219
+ }
220
+
221
+ input[type="range"]::-webkit-slider-thumb {
222
+ -webkit-appearance: none;
223
+ width: 20px;
224
+ height: 20px;
225
+ background: var(--c64-yellow);
226
+ border-radius: 50%;
227
+ cursor: pointer;
228
+ box-shadow: 0 0 10px rgba(255, 255, 0, 0.5);
229
+ transition: all 0.3s;
230
+ }
231
+
232
+ input[type="range"]::-webkit-slider-thumb:hover {
233
+ background: var(--c64-orange);
234
+ box-shadow: 0 0 20px rgba(255, 119, 0, 0.8);
235
+ }
236
+
237
+ .tracks-container {
238
+ background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
239
+ border-radius: 15px;
240
+ padding: 20px;
241
+ border: 3px solid var(--c64-cyan);
242
+ box-shadow: 0 10px 30px rgba(0, 160, 160, 0.3);
243
+ }
244
+
245
+ .tracks-header {
246
+ display: grid;
247
+ grid-template-columns: 80px repeat(4, 1fr) 100px;
248
+ gap: 10px;
249
+ margin-bottom: 15px;
250
+ padding: 10px;
251
+ background: rgba(0, 0, 0, 0.3);
252
+ border-radius: 8px;
253
+ }
254
+
255
+ .header-cell {
256
+ color: var(--c64-yellow);
257
+ font-weight: bold;
258
+ text-align: center;
259
+ font-size: 0.9em;
260
+ text-transform: uppercase;
261
+ letter-spacing: 1px;
262
+ }
263
+
264
+ .track-row {
265
+ display: grid;
266
+ grid-template-columns: 80px repeat(4, 1fr) 100px;
267
+ gap: 10px;
268
+ margin-bottom: 10px;
269
+ padding: 10px;
270
+ background: rgba(0, 0, 0, 0.2);
271
+ border-radius: 8px;
272
+ transition: all 0.3s;
273
+ align-items: center;
274
+ }
275
+
276
+ .track-row:hover {
277
+ background: rgba(0, 160, 160, 0.1);
278
+ transform: translateX(5px);
279
+ }
280
+
281
+ .track-row.playing {
282
+ background: rgba(255, 255, 0, 0.1);
283
+ box-shadow: 0 0 15px rgba(255, 255, 0, 0.3);
284
+ animation: pulse 0.5s ease-in-out infinite alternate;
285
+ }
286
+
287
+ @keyframes pulse {
288
+ from {
289
+ opacity: 0.8;
290
+ }
291
+
292
+ to {
293
+ opacity: 1;
294
+ }
295
+ }
296
+
297
+ .track-number {
298
+ color: var(--c64-cyan);
299
+ font-weight: bold;
300
+ text-align: center;
301
+ font-size: 1.2em;
302
+ }
303
+
304
+ .instrument-cell {
305
+ display: flex;
306
+ align-items: center;
307
+ justify-content: center;
308
+ gap: 5px;
309
+ }
310
+
311
+ .instrument-indicator {
312
+ width: 12px;
313
+ height: 12px;
314
+ border-radius: 50%;
315
+ background: var(--c64-gray);
316
+ transition: all 0.3s;
317
+ }
318
+
319
+ .instrument-indicator.active {
320
+ box-shadow: 0 0 10px currentColor;
321
+ animation: blink 0.5s ease-in-out infinite;
322
+ }
323
+
324
+ .instrument-indicator.lead {
325
+ background: var(--c64-yellow);
326
+ }
327
+
328
+ .instrument-indicator.bass {
329
+ background: var(--c64-red);
330
+ }
331
+
332
+ .instrument-indicator.arpeggio {
333
+ background: var(--c64-green);
334
+ }
335
+
336
+ .instrument-indicator.drums {
337
+ background: var(--c64-purple);
338
+ }
339
+
340
+ @keyframes blink {
341
+
342
+ 0%,
343
+ 100% {
344
+ opacity: 1;
345
+ }
346
+
347
+ 50% {
348
+ opacity: 0.3;
349
+ }
350
+ }
351
+
352
+ .track-toggle {
353
+ background: var(--c64-blue);
354
+ color: var(--c64-white);
355
+ border: 2px solid var(--c64-cyan);
356
+ padding: 8px 15px;
357
+ border-radius: 5px;
358
+ cursor: pointer;
359
+ transition: all 0.3s;
360
+ font-size: 0.9em;
361
+ font-weight: bold;
362
+ }
363
+
364
+ .track-toggle:hover {
365
+ background: var(--c64-cyan);
366
+ transform: scale(1.05);
367
+ }
368
+
369
+ .track-toggle.enabled {
370
+ background: var(--c64-green);
371
+ border-color: var(--c64-yellow);
372
+ }
373
+
374
+ .visualizer {
375
+ margin-top: 30px;
376
+ padding: 20px;
377
+ background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
378
+ border-radius: 15px;
379
+ border: 2px solid var(--c64-cyan);
380
+ height: 200px;
381
+ position: relative;
382
+ overflow: hidden;
383
+ }
384
+
385
+ .visualizer canvas {
386
+ width: 100%;
387
+ height: 100%;
388
+ display: block;
389
+ }
390
+
391
+ .pattern-display {
392
+ position: absolute;
393
+ top: 10px;
394
+ right: 10px;
395
+ background: rgba(0, 0, 0, 0.7);
396
+ padding: 10px;
397
+ border-radius: 5px;
398
+ color: var(--c64-yellow);
399
+ font-size: 0.9em;
400
+ }
401
+
402
+ .pattern-selector {
403
+ background: linear-gradient(135deg, var(--bg-light), var(--bg-medium));
404
+ padding: 15px;
405
+ border-radius: 10px;
406
+ border: 2px solid var(--c64-cyan);
407
+ margin-bottom: 20px;
408
+ }
409
+
410
+ .pattern-selector h3 {
411
+ color: var(--c64-cyan);
412
+ margin-bottom: 10px;
413
+ font-size: 1.1em;
414
+ text-transform: uppercase;
415
+ letter-spacing: 2px;
416
+ }
417
+
418
+ .pattern-grid {
419
+ display: grid;
420
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
421
+ gap: 10px;
422
+ }
423
+
424
+ .pattern-btn {
425
+ background: linear-gradient(135deg, var(--c64-blue), var(--c64-purple));
426
+ color: var(--c64-white);
427
+ border: 2px solid var(--c64-cyan);
428
+ padding: 10px 15px;
429
+ border-radius: 8px;
430
+ cursor: pointer;
431
+ transition: all 0.3s;
432
+ font-size: 0.9em;
433
+ font-weight: bold;
434
+ text-align: center;
435
+ }
436
+
437
+ .pattern-btn:hover {
438
+ background: linear-gradient(135deg, var(--c64-cyan), var(--c64-blue));
439
+ transform: scale(1.05);
440
+ box-shadow: 0 5px 15px rgba(0, 160, 160, 0.4);
441
+ }
442
+
443
+ .pattern-btn.active {
444
+ background: linear-gradient(135deg, var(--c64-green), var(--c64-yellow));
445
+ border-color: var(--c64-yellow);
446
+ box-shadow: 0 0 20px rgba(0, 255, 0, 0.5);
447
+ }
448
+
449
+ @media (max-width: 768px) {
450
+ h1 {
451
+ font-size: 2em;
452
+ }
453
+
454
+ .tracks-header,
455
+ .track-row {
456
+ grid-template-columns: 60px repeat(4, 1fr) 80px;
457
+ font-size: 0.8em;
458
+ }
459
+
460
+ .controls {
461
+ grid-template-columns: 1fr;
462
+ }
463
+
464
+ .pattern-grid {
465
+ grid-template-columns: repeat(2, 1fr);
466
+ }
467
+ }
468
+
469
+ .loading-overlay {
470
+ position: fixed;
471
+ top: 0;
472
+ left: 0;
473
+ right: 0;
474
+ bottom: 0;
475
+ background: rgba(0, 0, 0, 0.9);
476
+ display: flex;
477
+ align-items: center;
478
+ justify-content: center;
479
+ z-index: 1000;
480
+ opacity: 0;
481
+ pointer-events: none;
482
+ transition: opacity 0.3s;
483
+ }
484
+
485
+ .loading-overlay.active {
486
+ opacity: 1;
487
+ pointer-events: all;
488
+ }
489
+
490
+ .loading-text {
491
+ color: var(--c64-cyan);
492
+ font-size: 2em;
493
+ animation: flash 0.5s ease-in-out infinite;
494
+ }
495
+
496
+ @keyframes flash {
497
+
498
+ 0%,
499
+ 100% {
500
+ opacity: 1;
501
+ }
502
+
503
+ 50% {
504
+ opacity: 0.5;
505
+ }
506
+ }
507
+
508
+ .info-panel {
509
+ background: rgba(0, 0, 0, 0.5);
510
+ padding: 10px;
511
+ border-radius: 8px;
512
+ margin-top: 10px;
513
+ font-size: 0.9em;
514
+ color: var(--c64-cyan);
515
+ border: 1px solid var(--c64-cyan);
516
+ }
517
+
518
+ .info-panel p {
519
+ margin: 5px 0;
520
+ }
521
+ </style>
522
  </head>
523
+
524
  <body>
525
+ <div class="loading-overlay" id="loadingOverlay">
526
+ <div class="loading-text">INITIALIZING SID CHIP...</div>
527
+ </div>
528
+
529
+ <div class="container">
530
+ <header>
531
+ <h1>🎵 SID CHIP TUNE STUDIO 🎵</h1>
532
+ <div class="subtitle">8-Bit Music Synthesizer with Pattern Library</div>
533
+ <div class="credits">
534
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
535
+ </div>
536
+ </header>
537
+
538
+ <div class="pattern-selector">
539
+ <h3>📚 Pattern Library</h3>
540
+ <div class="pattern-grid" id="patternGrid">
541
+ <button class="pattern-btn active" onclick="loadPattern('arcade')">🕹️ Arcade</button>
542
+ <button class="pattern-btn" onclick="loadPattern('demoscene')">🎨 Demoscene</button>
543
+ <button class="pattern-btn" onclick="loadPattern('techno')">🎛️ Techno</button>
544
+ <button class="pattern-btn" onclick="loadPattern('chiptune')">🎵 Chiptune</button>
545
+ <button class="pattern-btn" onclick="loadPattern('platformer')">🏃 Platformer</button>
546
+ <button class="pattern-btn" onclick="loadPattern('shooter')">🚀 Shooter</button>
547
+ <button class="pattern-btn" onclick="loadPattern('puzzle')">🧩 Puzzle</button>
548
+ <button class="pattern-btn" onclick="loadPattern('random')">🎲 Random</button>
549
+ </div>
550
+ <div class="info-panel">
551
+ <p>Current Pattern: <span id="currentPatternName" style="color: var(--c64-yellow);">Arcade</span></p>
552
+ <p id="patternDescription">Classic arcade game style with upbeat rhythms</p>
553
+ </div>
554
  </div>
555
 
556
+ <div class="controls">
557
+ <div class="control-group">
558
+ <h3>🎛️ Master Controls</h3>
559
+ <button class="btn" id="playBtn" onclick="togglePlay()">▶ PLAY</button>
560
+ <button class="btn" id="stopBtn" onclick="stopMusic()">⬛ STOP</button>
561
+ <button class="btn" id="randomBtn" onclick="randomizeTracks()">🎲 RANDOM</button>
562
+ </div>
563
+
564
+ <div class="control-group">
565
+ <h3>🎵 Tempo & Volume</h3>
566
+ <div class="slider-container">
567
+ <div class="slider-label">
568
+ <span>BPM</span>
569
+ <span id="bpmValue">120</span>
570
+ </div>
571
+ <input type="range" id="bpmSlider" min="60" max="200" value="120" oninput="updateBPM(this.value)">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
  </div>
573
+ <div class="slider-container">
574
+ <div class="slider-label">
575
+ <span>Volume</span>
576
+ <span id="volumeValue">70%</span>
577
+ </div>
578
+ <input type="range" id="volumeSlider" min="0" max="100" value="70" oninput="updateVolume(this.value)">
 
 
 
 
 
579
  </div>
580
+ </div>
581
+
582
+ <div class="control-group">
583
+ <h3>🎹 Instruments</h3>
584
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 5px;">
585
+ <button class="btn" id="leadBtn" onclick="toggleInstrument('lead')">LEAD</button>
586
+ <button class="btn" id="bassBtn" onclick="toggleInstrument('bass')">BASS</button>
587
+ <button class="btn" id="arpBtn" onclick="toggleInstrument('arpeggio')">ARP</button>
588
+ <button class="btn" id="drumBtn" onclick="toggleInstrument('drums')">DRUMS</button>
589
  </div>
590
+ </div>
591
  </div>
592
 
593
+ <div class="tracks-container">
594
+ <div class="tracks-header">
595
+ <div class="header-cell">TRACK</div>
596
+ <div class="header-cell">LEAD</div>
597
+ <div class="header-cell">BASS</div>
598
+ <div class="header-cell">ARPEGGIO</div>
599
+ <div class="header-cell">DRUMS</div>
600
+ <div class="header-cell">ENABLE</div>
601
+ </div>
602
+ <div id="tracksGrid"></div>
603
+ </div>
604
+
605
+ <div class="visualizer">
606
+ <canvas id="visualizer"></canvas>
607
+ <div class="pattern-display">
608
+ <div>Pattern: <span id="currentPattern">0</span>/10</div>
609
+ <div>Beat: <span id="currentBeat">0</span>/4</div>
610
+ </div>
611
+ </div>
612
+ </div>
613
+
614
+ <script>
615
+ // Audio Context and Global Variables
616
+ let audioContext;
617
+ let isPlaying = false;
618
+ let currentTrack = 0;
619
+ let currentBeat = 0;
620
+ let bpm = 120;
621
+ let masterVolume = 0.7;
622
+ let intervalId;
623
+ let analyser;
624
+ let dataArray;
625
+ let animationId;
626
+
627
+ // Instrument states
628
+ const instruments = {
629
+ lead: true,
630
+ bass: true,
631
+ arpeggio: true,
632
+ drums: true
633
+ };
634
+
635
+ // Note frequencies
636
+ const noteFrequencies = {
637
+ 'C1': 32.70, 'C#1': 34.65, 'D1': 36.71, 'D#1': 38.89, 'E1': 41.20, 'F1': 43.65, 'F#1': 46.25, 'G1': 49.00, 'G#1': 51.91, 'A1': 55.00, 'A#1': 58.27, 'B1': 61.74,
638
+ 'C2': 65.41, 'C#2': 69.30, 'D2': 73.42, 'D#2': 77.78, 'E2': 82.41, 'F2': 87.31, 'F#2': 92.50, 'G2': 98.00, 'G#2': 103.83, 'A2': 110.00, 'A#2': 116.54, 'B2': 123.47,
639
+ 'C3': 130.81, 'C#3': 138.59, 'D3': 146.83, 'D#3': 155.56, 'E3': 164.81, 'F3': 174.61, 'F#3': 185.00, 'G3': 196.00, 'G#3': 207.65, 'A3': 220.00, 'A#3': 233.08, 'B3': 246.94,
640
+ 'C4': 261.63, 'C#4': 277.18, 'D4': 293.66, 'D#4': 311.13, 'E4': 329.63, 'F4': 349.23, 'F#4': 369.99, 'G4': 392.00, 'G#4': 415.30, 'A4': 440.00, 'A#4': 466.16, 'B4': 493.88,
641
+ 'C5': 523.25, 'C#5': 554.37, 'D5': 587.33, 'D#5': 622.25, 'E5': 659.25, 'F5': 698.46, 'F#5': 739.99, 'G5': 783.99, 'G#5': 830.61, 'A5': 880.00, 'A#5': 932.33, 'B5': 987.77,
642
+ 'C6': 1046.50, 'D6': 1174.66, 'E6': 1318.51, 'G6': 1567.98
643
+ };
644
+
645
+ // Pattern Library
646
+ const patternLibrary = {
647
+ arcade: {
648
+ name: "Arcade",
649
+ description: "Classic arcade game style with upbeat rhythms",
650
+ tracks: [
651
+ {
652
+ lead: ['E4', null, 'G4', null, 'A4', null, 'C5', null, 'E5', null, 'C5', null, 'A4', null, 'G4', null],
653
+ bass: ['C2', null, 'C2', null, 'G2', null, 'G2', null, 'C3', null, 'C3', null, 'G2', null, 'G2', null],
654
+ arpeggio: ['C3', 'E3', 'G3', 'C4', 'E4', 'G4', 'C5', 'E5', null, null, null, null, null, null, null, null],
655
+ drums: ['C1', null, null, 'C#1', 'C1', null, 'D1', null, 'C1', null, null, 'C#1', 'C1', null, 'D1', null]
656
+ },
657
+ {
658
+ lead: ['G4', null, 'B4', null, 'D5', null, 'G5', null, 'B5', null, 'G5', null, 'D5', null, 'B4', null],
659
+ bass: ['G2', null, 'G2', null, 'D3', null, 'D3', null, 'G3', null, 'G3', null, 'D3', null, 'D3', null],
660
+ arpeggio: ['G3', 'B3', 'D4', 'G4', 'B4', 'D5', 'G5', 'B5', null, null, null, null, null, null, null, null],
661
+ drums: ['C1', null, 'C#1', null, 'C1', null, 'D1', null, 'C1', null, 'C#1', null, 'C1', null, 'D1', null]
662
+ },
663
+ {
664
+ lead: ['A4', null, 'C5', null, 'E5', null, 'A5', null, 'E5', null, 'C5', null, 'A4', null, 'E4', null],
665
+ bass: ['A2', null, 'A2', null, 'E3', null, 'E3', null, 'A3', null, 'A3', null, 'E3', null, 'E3', null],
666
+ arpeggio: ['A3', 'C4', 'E4', 'A4', 'C5', 'E5', 'A5', 'C6', null, null, null, null, null, null, null, null],
667
+ drums: ['D1', null, null, 'C#1', 'D1', null, 'C1', null, 'D1', null, null, 'C#1', 'D1', null, 'C1', null]
668
+ },
669
+ {
670
+ lead: ['F4', null, 'A4', null, 'C5', null, 'F5', null, 'A5', null, 'F5', null, 'C5', null, 'A4', null],
671
+ bass: ['F2', null, 'F2', null, 'C3', null, 'C3', null, 'F3', null, 'F3', null, 'C3', null, 'C3', null],
672
+ arpeggio: ['F3', 'A3', 'C4', 'F4', 'A4', 'C5', 'F5', 'A5', null, null, null, null, null, null, null, null],
673
+ drums: ['C1', 'C#1', null, null, 'C1', 'C#1', null, null, 'C1', 'C#1', null, null, 'C1', 'C#1', null, null]
674
+ },
675
+ {
676
+ lead: ['C5', null, 'E5', null, 'G5', null, 'C6', null, 'G5', null, 'E5', null, 'C5', null, 'G4', null],
677
+ bass: ['C3', null, 'C3', null, 'G3', null, 'G3', null, 'C4', null, 'C4', null, 'G3', null, 'G3', null],
678
+ arpeggio: ['C4', 'E4', 'G4', 'C5', 'E5', 'G5', 'C6', 'E6', null, null, null, null, null, null, null, null],
679
+ drums: ['C#1', null, 'D1', null, 'C#1', null, 'D1', null, 'C#1', null, 'D1', null, 'C#1', null, 'D1', null]
680
+ },
681
+ {
682
+ lead: ['D5', null, 'F5', null, 'A5', null, 'D6', null, 'A5', null, 'F5', null, 'D5', null, 'A4', null],
683
+ bass: ['D3', null, 'D3', null, 'A3', null, 'A3', null, 'D4', null, 'D4', null, 'A3', null, 'A3', null],
684
+ arpeggio: ['D4', 'F4', 'A4', 'D5', 'F5', 'A5', 'D6', 'F6', null, null, null, null, null, null, null, null],
685
+ drums: ['D1', 'C#1', 'C1', null, 'D1', 'C#1', 'C1', null, 'D1', 'C#1', 'C1', null, 'D1', 'C#1', 'C1', null]
686
+ },
687
+ {
688
+ lead: ['E5', null, 'G5', null, 'B5', null, 'E6', null, 'B5', null, 'G5', null, 'E5', null, 'B4', null],
689
+ bass: ['E3', null, 'E3', null, 'B3', null, 'B3', null, 'E4', null, 'E4', null, 'B3', null, 'B3', null],
690
+ arpeggio: ['E4', 'G4', 'B4', 'E5', 'G5', 'B5', 'E6', 'G6', null, null, null, null, null, null, null, null],
691
+ drums: ['C1', null, null, 'D1', 'C1', null, null, 'D1', 'C1', null, null, 'D1', 'C1', null, null, 'D1']
692
+ },
693
+ {
694
+ lead: ['G5', null, 'B5', null, 'D6', null, 'G6', null, 'D6', null, 'B5', null, 'G5', null, 'D5', null],
695
+ bass: ['G3', null, 'G3', null, 'D4', null, 'D4', null, 'G4', null, 'G4', null, 'D4', null, 'D4', null],
696
+ arpeggio: ['G4', 'B4', 'D5', 'G5', 'B5', 'D6', 'G6', 'B6', null, null, null, null, null, null, null, null],
697
+ drums: ['D1', null, 'C#1', null, 'D1', null, 'C#1', null, 'D1', null, 'C#1', null, 'D1', null, 'C#1', null]
698
+ },
699
+ {
700
+ lead: ['A5', null, 'C6', null, 'E6', null, 'A6', null, 'E6', null, 'C6', null, 'A5', null, 'E5', null],
701
+ bass: ['A3', null, 'A3', null, 'E4', null, 'E4', null, 'A4', null, 'A4', null, 'E4', null, 'E4', null],
702
+ arpeggio: ['A4', 'C5', 'E5', 'A5', 'C6', 'E6', 'A6', 'C7', null, null, null, null, null, null, null, null],
703
+ drums: ['C#1', 'D1', null, null, 'C#1', 'D1', null, null, 'C#1', 'D1', null, null, 'C#1', 'D1', null, null]
704
+ },
705
+ {
706
+ lead: ['F5', null, 'A5', null, 'C6', null, 'F6', null, 'C6', null, 'A5', null, 'F5', null, 'C5', null],
707
+ bass: ['F3', null, 'F3', null, 'C4', null, 'C4', null, 'F4', null, 'F4', null, 'C4', null, 'C4', null],
708
+ arpeggio: ['F4', 'A4', 'C5', 'F5', 'A5', 'C6', 'F6', 'A6', null, null, null, null, null, null, null, null],
709
+ drums: ['D1', null, 'C1', null, 'D1', null, 'C1', null, 'D1', null, 'C1', null, 'D1', null, 'C1', null]
710
+ }
711
+ ]
712
+ },
713
+ demoscene: {
714
+ name: "Demoscene",
715
+ description: "Complex demoscene style with fast arpeggios and effects",
716
+ tracks: [
717
+ {
718
+ lead: ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5', 'D5', 'E5', 'F5', 'G5', 'A5', 'B5', 'C6', 'D6'],
719
+ bass: ['C1', null, 'G1', null, 'C2', null, 'G2', null, 'C3', null, 'G3', null, 'C4', null, 'G4', null],
720
+ arpeggio: ['C2', 'E2', 'G2', 'C3', 'E3', 'G3', 'C4', 'E4', 'G4', 'C5', 'E5', 'G5', 'C6', 'E6', 'G6', 'C7'],
721
+ drums: ['C1', 'C#1', 'D1', 'C#1', 'C1', 'C#1', 'D1', 'C#1', 'C1', 'C#1', 'D1', 'C#1', 'C1', 'C#1', 'D1', 'C#1']
722
+ },
723
+ {
724
+ lead: ['D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5', 'D5', 'E5', 'F