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]
|