SREAL commited on
Commit
ef82ce6
·
verified ·
1 Parent(s): abbc701

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +657 -19
index.html CHANGED
@@ -1,19 +1,657 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Advanced MIDI Melody Generator</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
8
+ <style>
9
+ :root {
10
+ --primary: #2c3e50;
11
+ --secondary: #3498db;
12
+ --accent: #e74c3c;
13
+ --background: #f5f6fa;
14
+ --surface: #ffffff;
15
+ }
16
+
17
+ * {
18
+ margin: 0;
19
+ padding: 0;
20
+ box-sizing: border-box;
21
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
22
+ }
23
+
24
+ body {
25
+ background: var(--background);
26
+ color: var(--primary);
27
+ min-height: 100vh;
28
+ padding: 2rem;
29
+ }
30
+
31
+ .container {
32
+ max-width: 1400px;
33
+ margin: 0 auto;
34
+ background: var(--surface);
35
+ border-radius: 16px;
36
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
37
+ padding: 2rem;
38
+ }
39
+
40
+ .workspace {
41
+ display: grid;
42
+ grid-template-columns: 350px 1fr;
43
+ gap: 2rem;
44
+ }
45
+
46
+ .panel {
47
+ background: #f8f9fa;
48
+ border-radius: 12px;
49
+ padding: 1.5rem;
50
+ height: fit-content;
51
+ }
52
+
53
+ .section {
54
+ margin-bottom: 2rem;
55
+ }
56
+
57
+ h2, h3 {
58
+ margin-bottom: 1rem;
59
+ color: var(--primary);
60
+ }
61
+
62
+ .control {
63
+ margin-bottom: 1rem;
64
+ }
65
+
66
+ label {
67
+ display: block;
68
+ margin-bottom: 0.5rem;
69
+ font-size: 0.9rem;
70
+ color: #666;
71
+ }
72
+
73
+ select, input[type="range"], input[type="number"] {
74
+ width: 100%;
75
+ padding: 0.5rem;
76
+ border: 1px solid #ddd;
77
+ border-radius: 6px;
78
+ background: white;
79
+ }
80
+
81
+ input[type="range"] {
82
+ -webkit-appearance: none;
83
+ height: 8px;
84
+ background: #ddd;
85
+ }
86
+
87
+ input[type="range"]::-webkit-slider-thumb {
88
+ -webkit-appearance: none;
89
+ width: 16px;
90
+ height: 16px;
91
+ background: var(--secondary);
92
+ border-radius: 50%;
93
+ cursor: pointer;
94
+ }
95
+
96
+ .editor {
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: 1rem;
100
+ }
101
+
102
+ .piano-roll {
103
+ background: #1a1a1a;
104
+ border-radius: 12px;
105
+ height: 500px;
106
+ position: relative;
107
+ overflow: hidden;
108
+ transform: scaleY(-1);
109
+ }
110
+
111
+ .grid {
112
+ position: absolute;
113
+ inset: 0;
114
+ display: grid;
115
+ grid-template-columns: repeat(32, 1fr);
116
+ grid-template-rows: repeat(88, 1fr);
117
+ gap: 1px;
118
+ padding: 1px;
119
+ background: #2a2a2a;
120
+ }
121
+
122
+ .cell {
123
+ background: #333;
124
+ cursor: pointer;
125
+ transition: all 0.1s ease;
126
+ }
127
+
128
+ .cell.white-key {
129
+ background: #444;
130
+ }
131
+
132
+ .cell.black-key {
133
+ background: #222;
134
+ }
135
+
136
+ .cell:hover {
137
+ background: #555;
138
+ }
139
+
140
+ .cell.active {
141
+ background: var(--secondary);
142
+ }
143
+
144
+ .transport {
145
+ display: flex;
146
+ gap: 1rem;
147
+ padding: 1rem;
148
+ background: #f8f9fa;
149
+ border-radius: 12px;
150
+ }
151
+
152
+ button {
153
+ padding: 0.8rem 1.5rem;
154
+ border: none;
155
+ border-radius: 6px;
156
+ font-weight: 600;
157
+ cursor: pointer;
158
+ transition: all 0.2s;
159
+ color: white;
160
+ }
161
+
162
+ .btn-primary { background: var(--primary); }
163
+ .btn-secondary { background: var(--secondary); }
164
+ .btn-accent { background: var(--accent); }
165
+
166
+ button:hover {
167
+ opacity: 0.9;
168
+ transform: translateY(-1px);
169
+ }
170
+
171
+ .synth-controls {
172
+ display: grid;
173
+ grid-template-columns: repeat(2, 1fr);
174
+ gap: 1rem;
175
+ margin-bottom: 1rem;
176
+ }
177
+
178
+ .wave-selector {
179
+ display: flex;
180
+ gap: 0.5rem;
181
+ flex-wrap: wrap;
182
+ }
183
+
184
+ .wave-btn {
185
+ padding: 0.5rem 1rem;
186
+ background: white;
187
+ border: 1px solid #ddd;
188
+ border-radius: 20px;
189
+ color: #666;
190
+ cursor: pointer;
191
+ font-size: 0.9rem;
192
+ }
193
+
194
+ .wave-btn.active {
195
+ background: var(--secondary);
196
+ color: white;
197
+ border-color: var(--secondary);
198
+ }
199
+
200
+ .chord-progression {
201
+ display: grid;
202
+ grid-template-columns: repeat(4, 1fr);
203
+ gap: 0.5rem;
204
+ margin-top: 1rem;
205
+ }
206
+
207
+ .chord-slot {
208
+ padding: 0.5rem;
209
+ text-align: center;
210
+ background: white;
211
+ border: 1px solid #ddd;
212
+ border-radius: 6px;
213
+ font-size: 0.9rem;
214
+ }
215
+
216
+ </style>
217
+ </head>
218
+ <body>
219
+ <div class="container">
220
+ <div class="workspace">
221
+ <div class="panel">
222
+ <div class="section">
223
+ <h3>Sound Design</h3>
224
+ <div class="wave-selector">
225
+ <div class="wave-btn active" data-wave="sine">Sine</div>
226
+ <div class="wave-btn" data-wave="square">Square</div>
227
+ <div class="wave-btn" data-wave="sawtooth">Saw</div>
228
+ <div class="wave-btn" data-wave="triangle">Triangle</div>
229
+ </div>
230
+
231
+ <div class="control">
232
+ <label>Filter Cutoff</label>
233
+ <input type="range" id="filterCutoff" min="20" max="20000" value="2000">
234
+ </div>
235
+
236
+ <div class="control">
237
+ <label>Resonance</label>
238
+ <input type="range" id="filterResonance" min="0" max="20" value="1">
239
+ </div>
240
+ </div>
241
+
242
+ <div class="section">
243
+ <h3>Music Theory</h3>
244
+ <div class="control">
245
+ <label>Key</label>
246
+ <select id="key">
247
+ <option value="C">C</option>
248
+ <option value="C#">C#/Db</option>
249
+ <option value="D">D</option>
250
+ <option value="D#">D#/Eb</option>
251
+ <option value="E">E</option>
252
+ <option value="F">F</option>
253
+ <option value="F#">F#/Gb</option>
254
+ <option value="G">G</option>
255
+ <option value="G#">G#/Ab</option>
256
+ <option value="A">A</option>
257
+ <option value="A#">A#/Bb</option>
258
+ <option value="B">B</option>
259
+ </select>
260
+ </div>
261
+
262
+ <div class="control">
263
+ <label>Mode/Scale</label>
264
+ <select id="scale">
265
+ <option value="major">Major</option>
266
+ <option value="minor">Natural Minor</option>
267
+ <option value="harmonicMinor">Harmonic Minor</option>
268
+ <option value="melodicMinor">Melodic Minor</option>
269
+ <option value="dorian">Dorian</option>
270
+ <option value="phrygian">Phrygian</option>
271
+ <option value="lydian">Lydian</option>
272
+ <option value="mixolydian">Mixolydian</option>
273
+ <option value="locrian">Locrian</option>
274
+ </select>
275
+ </div>
276
+
277
+ <div class="control">
278
+ <label>Chord Progression</label>
279
+ <select id="chordProgression">
280
+ <option value="I-IV-V-I">I-IV-V-I (Pop)</option>
281
+ <option value="ii-V-I">ii-V-I (Jazz)</option>
282
+ <option value="I-vi-IV-V">I-vi-IV-V (50s)</option>
283
+ <option value="I-V-vi-IV">I-V-vi-IV (Pop)</option>
284
+ <option value="vi-IV-I-V">vi-IV-I-V (Pop)</option>
285
+ </select>
286
+ <div class="chord-progression" id="progressionDisplay">
287
+ <div class="chord-slot">I</div>
288
+ <div class="chord-slot">IV</div>
289
+ <div class="chord-slot">V</div>
290
+ <div class="chord-slot">I</div>
291
+ </div>
292
+ </div>
293
+ </div>
294
+
295
+ <div class="section">
296
+ <h3>Rhythm</h3>
297
+ <div class="control">
298
+ <label>Tempo: <span id="tempo-value">120</span> BPM</label>
299
+ <input type="range" id="tempo" min="60" max="200" value="120">
300
+ </div>
301
+
302
+ <div class="control">
303
+ <label>Time Signature</label>
304
+ <select id="timeSignature">
305
+ <option value="4/4">4/4</option>
306
+ <option value="3/4">3/4</option>
307
+ <option value="6/8">6/8</option>
308
+ <option value="5/4">5/4</option>
309
+ </select>
310
+ </div>
311
+
312
+ <div class="control">
313
+ <label>Swing</label>
314
+ <input type="range" id="swing" min="0" max="100" value="0">
315
+ </div>
316
+ </div>
317
+
318
+ <div class="section">
319
+ <h3>Generation</h3>
320
+ <div class="control">
321
+ <label>Complexity: <span id="complexity-value">5</span></label>
322
+ <input type="range" id="complexity" min="1" max="10" value="5">
323
+ </div>
324
+
325
+ <div class="control">
326
+ <label>Base Octave: <span id="octave-value">4</span></label>
327
+ <input type="range" id="octave" min="2" max="6" value="4">
328
+ </div>
329
+
330
+ <div class="control">
331
+ <label>Melodic Direction</label>
332
+ <select id="direction">
333
+ <option value="ascending">Ascending</option>
334
+ <option value="descending">Descending</option>
335
+ <option value="mixed">Mixed</option>
336
+ </select>
337
+ </div>
338
+ </div>
339
+ </div>
340
+
341
+ <div class="editor">
342
+ <div class="piano-roll">
343
+ <div class="grid" id="grid"></div>
344
+ </div>
345
+
346
+ <div class="transport">
347
+ <button class="btn-primary" id="generate">Generate</button>
348
+ <button class="btn-secondary" id="play">Play</button>
349
+ <button class="btn-secondary" id="stop">Stop</button>
350
+ <button class="btn-accent" id="clear">Clear</button>
351
+ <button class="btn-accent" id="download">Download MIDI</button>
352
+ </div>
353
+ </div>
354
+ </div>
355
+ </div>
356
+
357
+ <script>
358
+ class AdvancedMelodyGenerator {
359
+ constructor() {
360
+ // Initialize Tone.js components
361
+ this.filter = new Tone.Filter({
362
+ type: "lowpass",
363
+ frequency: 2000,
364
+ Q: 1
365
+ }).toDestination();
366
+
367
+ this.synth = new Tone.PolySynth(Tone.Synth, {
368
+ oscillator: {
369
+ type: "sine"
370
+ },
371
+ envelope: {
372
+ attack: 0.05,
373
+ decay: 0.2,
374
+ sustain: 0.2,
375
+ release: 0.5
376
+ }
377
+ }).connect(this.filter);
378
+
379
+ this.sequence = [];
380
+ this.isPlaying = false;
381
+ this.currentPart = null;
382
+ this.initUI();
383
+ this.setupEventListeners();
384
+ }
385
+
386
+ initUI() {
387
+ const grid = document.getElementById('grid');
388
+ const notes = this.getAllNotes();
389
+
390
+ for (let i = 0; i < 88; i++) {
391
+ for (let j = 0; j < 32; j++) {
392
+ const cell = document.createElement('div');
393
+ cell.className = 'cell';
394
+ const noteName = notes[i].replace(/[0-9]/, '');
395
+ cell.classList.add(noteName.includes('#') ? 'black-key' : 'white-key');
396
+ cell.dataset.note = notes[i];
397
+ cell.dataset.time = j;
398
+ cell.onclick = () => this.toggleCell(cell);
399
+ grid.appendChild(cell);
400
+ }
401
+ }
402
+
403
+ document.querySelectorAll('input[type="range"]').forEach(input => {
404
+ const display = document.getElementById(`${input.id}-value`);
405
+ if (display) display.textContent = input.value;
406
+ });
407
+ }
408
+
409
+ getAllNotes() {
410
+ const notes = [];
411
+ const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
412
+ for (let octave = 0; octave < 8; octave++) {
413
+ noteNames.forEach(note => {
414
+ notes.push(`${note}${octave}`);
415
+ });
416
+ }
417
+ return notes;
418
+ }
419
+
420
+ setupEventListeners() {
421
+ document.getElementById('generate').onclick = () => this.generateMelody();
422
+ document.getElementById('play').onclick = () => this.togglePlay();
423
+ document.getElementById('stop').onclick = () => this.stop();
424
+ document.getElementById('clear').onclick = () => this.clearGrid();
425
+ document.getElementById('download').onclick = () => this.downloadMIDI();
426
+
427
+ document.querySelectorAll('.wave-btn').forEach(btn => {
428
+ btn.onclick = (e) => {
429
+ document.querySelectorAll('.wave-btn').forEach(b => b.classList.remove('active'));
430
+ e.target.classList.add('active');
431
+ this.updateSynthSettings('oscillator', { type: e.target.dataset.wave });
432
+ };
433
+ });
434
+
435
+ document.getElementById('filterCutoff').oninput = (e) => {
436
+ this.filter.frequency.value = e.target.value;
437
+ };
438
+
439
+ document.getElementById('filterResonance').oninput = (e) => {
440
+ this.filter.Q.value = e.target.value;
441
+ };
442
+
443
+ document.getElementById('chordProgression').onchange = (e) => {
444
+ this.updateChordDisplay(e.target.value);
445
+ };
446
+ }
447
+
448
+ updateChordDisplay(progression) {
449
+ const chords = progression.split('-');
450
+ const display = document.getElementById('progressionDisplay');
451
+ display.innerHTML = '';
452
+ chords.forEach(chord => {
453
+ const slot = document.createElement('div');
454
+ slot.className = 'chord-slot';
455
+ slot.textContent = chord;
456
+ display.appendChild(slot);
457
+ });
458
+ }
459
+
460
+ updateSynthSettings(param, value) {
461
+ this.synth.set({
462
+ [param]: value
463
+ });
464
+ }
465
+
466
+ getChordProgression(key, type) {
467
+ const progressions = {
468
+ 'I-IV-V-I': ['I', 'IV', 'V', 'I'],
469
+ 'ii-V-I': ['ii', 'V', 'I'],
470
+ 'I-vi-IV-V': ['I', 'vi', 'IV', 'V'],
471
+ 'I-V-vi-IV': ['I', 'V', 'vi', 'IV'],
472
+ 'vi-IV-I-V': ['vi', 'IV', 'I', 'V']
473
+ };
474
+
475
+ const chordMap = {
476
+ 'I': this.getChord(key, 1),
477
+ 'ii': this.getChord(key, 2),
478
+ 'iii': this.getChord(key, 3),
479
+ 'IV': this.getChord(key, 4),
480
+ 'V': this.getChord(key, 5),
481
+ 'vi': this.getChord(key, 6),
482
+ 'vii': this.getChord(key, 7)
483
+ };
484
+
485
+ return progressions[type].map(chord => chordMap[chord]);
486
+ }
487
+
488
+ getChord(root, degree) {
489
+ const scale = this.getScaleNotes(root, document.getElementById('scale').value);
490
+ const chordTones = [0, 2, 4].map(interval => scale[(degree - 1 + interval) % 7]);
491
+ return chordTones;
492
+ }
493
+
494
+ generateMelody() {
495
+ this.stop();
496
+ this.clearGrid();
497
+
498
+ const key = document.getElementById('key').value;
499
+ const scale = document.getElementById('scale').value;
500
+ const complexity = parseInt(document.getElementById('complexity').value);
501
+ const baseOctave = parseInt(document.getElementById('octave').value);
502
+ const progression = document.getElementById('chordProgression').value;
503
+
504
+ const chords = this.getChordProgression(key, progression);
505
+ this.sequence = this.createMelodySequence(key, scale, complexity, baseOctave, chords);
506
+ this.visualizeSequence();
507
+ }
508
+
509
+ createMelodySequence(key, scale, complexity, baseOctave, chords) {
510
+ const sequence = [];
511
+ const scaleNotes = this.getScaleNotes(key, scale);
512
+ const noteCount = Math.floor(complexity * 4);
513
+ const direction = document.getElementById('direction').value;
514
+
515
+ let previousNote = null;
516
+ for (let i = 0; i < noteCount; i++) {
517
+ const time = Math.floor(i * (32 / noteCount));
518
+ let note;
519
+
520
+ if (direction === 'ascending') {
521
+ note = scaleNotes[i % scaleNotes.length];
522
+ } else if (direction === 'descending') {
523
+ note = scaleNotes[scaleNotes.length - 1 - (i % scaleNotes.length)];
524
+ } else {
525
+ if (previousNote) {
526
+ const currentIndex = scaleNotes.indexOf(previousNote.replace(/[0-9]/, ''));
527
+ const step = Math.floor(Math.random() * 3) - 1; // -1, 0, or 1
528
+ const newIndex = Math.min(Math.max(0, currentIndex + step), scaleNotes.length - 1);
529
+ note = scaleNotes[newIndex];
530
+ } else {
531
+ note = scaleNotes[Math.floor(Math.random() * scaleNotes.length)];
532
+ }
533
+ }
534
+
535
+ const octaveOffset = Math.floor(Math.random() * 2);
536
+ const fullNote = `${note}${baseOctave + octaveOffset}`;
537
+ previousNote = fullNote;
538
+
539
+ sequence.push({
540
+ note: fullNote,
541
+ time: time,
542
+ duration: 0.25
543
+ });
544
+ }
545
+
546
+ return sequence;
547
+ }
548
+
549
+ visualizeSequence() {
550
+ this.sequence.forEach(note => {
551
+ const noteIndex = this.getNoteIndex(note.note);
552
+ const cell = document.querySelector(
553
+ `.cell[data-note="${note.note}"][data-time="${note.time}"]`
554
+ );
555
+ if (cell) cell.classList.add('active');
556
+ });
557
+ }
558
+
559
+ getNoteIndex(note) {
560
+ const notes = this.getAllNotes();
561
+ return notes.indexOf(note);
562
+ }
563
+
564
+ togglePlay() {
565
+ if (this.isPlaying) {
566
+ this.stop();
567
+ } else {
568
+ Tone.start().then(() => this.play());
569
+ }
570
+ }
571
+
572
+ play() {
573
+ this.isPlaying = true;
574
+ Tone.Transport.bpm.value = document.getElementById('tempo').value;
575
+
576
+ if (this.currentPart) {
577
+ this.currentPart.dispose();
578
+ }
579
+
580
+ this.currentPart = new Tone.Part(((time, note) => {
581
+ this.synth.triggerAttackRelease(note.note, note.duration, time);
582
+ }), this.sequence.map(note => ({
583
+ time: note.time * 0.25,
584
+ note: note.note,
585
+ duration: note.duration
586
+ }))).start(0);
587
+
588
+ Tone.Transport.start();
589
+ }
590
+
591
+ stop() {
592
+ this.isPlaying = false;
593
+ if (this.currentPart) {
594
+ this.currentPart.dispose();
595
+ }
596
+ Tone.Transport.stop();
597
+ }
598
+
599
+ toggleCell(cell) {
600
+ cell.classList.toggle('active');
601
+ // Update sequence based on UI state
602
+ const activeNotes = Array.from(document.querySelectorAll('.cell.active')).map(cell => ({
603
+ note: cell.dataset.note,
604
+ time: parseInt(cell.dataset.time),
605
+ duration: 0.25
606
+ }));
607
+ this.sequence = activeNotes;
608
+ }
609
+
610
+ clearGrid() {
611
+ document.querySelectorAll('.cell').forEach(cell => {
612
+ cell.classList.remove('active');
613
+ });
614
+ this.sequence = [];
615
+ }
616
+
617
+ getScaleNotes(key, scale) {
618
+ const notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
619
+ const scales = {
620
+ major: [0, 2, 4, 5, 7, 9, 11],
621
+ minor: [0, 2, 3, 5, 7, 8, 10],
622
+ harmonicMinor: [0, 2, 3, 5, 7, 8, 11],
623
+ melodicMinor: [0, 2, 3, 5, 7, 9, 11],
624
+ dorian: [0, 2, 3, 5, 7, 9, 10],
625
+ phrygian: [0, 1, 3, 5, 7, 8, 10],
626
+ lydian: [0, 2, 4, 6, 7, 9, 11],
627
+ mixolydian: [0, 2, 4, 5, 7, 9, 10],
628
+ locrian: [0, 1, 3, 5, 6, 8, 10]
629
+ };
630
+
631
+ const keyIndex = notes.indexOf(key);
632
+ return scales[scale].map(interval => notes[(keyIndex + interval) % 12]);
633
+ }
634
+
635
+ downloadMIDI() {
636
+ const midiData = [
637
+ 0x4D, 0x54, 0x68, 0x64,
638
+ 0x00, 0x00, 0x00, 0x06,
639
+ 0x00, 0x01,
640
+ 0x00, 0x01,
641
+ 0x01, 0x80
642
+ ];
643
+
644
+ const blob = new Blob([new Uint8Array(midiData)], { type: 'audio/midi' });
645
+ const url = window.URL.createObjectURL(blob);
646
+ const a = document.createElement('a');
647
+ a.href = url;
648
+ a.download = 'melody.mid';
649
+ a.click();
650
+ window.URL.revokeObjectURL(url);
651
+ }
652
+ }
653
+
654
+ const generator = new AdvancedMelodyGenerator();
655
+ </script>
656
+ </body>
657
+ </html>