baouws commited on
Commit
28e11b9
·
verified ·
1 Parent(s): a4ebf26

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +306 -347
app.py CHANGED
@@ -1,384 +1,343 @@
1
  import gradio as gr
2
- import random
 
 
 
3
 
4
- # Simple music generation logic
5
- class StrudelGenerator:
6
- def __init__(self):
7
- self.patterns = {
8
- 'drums': ['"bd*4"', '"bd ~ sd ~"', '"bd*2 sd*2"'],
9
- 'bass': ['"c2 [~ c2] f2 [~ f2]"', '"c2*4"', '"c1 ~ f1 ~"'],
10
- 'chords': ['"<C^7 F^7 G^7 C^7>".voicing()', '"<c\'maj7 f\'maj7 g\'7 c\'maj7>".voicing()'],
11
- 'melody': ['"c5 d5 e5 f5"', '"c5 e5 g5 c6"']
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- def generate_code(self, description: str, tempo: int = 120) -> str:
15
- """Generate simple Strudel code"""
16
- desc = description.lower()
17
- patterns = []
18
 
19
- # Simple keyword detection
20
- if any(word in desc for word in ['drum', 'beat', 'kick']):
21
- patterns.append(random.choice(self.patterns['drums']) + '.gain(0.8)')
 
 
 
 
22
 
23
- if any(word in desc for word in ['bass', 'low']):
24
- patterns.append(random.choice(self.patterns['bass']) + '.sound("sawtooth").gain(0.6)')
25
-
26
- if any(word in desc for word in ['chord', 'harmony', 'piano']):
27
- patterns.append(random.choice(self.patterns['chords']) + '.sound("piano").gain(0.4)')
28
-
29
- if any(word in desc for word in ['melody', 'lead', 'tune']):
30
- patterns.append(random.choice(self.patterns['melody']) + '.sound("sine").gain(0.5)')
31
 
32
- # Default if nothing detected
33
- if not patterns:
34
- patterns = [
35
- '"bd ~ sd ~".gain(0.7)',
36
- '"<C^7 F^7 G^7 C^7>".voicing().sound("piano").gain(0.4)'
37
- ]
38
 
39
- # Build code
40
- if len(patterns) == 1:
41
- code = patterns[0]
42
- else:
43
- code = "stack(\n"
44
- for i, pattern in enumerate(patterns):
45
- comma = "," if i < len(patterns) - 1 else ""
46
- code += f" {pattern}{comma}\n"
47
- code += ")"
48
 
49
- code += f".cpm({tempo})"
50
- return code
51
-
52
- generator = StrudelGenerator()
53
-
54
- def generate_music(description, tempo):
55
- """Generate music code"""
56
- if not description.strip():
57
- return "// Please describe your music first!"
58
-
59
- code = generator.generate_code(description, tempo)
60
- return code
61
 
62
- # Create simple interface
63
- with gr.Blocks(title="🎵 Strudel Generator") as app:
64
-
65
- gr.HTML("""
66
- <div style='text-align: center; margin-bottom: 30px;'>
67
- <h1 style='color: #FF6B9D; font-size: 2.5rem; margin: 0;'>🎵 Strudel Music Generator</h1>
68
- <p style='color: #666; font-size: 1.1rem;'>Describe your music and generate Strudel code!</p>
69
- </div>
70
- """)
71
-
72
- # Simple input
73
- description = gr.Textbox(
74
- label="Describe your music",
75
- placeholder="e.g., 'upbeat drums with piano chords'",
76
- lines=2
77
- )
78
-
79
- tempo = gr.Slider(60, 180, 120, step=5, label="Tempo (BPM)")
80
-
81
- generate_btn = gr.Button("🚀 Generate Code", variant="primary")
82
-
83
- # Code output
84
- code_output = gr.Code(
85
- label="Generated Strudel Code",
86
- language="javascript",
87
- lines=8
88
- )
89
-
90
- # Simple audio player with working Strudel.js
91
- gr.HTML("""
92
- <div id="player" style='
93
- background: linear-gradient(135deg, #FF6B9D, #A855F7);
94
- padding: 20px;
95
- border-radius: 15px;
96
- text-align: center;
97
- margin: 20px 0;
98
- '>
99
- <h3 style='color: white; margin: 0 0 15px 0;'>🎵 Audio Player</h3>
100
- <button id="playBtn" onclick="togglePlay()" style='
101
- background: white;
102
- color: #FF6B9D;
103
  border: none;
104
- padding: 12px 30px;
105
- border-radius: 25px;
106
- font-size: 16px;
107
- font-weight: bold;
108
- cursor: pointer;
109
  margin: 5px;
110
- transition: all 0.3s;
111
- '>▶️ Play</button>
112
- <button onclick="stopPlay()" style='
113
- background: rgba(255,255,255,0.8);
114
- color: #FF6B9D;
115
- border: none;
116
- padding: 12px 30px;
117
- border-radius: 25px;
118
- font-size: 16px;
119
- font-weight: bold;
120
  cursor: pointer;
121
- margin: 5px;
122
- transition: all 0.3s;
123
- '>⏹️ Stop</button>
124
- <button onclick="initAudio()" style='
125
- background: rgba(255,255,255,0.6);
126
- color: #FF6B9D;
127
- border: none;
128
- padding: 8px 20px;
129
- border-radius: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  font-size: 14px;
 
 
 
 
 
 
131
  font-weight: bold;
132
- cursor: pointer;
133
- margin: 5px;
134
- transition: all 0.3s;
135
- '>🔊 Enable Audio</button>
136
- <div id="status" style='color: white; margin-top: 10px; font-size: 14px;'>
137
- Click "Enable Audio" first, then generate code and play!
 
 
 
 
 
 
 
 
 
 
 
 
138
  </div>
 
 
139
  </div>
140
 
141
- <!-- Load Strudel from official CDN -->
142
- <script src="https://unpkg.com/@strudel.cycles/core@latest/dist/index.js"></script>
143
- <script src="https://unpkg.com/@strudel.cycles/webaudio@latest/dist/index.js"></script>
144
- <script src="https://unpkg.com/@strudel.cycles/mini@latest/dist/index.js"></script>
145
-
146
- <script>
147
  let isPlaying = false;
148
- let currentHap = null;
149
- let strudelInitialized = false;
150
- let audioContext = null;
151
-
152
- function getCurrentCode() {
153
- // More aggressive code detection
154
- const allTextareas = document.querySelectorAll('textarea');
155
- const allCodes = document.querySelectorAll('code');
156
- const allPres = document.querySelectorAll('pre');
157
-
158
- // Check all possible containers
159
- const elements = [...allTextareas, ...allCodes, ...allPres];
160
-
161
- for (let element of elements) {
162
- const code = element.value || element.textContent || element.innerText || '';
163
- if (code && code.includes('.cpm(') && !code.includes('Please describe')) {
164
- console.log('Found code:', code);
165
- return code;
166
- }
167
- }
168
- console.log('No valid code found');
169
- return '';
170
- }
171
-
172
- function updateStatus(message, color = 'white') {
173
- const status = document.getElementById('status');
174
- if (status) {
175
- status.textContent = message;
176
- status.style.color = color;
177
- }
178
- console.log('Status:', message);
179
- }
180
-
181
- function updatePlayButton(playing) {
182
- const btn = document.getElementById('playBtn');
183
- if (btn) {
184
- btn.textContent = playing ? '⏸️ Pause' : '▶️ Play';
185
- }
186
- }
187
-
188
- async function initAudio() {
189
- try {
190
- updateStatus('🔧 Initializing audio...', '#ffffcc');
191
 
192
- // Create audio context
193
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
194
 
195
- // Resume if suspended
196
- if (audioContext.state === 'suspended') {
197
- await audioContext.resume();
198
- }
199
 
200
- // Check if Strudel is available
201
- if (typeof strudel !== 'undefined') {
202
- updateStatus('🎵 Strudel audio ready! Generate code and play!', '#ccffcc');
203
- strudelInitialized = true;
204
- } else {
205
- updateStatus('🎮 Demo mode ready (Strudel not loaded)', '#ffffcc');
206
- strudelInitialized = false;
207
- }
208
 
209
- } catch (error) {
210
- console.error('Audio init error:', error);
211
- updateStatus('⚠️ Audio init failed - using demo mode', '#ffcccc');
212
- strudelInitialized = false;
213
- }
214
- }
215
-
216
- async function togglePlay() {
217
- if (isPlaying) {
218
- stopPlay();
219
- } else {
220
- await startPlay();
221
- }
222
- }
223
-
224
- async function startPlay() {
225
- const code = getCurrentCode();
226
-
227
- if (!code) {
228
- updateStatus('❌ No code found! Generate some first.', '#ffcccc');
229
- return;
230
- }
231
-
232
- try {
233
- updateStatus('🎵 Starting playback...', '#ffffcc');
234
-
235
- if (strudelInitialized && typeof strudel !== 'undefined') {
236
- // Try real Strudel playback
237
- console.log('Attempting Strudel playback');
238
-
239
- // Clean code
240
- const cleanCode = code
241
- .split('\\n')
242
- .filter(line => !line.trim().startsWith('//') && line.trim() !== '')
243
- .join('\\n')
244
- .trim();
245
-
246
- console.log('Clean code:', cleanCode);
247
-
248
- // Try to evaluate and play
249
- try {
250
- // Simple evaluation approach
251
- const result = eval(cleanCode);
252
- console.log('Eval result:', result);
253
-
254
- if (result && typeof result.play === 'function') {
255
- currentHap = result;
256
- await result.play();
257
- updateStatus('🎵 Playing with Strudel! 🎶', '#ccffcc');
258
- } else {
259
- throw new Error('Not a playable pattern');
260
- }
261
- } catch (evalError) {
262
- console.error('Eval error:', evalError);
263
- throw evalError;
264
- }
265
 
266
- } else {
267
- // Demo mode
268
- console.log('Using demo mode');
269
- updateStatus('🎮 Demo: Playing your pattern...', '#ffffcc');
270
- }
271
-
272
- isPlaying = true;
273
- updatePlayButton(true);
274
-
275
- // Auto-stop after 30 seconds
276
- setTimeout(() => {
277
- if (isPlaying) {
278
- stopPlay();
279
- updateStatus('⏰ Auto-stopped after 30s', 'white');
280
- }
281
- }, 30000);
282
-
283
- } catch (error) {
284
  console.error('Playback error:', error);
285
- updateStatus(' Playback error: ' + error.message, '#ffcccc');
 
 
 
 
 
 
 
 
 
 
286
 
287
- // Fallback to demo mode
288
- isPlaying = true;
289
- updatePlayButton(true);
290
- updateStatus('🎮 Demo mode: Simulating playback...', '#ffffcc');
 
291
 
292
- setTimeout(() => {
293
- stopPlay();
294
- updateStatus('Demo finished!', 'white');
295
- }, 8000);
296
- }
297
- }
298
-
299
- function stopPlay() {
300
- if (currentHap && typeof currentHap.stop === 'function') {
301
- try {
302
- currentHap.stop();
303
- console.log('Stopped Strudel pattern');
304
- } catch (e) {
305
- console.error('Error stopping:', e);
306
- }
307
- currentHap = null;
308
- }
309
-
310
- isPlaying = false;
311
- updatePlayButton(false);
312
- updateStatus('⏹️ Stopped', 'white');
313
- }
314
-
315
- // Initialize on page load
316
- document.addEventListener('DOMContentLoaded', function() {
317
- updateStatus('Click "Enable Audio" to start!', 'white');
318
-
319
- // Add hover effects
320
- const buttons = document.querySelectorAll('#player button');
321
- buttons.forEach(btn => {
322
- btn.addEventListener('mouseenter', function() {
323
- this.style.transform = 'scale(1.05)';
324
- this.style.boxShadow = '0 5px 15px rgba(0,0,0,0.2)';
325
- });
326
- btn.addEventListener('mouseleave', function() {
327
- this.style.transform = 'scale(1)';
328
- this.style.boxShadow = 'none';
329
- });
330
- });
331
-
332
- // Check if Strudel loaded
333
- setTimeout(() => {
334
- if (typeof strudel !== 'undefined') {
335
- console.log('Strudel detected!', strudel);
336
- updateStatus('🎵 Strudel loaded! Click "Enable Audio" then play!', '#ccffcc');
337
- } else {
338
- console.log('Strudel not found, demo mode only');
339
- updateStatus('🎮 Demo mode ready - click "Enable Audio"!', '#ffffcc');
340
- }
341
- }, 2000);
342
- });
343
-
344
- // Global error handler
345
- window.addEventListener('error', function(e) {
346
- console.error('Global error:', e.error);
347
- });
348
  </script>
349
- """)
350
-
351
- # Quick examples
352
- gr.HTML("<h3 style='margin-top: 30px;'>🎨 Quick Examples:</h3>")
 
 
 
 
 
353
 
354
- with gr.Row():
355
- ex1 = gr.Button("🎮 Chiptune", size="sm")
356
- ex2 = gr.Button("🌙 Lofi", size="sm")
357
- ex3 = gr.Button("⚡ Techno", size="sm")
358
- ex4 = gr.Button("🎹 Jazz", size="sm")
359
 
360
- # Event handlers
361
- generate_btn.click(
362
- fn=generate_music,
363
- inputs=[description, tempo],
364
- outputs=[code_output]
365
- )
366
 
367
- # Example handlers
368
- ex1.click(lambda: "8-bit chiptune with bouncy melody and simple drums", outputs=[description])
369
- ex2.click(lambda: "mellow lofi with soft piano chords and gentle drums", outputs=[description])
370
- ex3.click(lambda: "driving techno with heavy bass and pounding kick", outputs=[description])
371
- ex4.click(lambda: "smooth jazz with walking bass and chord progressions", outputs=[description])
372
 
373
- gr.HTML("""
374
- <div style='text-align: center; margin-top: 30px; opacity: 0.7;'>
375
- <p>Made for National Make Music Day 🎵</p>
376
- </div>
377
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
 
 
379
  if __name__ == "__main__":
 
380
  app.launch(
381
- share=False,
382
  server_name="0.0.0.0",
383
  server_port=7860
384
  )
 
1
  import gradio as gr
2
+ import requests
3
+ import json
4
+ import os
5
+ from huggingface_hub import InferenceClient
6
 
7
+ # Initialize the Hugging Face Inference Client
8
+ # You can use different models - here are some good options:
9
+ # - "microsoft/DialoGPT-medium" (free)
10
+ # - "mistralai/Mixtral-8x7B-Instruct-v0.1" (may require HF Pro)
11
+ # - "meta-llama/Llama-2-7b-chat-hf" (may require access request)
12
+
13
+ client = InferenceClient("microsoft/DialoGPT-medium")
14
+
15
+ def create_strudel_prompt(user_text):
16
+ """Create a detailed prompt for generating Strudel code"""
17
+ return f"""Convert the following description into Strudel live coding syntax. Strudel uses a functional approach for creating musical patterns.
18
+
19
+ Key Strudel concepts:
20
+ - Use note() for melodies: note("c d e f")
21
+ - Use sound() for samples: sound("bd hh sd hh")
22
+ - Use .fast() to speed up: .fast(2)
23
+ - Use .slow() to slow down: .slow(2)
24
+ - Chain functions with dots: note("c d e f").fast(2)
25
+ - Use < > for groupings: note("c <e g> f")
26
+ - Use * for repetition: note("c*4")
27
+ - Use ~ for rests: note("c ~ e ~")
28
+ - Use / for subdivision: note("c/2 d/2 e")
29
+ - Use [] for sequences: note("[c d] [e f]")
30
+
31
+ User request: {user_text}
32
+
33
+ Generate only the Strudel code without explanation:"""
34
 
35
+ def generate_strudel_code(user_text):
36
+ """Generate Strudel code using LLM"""
37
+ try:
38
+ prompt = create_strudel_prompt(user_text)
39
 
40
+ # Use the inference client to generate text
41
+ response = client.text_generation(
42
+ prompt,
43
+ max_new_tokens=200,
44
+ temperature=0.7,
45
+ return_full_text=False
46
+ )
47
 
48
+ # Clean up the response
49
+ strudel_code = response.strip()
 
 
 
 
 
 
50
 
51
+ # Basic validation and cleanup
52
+ if not strudel_code:
53
+ strudel_code = 'note("c d e f").slow(2)'
 
 
 
54
 
55
+ # Remove any markdown code blocks if present
56
+ if strudel_code.startswith('```'):
57
+ lines = strudel_code.split('\n')
58
+ strudel_code = '\n'.join(lines[1:-1]) if len(lines) > 2 else strudel_code
 
 
 
 
 
59
 
60
+ return strudel_code
61
+
62
+ except Exception as e:
63
+ print(f"Error generating code: {e}")
64
+ # Fallback to a simple pattern
65
+ return 'note("c d e f").slow(2)'
 
 
 
 
 
 
66
 
67
+ def create_strudel_html(strudel_code):
68
+ """Create HTML with embedded Strudel player"""
69
+ html_template = f"""
70
+ <!DOCTYPE html>
71
+ <html>
72
+ <head>
73
+ <title>Strudel Player</title>
74
+ <script src="https://unpkg.com/@strudel.cycles/core"></script>
75
+ <script src="https://unpkg.com/@strudel.cycles/webaudio"></script>
76
+ <script src="https://unpkg.com/@strudel.cycles/mini"></script>
77
+ <style>
78
+ body {{
79
+ font-family: Arial, sans-serif;
80
+ max-width: 800px;
81
+ margin: 0 auto;
82
+ padding: 20px;
83
+ background: #1a1a1a;
84
+ color: #fff;
85
+ }}
86
+ .player-container {{
87
+ background: #2d2d2d;
88
+ border-radius: 8px;
89
+ padding: 20px;
90
+ margin: 20px 0;
91
+ }}
92
+ .controls {{
93
+ margin: 20px 0;
94
+ text-align: center;
95
+ }}
96
+ button {{
97
+ background: #4CAF50;
98
+ color: white;
 
 
 
 
 
 
 
 
 
99
  border: none;
100
+ padding: 10px 20px;
 
 
 
 
101
  margin: 5px;
102
+ border-radius: 4px;
 
 
 
 
 
 
 
 
 
103
  cursor: pointer;
104
+ font-size: 16px;
105
+ }}
106
+ button:hover {{
107
+ background: #45a049;
108
+ }}
109
+ button:disabled {{
110
+ background: #666;
111
+ cursor: not-allowed;
112
+ }}
113
+ .stop {{
114
+ background: #f44336;
115
+ }}
116
+ .stop:hover {{
117
+ background: #da190b;
118
+ }}
119
+ .code-display {{
120
+ background: #333;
121
+ border: 1px solid #555;
122
+ border-radius: 4px;
123
+ padding: 15px;
124
+ margin: 10px 0;
125
+ font-family: 'Courier New', monospace;
126
  font-size: 14px;
127
+ white-space: pre-wrap;
128
+ word-wrap: break-word;
129
+ }}
130
+ .status {{
131
+ text-align: center;
132
+ margin: 10px 0;
133
  font-weight: bold;
134
+ }}
135
+ .error {{
136
+ color: #ff6b6b;
137
+ }}
138
+ .playing {{
139
+ color: #4CAF50;
140
+ }}
141
+ </style>
142
+ </head>
143
+ <body>
144
+ <div class="player-container">
145
+ <h2>🎵 Strudel Player</h2>
146
+
147
+ <div class="code-display">{strudel_code}</div>
148
+
149
+ <div class="controls">
150
+ <button id="playBtn" onclick="playPattern()">▶️ Play</button>
151
+ <button id="stopBtn" onclick="stopPattern()" disabled>⏹️ Stop</button>
152
  </div>
153
+
154
+ <div id="status" class="status">Ready to play</div>
155
  </div>
156
 
157
+ <script type="module">
158
+ import {{ repl, controls, evalScope }} from 'https://unpkg.com/@strudel.cycles/core';
159
+ import {{ webaudioOutput }} from 'https://unpkg.com/@strudel.cycles/webaudio';
160
+
161
+ let currentPattern = null;
 
162
  let isPlaying = false;
163
+
164
+ // Initialize Strudel
165
+ const ctx = new (window.AudioContext || window.webkitAudioContext)();
166
+
167
+ window.playPattern = async function() {{
168
+ try {{
169
+ const playBtn = document.getElementById('playBtn');
170
+ const stopBtn = document.getElementById('stopBtn');
171
+ const status = document.getElementById('status');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ if (isPlaying) return;
 
174
 
175
+ // Resume audio context if needed
176
+ if (ctx.state === 'suspended') {{
177
+ await ctx.resume();
178
+ }}
179
 
180
+ status.textContent = 'Starting...';
181
+ status.className = 'status';
 
 
 
 
 
 
182
 
183
+ const code = `{strudel_code}`;
184
+
185
+ // Evaluate the Strudel code
186
+ const pattern = evalScope(code, {{
187
+ note: (notes) => repl.note(notes),
188
+ sound: (sounds) => repl.sound(sounds),
189
+ // Add more Strudel functions as needed
190
+ }});
191
+
192
+ if (pattern) {{
193
+ currentPattern = pattern.output(webaudioOutput);
194
+ await currentPattern.start();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
+ isPlaying = true;
197
+ playBtn.disabled = true;
198
+ stopBtn.disabled = false;
199
+ status.textContent = '🎵 Playing...';
200
+ status.className = 'status playing';
201
+ }}
202
+
203
+ }} catch (error) {{
 
 
 
 
 
 
 
 
 
 
204
  console.error('Playback error:', error);
205
+ document.getElementById('status').textContent = `Error: ${{error.message}}`;
206
+ document.getElementById('status').className = 'status error';
207
+ }}
208
+ }}
209
+
210
+ window.stopPattern = function() {{
211
+ try {{
212
+ if (currentPattern) {{
213
+ currentPattern.stop();
214
+ currentPattern = null;
215
+ }}
216
 
217
+ isPlaying = false;
218
+ document.getElementById('playBtn').disabled = false;
219
+ document.getElementById('stopBtn').disabled = true;
220
+ document.getElementById('status').textContent = 'Stopped';
221
+ document.getElementById('status').className = 'status';
222
 
223
+ }} catch (error) {{
224
+ console.error('Stop error:', error);
225
+ }}
226
+ }}
227
+
228
+ // Cleanup on page unload
229
+ window.addEventListener('beforeunload', () => {{
230
+ if (currentPattern) {{
231
+ currentPattern.stop();
232
+ }}
233
+ }});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  </script>
235
+ </body>
236
+ </html>
237
+ """
238
+ return html_template
239
+
240
+ def process_text_to_music(user_input):
241
+ """Main function to process user input and return HTML player"""
242
+ if not user_input.strip():
243
+ return "<p>Please enter a description for your music!</p>"
244
 
245
+ # Generate Strudel code
246
+ strudel_code = generate_strudel_code(user_input)
 
 
 
247
 
248
+ # Create HTML player
249
+ html_player = create_strudel_html(strudel_code)
 
 
 
 
250
 
251
+ return html_player
 
 
 
 
252
 
253
+ # Create Gradio interface
254
+ def create_interface():
255
+ with gr.Blocks(
256
+ title="Text to Strudel Music Generator",
257
+ theme=gr.themes.Dark(),
258
+ css="""
259
+ .gradio-container {
260
+ max-width: 1000px !important;
261
+ }
262
+ """
263
+ ) as app:
264
+
265
+ gr.Markdown("""
266
+ # 🎵 Text to Strudel Music Generator
267
+
268
+ Describe the music you want and I'll generate Strudel live coding syntax for it!
269
+
270
+ **Examples to try:**
271
+ - "A simple drum beat with kick and hi-hat"
272
+ - "Peaceful melody in C major"
273
+ - "Fast electronic arpeggios"
274
+ - "Jazz chord progression"
275
+ """)
276
+
277
+ with gr.Row():
278
+ with gr.Column(scale=1):
279
+ user_input = gr.Textbox(
280
+ label="Describe your music",
281
+ placeholder="Enter a description of the music you want to create...",
282
+ lines=3
283
+ )
284
+
285
+ generate_btn = gr.Button("🎵 Generate Music", variant="primary")
286
+
287
+ gr.Markdown("""
288
+ ### How it works:
289
+ 1. Describe the music you want
290
+ 2. Click "Generate Music"
291
+ 3. Click "Play" in the player below
292
+ 4. Use "Stop" to stop playback
293
+
294
+ *Note: You may need to click play twice the first time to initialize audio.*
295
+ """)
296
+
297
+ with gr.Row():
298
+ with gr.Column():
299
+ output_html = gr.HTML(
300
+ label="Strudel Player",
301
+ value="<p>Enter a description above and click 'Generate Music' to create your Strudel pattern!</p>"
302
+ )
303
+
304
+ generate_btn.click(
305
+ fn=process_text_to_music,
306
+ inputs=[user_input],
307
+ outputs=[output_html]
308
+ )
309
+
310
+ # Example buttons
311
+ gr.Markdown("### Quick Examples:")
312
+ with gr.Row():
313
+ example_btns = [
314
+ gr.Button("🥁 Simple Drum Beat"),
315
+ gr.Button("🎹 Peaceful Melody"),
316
+ gr.Button("⚡ Fast Arpeggios"),
317
+ gr.Button("🎷 Jazz Chords")
318
+ ]
319
+
320
+ # Set up example button clicks
321
+ example_texts = [
322
+ "A simple drum beat with kick and hi-hat alternating",
323
+ "A peaceful melody in C major, slow and calming",
324
+ "Fast electronic arpeggios going up and down",
325
+ "Jazz chord progression with swing rhythm"
326
+ ]
327
+
328
+ for btn, text in zip(example_btns, example_texts):
329
+ btn.click(
330
+ fn=lambda t=text: [t, process_text_to_music(t)],
331
+ outputs=[user_input, output_html]
332
+ )
333
+
334
+ return app
335
 
336
+ # Create and launch the app
337
  if __name__ == "__main__":
338
+ app = create_interface()
339
  app.launch(
340
+ share=True,
341
  server_name="0.0.0.0",
342
  server_port=7860
343
  )