FJFehr commited on
Commit
9c0f1ff
·
1 Parent(s): c427c8f

Changed visuals of the midi keyboard

Browse files
Files changed (4) hide show
  1. app.py +1 -1
  2. keyboard.html +10 -6
  3. static/keyboard.js +16 -5
  4. static/styles.css +198 -44
app.py CHANGED
@@ -134,7 +134,7 @@ keyboard_html = html_content.replace(
134
  iframe_html = (
135
  '<iframe srcdoc="'
136
  + html.escape(keyboard_html, quote=True)
137
- + '" style="width:100%;height:550px;border:0;"></iframe>'
138
  )
139
 
140
  # Create Gradio interface
 
134
  iframe_html = (
135
  '<iframe srcdoc="'
136
  + html.escape(keyboard_html, quote=True)
137
+ + '" style="width:100%;height:750px;border:0;"></iframe>'
138
  )
139
 
140
  # Create Gradio interface
keyboard.html CHANGED
@@ -7,11 +7,15 @@
7
  <link rel="stylesheet" href="/file=static/styles.css" />
8
  </head>
9
  <body>
10
- <h3>Virtual MIDI Keyboard (prototype)</h3>
 
 
 
 
11
 
12
  <div id="mainContainer">
13
- <!-- Left Panel: Keyboard and Controls -->
14
- <div id="leftPanel">
15
  <div id="keyboard"></div>
16
 
17
  <div class="controls">
@@ -40,10 +44,10 @@
40
  </div>
41
  </div>
42
 
43
- <!-- Right Panel: MIDI Monitor -->
44
- <div id="rightPanel">
45
  <div class="terminal-header">
46
- <h4 style="margin: 0;">MIDI Monitor</h4>
47
  <button id="clearTerminal">Clear</button>
48
  </div>
49
  <div id="terminal"></div>
 
7
  <link rel="stylesheet" href="/file=static/styles.css" />
8
  </head>
9
  <body>
10
+ <!-- Welcome Header -->
11
+ <div class="welcome-header">
12
+ <h1 class="neon-text">🎹 VIRTUAL MIDI KEYBOARD</h1>
13
+ <p class="subtitle">Play, record, and export your musical ideas • Two octaves • Multiple instruments • Real-time MIDI monitoring</p>
14
+ </div>
15
 
16
  <div id="mainContainer">
17
+ <!-- Keyboard Section -->
18
+ <div class="keyboard-section">
19
  <div id="keyboard"></div>
20
 
21
  <div class="controls">
 
44
  </div>
45
  </div>
46
 
47
+ <!-- MIDI Monitor Section -->
48
+ <div class="monitor-section">
49
  <div class="terminal-header">
50
+ <h4>MIDI MONITOR</h4>
51
  <button id="clearTerminal">Clear</button>
52
  </div>
53
  <div id="terminal"></div>
static/keyboard.js CHANGED
@@ -182,8 +182,11 @@ function logToTerminal(message, className = '') {
182
  }
183
 
184
  function initTerminal() {
185
- logToTerminal('=== MIDI Monitor Ready ===', 'timestamp');
186
- logToTerminal('Play notes to see MIDI events...', 'timestamp');
 
 
 
187
  }
188
 
189
  // =============================================================================
@@ -198,7 +201,9 @@ function beginRecord() {
198
  recordBtn.disabled = true;
199
  stopBtn.disabled = false;
200
  saveBtn.disabled = true;
201
- logToTerminal('\n=== RECORDING STARTED ===', 'timestamp');
 
 
202
  }
203
 
204
  function stopRecord() {
@@ -207,7 +212,9 @@ function stopRecord() {
207
  recordBtn.disabled = false;
208
  stopBtn.disabled = true;
209
  saveBtn.disabled = events.length === 0;
210
- logToTerminal(`=== RECORDING STOPPED (${events.length} events) ===\n`, 'timestamp');
 
 
211
  }
212
 
213
  // =============================================================================
@@ -428,7 +435,11 @@ keyboardToggle.addEventListener('change', () => {
428
 
429
  clearTerminal.addEventListener('click', () => {
430
  terminal.innerHTML = '';
431
- logToTerminal('=== MIDI Monitor Ready ===', 'timestamp');
 
 
 
 
432
  });
433
 
434
  recordBtn.addEventListener('click', async () => {
 
182
  }
183
 
184
  function initTerminal() {
185
+ logToTerminal('╔═══════════════════════════════════════════════════════╗', 'timestamp');
186
+ logToTerminal('║ 🎹 MIDI MONITOR INITIALIZED 🎹 ║', 'timestamp');
187
+ logToTerminal('╚═══════════════════════════════════════════════════════╝', 'timestamp');
188
+ logToTerminal('Ready to capture MIDI events...', 'timestamp');
189
+ logToTerminal('', '');
190
  }
191
 
192
  // =============================================================================
 
201
  recordBtn.disabled = true;
202
  stopBtn.disabled = false;
203
  saveBtn.disabled = true;
204
+ logToTerminal('', '');
205
+ logToTerminal('▶▶▶ RECORDING STARTED ◀◀◀', 'timestamp');
206
+ logToTerminal('', '');
207
  }
208
 
209
  function stopRecord() {
 
212
  recordBtn.disabled = false;
213
  stopBtn.disabled = true;
214
  saveBtn.disabled = events.length === 0;
215
+ logToTerminal('', '');
216
+ logToTerminal(`■■■ RECORDING STOPPED (${events.length} events captured) ■■■`, 'timestamp');
217
+ logToTerminal('', '');
218
  }
219
 
220
  // =============================================================================
 
435
 
436
  clearTerminal.addEventListener('click', () => {
437
  terminal.innerHTML = '';
438
+ logToTerminal('╔═══════════════════════════════════════════════════════╗', 'timestamp');
439
+ logToTerminal('║ 🎹 MIDI MONITOR INITIALIZED 🎹 ║', 'timestamp');
440
+ logToTerminal('╚═══════════════════════════════════════════════════════╝', 'timestamp');
441
+ logToTerminal('Ready to capture MIDI events...', 'timestamp');
442
+ logToTerminal('', '');
443
  });
444
 
445
  recordBtn.addEventListener('click', async () => {
static/styles.css CHANGED
@@ -1,113 +1,267 @@
1
- /* Virtual MIDI Keyboard - Styles */
2
 
3
  /* Layout */
4
  body {
5
- font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
6
- padding: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  }
8
 
9
  #mainContainer {
10
- display: flex;
11
- gap: 20px;
 
 
 
 
 
12
  }
13
 
14
- #leftPanel {
15
- flex: 0 0 auto;
 
 
 
 
16
  }
17
 
18
- #rightPanel {
19
- flex: 1;
20
- min-width: 300px;
21
  }
22
 
23
  /* Keyboard */
24
  #keyboard {
25
  display: flex;
26
- user-select: none;
 
 
 
 
 
 
 
27
  }
28
 
29
  .key {
30
  width: 42px;
31
  height: 180px;
32
- border: 1px solid #333;
33
  margin: 0 1px;
34
- background: white;
35
  position: relative;
36
  display: flex;
37
  align-items: flex-end;
38
  justify-content: center;
39
- cursor: pointer;
 
 
 
 
 
 
 
 
 
 
40
  }
41
 
42
  .key.black {
43
  width: 30px;
44
  height: 110px;
45
- background: #222;
46
- color: white;
 
47
  margin-left: -15px;
48
  margin-right: -15px;
49
  z-index: 2;
50
- position: relative;
 
 
 
 
 
 
 
 
 
51
  }
52
 
53
  /* Controls */
54
  .controls {
55
- margin-top: 10px;
56
  display: flex;
57
- gap: 8px;
58
  align-items: center;
59
- flex-wrap: wrap;
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
 
 
62
  button {
63
- padding: 8px 12px;
 
 
 
 
 
 
 
 
 
64
  }
65
 
66
- #status {
67
- margin-left: 8px;
68
- color: #666;
 
 
 
 
 
 
 
 
 
69
  }
70
 
71
- #downloadLink {
72
- display: inline-block;
73
- margin-left: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
 
76
  /* MIDI Terminal */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  #terminal {
78
- background: #1e1e1e;
79
  color: #00ff00;
80
  font-family: 'Courier New', monospace;
81
- font-size: 12px;
82
- padding: 12px;
83
- height: 400px;
84
  overflow-y: auto;
85
- border: 1px solid #333;
86
- border-radius: 4px;
 
87
  white-space: pre-wrap;
88
  word-wrap: break-word;
 
 
 
89
  }
90
 
91
  #terminal .note-on {
92
- color: #00ff00;
 
93
  }
