namelessai commited on
Commit
759be12
·
verified ·
1 Parent(s): 6f818d7

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +374 -19
index.html CHANGED
@@ -1,19 +1,374 @@
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
+ <title>Modern Music Editor</title>
6
+ <script src="https://www.verovio.org/javascript/latest/verovio-toolkit.js"></script>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/midi.js/0.3.0/midi.min.js"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
9
+ <style>
10
+ :root {
11
+ --primary: #1a1a1a;
12
+ --secondary: #2d2d2d;
13
+ --accent: #00ffdd;
14
+ --text: #ffffff;
15
+ }
16
+
17
+ body {
18
+ margin: 0;
19
+ padding: 20px;
20
+ background-color: var(--primary);
21
+ color: var(--text);
22
+ font-family: 'Arial', sans-serif;
23
+ min-height: 100vh;
24
+ }
25
+
26
+ .toolbar {
27
+ background: var(--secondary);
28
+ padding: 15px;
29
+ border-radius: 10px;
30
+ margin-bottom: 20px;
31
+ display: flex;
32
+ gap: 15px;
33
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
34
+ flex-wrap: wrap;
35
+ }
36
+
37
+ button {
38
+ background: linear-gradient(145deg, var(--accent), #00ccbb);
39
+ color: var(--primary);
40
+ border: none;
41
+ padding: 10px 20px;
42
+ border-radius: 5px;
43
+ cursor: pointer;
44
+ transition: all 0.3s ease;
45
+ font-weight: bold;
46
+ min-width: 120px;
47
+ }
48
+
49
+ button:hover {
50
+ transform: translateY(-2px);
51
+ box-shadow: 0 2px 8px rgba(0, 255, 221, 0.4);
52
+ }
53
+
54
+ input[type="file"] {
55
+ display: none;
56
+ }
57
+
58
+ .editor-container {
59
+ background: var(--secondary);
60
+ border-radius: 10px;
61
+ padding: 20px;
62
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
63
+ overflow: auto;
64
+ margin-bottom: 20px;
65
+ }
66
+
67
+ #notation-container {
68
+ background: white;
69
+ border-radius: 5px;
70
+ min-height: 500px;
71
+ padding: 20px;
72
+ transition: transform 0.3s ease;
73
+ }
74
+
75
+ .status-bar {
76
+ padding: 10px;
77
+ background: var(--secondary);
78
+ border-radius: 5px;
79
+ color: var(--accent);
80
+ position: fixed;
81
+ bottom: 20px;
82
+ left: 20px;
83
+ right: 20px;
84
+ }
85
+
86
+ svg {
87
+ width: 100%;
88
+ height: auto;
89
+ }
90
+
91
+ .controls {
92
+ display: flex;
93
+ gap: 15px;
94
+ align-items: center;
95
+ margin-left: auto;
96
+ }
97
+
98
+ input[type="range"] {
99
+ width: 150px;
100
+ accent-color: var(--accent);
101
+ }
102
+ </style>
103
+ </head>
104
+ <body>
105
+ <div class="toolbar">
106
+ <button onclick="document.getElementById('fileInput').click()">📁 Open MusicXML</button>
107
+ <button onclick="document.getElementById('midiInput').click()">🎹 Import MIDI</button>
108
+ <div class="controls">
109
+ <button id="playButton" onclick="togglePlay()">▶ Play</button>
110
+ <button onclick="stopPlayback()">⏹ Stop</button>
111
+ <input type="range" id="zoom" min="10" max="200" value="100">
112
+ <span id="zoomValue">100%</span>
113
+ </div>
114
+ <input type="file" id="fileInput" accept=".xml,.musicxml">
115
+ <input type="file" id="midiInput" accept=".mid,.midi">
116
+ </div>
117
+
118
+ <div class="editor-container">
119
+ <div id="notation-container"></div>
120
+ </div>
121
+
122
+ <div class="status-bar" id="status">
123
+ Ready
124
+ </div>
125
+
126
+ <script>
127
+ const vrvToolkit = new verovio.toolkit();
128
+ let midiSequence = [];
129
+ let isPlaying = false;
130
+ let currentBPM = 120;
131
+
132
+ // Initialize Verovio
133
+ vrvToolkit.setOptions({
134
+ scale: 50,
135
+ pageMarginTop: 20,
136
+ pageMarginBottom: 20,
137
+ pageMarginLeft: 20,
138
+ pageMarginRight: 20,
139
+ spacingStaff: 1.2
140
+ });
141
+
142
+ // Initialize Tone.js
143
+ const synth = new Tone.PolySynth(Tone.Synth, {
144
+ oscillator: { type: 'sine' },
145
+ envelope: {
146
+ attack: 0.02,
147
+ decay: 0.1,
148
+ sustain: 0.3,
149
+ release: 0.4
150
+ }
151
+ }).toDestination();
152
+
153
+ // Setup Transport
154
+ Tone.Transport.bpm.value = currentBPM;
155
+
156
+ // File Handlers
157
+ document.getElementById('fileInput').addEventListener('change', function(e) {
158
+ const file = e.target.files[0];
159
+ if (file) handleMusicXML(file);
160
+ });
161
+
162
+ document.getElementById('midiInput').addEventListener('change', function(e) {
163
+ const file = e.target.files[0];
164
+ if (file) handleMIDI(file);
165
+ });
166
+
167
+ async function handleMusicXML(file) {
168
+ try {
169
+ const xmlData = await readFile(file);
170
+ vrvToolkit.loadData(xmlData);
171
+ renderNotation();
172
+ updateStatus(`Loaded: ${file.name}`);
173
+ } catch (error) {
174
+ updateStatus(`Error loading MusicXML: ${error.message}`, true);
175
+ }
176
+ }
177
+
178
+ async function handleMIDI(file) {
179
+ try {
180
+ const arrayBuffer = await readFile(file, 'arrayBuffer');
181
+ MIDI.parse(arrayBuffer, function(midi) {
182
+ midiSequence = processMIDI(midi);
183
+ updateStatus(`Imported MIDI: ${file.name}`);
184
+ convertMIDIToMusicXML(midi);
185
+ });
186
+ } catch (error) {
187
+ updateStatus(`Error loading MIDI: ${error.message}`, true);
188
+ }
189
+ }
190
+
191
+ function processMIDI(midiData) {
192
+ const tracks = [];
193
+ midiData.tracks.forEach(track => {
194
+ const notes = [];
195
+ let currentTime = 0;
196
+
197
+ track.forEach(event => {
198
+ currentTime += event.deltaTime;
199
+
200
+ if (event.type === "channel" && event.subtype === "noteOn") {
201
+ notes.push({
202
+ time: currentTime / midiData.header.ticksPerBeat,
203
+ note: Tone.Frequency(event.noteNumber, "midi").toNote(),
204
+ velocity: event.velocity / 127,
205
+ duration: (event.duration || 1) / midiData.header.ticksPerBeat
206
+ });
207
+ }
208
+ });
209
+
210
+ tracks.push(notes);
211
+ });
212
+ return tracks;
213
+ }
214
+
215
+ function convertMIDIToMusicXML(midiData) {
216
+ // Basic conversion logic (simplified)
217
+ let xml = `<?xml version="1.0" encoding="UTF-8"?>
218
+ <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 4.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
219
+ <score-partwise version="4.0">
220
+ <part-list>
221
+ <score-part id="P1">
222
+ <part-name>MIDI Import</part-name>
223
+ </score-part>
224
+ </part-list>
225
+ <part id="P1">
226
+ <measure number="1">
227
+ <attributes>
228
+ <divisions>${midiData.header.ticksPerBeat}</divisions>
229
+ <time>
230
+ <beats>4</beats>
231
+ <beat-type>4</beat-type>
232
+ </time>
233
+ <key>
234
+ <fifths>0</fifths>
235
+ </key>
236
+ <clef>
237
+ <sign>G</sign>
238
+ <line>2</line>
239
+ </clef>
240
+ </attributes>`;
241
+
242
+ midiData.tracks[0].forEach(event => {
243
+ if (event.type === "channel" && event.subtype === "noteOn") {
244
+ xml += `
245
+ <note>
246
+ <pitch>
247
+ <step>${Tone.Frequency(event.noteNumber, "midi").toNote().slice(0, -1)}</step>
248
+ <octave>${Tone.Frequency(event.noteNumber, "midi").toNote().slice(-1)}</octave>
249
+ </pitch>
250
+ <duration>${event.duration || 1}</duration>
251
+ <type>quarter</type>
252
+ </note>`;
253
+ }
254
+ });
255
+
256
+ xml += `
257
+ </measure>
258
+ </part>
259
+ </score-partwise>`;
260
+
261
+ vrvToolkit.loadData(xml);
262
+ renderNotation();
263
+ }
264
+
265
+ function togglePlay() {
266
+ if (!isPlaying) {
267
+ isPlaying = true;
268
+ document.getElementById('playButton').textContent = "⏸ Pause";
269
+
270
+ Tone.Transport.cancel();
271
+
272
+ midiSequence.forEach(track => {
273
+ track.forEach(({ time, note, velocity, duration }) => {
274
+ synth.triggerAttackRelease(
275
+ note,
276
+ duration,
277
+ `+${time}`,
278
+ velocity
279
+ );
280
+ });
281
+ });
282
+
283
+ Tone.Transport.start();
284
+ updateStatus("Playing...");
285
+ } else {
286
+ isPlaying = false;
287
+ document.getElementById('playButton').textContent = "▶ Play";
288
+ Tone.Transport.pause();
289
+ updateStatus("Paused");
290
+ }
291
+ }
292
+
293
+ function stopPlayback() {
294
+ isPlaying = false;
295
+ Tone.Transport.stop();
296
+ synth.releaseAll();
297
+ document.getElementById('playButton').textContent = "▶ Play";
298
+ updateStatus("Stopped");
299
+ }
300
+
301
+ function renderNotation() {
302
+ const svg = vrvToolkit.renderToSVG(1);
303
+ document.getElementById('notation-container').innerHTML = svg;
304
+ }
305
+
306
+ function updateStatus(message, isError = false) {
307
+ const statusBar = document.getElementById('status');
308
+ statusBar.textContent = message;
309
+ statusBar.style.color = isError ? '#ff4444' : var('--accent');
310
+ }
311
+
312
+ // Utility Functions
313
+ function readFile(file, readAs = 'text') {
314
+ return new Promise((resolve, reject) => {
315
+ const reader = new FileReader();
316
+ reader.onload = () => resolve(reader.result);
317
+ reader.onerror = () => reject(new Error('Error reading file'));
318
+
319
+ if (readAs === 'arrayBuffer') {
320
+ reader.readAsArrayBuffer(file);
321
+ } else {
322
+ reader.readAsText(file);
323
+ }
324
+ });
325
+ }
326
+
327
+ // Zoom Control
328
+ document.getElementById('zoom').addEventListener('input', function(e) {
329
+ const scaleValue = parseInt(e.target.value);
330
+ vrvToolkit.setOptions({ scale: scaleValue / 2 });
331
+ renderNotation();
332
+ document.getElementById('zoomValue').textContent = `${scaleValue}%`;
333
+ });
334
+
335
+ // Initial Sample Score
336
+ vrvToolkit.loadData(`<?xml version="1.0" encoding="UTF-8"?>
337
+ <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 4.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
338
+ <score-partwise>
339
+ <part-list>
340
+ <score-part id="P1">
341
+ <part-name>Sample</part-name>
342
+ </score-part>
343
+ </part-list>
344
+ <part id="P1">
345
+ <measure number="1">
346
+ <attributes>
347
+ <divisions>1</divisions>
348
+ <key>
349
+ <fifths>0</fifths>
350
+ </key>
351
+ <time>
352
+ <beats>4</beats>
353
+ <beat-type>4</beat-type>
354
+ </time>
355
+ <clef>
356
+ <sign>G</sign>
357
+ <line>2</line>
358
+ </clef>
359
+ </attributes>
360
+ <note>
361
+ <pitch>
362
+ <step>C</step>
363
+ <octave>4</octave>
364
+ </pitch>
365
+ <duration>1</duration>
366
+ <type>quarter</type>
367
+ </note>
368
+ </measure>
369
+ </part>
370
+ </score-partwise>`);
371
+ renderNotation();
372
+ </script>
373
+ </body>
374
+ </html>