baouws commited on
Commit
dfa7009
Β·
verified Β·
1 Parent(s): deb5deb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +283 -133
app.py CHANGED
@@ -3,6 +3,7 @@ import requests
3
  import json
4
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
5
  import torch
 
6
 
7
  # Use CodeGen instead of StarCoder (no authentication needed)
8
  MODEL_NAME = "Salesforce/codegen-350M-mono"
@@ -27,236 +28,385 @@ except Exception as e:
27
  device_map=None
28
  )
29
 
30
- # Strudel code examples for few-shot prompting
31
- STRUDEL_EXAMPLES = """
32
- // Basic drum pattern
33
- s("bd hh sn hh").gain(0.8)
 
 
 
 
34
 
35
- // Melodic pattern
36
- n("0 2 4 7").s("sine").octave(4).lpf(2000)
 
 
 
 
37
 
38
- // Techno beat
39
  stack(
40
- s("bd*4").gain(0.8),
41
- s("~ hh ~ hh").gain(0.6),
42
- n("0 ~ 3 ~").s("sawtooth").octave(2).lpf(800)
43
- )
44
 
45
- // Ambient pattern
46
- n("[0 2 4]/3").s("sine").octave(3).slow(4).room(0.9).gain(0.5)
 
 
 
 
47
  """
48
 
49
- def generate_strudel_code(prompt, genre="general", complexity="simple", max_length=150, temperature=0.7):
50
- """Generate Strudel code using CodeGen"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- # Build context-aware prompt
53
- system_prompt = f"""// Strudel live coding language for music
54
- // Generate {complexity} {genre} music patterns
55
- // Examples:
56
- {STRUDEL_EXAMPLES}
57
 
58
- // Create: {prompt}
 
59
  // Code:
60
  """
61
 
62
  try:
63
- # Generate code using pipeline
64
  outputs = code_generator(
65
  system_prompt,
66
- max_length=len(system_prompt.split()) + max_length,
67
- temperature=temperature,
68
  do_sample=True,
69
  top_p=0.9,
70
  num_return_sequences=1,
71
  pad_token_id=code_generator.tokenizer.eos_token_id
72
  )
73
 
74
- # Extract generated text
75
  generated_text = outputs[0]['generated_text']
76
-
77
- # Extract only the new generated part
78
  strudel_code = generated_text[len(system_prompt):].strip()
79
-
80
- # Clean up the code
81
  strudel_code = clean_strudel_code(strudel_code)
82
 
 
 
 
 
83
  return strudel_code
84
 
85
  except Exception as e:
86
- return f"// Error generating code: {str(e)}\n// Fallback pattern:\ns(\"bd hh sn hh\").gain(0.8)"
 
87
 
88
  def clean_strudel_code(code):
89
- """Clean and format generated Strudel code"""
90
  lines = code.split('\n')
91
  cleaned_lines = []
 
92
 
93
  for line in lines:
94
  line = line.strip()
95
- # Stop at comments that indicate end of generation
96
- if line.startswith('//') and any(word in line.lower() for word in ['user', 'request', 'example', 'create']):
97
- break
98
- # Include actual code lines
99
- if line and (line.startswith('s(') or line.startswith('n(') or line.startswith('stack(') or
100
- line.startswith('$:') or line.startswith('all(') or line.endswith(')') or
101
- line.endswith(',') or 'gain(' in line or 'lpf(' in line):
 
 
 
 
 
 
 
 
 
102
  cleaned_lines.append(line)
103
- # Stop if we hit obvious non-Strudel code
104
- elif any(keyword in line for keyword in ['function', 'var ', 'let ', 'const ', 'import', 'export']):
 
105
  break
106
 
107
- if len(cleaned_lines) >= 8: # Limit output length
108
  break
109
 
110
- # If no valid code was generated, provide a fallback
111
- if not cleaned_lines:
112
- return generate_fallback_pattern(genre)
113
-
114
- return '\n'.join(cleaned_lines)
115
 
116
- def generate_fallback_pattern(genre):
117
- """Generate a simple fallback pattern based on genre"""
118
- patterns = {
119
- "techno": 'stack(\n s("bd*4").gain(0.8),\n s("~ hh ~ hh").gain(0.6),\n n("0 ~ 3 ~").s("sawtooth").octave(2)\n)',
120
- "house": 'stack(\n s("bd ~ ~ ~ bd ~ ~ ~").gain(0.7),\n s("~ hh ~ hh").gain(0.5),\n n("0 2 4 7").s("sine").octave(3)\n)',
121
- "ambient": 'n("[0 2 4]/3").s("sine").octave(3).slow(4).room(0.9).gain(0.5)',
122
- "jazz": 'stack(\n s("bd ~ sn ~").gain(0.7),\n s("~ ~ hh ~").gain(0.4),\n n("0 3 5 7").s("triangle").octave(4)\n)',
123
- "rock": 'stack(\n s("bd sn bd sn").gain(0.8),\n s("hh*8").gain(0.5),\n n("0 0 3 5").s("square").octave(2)\n)'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  }
125
- return patterns.get(genre, 's("bd hh sn hh").gain(0.8)')
126
-
127
- def create_full_strudel_template(generated_code, include_visuals=True):
128
- """Wrap generated code in a complete Strudel template"""
129
 
130
- visual_code = """// Hydra visuals
131
- await initHydra({feedStrudel:5})
132
 