94
 
95
  #terminal .note-off {
96
- color: #888;
 
97
  }
98
 
99
  #terminal .timestamp {
100
- color: #448;
 
101
  }
102
 
103
- .terminal-header {
104
- display: flex;
105
- justify-content: space-between;
106
- align-items: center;
107
- margin-bottom: 8px;
108
  }
109
 
110
- .terminal-header button {
111
- padding: 4px 8px;
112
- font-size: 11px;
 
 
 
 
 
 
 
 
113
  }
 
1
+ /* Virtual MIDI Keyboard - Retro Synth Theme */
2
 
3
  /* Layout */
4
  body {
5
+ font-family: 'Courier New', 'Consolas', monospace;
6
+ padding: 0;
7
+ margin: 0;
8
+ background: linear-gradient(180deg, #0a0a0f 0%, #1a0a1f 100%);
9
+ color: #e0e0ff;
10
+ min-height: 100vh;
11
+ }
12
+
13
+ /* Welcome Header */
14
+ .welcome-header {
15
+ text-align: center;
16
+ padding: 30px 20px 20px;
17
+ background: linear-gradient(180deg, rgba(138, 43, 226, 0.1) 0%, transparent 100%);
18
+ border-bottom: 2px solid rgba(138, 43, 226, 0.3);
19
+ }
20
+
21
+ .neon-text {
22
+ font-size: 2.5em;
23
+ font-weight: bold;
24
+ margin: 0 0 10px;
25
+ color: #ff00ff;
26
+ text-shadow:
27
+ 0 0 10px #ff00ff,
28
+ 0 0 20px #ff00ff,
29
+ 0 0 30px #ff00ff,
30
+ 0 0 40px #8b00ff,
31
+ 0 0 70px #8b00ff;
32
+ letter-spacing: 2px;
33
+ }
34
+
35
+ .subtitle {
36
+ font-size: 1em;
37
+ color: #00ffff;
38
+ margin: 0;
39
+ text-shadow: 0 0 5px #00ffff;
40
+ opacity: 0.9;
41
  }
42
 
43
  #mainContainer {
44
+ display: flex;
45
+ flex-direction: column;
46
+ align-items: center;
47
+ gap: 30px;
48
+ padding: 20px;
49
+ max-width: 1400px;
50
+ margin: 0 auto;
51
  }
