Update app.py
Browse files
app.py
CHANGED
@@ -28,92 +28,165 @@ except Exception as e:
|
|
28 |
device_map=None
|
29 |
)
|
30 |
|
31 |
-
#
|
32 |
WORKING_PATTERNS = {
|
33 |
"techno": [
|
34 |
"""stack(
|
35 |
-
s("bd*4").gain(0.
|
36 |
-
s("~ hh ~ hh").gain(0.
|
37 |
-
n("0 ~ 3 ~").s("sawtooth").octave(2).lpf(1200).gain(0.
|
|
|
38 |
).scale("a:minor")""",
|
39 |
|
40 |
"""stack(
|
41 |
-
s("bd bd ~ bd").gain(0.
|
42 |
-
s("[hh ch]*4").gain(0.
|
43 |
-
n("[0 3 5 7]*2").s("square").octave(2).cutoff(
|
44 |
-
n("7 9 7 4").s("triangle").octave(4).delay(0.25).gain(0.5)
|
45 |
).scale("d:minor")""",
|
46 |
|
47 |
"""stack(
|
48 |
-
s("bd*4, ~ rim
|
49 |
-
n("0 0 3 3").s("sawtooth").octave(2).lpf(2000).gain(0.
|
50 |
-
n("[7 9]*4").s("square").octave(4).room(0.
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
],
|
53 |
|
54 |
"house": [
|
55 |
"""stack(
|
56 |
-
s("bd ~ ~ ~ bd ~ ~ ~").gain(0.
|
57 |
s("~ hh ~ hh").gain(0.5),
|
58 |
-
n("0 2 4 7").s("sine").octave(3).room(0.6).gain(0.
|
|
|
59 |
).scale("c:major")""",
|
60 |
|
61 |
"""stack(
|
62 |
-
s("bd ~ [~ bd] ~").gain(0.8),
|
63 |
-
s("[~ ch ~ hh]*2").gain(0.4),
|
64 |
-
n("[0 4 7]*2").s("sawtooth").octave(2).lpf(1500).gain(0.
|
65 |
-
n("0 7 4 2").s("triangle").octave(4).delay(0.125).gain(0.
|
66 |
).scale("f:major")""",
|
67 |
|
68 |
"""stack(
|
69 |
-
s("bd ~ ~ ~ bd ~ ~ ~").
|
70 |
-
n("[0 2] [4 7] [2 4] [7 0]").s("sine").octave(2).gain(0.
|
71 |
-
s("hh*8").degradeBy(0.3).gain(0.
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
],
|
74 |
|
75 |
"ambient": [
|
76 |
"""stack(
|
77 |
-
s("~ ~ ~ rim").slow(
|
78 |
-
n("[0 2 4]/3").s("sine").octave(3).slow(
|
79 |
-
n("[7 9 11]/5").s("triangle").octave(4).slow(
|
|
|
80 |
).scale("d:minor")""",
|
81 |
|
82 |
"""stack(
|
83 |
-
n("0 2 4 7").s("sine").octave(2).slow(
|
84 |
-
n("[4 7 9]/7").s("triangle").octave(4).slow(12).delay(0.
|
85 |
-
s("~ ~ rim ~").slow(
|
|
|
86 |
).scale("a:minor")""",
|
87 |
|
88 |
-
"""n("[0 4 7 11]/4").s("sine").octave(3).slow(
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
],
|
90 |
|
91 |
"breakbeat": [
|
92 |
"""stack(
|
93 |
-
s("[bd sn]*2").sometimes(rev).gain(0.
|
94 |
-
s("[hh ch]*4").degradeBy(0.
|
95 |
-
n("0 4 7 0").s("square").octave(2).cutoff(1000).gain(0.
|
|
|
96 |
).scale("a:minor")""",
|
97 |
|
98 |
"""stack(
|
99 |
-
s("bd [sn sn] bd sn").speed(0.
|
100 |
-
n("[0 ~ 7] [3 5]").s("sawtooth").octave(2).lpf(1500).gain(0.
|
101 |
-
s("hh*8").sometimes(fast(2)).gain(0.
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
],
|
104 |
|
105 |
"experimental": [
|
106 |
"""stack(
|
107 |
-
s("[bd rim]*3").degradeBy(0.
|
108 |
-
n("[0 3 7]/5").s("square").octave(2).cutoff(perlin.range(400,2000)).gain(0.
|
109 |
-
s("~ [hh hh] ~").pan(sine.slow(3)).gain(0.
|
|
|
110 |
).scale("g:minor")""",
|
111 |
|
112 |
"""stack(
|
113 |
-
s("bd ~ [perc:0 perc:1]").speed(rand.range(0.
|
114 |
-
n("0 [2 5] 7").s("sawtooth").octave(2).sometimes(add(note(12))).gain(0.
|
115 |
-
s("[ch oh]*5").degradeBy(0.
|
116 |
-
).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
]
|
118 |
}
|
119 |
|
@@ -124,11 +197,12 @@ def get_random_working_pattern(genre, complexity="moderate"):
|
|
124 |
if complexity == "simple":
|
125 |
# Return simpler single-line patterns
|
126 |
simple_patterns = {
|
127 |
-
"techno": 's("bd*4").gain(0.8)',
|
128 |
-
"house": 's("bd ~ ~ ~ bd ~ ~ ~").gain(0.7)',
|
129 |
-
"ambient": 'n("[0 2 4]/3").s("sine").octave(3).slow(
|
130 |
-
"breakbeat": 's("[bd sn]*2").gain(0.8)',
|
131 |
-
"experimental": 's("bd ~ [perc:0 perc:1]").degradeBy(0.4).gain(0.7)'
|
|
|
132 |
}
|
133 |
return simple_patterns.get(genre, simple_patterns["techno"])
|
134 |
|
@@ -151,7 +225,7 @@ def create_variations(base_pattern, genre):
|
|
151 |
variations.append(base_pattern.replace(".gain(0.8)", ".gain(0.8).room(0.4)"))
|
152 |
|
153 |
# Scale variations
|
154 |
-
scales = ["a:minor", "d:minor", "g:minor", "c:major", "f:major", "e:minor"]
|
155 |
for scale in scales:
|
156 |
if scale not in base_pattern:
|
157 |
new_pattern = base_pattern
|
@@ -172,29 +246,33 @@ def generate_working_strudel_code(prompt, genre="techno", complexity="moderate")
|
|
172 |
base_pattern = get_random_working_pattern(genre, complexity)
|
173 |
|
174 |
# Create variations based on prompt keywords
|
175 |
-
if any(word in prompt.lower() for word in ["fast", "speed", "quick", "rapid"]):
|
176 |
if "sometimes(fast(2))" not in base_pattern:
|
177 |
base_pattern = base_pattern.replace(".gain(", ".sometimes(fast(2)).gain(")
|
178 |
|
179 |
-
if any(word in prompt.lower() for word in ["slow", "chill", "ambient", "relaxed"]):
|
180 |
if ".slow(" not in base_pattern:
|
181 |
base_pattern = base_pattern.replace(".gain(", ".slow(2).gain(")
|
182 |
|
183 |
-
if any(word in prompt.lower() for word in ["reverb", "space", "room", "hall"]):
|
184 |
if ".room(" not in base_pattern:
|
185 |
-
base_pattern = base_pattern.replace(".gain(", ".room(0.
|
186 |
|
187 |
-
if any(word in prompt.lower() for word in ["delay", "echo", "repeat"]):
|
188 |
if ".delay(" not in base_pattern:
|
189 |
base_pattern = base_pattern.replace(".gain(", ".delay(0.25).gain(")
|
190 |
|
191 |
-
if any(word in prompt.lower() for word in ["filter", "sweep", "cutoff", "lpf"]):
|
192 |
if ".lpf(" not in base_pattern and ".cutoff(" not in base_pattern:
|
193 |
-
base_pattern = base_pattern.replace(".gain(", ".lpf(
|
194 |
|
195 |
-
if any(word in prompt.lower() for word in ["glitch", "degraded", "broken", "corrupt"]):
|
196 |
if ".degradeBy(" not in base_pattern:
|
197 |
-
base_pattern = base_pattern.replace(".gain(", ".degradeBy(0.
|
|
|
|
|
|
|
|
|
198 |
|
199 |
# Add comment based on prompt
|
200 |
comment_line = f"// {prompt[:50]}{'...' if len(prompt) > 50 else ''}"
|
@@ -256,21 +334,22 @@ def generate_interface(prompt, genre, complexity, include_visuals, visual_style,
|
|
256 |
return "Please enter a description of the music you want to create."
|
257 |
|
258 |
if use_ai:
|
259 |
-
# Use AI generation
|
260 |
system_prompt = f"""Generate working Strudel live coding pattern for: {prompt}
|
261 |
Genre: {genre}, Complexity: {complexity}
|
262 |
|
263 |
-
Example patterns:
|
264 |
-
s("bd*4").gain(0.8)
|
265 |
-
stack(s("bd ~
|
|
|
266 |
|
267 |
-
|
268 |
|
269 |
try:
|
270 |
outputs = code_generator(
|
271 |
system_prompt,
|
272 |
-
max_length=len(system_prompt.split()) +
|
273 |
-
temperature=0.
|
274 |
do_sample=True,
|
275 |
top_p=0.9,
|
276 |
num_return_sequences=1
|
@@ -279,26 +358,32 @@ Pattern:"""
|
|
279 |
generated_text = outputs[0]['generated_text']
|
280 |
strudel_code = generated_text[len(system_prompt):].strip()
|
281 |
|
282 |
-
# Clean the AI output
|
283 |
lines = strudel_code.split('\n')
|
284 |
clean_lines = []
|
285 |
-
for line in lines[:
|
286 |
line = line.strip()
|
|
|
287 |
if line and (line.startswith('s(') or line.startswith('n(') or line.startswith('stack(') or
|
288 |
-
'.gain(' in line or '.s(' in line or line.
|
|
|
289 |
clean_lines.append(line)
|
|
|
|
|
|
|
290 |
|
291 |
if clean_lines:
|
292 |
strudel_code = '\n'.join(clean_lines)
|
293 |
strudel_code = f"// AI Generated: {prompt}\n{strudel_code}"
|
294 |
else:
|
295 |
-
# Fallback to
|
296 |
strudel_code = generate_working_strudel_code(prompt, genre, complexity)
|
297 |
-
except:
|
298 |
-
# Fallback to
|
|
|
299 |
strudel_code = generate_working_strudel_code(prompt, genre, complexity)
|
300 |
else:
|
301 |
-
# Use
|
302 |
strudel_code = generate_working_strudel_code(prompt, genre, complexity)
|
303 |
|
304 |
# Create complete working template
|
@@ -311,12 +396,13 @@ with gr.Blocks(title="Working Strudel Generator", theme=gr.themes.Soft()) as app
|
|
311 |
gr.Markdown("""
|
312 |
# π΅ CODEL: Strudel Code Generator
|
313 |
|
314 |
-
Generate Strudel live coding patterns!
|
315 |
|
316 |
-
β
**
|
317 |
ποΈ **Real Strudel syntax** - copy & paste ready
|
318 |
-
π¨ **
|
319 |
-
π΅ **
|
|
|
320 |
|
321 |
**Usage:** Describe music β Generate β Copy to [strudel.cc](https://strudel.cc) β Play!
|
322 |
""")
|
@@ -331,7 +417,7 @@ with gr.Blocks(title="Working Strudel Generator", theme=gr.themes.Soft()) as app
|
|
331 |
|
332 |
with gr.Row():
|
333 |
genre_dropdown = gr.Dropdown(
|
334 |
-
choices=["techno", "house", "ambient", "breakbeat", "experimental"],
|
335 |
value="techno",
|
336 |
label="π΅ Genre"
|
337 |
)
|
@@ -359,11 +445,11 @@ with gr.Blocks(title="Working Strudel Generator", theme=gr.themes.Soft()) as app
|
|
359 |
label="ποΈ Visual Style"
|
360 |
)
|
361 |
|
362 |
-
generate_btn = gr.Button("π΅ Generate
|
363 |
|
364 |
with gr.Column():
|
365 |
output_code = gr.Code(
|
366 |
-
label="β
|
367 |
language="javascript",
|
368 |
lines=18
|
369 |
)
|
@@ -374,26 +460,26 @@ with gr.Blocks(title="Working Strudel Generator", theme=gr.themes.Soft()) as app
|
|
374 |
2. **Go to** [strudel.cc](https://strudel.cc)
|
375 |
3. **Paste** and **click the play button** βΆοΈ
|
376 |
|
377 |
-
**π§
|
378 |
-
- Change `.gain()` values (0.1 to 1.0)
|
379 |
-
- Try different scales: "a:minor", "c:major",
|
380 |
-
-
|
381 |
-
- Add `.room()
|
382 |
""")
|
383 |
|
384 |
-
#
|
385 |
-
gr.Markdown("### πͺ
|
386 |
with gr.Row():
|
387 |
working_examples = [
|
388 |
-
["
|
389 |
-
["
|
390 |
-
["
|
391 |
-
["
|
392 |
-
["
|
393 |
]
|
394 |
|
395 |
for example_text, example_genre, example_complexity in working_examples:
|
396 |
-
btn = gr.Button(f"
|
397 |
btn.click(
|
398 |
lambda t=example_text, g=example_genre, c=example_complexity: (t, g, c),
|
399 |
outputs=[prompt_input, genre_dropdown, complexity_dropdown]
|
|
|
28 |
device_map=None
|
29 |
)
|
30 |
|
31 |
+
# Enhanced working Strudel patterns - these are all tested and functional
|
32 |
WORKING_PATTERNS = {
|
33 |
"techno": [
|
34 |
"""stack(
|
35 |
+
s("bd*4").gain(0.9),
|
36 |
+
s("~ hh ~ hh").gain(0.6),
|
37 |
+
n("0 ~ 3 ~").s("sawtooth").octave(2).lpf(1200).gain(0.8),
|
38 |
+
s("~ ~ rim ~").slow(2).gain(0.5)
|
39 |
).scale("a:minor")""",
|
40 |
|
41 |
"""stack(
|
42 |
+
s("bd bd ~ bd, ~ rim ~ rim").bank("RolandTR909").gain(0.9),
|
43 |
+
s("[hh ch]*4").degradeBy(0.1).gain(0.5),
|
44 |
+
n("[0 3 5 7]*2").s("square").octave(2).cutoff(sine.range(400,1600).slow(8)).gain(0.7),
|
45 |
+
n("7 9 7 4").s("triangle").octave(4).delay(0.25).room(0.4).gain(0.5)
|
46 |
).scale("d:minor")""",
|
47 |
|
48 |
"""stack(
|
49 |
+
s("bd*4, [~ rim]*2, hh*8").bank("RolandTR909").speed(0.95).gain(0.8),
|
50 |
+
n("0 0 3 3").s("sawtooth").octave(2).lpf(2000).lpq(8).gain(0.8),
|
51 |
+
n("[7 9]*4").s("square").octave(4).room(0.5).cutoff(1800).gain(0.4),
|
52 |
+
s("~ ~ ~ clap").slow(2).gain(0.6).room(0.3)
|
53 |
+
).scale("g:minor")""",
|
54 |
+
|
55 |
+
"""stack(
|
56 |
+
s("bd*4").sometimes(fast(2)).gain(0.9),
|
57 |
+
s("hh*8").degradeBy(0.2).gain(0.4),
|
58 |
+
n("[0 3 [5 0] 7]*2").s("sawtooth").octave(2).lpf(sine.range(600,2400).slow(4)).gain(0.8),
|
59 |
+
n("0 7 4 2").s("triangle").octave(5).delay(0.125).room(0.6).gain(0.5)
|
60 |
+
).scale("e:minor")"""
|
61 |
],
|
62 |
|
63 |
"house": [
|
64 |
"""stack(
|
65 |
+
s("bd ~ ~ ~ bd ~ ~ ~").gain(0.8),
|
66 |
s("~ hh ~ hh").gain(0.5),
|
67 |
+
n("0 2 4 7").s("sine").octave(3).room(0.6).gain(0.7),
|
68 |
+
s("~ ~ ~ clap").gain(0.6)
|
69 |
).scale("c:major")""",
|
70 |
|
71 |
"""stack(
|
72 |
+
s("bd ~ [~ bd] ~").sometimes(fast(2)).gain(0.8),
|
73 |
+
s("[~ ch ~ hh]*2").pan(sine.slow(4)).gain(0.4),
|
74 |
+
n("[0 4 7]*2").s("sawtooth").octave(2).lpf(1500).gain(0.8),
|
75 |
+
n("0 7 4 2").s("triangle").octave(4).delay(0.125).room(0.5).gain(0.5)
|
76 |
).scale("f:major")""",
|
77 |
|
78 |
"""stack(
|
79 |
+
s("bd ~ ~ ~ bd ~ ~ ~").gain(0.8),
|
80 |
+
n("[0 2] [4 7] [2 4] [7 0]").s("sine").octave(2).lpf(2000).gain(0.7),
|
81 |
+
s("hh*8").degradeBy(0.3).pan(cosine.slow(6)).gain(0.4),
|
82 |
+
s("~ ~ clap ~").room(0.4).gain(0.6)
|
83 |
+
).scale("g:major")""",
|
84 |
+
|
85 |
+
"""stack(
|
86 |
+
s("bd ~ [bd ~] [~ bd] ~").gain(0.8),
|
87 |
+
s("~ hh ~ [hh ch]").gain(0.5),
|
88 |
+
n("0 4 7 9").s("sawtooth").octave(2).sometimes(add(note(12))).lpf(1800).gain(0.7),
|
89 |
+
n("[2 4]*4").s("triangle").octave(4).delay(0.25).gain(0.4)
|
90 |
+
).scale("d:major")"""
|
91 |
],
|
92 |
|
93 |
"ambient": [
|
94 |
"""stack(
|
95 |
+
s("~ ~ ~ rim").slow(4).gain(0.3).room(0.9),
|
96 |
+
n("[0 2 4]/3").s("sine").octave(3).slow(8).room(0.9).lpf(800).gain(0.6),
|
97 |
+
n("[7 9 11]/5").s("triangle").octave(4).slow(12).delay(0.5).room(0.8).gain(0.4),
|
98 |
+
n("[0 4]/7").s("sawtooth").octave(2).slow(16).lpf(400).gain(0.3)
|
99 |
).scale("d:minor")""",
|
100 |
|
101 |
"""stack(
|
102 |
+
n("0 2 4 7").s("sine").octave(2).slow(16).room(0.9).lpf(600).gain(0.5),
|
103 |
+
n("[4 7 9]/7").s("triangle").octave(4).slow(12).delay(0.75).room(0.9).gain(0.4),
|
104 |
+
s("~ ~ rim ~").slow(8).gain(0.2).room(0.9),
|
105 |
+
n("[11 14]/11").s("sine").octave(5).slow(20).gain(0.3)
|
106 |
).scale("a:minor")""",
|
107 |
|
108 |
+
"""n("[0 4 7 11]/4").s("sine").octave(3).slow(12).room(0.9).lpf(perlin.range(400,1200).slow(8)).gain(0.7).scale("e:minor")""",
|
109 |
+
|
110 |
+
"""stack(
|
111 |
+
n("[0 2]/5").s("sine").octave(2).slow(16).room(0.9).gain(0.4),
|
112 |
+
n("[4 7]/7").s("triangle").octave(4).slow(20).delay(1).room(0.9).gain(0.3),
|
113 |
+
s("~ ~ ~ [rim vinyl]").slow(8).gain(0.2).room(0.9)
|
114 |
+
).scale("f:major")"""
|
115 |
],
|
116 |
|
117 |
"breakbeat": [
|
118 |
"""stack(
|
119 |
+
s("[bd sn]*2").sometimes(rev).speed(0.9).gain(0.9),
|
120 |
+
s("[hh ch]*4").degradeBy(0.3).gain(0.6),
|
121 |
+
n("0 4 7 0").s("square").octave(2).cutoff(1000).gain(0.8),
|
122 |
+
s("~ [perc:0 perc:1] ~").gain(0.4)
|
123 |
).scale("a:minor")""",
|
124 |
|
125 |
"""stack(
|
126 |
+
s("bd [sn sn] bd sn").speed(0.85).gain(0.9),
|
127 |
+
n("[0 ~ 7] [3 5]").s("sawtooth").octave(2).lpf(1500).gain(0.7),
|
128 |
+
s("hh*8").sometimes(fast(2)).degradeBy(0.2).gain(0.5),
|
129 |
+
s("~ ~ [perc:2 perc:3] ~").gain(0.5)
|
130 |
+
).scale("d:minor")""",
|
131 |
+
|
132 |
+
"""stack(
|
133 |
+
s("[bd ~ sn ~]*2").sometimes(rev).gain(0.9),
|
134 |
+
s("[hh ch oh]*3").degradeBy(0.4).pan(perlin.slow(2)).gain(0.5),
|
135 |
+
n("[0 7 4 2]*2").s("square").octave(2).cutoff(rand.range(600,1800)).gain(0.7)
|
136 |
+
).scale("g:minor")"""
|
137 |
],
|
138 |
|
139 |
"experimental": [
|
140 |
"""stack(
|
141 |
+
s("[bd rim]*3").degradeBy(0.5).speed(perlin.range(0.8,1.2)).gain(0.8),
|
142 |
+
n("[0 3 7]/5").s("square").octave(2).cutoff(perlin.range(400,2000)).gain(0.7),
|
143 |
+
s("~ [hh hh] ~").pan(sine.slow(3)).degradeBy(0.6).gain(0.5),
|
144 |
+
s("[noise:0]/16").gain(0.2).hpf(2000)
|
145 |
).scale("g:minor")""",
|
146 |
|
147 |
"""stack(
|
148 |
+
s("bd ~ [perc:0 perc:1]").speed(rand.range(0.7,1.3)).gain(0.8),
|
149 |
+
n("0 [2 5] 7").s("sawtooth").octave(2).sometimes(add(note(12))).cutoff(sine.range(300,1500)).gain(0.7),
|
150 |
+
s("[ch oh]*5").degradeBy(0.7).pan(cosine.slow(2)).gain(0.4),
|
151 |
+
n("[9 11]/9").s("triangle").octave(5).delay(0.75).gain(0.3)
|
152 |
+
).scale("f#:minor")""",
|
153 |
+
|
154 |
+
"""stack(
|
155 |
+
s("[bd ~ rim]*2").rev().degradeBy(0.4).gain(0.8),
|
156 |
+
n("[0 4 7]/7").s("square").octave(2).cutoff(perlin.range(200,2000)).sometimes(fast(4)).gain(0.6),
|
157 |
+
s("~ [vinyl:0 vinyl:1]/8").gain(0.3).hpf(1500)
|
158 |
+
).scale("bb:minor")"""
|
159 |
+
],
|
160 |
+
|
161 |
+
"hiphop": [
|
162 |
+
"""stack(
|
163 |
+
s("bd ~ sn ~").gain(0.9),
|
164 |
+
s("hh ~ hh hh ~ hh ~ hh").gain(0.5),
|
165 |
+
n("0 0 3 5").s("sawtooth").octave(2).lpf(1000).gain(0.8),
|
166 |
+
s("~ ~ ~ [clap clap]").slow(2).gain(0.6)
|
167 |
+
).scale("c:minor")""",
|
168 |
+
|
169 |
+
"""stack(
|
170 |
+
s("bd ~ [bd sn] ~").gain(0.9),
|
171 |
+
s("[hh ch]*4").degradeBy(0.1).gain(0.5),
|
172 |
+
n("[0 3 5]*2").s("square").octave(2).lpf(800).gain(0.8),
|
173 |
+
s("~ ~ clap ~").room(0.3).gain(0.7),
|
174 |
+
s("~ [perc:0]/4 ~ [perc:1]/4").gain(0.4)
|
175 |
+
).scale("a:minor")""",
|
176 |
+
|
177 |
+
"""stack(
|
178 |
+
s("bd ~ sn [~ bd]").sometimes(fast(2)).gain(0.9),
|
179 |
+
s("hh*8").degradeBy(0.2).gain(0.4),
|
180 |
+
n("0 ~ 3 ~").s("sawtooth").octave(2).lpf(1200).sometimes(add(note(7))).gain(0.8),
|
181 |
+
s("~ ~ [clap rim] ~").gain(0.6).room(0.4)
|
182 |
+
).scale("d:minor")""",
|
183 |
+
|
184 |
+
"""stack(
|
185 |
+
s("[bd bd] ~ sn ~").gain(0.9),
|
186 |
+
s("~ hh ~ [hh ch hh]").gain(0.5),
|
187 |
+
n("[0 3] [5 0] [7 3] [5 0]").s("sine").octave(2).lpf(1500).gain(0.7),
|
188 |
+
s("~ ~ clap ~").delay(0.125).gain(0.7)
|
189 |
+
).scale("g:minor")"""
|
190 |
]
|
191 |
}
|
192 |
|
|
|
197 |
if complexity == "simple":
|
198 |
# Return simpler single-line patterns
|
199 |
simple_patterns = {
|
200 |
+
"techno": 's("bd*4, hh*8").gain(0.8)',
|
201 |
+
"house": 's("bd ~ ~ ~ bd ~ ~ ~, ~ hh ~ hh").gain(0.7)',
|
202 |
+
"ambient": 'n("[0 2 4]/3").s("sine").octave(3).slow(8).room(0.9).gain(0.6).scale("d:minor")',
|
203 |
+
"breakbeat": 's("[bd sn]*2, hh*8").speed(0.9).gain(0.8)',
|
204 |
+
"experimental": 's("bd ~ [perc:0 perc:1]").degradeBy(0.4).speed(rand.range(0.8,1.2)).gain(0.7)',
|
205 |
+
"hiphop": 's("bd ~ sn ~, hh ~ hh hh ~ hh ~ hh").gain(0.8)'
|
206 |
}
|
207 |
return simple_patterns.get(genre, simple_patterns["techno"])
|
208 |
|
|
|
225 |
variations.append(base_pattern.replace(".gain(0.8)", ".gain(0.8).room(0.4)"))
|
226 |
|
227 |
# Scale variations
|
228 |
+
scales = ["a:minor", "d:minor", "g:minor", "c:major", "f:major", "e:minor", "bb:minor", "f#:minor"]
|
229 |
for scale in scales:
|
230 |
if scale not in base_pattern:
|
231 |
new_pattern = base_pattern
|
|
|
246 |
base_pattern = get_random_working_pattern(genre, complexity)
|
247 |
|
248 |
# Create variations based on prompt keywords
|
249 |
+
if any(word in prompt.lower() for word in ["fast", "speed", "quick", "rapid", "energetic"]):
|
250 |
if "sometimes(fast(2))" not in base_pattern:
|
251 |
base_pattern = base_pattern.replace(".gain(", ".sometimes(fast(2)).gain(")
|
252 |
|
253 |
+
if any(word in prompt.lower() for word in ["slow", "chill", "ambient", "relaxed", "calm"]):
|
254 |
if ".slow(" not in base_pattern:
|
255 |
base_pattern = base_pattern.replace(".gain(", ".slow(2).gain(")
|
256 |
|
257 |
+
if any(word in prompt.lower() for word in ["reverb", "space", "room", "hall", "spacious"]):
|
258 |
if ".room(" not in base_pattern:
|
259 |
+
base_pattern = base_pattern.replace(".gain(", ".room(0.7).gain(")
|
260 |
|
261 |
+
if any(word in prompt.lower() for word in ["delay", "echo", "repeat", "dub"]):
|
262 |
if ".delay(" not in base_pattern:
|
263 |
base_pattern = base_pattern.replace(".gain(", ".delay(0.25).gain(")
|
264 |
|
265 |
+
if any(word in prompt.lower() for word in ["filter", "sweep", "cutoff", "lpf", "filtered"]):
|
266 |
if ".lpf(" not in base_pattern and ".cutoff(" not in base_pattern:
|
267 |
+
base_pattern = base_pattern.replace(".gain(", ".lpf(sine.range(400,1600).slow(8)).gain(")
|
268 |
|
269 |
+
if any(word in prompt.lower() for word in ["glitch", "degraded", "broken", "corrupt", "dirty"]):
|
270 |
if ".degradeBy(" not in base_pattern:
|
271 |
+
base_pattern = base_pattern.replace(".gain(", ".degradeBy(0.4).gain(")
|
272 |
+
|
273 |
+
if any(word in prompt.lower() for word in ["pan", "stereo", "wide", "spatial"]):
|
274 |
+
if ".pan(" not in base_pattern:
|
275 |
+
base_pattern = base_pattern.replace(".gain(", ".pan(sine.slow(4)).gain(")
|
276 |
|
277 |
# Add comment based on prompt
|
278 |
comment_line = f"// {prompt[:50]}{'...' if len(prompt) > 50 else ''}"
|
|
|
334 |
return "Please enter a description of the music you want to create."
|
335 |
|
336 |
if use_ai:
|
337 |
+
# Use AI generation with better examples
|
338 |
system_prompt = f"""Generate working Strudel live coding pattern for: {prompt}
|
339 |
Genre: {genre}, Complexity: {complexity}
|
340 |
|
341 |
+
Example Strudel patterns:
|
342 |
+
s("bd*4, hh*8").gain(0.8)
|
343 |
+
stack(s("bd ~ sn ~"), n("0 2 4").s("sine").octave(3).gain(0.7))
|
344 |
+
n("[0 3 5 7]*2").s("sawtooth").octave(2).lpf(1200).gain(0.8).scale("a:minor")
|
345 |
|
346 |
+
Generate a {complexity} {genre} pattern:"""
|
347 |
|
348 |
try:
|
349 |
outputs = code_generator(
|
350 |
system_prompt,
|
351 |
+
max_length=len(system_prompt.split()) + 80,
|
352 |
+
temperature=0.8,
|
353 |
do_sample=True,
|
354 |
top_p=0.9,
|
355 |
num_return_sequences=1
|
|
|
358 |
generated_text = outputs[0]['generated_text']
|
359 |
strudel_code = generated_text[len(system_prompt):].strip()
|
360 |
|
361 |
+
# Clean the AI output more thoroughly
|
362 |
lines = strudel_code.split('\n')
|
363 |
clean_lines = []
|
364 |
+
for line in lines[:8]: # Limit to 8 lines
|
365 |
line = line.strip()
|
366 |
+
# More robust pattern matching for Strudel code
|
367 |
if line and (line.startswith('s(') or line.startswith('n(') or line.startswith('stack(') or
|
368 |
+
'.gain(' in line or '.s(' in line or '.octave(' in line or '.scale(' in line or
|
369 |
+
line.endswith(')') or line.endswith(',') or '.lpf(' in line):
|
370 |
clean_lines.append(line)
|
371 |
+
# Stop at obvious non-Strudel patterns
|
372 |
+
elif any(stop_word in line.lower() for stop_word in ['function', 'var ', 'let ', 'const ', 'import', '//']):
|
373 |
+
break
|
374 |
|
375 |
if clean_lines:
|
376 |
strudel_code = '\n'.join(clean_lines)
|
377 |
strudel_code = f"// AI Generated: {prompt}\n{strudel_code}"
|
378 |
else:
|
379 |
+
# Fallback to curated patterns if AI fails
|
380 |
strudel_code = generate_working_strudel_code(prompt, genre, complexity)
|
381 |
+
except Exception as e:
|
382 |
+
# Fallback to curated patterns if AI fails
|
383 |
+
print(f"AI generation failed: {e}")
|
384 |
strudel_code = generate_working_strudel_code(prompt, genre, complexity)
|
385 |
else:
|
386 |
+
# Use curated pattern generation
|
387 |
strudel_code = generate_working_strudel_code(prompt, genre, complexity)
|
388 |
|
389 |
# Create complete working template
|
|
|
396 |
gr.Markdown("""
|
397 |
# π΅ CODEL: Strudel Code Generator
|
398 |
|
399 |
+
Generate high-quality Strudel live coding patterns!
|
400 |
|
401 |
+
β
**Premium curated patterns** - professional quality sounds
|
402 |
ποΈ **Real Strudel syntax** - copy & paste ready
|
403 |
+
π¨ **Reactive Hydra visuals** included
|
404 |
+
π΅ **6 genres** with authentic patterns
|
405 |
+
π€ **Optional AI generation** for creative variations
|
406 |
|
407 |
**Usage:** Describe music β Generate β Copy to [strudel.cc](https://strudel.cc) β Play!
|
408 |
""")
|
|
|
417 |
|
418 |
with gr.Row():
|
419 |
genre_dropdown = gr.Dropdown(
|
420 |
+
choices=["techno", "house", "ambient", "breakbeat", "experimental", "hiphop"],
|
421 |
value="techno",
|
422 |
label="π΅ Genre"
|
423 |
)
|
|
|
445 |
label="ποΈ Visual Style"
|
446 |
)
|
447 |
|
448 |
+
generate_btn = gr.Button("π΅ Generate Premium Code", variant="primary", size="lg")
|
449 |
|
450 |
with gr.Column():
|
451 |
output_code = gr.Code(
|
452 |
+
label="β
Premium Strudel Code (Ready to Copy)",
|
453 |
language="javascript",
|
454 |
lines=18
|
455 |
)
|
|
|
460 |
2. **Go to** [strudel.cc](https://strudel.cc)
|
461 |
3. **Paste** and **click the play button** βΆοΈ
|
462 |
|
463 |
+
**π§ Pro Tips:**
|
464 |
+
- Change `.gain()` values (0.1 to 1.0) to balance levels
|
465 |
+
- Try different scales: "a:minor", "c:major", "d:minor"
|
466 |
+
- Use `.sometimes()` for variation: `.sometimes(fast(2))`
|
467 |
+
- Add effects: `.room()`, `.delay()`, `.lpf()`, `.degradeBy()`
|
468 |
""")
|
469 |
|
470 |
+
# Enhanced examples
|
471 |
+
gr.Markdown("### πͺ Premium Examples (Pro Quality)")
|
472 |
with gr.Row():
|
473 |
working_examples = [
|
474 |
+
["Driving techno with filter sweeps", "techno", "complex"],
|
475 |
+
["Deep house with swing", "house", "moderate"],
|
476 |
+
["Ethereal ambient soundscape", "ambient", "complex"],
|
477 |
+
["Crunchy hip-hop beat", "hiphop", "moderate"],
|
478 |
+
["Glitchy experimental textures", "experimental", "complex"],
|
479 |
]
|
480 |
|
481 |
for example_text, example_genre, example_complexity in working_examples:
|
482 |
+
btn = gr.Button(f"π₯ {example_text}", size="sm")
|
483 |
btn.click(
|
484 |
lambda t=example_text, g=example_genre, c=example_complexity: (t, g, c),
|
485 |
outputs=[prompt_input, genre_dropdown, complexity_dropdown]
|