133
- osc(10, 0.1, 0.8)
134
- .kaleid(4)
135
- .color(1.5, 0.8, 1.2)
136
- .out()
137
 
138
  """ if include_visuals else ""
139
 
140
- template = f"""{visual_code}// AI-Generated Strudel Music Code
141
  {generated_code}
142
 
143
- // Global effects (optional)
144
- // all(x => x.fft(5).scope())
145
  """
146
 
147
  return template
148
 
149
- # Gradio interface
150
- def generate_interface(prompt, genre, complexity, include_visuals, max_length, temperature):
151
- """Main interface function"""
152
 
153
  if not prompt.strip():
154
  return "Please enter a description of the music you want to create."
155
 
156
- # Generate the core Strudel code
157
- generated_code = generate_strudel_code(
158
- prompt=prompt,
159
- genre=genre,
160
- complexity=complexity,
161
- max_length=max_length,
162
- temperature=temperature
163
- )
164
 
165
  # Create full template
166
- full_code = create_full_strudel_template(generated_code, include_visuals)
167
 
168
  return full_code
169
 
170
- # Create Gradio app
171
- with gr.Blocks(title="Strudel Code Generator", theme=gr.themes.Soft()) as app:
172
  gr.Markdown("""
173
- # 🎡 AI Strudel Code Generator
174
 
175
- Generate live coding music patterns using AI! Powered by CodeGen-350M.
176
 
