baouws commited on
Commit
f2a5f6c
ยท
verified ยท
1 Parent(s): 0add303

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +548 -0
app.py ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import re
4
+ import random
5
+ from typing import Dict, List, Tuple
6
+
7
+ # Music generation logic
8
+ class StrudelGenerator:
9
+ def __init__(self):
10
+ self.instrument_patterns = {
11
+ 'drums': {
12
+ 'kick': '"bd*4"',
13
+ 'snare': '"~ sd ~ sd"',
14
+ 'hihat': '"hh*8"',
15
+ 'techno_kick': '"bd*4"',
16
+ 'house_kick': '"bd ~ ~ ~ bd ~ ~ ~"',
17
+ 'breakbeat': '"bd ~ sd ~ bd sd ~ sd"',
18
+ 'trap': '"bd ~ ~ bd ~ sd ~ ~"',
19
+ 'dnb': '"bd ~ ~ ~ sd ~ bd sd"'
20
+ },
21
+ 'bass': {
22
+ 'basic': '"c2 [~ c2] f2 [~ f2]"',
23
+ 'funk': '"c2 ~ c2 ~ f2 ~ f2 ~"',
24
+ 'walking': '"c2 e2 g2 c3 f2 a2 c3 f3".slow(2)',
25
+ 'techno': '"c2*4"',
26
+ 'wobble': '"c2 c2 f2 f2".sound("sawtooth").lpf(sine.range(200,800))',
27
+ 'deep': '"c1 ~ f1 ~ g1 ~ c1 ~".slow(2)'
28
+ },
29
+ 'chords': {
30
+ 'jazz': '"<c\'maj7 f\'maj7 g\'7 c\'maj7>".voicing()',
31
+ 'basic': '"<C^7 F^7 G^7 C^7>".voicing()',
32
+ 'ambient': '"<c\'maj e\'min f\'maj g\'maj>".voicing()',
33
+ 'emotional': '"<c\'min f\'maj g\'maj a\'min>".voicing()',
34
+ 'uplifting': '"<C^7 F^7 Am7 G^7>".voicing()'
35
+ },
36
+ 'melody': {
37
+ 'basic': '"c5 d5 e5 f5 g5 a5 b5 c6".slow(2)',
38
+ 'ambient': '"c5 d5 e5 f5 g5 a5 b5 c6".slow(4)',
39
+ 'fast': '"c5 d5 e5 f5 g5 a5 b5 c6"',
40
+ 'anime': '"c5 e5 g5 c6 b5 g5 e5 c5".slow(1.5)',
41
+ 'chiptune': '"c6 d6 e6 f6 g6 a6 b6 c7"'
42
+ },
43
+ 'arpeggios': {
44
+ 'basic': '"c4 e4 g4 c5".fast(2)',
45
+ 'dreamy': '"c4 e4 g4 b4 c5 b4 g4 e4".slow(2)',
46
+ 'energetic': '"c4 e4 g4 c5".fast(4)'
47
+ }
48
+ }
49
+
50
+ self.style_effects = {
51
+ 'lofi': ['.room(0.7)', '.lpf(2000)', '.hpf(100)', '.gain(0.6)'],
52
+ 'techno': ['.room(0.2)', '.lpf(sine.range(400,2000))', '.distort(0.1)'],
53
+ 'house': ['.room(0.4)', '.lpf(3000)', '.compress(0.8)'],
54
+ 'ambient': ['.room(0.9)', '.size(0.8)', '.lpf(1000)', '.gain(0.4)'],
55
+ 'jazz': ['.room(0.6)', '.lpf(4000)', '.compress(0.6)'],
56
+ 'cyberpunk': ['.room(0.3)', '.distort(0.2)', '.lpf(sine.range(300,1500))'],
57
+ 'anime': ['.room(0.5)', '.lpf(3500)', '.delay(0.125)', '.gain(0.7)'],
58
+ 'chiptune': ['.room(0.1)', '.lpf(8000)', '.bitcrush(8)', '.gain(0.8)']
59
+ }
60
+
61
+ def analyze_description(self, description: str) -> Dict[str, List[str]]:
62
+ """Enhanced analysis with anime and electronic music focus"""
63
+ desc = description.lower()
64
+ elements = {
65
+ 'drums': [],
66
+ 'bass': [],
67
+ 'chords': [],
68
+ 'melody': [],
69
+ 'arpeggios': [],
70
+ 'style': [],
71
+ 'mood': []
72
+ }
73
+
74
+ # Enhanced drum detection
75
+ drum_keywords = {
76
+ 'kick': ['kick', 'bass drum', 'bd'],
77
+ 'snare': ['snare', 'sd', 'clap'],
78
+ 'hihat': ['hi-hat', 'hihat', 'hh', 'cymbal'],
79
+ 'trap': ['trap', '808'],
80
+ 'dnb': ['drum and bass', 'dnb', 'breakbeat'],
81
+ 'techno_kick': ['techno', 'four on the floor'],
82
+ 'house_kick': ['house']
83
+ }
84
+
85
+ for pattern, keywords in drum_keywords.items():
86
+ if any(keyword in desc for keyword in keywords):
87
+ elements['drums'].append(pattern)
88
+
89
+ if 'drum' in desc and not elements['drums']:
90
+ elements['drums'].extend(['kick', 'snare', 'hihat'])
91
+
92
+ # Enhanced bass detection
93
+ bass_keywords = {
94
+ 'wobble': ['wobble', 'dubstep', 'bass drop'],
95
+ 'deep': ['deep bass', 'sub bass'],
96
+ 'funk': ['funk', 'slap bass'],
97
+ 'walking': ['walking bass', 'jazz bass'],
98
+ 'techno': ['techno bass', 'driving bass']
99
+ }
100
+
101
+ for pattern, keywords in bass_keywords.items():
102
+ if any(keyword in desc for keyword in keywords):
103
+ elements['bass'].append(pattern)
104
+
105
+ if 'bass' in desc and not elements['bass']:
106
+ elements['bass'].append('basic')
107
+
108
+ # Enhanced harmony detection
109
+ chord_keywords = {
110
+ 'emotional': ['emotional', 'sad', 'melancholic', 'dramatic'],
111
+ 'uplifting': ['uplifting', 'happy', 'energetic', 'positive'],
112
+ 'jazz': ['jazz', 'sophisticated', 'complex'],
113
+ 'ambient': ['ambient', 'atmospheric', 'spacey']
114
+ }
115
+
116
+ for pattern, keywords in chord_keywords.items():
117
+ if any(keyword in desc for keyword in keywords):
118
+ elements['chords'].append(pattern)
119
+
120
+ if any(word in desc for word in ['chord', 'harmony', 'piano']) and not elements['chords']:
121
+ elements['chords'].append('basic')
122
+
123
+ # Enhanced melody detection
124
+ melody_keywords = {
125
+ 'anime': ['anime', 'japanese', 'kawaii', 'manga'],
126
+ 'chiptu ne': ['8-bit', 'chiptune', 'retro', 'game'],
127
+ 'ambient': ['ethereal', 'floating', 'dreamy'],
128
+ 'fast': ['fast', 'rapid', 'quick', 'energetic']
129
+ }
130
+
131
+ for pattern, keywords in melody_keywords.items():
132
+ if any(keyword in desc for keyword in keywords):
133
+ elements['melody'].append(pattern)
134
+
135
+ if any(word in desc for word in ['melody', 'lead', 'tune']) and not elements['melody']:
136
+ elements['melody'].append('basic')
137
+
138
+ # Arpeggio detection
139
+ if any(word in desc for word in ['arpeggio', 'arpeggiated', 'broken chord']):
140
+ if 'dreamy' in desc or 'floating' in desc:
141
+ elements['arpeggios'].append('dreamy')
142
+ elif 'energetic' in desc or 'fast' in desc:
143
+ elements['arpeggios'].append('energetic')
144
+ else:
145
+ elements['arpeggios'].append('basic')
146
+
147
+ # Style detection
148
+ styles = ['lofi', 'techno', 'house', 'ambient', 'jazz', 'cyberpunk', 'anime', 'chiptune', 'trap', 'dubstep']
149
+ for style in styles:
150
+ if style in desc:
151
+ elements['style'].append(style)
152
+
153
+ return elements
154
+
155
+ def generate_code(self, description: str, tempo: int = 120, style: str = None) -> Tuple[str, str]:
156
+ """Generate Strudel code and return code + analysis"""
157
+ elements = self.analyze_description(description)
158
+
159
+ # Use provided style or detected style
160
+ if style and style.lower() != 'auto-detect':
161
+ main_style = style.lower()
162
+ elif elements['style']:
163
+ main_style = elements['style'][0]
164
+ else:
165
+ main_style = 'basic'
166
+
167
+ patterns = []
168
+ analysis_parts = []
169
+
170
+ # Build patterns based on analysis
171
+ for category in ['drums', 'bass', 'chords', 'melody', 'arpeggios']:
172
+ for element in elements[category]:
173
+ if category in self.instrument_patterns and element in self.instrument_patterns[category]:
174
+ pattern = self.instrument_patterns[category][element]
175
+
176
+ # Add appropriate sound and effects
177
+ if category == 'bass':
178
+ pattern += '.sound("sawtooth").lpf(800)'
179
+ analysis_parts.append(f"๐ŸŽธ Bass: {element}")
180
+ elif category == 'chords':
181
+ pattern += '.sound("piano")'
182
+ analysis_parts.append(f"๐ŸŽน Chords: {element}")
183
+ elif category == 'melody':
184
+ pattern += '.sound("sine").lpf(2000)'
185
+ analysis_parts.append(f"๐ŸŽต Melody: {element}")
186
+ elif category == 'arpeggios':
187
+ pattern += '.sound("triangle").lpf(3000)'
188
+ analysis_parts.append(f"๐ŸŒธ Arpeggios: {element}")
189
+ elif category == 'drums':
190
+ analysis_parts.append(f"๐Ÿฅ Drums: {element}")
191
+
192
+ # Add gain
193
+ if category == 'drums':
194
+ pattern += '.gain(0.7)'
195
+ else:
196
+ pattern += '.gain(0.4)'
197
+
198
+ patterns.append(pattern)
199
+
200
+ # If no patterns generated, create default
201
+ if not patterns:
202
+ patterns = [
203
+ '"bd ~ sd ~".gain(0.7)',
204
+ '"<C^7 F^7 G^7 C^7>".voicing().sound("piano").gain(0.4)'
205
+ ]
206
+ analysis_parts = ["๐Ÿฅ Basic drums", "๐ŸŽน Simple chords"]
207
+
208
+ # Build final code
209
+ code_lines = [
210
+ f'// ๐ŸŽต Generated from: "{description}"',
211
+ f'// ๐ŸŽญ Style: {style or main_style}, โฑ๏ธ Tempo: {tempo} BPM',
212
+ f'// ๐ŸŽจ Elements: {", ".join(analysis_parts)}',
213
+ '',
214
+ ]
215
+
216
+ if len(patterns) == 1:
217
+ code_lines.append(patterns[0])
218
+ else:
219
+ code_lines.append('stack(')
220
+ for i, pattern in enumerate(patterns):
221
+ comma = ',' if i < len(patterns) - 1 else ''
222
+ code_lines.append(f' {pattern}{comma}')
223
+ code_lines.append(')')
224
+
225
+ code_lines.append(f'.cpm({tempo})')
226
+
227
+ # Add style-specific effects
228
+ if main_style in self.style_effects:
229
+ effects = self.style_effects[main_style]
230
+ for effect in effects[:2]: # Limit effects to avoid overload
231
+ code_lines.append(effect)
232
+
233
+ analysis = f"**Detected Elements:** {', '.join(analysis_parts)}\n**Style:** {main_style}"
234
+
235
+ return '\n'.join(code_lines), analysis
236
+
237
+ def add_variation(self, code: str) -> str:
238
+ """Add random variations to existing code"""
239
+ if not code.strip():
240
+ return code
241
+
242
+ variations = [
243
+ ".sometimes(x=>x.rev())",
244
+ ".every(4, x=>x.fast(2))",
245
+ ".rarely(x=>x.gain(0.1))",
246
+ ".jux(x=>x.rev())",
247
+ ".every(8, x=>x.slow(2))",
248
+ ".sometimes(x=>x.ply(2))",
249
+ ".degradeBy(0.1)",
250
+ ".when(rand.range(0,1) > 0.7, x=>x.lpf(500))"
251
+ ]
252
+
253
+ variation = random.choice(variations)
254
+ return code + variation
255
+
256
+ # Initialize generator
257
+ generator = StrudelGenerator()
258
+
259
+ # Example descriptions with anime themes
260
+ examples = {
261
+ "๐ŸŒธ Kawaii Lofi": "Soft kawaii lofi with gentle piano chords, mellow drums, and a dreamy floating melody",
262
+ "โšก Cyberpunk Action": "High energy cyberpunk techno with driving bass, glitchy effects, and dramatic synths",
263
+ "๐ŸŽฎ 8-bit Adventure": "Retro chiptune with bouncy 8-bit melody, simple drums, and nostalgic video game vibes",
264
+ "๐ŸŒ™ Anime Ballad": "Emotional anime ballad with beautiful piano, soft strings, and a soaring melody",
265
+ "๐Ÿ”ฅ Epic Battle": "Intense battle music with powerful drums, dramatic chords, and heroic melody",
266
+ "๐Ÿ’ซ Future Bass Drop": "Melodic future bass with emotional buildup, punchy drums, and ethereal pads",
267
+ "๐ŸŒŠ Peaceful Ambient": "Tranquil ambient soundscape with gentle pads, soft percussion, and floating tones",
268
+ "๐ŸŽช Funky Anime OP": "Upbeat anime opening with funky bass, energetic drums, and catchy melody"
269
+ }
270
+
271
+ def generate_music(description, tempo, style):
272
+ """Main generation function"""
273
+ if not description.strip():
274
+ return "", "Please describe your music first! ๐ŸŽต", ""
275
+
276
+ try:
277
+ code, analysis = generator.generate_code(description, tempo, style)
278
+ success_msg = "๐ŸŽ‰ Music code generated successfully! Copy it to use in Strudel."
279
+ return code, success_msg, analysis
280
+ except Exception as e:
281
+ error_msg = f"โŒ Error generating music: {str(e)}"
282
+ return "", error_msg, ""
283
+
284
+ def add_magic(code):
285
+ """Add variations to existing code"""
286
+ if not code.strip():
287
+ return code, "Generate some code first! ๐ŸŽผ"
288
+
289
+ try:
290
+ new_code = generator.add_variation(code)
291
+ return new_code, "โœจ Added magical variation!"
292
+ except Exception as e:
293
+ return code, f"โŒ Error adding variation: {str(e)}"
294
+
295
+ def load_example(example_key):
296
+ """Load example description"""
297
+ return examples.get(example_key, "")
298
+
299
+ # Custom CSS for anime theme
300
+ anime_css = """
301
+ <style>
302
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
303
+
304
+ :root {
305
+ --primary-pink: #FF6B9D;
306
+ --primary-purple: #A855F7;
307
+ --primary-blue: #3B82F6;
308
+ --accent-cyan: #06B6D4;
309
+ --accent-yellow: #FCD34D;
310
+ --dark-bg: #1A1B2E;
311
+ --darker-bg: #16213E;
312
+ --card-bg: rgba(255, 255, 255, 0.1);
313
+ --text-light: #E2E8F0;
314
+ }
315
+
316
+ .gradio-container {
317
+ font-family: 'Poppins', sans-serif !important;
318
+ background: linear-gradient(135deg, #1A1B2E 0%, #16213E 25%, #0F3460 50%, #16213E 75%, #1A1B2E 100%) !important;
319
+ min-height: 100vh;
320
+ }
321
+
322
+ .main-header {
323
+ text-align: center;
324
+ background: linear-gradient(45deg, var(--primary-pink), var(--primary-purple), var(--primary-blue));
325
+ -webkit-background-clip: text;
326
+ -webkit-text-fill-color: transparent;
327
+ background-clip: text;
328
+ font-size: 3rem;
329
+ font-weight: 700;
330
+ margin: 1rem 0;
331
+ text-shadow: 0 0 30px rgba(255, 107, 157, 0.5);
332
+ }
333
+
334
+ .subtitle {
335
+ text-align: center;
336
+ color: var(--text-light);
337
+ font-size: 1.2rem;
338
+ margin-bottom: 2rem;
339
+ opacity: 0.9;
340
+ }
341
+
342
+ /* Button styling */
343
+ .btn-primary {
344
+ background: linear-gradient(45deg, var(--primary-pink), var(--primary-purple)) !important;
345
+ border: none !important;
346
+ border-radius: 25px !important;
347
+ padding: 0.75rem 2rem !important;
348
+ font-weight: 600 !important;
349
+ transition: all 0.3s ease !important;
350
+ box-shadow: 0 4px 15px rgba(255, 107, 157, 0.4) !important;
351
+ }
352
+
353
+ .btn-primary:hover {
354
+ transform: translateY(-2px) !important;
355
+ box-shadow: 0 8px 25px rgba(255, 107, 157, 0.6) !important;
356
+ }
357
+
358
+ /* Input styling */
359
+ textarea, input {
360
+ background: rgba(255, 255, 255, 0.1) !important;
361
+ border: 2px solid transparent !important;
362
+ border-radius: 15px !important;
363
+ color: var(--text-light) !important;
364
+ transition: all 0.3s ease !important;
365
+ }
366
+
367
+ textarea:focus, input:focus {
368
+ border-color: var(--primary-pink) !important;
369
+ box-shadow: 0 0 20px rgba(255, 107, 157, 0.3) !important;
370
+ }
371
+
372
+ /* Gradio component styling */
373
+ .gr-form {
374
+ background: var(--card-bg) !important;
375
+ backdrop-filter: blur(10px) !important;
376
+ border: 1px solid rgba(255, 255, 255, 0.1) !important;
377
+ border-radius: 20px !important;
378
+ padding: 1.5rem !important;
379
+ margin: 1rem 0 !important;
380
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
381
+ }
382
+
383
+ /* Animations */
384
+ @keyframes sparkle {
385
+ 0%, 100% { opacity: 1; transform: scale(1); }
386
+ 50% { opacity: 0.5; transform: scale(1.2); }
387
+ }
388
+
389
+ .sparkle::after {
390
+ content: "โœจ";
391
+ animation: sparkle 2s infinite;
392
+ }
393
+ </style>
394
+ """
395
+
396
+ # Create Gradio interface
397
+ with gr.Blocks(
398
+ theme=gr.themes.Soft(
399
+ primary_hue="pink",
400
+ secondary_hue="purple",
401
+ neutral_hue="slate"
402
+ ),
403
+ css=anime_css,
404
+ title="๐ŸŽต Strudel Music Generator"
405
+ ) as app:
406
+
407
+ # Header
408
+ gr.HTML("""
409
+ <div class="main-header">๐ŸŽต Strudel Music Generator</div>
410
+ <div class="subtitle">Transform your musical dreams into Strudel code with anime-powered AI! โœจ</div>
411
+ """)
412
+
413
+ with gr.Row():
414
+ with gr.Column(scale=1):
415
+ gr.Markdown("### ๐ŸŽผ Describe Your Music")
416
+
417
+ description = gr.Textbox(
418
+ label="Musical Description",
419
+ placeholder="e.g., 'A dreamy lofi track with soft piano chords, mellow drums, and a gentle melody that feels like floating on clouds...'",
420
+ lines=4,
421
+ elem_id="description"
422
+ )
423
+
424
+ with gr.Row():
425
+ tempo = gr.Slider(
426
+ minimum=60,
427
+ maximum=200,
428
+ value=120,
429
+ step=5,
430
+ label="๐ŸŽต Tempo (BPM)"
431
+ )
432
+
433
+ style = gr.Dropdown(
434
+ choices=["Auto-detect", "Lofi", "Techno", "House", "Ambient", "Jazz", "Cyberpunk", "Anime", "Chiptune"],
435
+ value="Auto-detect",
436
+ label="๐ŸŽญ Style Override"
437
+ )
438
+
439
+ with gr.Row():
440
+ generate_btn = gr.Button(
441
+ "๐Ÿš€ Generate Strudel Code",
442
+ variant="primary",
443
+ elem_id="generate-btn"
444
+ )
445
+ magic_btn = gr.Button(
446
+ "โœจ Add Magic",
447
+ elem_id="magic-btn"
448
+ )
449
+
450
+ with gr.Column(scale=1):
451
+ gr.Markdown("### ๐ŸŽน Generated Strudel Code")
452
+
453
+ code_output = gr.Code(
454
+ label="Your Strudel Code (Editable)",
455
+ language="javascript",
456
+ lines=15,
457
+ elem_id="code-output"
458
+ )
459
+
460
+ status_output = gr.Textbox(
461
+ label="Status",
462
+ interactive=False,
463
+ elem_id="status"
464
+ )
465
+
466
+ analysis_output = gr.Markdown(
467
+ label="๐Ÿ” Musical Analysis"
468
+ )
469
+
470
+ # Examples section
471
+ gr.Markdown("### ๐ŸŽจ Try These Anime-Inspired Examples")
472
+
473
+ with gr.Row():
474
+ example_buttons = []
475
+ for i, (title, desc) in enumerate(list(examples.items())[:4]):
476
+ btn = gr.Button(title, elem_id=f"example-{i}")
477
+ example_buttons.append((btn, desc))
478
+
479
+ with gr.Row():
480
+ for i, (title, desc) in enumerate(list(examples.items())[4:]):
481
+ btn = gr.Button(title, elem_id=f"example-{i+4}")
482
+ example_buttons.append((btn, desc))
483
+
484
+ # Instructions and tips
485
+ with gr.Accordion("๐ŸŽ“ Music Theory Helper & Strudel Tips", open=False):
486
+ gr.Markdown("""
487
+ **๐ŸŽต Musical Elements You Can Describe:**
488
+ - **Drums**: "kick drums", "snare", "hi-hats", "trap beats", "breakbeats"
489
+ - **Bass**: "deep bass", "funky bass", "wobble bass", "walking bass"
490
+ - **Harmony**: "jazz chords", "emotional chords", "uplifting progression"
491
+ - **Melody**: "anime melody", "8-bit tune", "ethereal lead", "fast arpeggios"
492
+
493
+ **๐ŸŽญ Styles & Moods:**
494
+ - **Lofi**: relaxed, mellow, nostalgic, cozy
495
+ - **Cyberpunk**: dark, futuristic, glitchy, intense
496
+ - **Anime**: emotional, dramatic, uplifting, kawaii
497
+ - **Chiptune**: retro, 8-bit, nostalgic, bouncy
498
+
499
+ **โšก Strudel Code Tips:**
500
+ - Use `stack()` to layer multiple patterns
501
+ - Add `.sound()` to choose different instruments
502
+ - Apply effects like `.lpf()`, `.room()`, `.delay()`
503
+ - Control timing with `.slow()`, `.fast()`, `.every()`
504
+ - Experiment with `.sometimes()` for variations
505
+
506
+ **๐ŸŽฎ Pro Tips:**
507
+ - Be descriptive about the mood and energy you want
508
+ - Mention specific instruments or sounds
509
+ - Describe the genre or style for better results
510
+ - Use the "Add Magic" button for instant variations!
511
+ """)
512
+
513
+ # Event handlers
514
+ generate_btn.click(
515
+ fn=generate_music,
516
+ inputs=[description, tempo, style],
517
+ outputs=[code_output, status_output, analysis_output]
518
+ )
519
+
520
+ magic_btn.click(
521
+ fn=add_magic,
522
+ inputs=[code_output],
523
+ outputs=[code_output, status_output]
524
+ )
525
+
526
+ # Example button handlers
527
+ for btn, desc in example_buttons:
528
+ btn.click(
529
+ fn=lambda x=desc: x,
530
+ outputs=[description]
531
+ )
532
+
533
+ # Footer
534
+ gr.HTML("""
535
+ <div style='text-align: center; margin-top: 2rem; opacity: 0.7; color: #E2E8F0;'>
536
+ <p>Made with ๐Ÿ’– for National Make Music Day | Powered by Strudel.js & Gradio</p>
537
+ <p><small>๐ŸŽต Turn your musical dreams into algorithmic reality! โœจ</small></p>
538
+ </div>
539
+ """)
540
+
541
+ # Launch configuration
542
+ if __name__ == "__main__":
543
+ app.launch(
544
+ share=False,
545
+ server_name="0.0.0.0",
546
+ server_port=7860,
547
+ show_error=True
548
+ )