52
 
53
+ .keyboard-section {
54
+ width: 100%;
55
+ display: flex;
56
+ flex-direction: column;
57
+ align-items: center;
58
+ gap: 15px;
59
  }
60
 
61
+ .monitor-section {
62
+ width: 100%;
63
+ max-width: 1200px;
64
  }
65
 
66
  /* Keyboard */
67
  #keyboard {
68
  display: flex;
69
+ user-select: none;
70
+ padding: 20px;
71
+ background: rgba(0, 0, 0, 0.4);
72
+ border-radius: 15px;
73
+ border: 2px solid rgba(138, 43, 226, 0.5);
74
+ box-shadow:
75
+ 0 0 20px rgba(138, 43, 226, 0.3),
76
+ inset 0 0 30px rgba(0, 0, 0, 0.5);
77
  }
78
 
79
  .key {
80
  width: 42px;
81
  height: 180px;
82
+ border: 2px solid #ff00ff;
83
  margin: 0 1px;
84
+ background: linear-gradient(180deg, #fff 0%, #f0f0ff 100%);
85
  position: relative;
86
  display: flex;
87
  align-items: flex-end;
88
  justify-content: center;
89
+ cursor: pointer;
90
+ transition: all 0.1s ease;
91
+ box-shadow:
92
+ 0 4px 8px rgba(0, 0, 0, 0.3),
93
+ inset 0 -2px 5px rgba(0, 0, 0, 0.1);
94
+ }
95
+
96
+ .key:hover {
97
+ box-shadow:
98
+ 0 0 15px rgba(255, 0, 255, 0.5),
99
+ inset 0 -2px 5px rgba(0, 0, 0, 0.1);
100
  }
101
 
102
  .key.black {
103
  width: 30px;
104
  height: 110px;
105
+ background: linear-gradient(180deg, #1a0a2e 0%, #0a0a1f 100%);
106
+ border: 2px solid #8b00ff;
107
+ color: #00ffff;
108
  margin-left: -15px;
109
  margin-right: -15px;
110
  z-index: 2;
111
+ position: relative;
112
+ box-shadow:
113
+ 0 4px 8px rgba(0, 0, 0, 0.5),
114
+ inset 0 -2px 5px rgba(138, 43, 226, 0.3);
115
+ }
116
+
117
+ .key.black:hover {
118
+ box-shadow:
119
+ 0 0 15px rgba(0, 255, 255, 0.5),
120
+ inset 0 -2px 5px rgba(138, 43, 226, 0.3);
121
  }
122
 
123
  /* Controls */
124
  .controls {
 
125
  display: flex;
126
+ gap: 10px;
127
  align-items: center;
128
+ flex-wrap: wrap;
129
+ justify-content: center;
130
+ padding: 15px;
131
+ background: rgba(0, 0, 0, 0.3);
132
+ border-radius: 10px;
133
+ border: 1px solid rgba(138, 43, 226, 0.3);
134
+ }
135
+
136
+ .controls label {
137
+ color: #00ffff;
138
+ font-weight: bold;
139
+ display: flex;
140
+ align-items: center;
141
+ gap: 5px;
142
  }
143
 
144
+ select,
145
  button {
146
+ padding: 8px 16px;
147
+ background: linear-gradient(180deg, #8b00ff 0%, #5a00cc 100%);
148
+ color: #00ffff;
149
+ border: 2px solid #ff00ff;
150
+ border-radius: 5px;
151
+ font-family: 'Courier New', monospace;
152
+ font-weight: bold;
153
+ cursor: pointer;
154
+ transition: all 0.2s ease;
155
+ box-shadow: 0 0 10px rgba(138, 43, 226, 0.3);
156
  }
157
 
158
+ select:hover,
159
+ button:hover:not(:disabled) {
160
+ background: linear-gradient(180deg, #a000ff 0%, #7000ee 100%);
161
+ box-shadow:
162
+ 0 0 20px rgba(255, 0, 255, 0.6),
163
+ 0 0 30px rgba(138, 43, 226, 0.4);
164
+ transform: translateY(-1px);
165
+ }
166
+
167
+ button:active:not(:disabled) {
168
+ transform: translateY(0);
169
+ box-shadow: 0 0 10px rgba(138, 43, 226, 0.3);
170
  }
171
 
172
+ button:disabled {
173
+ opacity: 0.3;
174
+ cursor: not-allowed;
175
+ }
176
+
177
+ input[type="checkbox"] {
178
+ cursor: pointer;
179
+ width: 18px;
180
+ height: 18px;
181
+ accent-color: #ff00ff;
182
+ }
183
+
184
+ #status {
185
+ color: #00ff00;
186
+ font-weight: bold;
187
+ text-shadow: 0 0 5px #00ff00;
188
+ padding: 5px 10px;
189
+ background: rgba(0, 0, 0, 0.5);
190
+ border-radius: 5px;
191
  }
192
 
193
  /* MIDI Terminal */
194
+ .terminal-header {
195
+ display: flex;
196
+ justify-content: space-between;
197
+ align-items: center;
198
+ padding: 10px 15px;
199
+ background: linear-gradient(90deg, rgba(138, 43, 226, 0.2) 0%, rgba(0, 255, 255, 0.1) 100%);
200
+ border: 2px solid rgba(138, 43, 226, 0.5);
201
+ border-bottom: none;
202
+ border-radius: 10px 10px 0 0;
203
+ }
204
+
205
+ .terminal-header h4 {
206
+ margin: 0;
207
+ color: #ff00ff;
208
+ font-size: 1.1em;
209
+ letter-spacing: 2px;
210
+ text-shadow: 0 0 10px #ff00ff;
211
+ }
212
+
213
+ .terminal-header button {
214
+ padding: 6px 12px;
215
+ font-size: 0.85em;
216
+ }
217
+
218
  #terminal {
219
+ background: #0a0a0f;
220
  color: #00ff00;
221
  font-family: 'Courier New', monospace;
222
+ font-size: 13px;
223
+ padding: 15px;
224
+ height: 250px;
225
  overflow-y: auto;
226
+ border: 2px solid rgba(138, 43, 226, 0.5);
227
+ border-top: 1px solid rgba(138, 43, 226, 0.3);
228
+ border-radius: 0 0 10px 10px;
229
  white-space: pre-wrap;
230
  word-wrap: break-word;
231
+ box-shadow:
232
+ inset 0 0 30px rgba(0, 0, 0, 0.8),
233
+ 0 0 20px rgba(138, 43, 226, 0.2);
234
  }
235
 
236
  #terminal .note-on {
237
+ color: #00ff00;
238
+ text-shadow: 0 0 5px #00ff00;
239
  }
240
 
241
  #terminal .note-off {
242
+ color: #ff00ff;
243
+ text-shadow: 0 0 5px #ff00ff;
244
  }
245
 
246
  #terminal .timestamp {
247
+ color: #00ffff;
248
+ text-shadow: 0 0 3px #00ffff;
249
  }
250
 
251
+ /* Scrollbar styling */
252
+ #terminal::-webkit-scrollbar {
253
+ width: 10px;
 
 
254
  }
255
 
256
+ #terminal::-webkit-scrollbar-track {
257
+ background: rgba(0, 0, 0, 0.5);
258
+ }
259
+
260
+ #terminal::-webkit-scrollbar-thumb {
261
+ background: linear-gradient(180deg, #ff00ff 0%, #8b00ff 100%);
262
+ border-radius: 5px;
263
+ }
264
+
265
+ #terminal::-webkit-scrollbar-thumb:hover {
266
+ background: linear-gradient(180deg, #ff33ff 0%, #aa00ff 100%);
267
  }