177
- **How to use:**
178
- 1. Describe the music you want (e.g., "techno beat with bass", "ambient soundscape")
179
- 2. Choose genre and complexity
180
- 3. Click Generate
181
- 4. Copy the code to [strudel.cc](https://strudel.cc) to hear it!
 
182
 
183
- *Note: AI-generated code may need tweaking for best results.*
184
  """)
185
 
186
  with gr.Row():
187
  with gr.Column():
188
  prompt_input = gr.Textbox(
189
- label="Describe your music",
190
- placeholder="e.g., 'Create a techno beat with kick drum and hi-hats'",
191
  lines=3
192
  )
193
 
194
  with gr.Row():
195
  genre_dropdown = gr.Dropdown(
196
- choices=["general", "techno", "house", "ambient", "jazz", "rock", "experimental"],
197
  value="techno",
198
- label="Genre"
199
  )
200
 
201
  complexity_dropdown = gr.Dropdown(
202
  choices=["simple", "moderate", "complex"],
203
- value="simple",
204
- label="Complexity"
205
  )
206
 
207
- include_visuals = gr.Checkbox(
208
- label="Include Hydra visuals",
209
- value=True
210
- )
211
-
212
- with gr.Accordion("Advanced Settings", open=False):
213
- max_length_slider = gr.Slider(
214
- minimum=50,
215
- maximum=300,
216
- value=150,
217
- step=25,
218
- label="Max code length"
219
  )
220
 
221
- temperature_slider = gr.Slider(
222
- minimum=0.3,
223
- maximum=1.0,
224
- value=0.7,
225
- step=0.1,
226
- label="Creativity (temperature)"
227
  )
228
 
229
- generate_btn = gr.Button("🎡 Generate Strudel Code", variant="primary", size="lg")
 
 
 
 
 
 
230
 
231
  with gr.Column():
232
  output_code = gr.Code(
233
- label="Generated Strudel Code",
234
  language="javascript",
235
- lines=15
236
  )
237
 
238
  gr.Markdown("""
239
- **Next steps:**
240
- 1. **Copy** the generated code above
241
- 2. **Go to** [strudel.cc](https://strudel.cc)
242
- 3. **Paste** the code and **click play**
243
- 4. **Enjoy** your AI-generated music! 🎢
244
 
245
- *Tip: You can modify the generated code to customize the sound!*
 
 
 
 
246
  """)
247
 
248
- # Example buttons
249
- gr.Markdown("### πŸ’‘ Quick Examples")
250
  with gr.Row():
251
- examples = [
252
- ["Create a minimal techno beat", "techno", "simple"],
253
- ["Ambient soundscape with reverb", "ambient", "simple"],
254
- ["House music with bass line", "house", "moderate"],
255
- ["Jazz drum pattern", "jazz", "moderate"],
 
256
  ]
257
 
258
- for example_text, example_genre, example_complexity in examples:
259
- btn = gr.Button(f"{example_text}", size="sm")
260
  btn.click(
261
  lambda t=example_text, g=example_genre, c=example_complexity: (t, g, c),
262
  outputs=[prompt_input, genre_dropdown, complexity_dropdown]
@@ -270,8 +420,8 @@ with gr.Blocks(title="Strudel Code Generator", theme=gr.themes.Soft()) as app:
270
  genre_dropdown,
271
  complexity_dropdown,
272
  include_visuals,
273
- max_length_slider,
274
- temperature_slider
275
  ],
276
  outputs=output_code
277
  )
 
3
  import json
4
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
5
  import torch
6
+ import random
7
 
8
  # Use CodeGen instead of StarCoder (no authentication needed)
9
  MODEL_NAME = "Salesforce/codegen-350M-mono"
 
28
  device_map=None
29
  )
30
 
31
+ # Enhanced Strudel examples with more advanced patterns
32
+ ADVANCED_STRUDEL_EXAMPLES = """
33
+ // Dynamic techno with evolving patterns
34
+ stack(
35
+ s("bd*4, [~ rim]*2, hh*8").bank("RolandTR909").speed(0.9).gain(0.8),
36
+ n("[0 3 [5 0] [7 5]]*2").s("sawtooth").octave(2).lpf(sine.range(400,2000).slow(8)),
37
+ n("7 9 7 4").s("square").octave(5).slow(2).delay(0.25).room(0.6)
38
+ ).scale("a:minor")
39
 
40
+ // Polyrhythmic ambient
41
+ stack(
42
+ n("[0 2 4]/3").s("sine").octave(3).slow(8).room(0.9).gain(0.4),
43
+ n("[7 9 11]/5").s("triangle").octave(4).slow(12).delay(0.375).gain(0.3),
44
+ s("~ ~ ~ rim").slow(4).gain(0.2).room(0.8)
45
+ ).scale("d:minor")
46
 
47
+ // Generative house
48
  stack(
49
+ s("bd ~ ~ ~ bd ~ ~ ~").sometimes(fast(2)).gain(0.7),
50
+ n("0 [2 4] 7 [5 0]").s("sawtooth").octave(2).sometimes(add(note(12))),
51
+ s("[hh ch]*4").degradeBy(0.3).gain(0.5).pan(perlin.slow(2))
52
+ ).scale("g:minor")
53
 
54
+ // Experimental breakbeat
55
+ stack(
56
+ s("[bd sn]*2").sometimes(rev).speed(choose([0.8,1,1.2])),
57
+ n("0 4 7 0 2 5 7 2").s("square").cutoff(sine.range(200,2000)),
58
+ s("~ [perc:0 perc:1]/2").degradeBy(0.4).speed(rand.range(0.8,1.2))
59
+ )
60
  """
61
 
62
+ # Genre-specific pattern templates with advanced features
63
+ GENRE_TEMPLATES = {
64
+ "techno": {
65
+ "drums": ["bd*4", "[bd bd]*2", "bd ~ bd [bd bd]", "bd*4, [~ rim]*2"],
66
+ "hats": ["hh*8", "[hh ch]*4", "~ hh ~ [hh ch]", "[oh ch hh]*2"],
67
+ "bass": ["0 ~ 3 ~", "[0 3 [5 0] 7]*2", "0 0 3 5", "[0 ~ 3] [~ 7]"],
68
+ "lead": ["7 9 7 4", "[0 4 7]*2", "9 7 4 2", "[7 9] [4 7] [2 4]"],
69
+ "effects": [".lpf(sine.range(400,2000).slow(8))", ".delay(0.25).room(0.6)", ".sometimes(add(note(12)))", ".cutoff(perlin.range(800,3000))"]
70
+ },
71
+ "house": {
72
+ "drums": ["bd ~ ~ ~ bd ~ ~ ~", "[bd ~ bd]*2", "bd ~ [~ bd] ~"],
73
+ "hats": ["~ hh ~ hh", "[~ ch ~ hh]*2", "hh ~ ch ~"],
74
+ "bass": ["0 2 4 7", "[0 ~ 2] [~ 4]", "0 4 2 7", "[0 2] [4 7]"],
75
+ "lead": ["[0 2 4]*2", "7 4 2 0", "[2 4 7]*3", "0 4 7 9"],
76
+ "effects": [".room(0.6).delay(0.125)", ".lpf(2000).sometimes(add(note(7)))", ".gain(sine.range(0.4,0.8).slow(4))", ".pan(cosine.slow(8))"]
77
+ },
78
+ "ambient": {
79
+ "drums": ["~ ~ ~ rim", "bd ~ ~ ~", "~ ~ rim ~"],
80
+ "hats": ["~ ~ hh ~", "~ ch ~ ~", ""],
81
+ "bass": ["[0 2 4]/3", "[0 4]/2", "[2 7]/5", "[0 2 4 7]/4"],
82
+ "lead": ["[7 9 11]/5", "[0 4 7]*2", "[2 4 9]/3", "[7 11 14]/7"],
83
+ "effects": [".slow(8).room(0.9)", ".slow(12).delay(0.375)", ".slow(16).gain(0.3)", ".slow(6).lpf(800).room(0.8)"]
84
+ },
85
+ "breakbeat": {
86
+ "drums": ["[bd sn]*2", "bd [sn sn] bd sn", "[bd ~ sn ~]*2"],
87
+ "hats": ["[hh ch]*4", "hh*8", "[ch hh hh]*2"],
88
+ "bass": ["0 4 7 0 2 5 7 2", "[0 ~ 7] [3 5]", "0 7 4 2"],
89
+ "lead": ["[0 4 7]*3", "9 7 4 0", "[7 4] [2 0]"],
90
+ "effects": [".speed(choose([0.8,1,1.2]))", ".degradeBy(0.3)", ".sometimes(rev)", ".cutoff(rand.range(400,2000))"]
91
+ },
92
+ "experimental": {
93
+ "drums": ["[bd rim]*3", "bd ~ [perc:0 perc:1]", "[~ bd] [rim ~]"],
94
+ "hats": ["[ch oh]*5", "~ [hh hh] ~", "[noise:0]/8"],
95
+ "bass": ["[0 3 7]/5", "[0 ~ 4] [~ 7]", "0 [2 5] 7"],
96
+ "lead": ["[0 4 7 11]/7", "[9 7] [4 2]", "[0 ~ 7] [~ 4]"],
97
+ "effects": [".degradeBy(rand.range(0.1,0.5))", ".speed(perlin.range(0.5,1.5))", ".pan(sine.slow(3))", ".room(cosine.range(0.2,0.9))"]
98
+ }
99
+ }
100
+
101
+ def generate_enhanced_strudel_code(prompt, genre="techno", complexity="moderate", include_polyrhythm=True, include_effects=True):
102
+ """Generate more sophisticated Strudel code"""
103
+
104
+ # Get genre templates
105
+ templates = GENRE_TEMPLATES.get(genre, GENRE_TEMPLATES["techno"])
106
+
107
+ # Build complexity-based structure
108
+ if complexity == "simple":
109
+ layers = 2
110
+ pattern_complexity = 1
111
+ elif complexity == "moderate":
112
+ layers = 3
113
+ pattern_complexity = 2
114
+ else: # complex
115
+ layers = 4
116
+ pattern_complexity = 3
117
+
118
+ # Generate drum layer
119
+ drum_pattern = random.choice(templates["drums"])
120
+ hat_pattern = random.choice(templates["hats"])
121
+
122
+ if hat_pattern:
123
+ drum_code = f's("{drum_pattern}, {hat_pattern}").gain(0.8)'
124
+ else:
125
+ drum_code = f's("{drum_pattern}").gain(0.8)'
126
+
127
+ layers_code = [drum_code]
128
+
129
+ # Generate bass layer
130
+ bass_pattern = random.choice(templates["bass"])
131
+ bass_effect = random.choice(templates["effects"]) if include_effects else ""
132
+ bass_synth = random.choice(["sawtooth", "sine", "square"])
133
+ octave = random.choice([1, 2])
134
+
135
+ bass_code = f'n("{bass_pattern}").s("{bass_synth}").octave({octave}){bass_effect}.gain(0.7)'
136
+ layers_code.append(bass_code)
137
+
138
+ # Add lead layer if complexity allows
139
+ if layers >= 3:
140
+ lead_pattern = random.choice(templates["lead"])
141
+ lead_effect = random.choice(templates["effects"]) if include_effects else ""
142
+ lead_synth = random.choice(["square", "triangle", "sawtooth"])
143
+ lead_octave = random.choice([4, 5])
144
+
145
+ lead_code = f'n("{lead_pattern}").s("{lead_synth}").octave({lead_octave}){lead_effect}.gain(0.5)'
146
+ layers_code.append(lead_code)
147
+
148
+ # Add atmospheric layer for complex patterns
149
+ if layers >= 4:
150
+ if genre == "ambient":
151
+ atmo_code = 'n("[0 2 4]/7").s("sine").octave(3).slow(16).room(0.9).gain(0.3)'
152
+ else:
153
+ perc_sounds = ["perc:0", "perc:1", "rim", "clap"]
154
+ perc_pattern = random.choice(perc_sounds)
155
+ atmo_code = f's("~ ~ {perc_pattern} ~").slow(2).gain(0.4).room(0.6)'
156
+ layers_code.append(atmo_code)
157
+
158
+ # Choose random scale
159
+ scales = ["a:minor", "d:minor", "g:minor", "c:major", "e:minor", "f:major"]
160
+ scale = random.choice(scales)
161
+
162
+ # Build final code
163
+ if len(layers_code) == 1:
164
+ final_code = f'{layers_code[0]}.scale("{scale}")'
165
+ else:
166
+ layers_str = ',\n '.join(layers_code)
167
+ final_code = f'stack(\n {layers_str}\n).scale("{scale}")'
168
+
169
+ # Add advanced features based on complexity
170
+ if complexity == "complex" and include_polyrhythm:
171
+ final_code += '\n\n// Add some spice\n'
172
+ spice_options = [
173
+ '.sometimes(fast(2))',
174
+ '.sometimes(slow(2))',
175
+ '.degradeBy(0.2)',
176
+ '.sometimes(rev)',
177
+ '.euclid(3,8)'
178
+ ]
179
+ final_code += f'// {random.choice(spice_options)}'
180
+
181
+ return final_code
182
+
183
+ def create_ai_assisted_code(prompt, genre, complexity):
184
+ """Create AI-assisted code with fallback to enhanced patterns"""
185
 
186
+ # Try AI generation first
187
+ system_prompt = f"""// Advanced Strudel live coding patterns
188
+ // Examples with complex features:
189
+ {ADVANCED_STRUDEL_EXAMPLES}
 
190
 
191
+ // Generate {complexity} {genre} pattern for: {prompt}
192
+ // Use stack(), effects, and dynamic patterns
193
  // Code:
194
  """
195
 
196
  try:
 
197
  outputs = code_generator(
198
  system_prompt,
199
+ max_length=len(system_prompt.split()) + 100,
200
+ temperature=0.8,
201
  do_sample=True,
202
  top_p=0.9,
203
  num_return_sequences=1,
204
  pad_token_id=code_generator.tokenizer.eos_token_id
205
  )
206
 
 
207
  generated_text = outputs[0]['generated_text']
 
 
208
  strudel_code = generated_text[len(system_prompt):].strip()
 
 
209
  strudel_code = clean_strudel_code(strudel_code)
210
 
211
+ # If AI generation is too simple or fails, enhance it
212
+ if len(strudel_code.split('\n')) < 3 or 'stack(' not in strudel_code:
213
+ strudel_code = generate_enhanced_strudel_code(prompt, genre, complexity)
214
+
215
  return strudel_code
216
 
217
  except Exception as e:
218
+ # Fallback to enhanced generation
219
+ return generate_enhanced_strudel_code(prompt, genre, complexity)
220
 
221
  def clean_strudel_code(code):
222
+ """Enhanced code cleaning with better pattern recognition"""
223
  lines = code.split('\n')
224
  cleaned_lines = []
225
+ in_stack = False
226
 
227
  for line in lines:
228
  line = line.strip()
229
+
230
+ # Detect stack structures
231
+ if 'stack(' in line:
232
+ in_stack = True
233
+ cleaned_lines.append(line)
234
+ continue
235
+
236
+ if in_stack and line == ')':
237
+ cleaned_lines.append(line)
238
+ in_stack = False
239
+ continue
240
+
241
+ # Include valid Strudel patterns
242
+ if (line.startswith('s(') or line.startswith('n(') or line.startswith('$:') or
243
+ line.startswith('all(') or '.scale(' in line or in_stack or
244
+ any(pattern in line for pattern in ['.gain(', '.lpf(', '.room(', '.delay(', '.octave('])):
245
  cleaned_lines.append(line)
246
+
247
+ # Stop at non-Strudel code
248
+ elif any(keyword in line for keyword in ['function', 'var ', 'let ', 'const ', 'import']):
249
  break
250
 
251
+ if len(cleaned_lines) >= 12:
252
  break
253
 
254
+ return '\n'.join(cleaned_lines) if cleaned_lines else generate_enhanced_strudel_code("fallback", "techno", "simple")
 
 
 
 
255
 
256
+ def create_full_strudel_template(generated_code, include_visuals=True, visual_style="reactive"):
257
+ """Enhanced template with better visuals"""
258
+
259
+ visual_styles = {
260
+ "reactive": """osc(8, 0.1, 1.2)
261
+ .color(1.8, 0.8, 1.5)
262
+ .modulate(noise(2), 0.3)
263
+ .kaleid(6)
264
+ .rotate(0, 0.05)
265
+ .out()""",
266
+ "kaleidoscope": """shape(6, 0.3, 0.01)
267
+ .repeat(4, 3)
268
+ .rotate(0, 0.03)
269
+ .color(1.2, 1.8, 0.8)
270
+ .kaleid(8)
271
+ .out()""",
272
+ "flowing": """noise(3, 0.1)
273
+ .color(1.5, 1.2, 0.8)
274
+ .modulate(osc(2, 0.05), 0.4)
275
+ .diff(osc(5, 0.1).color(0.8, 1.5, 1.2))
276
+ .contrast(1.4)
277
+ .out()""",
278
+ "geometric": """osc(12, 0.02, 0.8)
279
+ .pixelate(32, 24)
280
+ .color(2, 0.8, 1.5)
281
+ .add(shape(4).scale(0.3).repeat(6, 4))
282
+ .contrast(1.6)
283
+ .out()"""
284
  }
 
 
 
 
285
 
286
+ visual_code = f"""// Enhanced Hydra visuals
287
+ await initHydra({{feedStrudel:5}})
288
 
289
+ {visual_styles[visual_style]}
 
 
 
290
 
291
  """ if include_visuals else ""
292
 
293
+ template = f"""{visual_code}// 🎡 AI-Enhanced Strudel Code
294
  {generated_code}
295
 
296
+ // Optional global effects
297
+ // all(x => x.fft(5).scope().compressor(0.8))
298
  """
299
 
300
  return template
301
 
302
+ # Enhanced Gradio interface
303
+ def generate_interface(prompt, genre, complexity, include_visuals, visual_style, use_ai_assist):
304
+ """Enhanced interface with more options"""
305
 
306
  if not prompt.strip():
307
  return "Please enter a description of the music you want to create."
308
 
309
+ # Generate enhanced code
310
+ if use_ai_assist:
311
+ generated_code = create_ai_assisted_code(prompt, genre, complexity)
312
+ else:
313
+ generated_code = generate_enhanced_strudel_code(prompt, genre, complexity, True, True)
 
 
 
314
 
315
  # Create full template
316
+ full_code = create_full_strudel_template(generated_code, include_visuals, visual_style)
317
 
318
  return full_code
319
 
320
+ # Create enhanced Gradio app
321
+ with gr.Blocks(title="Enhanced Strudel Generator", theme=gr.themes.Soft()) as app:
322
  gr.Markdown("""
323
+ # 🎡 Enhanced AI Strudel Generator
324
 
325
+ Generate sophisticated live coding music with **advanced patterns**, **polyrhythms**, and **dynamic effects**!
326
 
327
+ **New Features:**
328
+ - πŸ”₯ **Complex polyrhythmic patterns** with stack() structures
329
+ - πŸŽ›οΈ **Dynamic effects** (LPF sweeps, delays, reverb, degradation)
330
+ - 🎨 **Multiple visual styles** (reactive, kaleidoscope, flowing, geometric)
331
+ - ⚑ **AI-assisted generation** with smart fallbacks
332
+ - 🎡 **Genre-specific templates** with authentic patterns
333
 
334
+ **Usage:** Describe your music β†’ Choose settings β†’ Generate β†’ Copy to [strudel.cc](https://strudel.cc)
335
  """)
336
 
337
  with gr.Row():
338
  with gr.Column():
339
  prompt_input = gr.Textbox(
340
+ label="🎼 Describe your music",
341
+ placeholder="e.g., 'Dark techno with evolving bassline', 'Polyrhythmic ambient with textures', 'Breakbeat with glitch effects'",
342
  lines=3
343
  )
344
 
345
  with gr.Row():
346
  genre_dropdown = gr.Dropdown(
347
+ choices=["techno", "house", "ambient", "breakbeat", "experimental"],
348
  value="techno",
349
+ label="🎡 Genre"
350
  )
351
 
352
  complexity_dropdown = gr.Dropdown(
353
  choices=["simple", "moderate", "complex"],
354
+ value="moderate",
355
+ label="βš™οΈ Complexity"
356
  )
357
 
358
+ with gr.Row():
359
+ include_visuals = gr.Checkbox(
360
+ label="🎨 Include Hydra visuals",
361
+ value=True
 
 
 
 
 
 
 
 
362
  )
363
 
364
+ use_ai_assist = gr.Checkbox(
365
+ label="πŸ€– AI-assisted generation",
366
+ value=True
 
 
 
367
  )
368
 
369
+ visual_style = gr.Dropdown(
370
+ choices=["reactive", "kaleidoscope", "flowing", "geometric"],
371
+ value="reactive",
372
+ label="πŸ‘οΈ Visual Style"
373
+ )
374
+
375
+ generate_btn = gr.Button("πŸš€ Generate Enhanced Code", variant="primary", size="lg")
376
 
377
  with gr.Column():
378
  output_code = gr.Code(
379
+ label="Generated Enhanced Strudel Code",
380
  language="javascript",
381
+ lines=20
382
  )
383
 
384
  gr.Markdown("""
385
+ **🎯 Next Steps:**
386
+ 1. **Copy** the generated code
387
+ 2. **Open** [strudel.cc](https://strudel.cc)
388
+ 3. **Paste & Play** - enjoy your enhanced music!
 
389
 
390
+ **πŸ’‘ Pro Tips:**
391
+ - Adjust `.gain()` values to balance layers
392
+ - Try `.sometimes()` for variation
393
+ - Use `.degradeBy()` for glitchy effects
394
+ - Experiment with `.slow()` and `.fast()`
395
  """)
396
 
397
+ # Enhanced examples
398
+ gr.Markdown("### πŸŽͺ Creative Examples")
399
  with gr.Row():
400
+ enhanced_examples = [
401
+ ["Dark techno with evolving filter sweeps", "techno", "complex"],
402
+ ["Polyrhythmic ambient soundscape", "ambient", "complex"],
403
+ ["Breakbeat with glitch and degradation", "breakbeat", "complex"],
404
+ ["Deep house with swinging groove", "house", "moderate"],
405
+ ["Experimental noise textures", "experimental", "complex"],
406
  ]
407
 
408
+ for example_text, example_genre, example_complexity in enhanced_examples:
409
+ btn = gr.Button(f"✨ {example_text}", size="sm")
410
  btn.click(
411
  lambda t=example_text, g=example_genre, c=example_complexity: (t, g, c),
412
  outputs=[prompt_input, genre_dropdown, complexity_dropdown]
 
420
  genre_dropdown,
421
  complexity_dropdown,
422
  include_visuals,
423
+ visual_style,
424
+ use_ai_assist
425
  ],
426
  outputs=output_code
427
  )