baouws commited on
Commit
021fbd4
Ā·
verified Ā·
1 Parent(s): f19fe63

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -125
app.py CHANGED
@@ -87,7 +87,7 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
87
  lines=8
88
  )
89
 
90
- # Simple audio player with full Strudel.js
91
  gr.HTML("""
92
  <div id="player" style='
93
  background: linear-gradient(135deg, #FF6B9D, #A855F7);
@@ -121,47 +121,51 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
121
  margin: 5px;
122
  transition: all 0.3s;
123
  '>ā¹ļø Stop</button>
 
 
 
 
 
 
 
 
 
 
 
 
124
  <div id="status" style='color: white; margin-top: 10px; font-size: 14px;'>
125
- Click to enable audio, then generate code and play!
126
  </div>
127
  </div>
128
 
129
- <!-- Load Strudel.js libraries -->
130
- <script type="module">
131
- import { repl, controls, mini, initAudioOnFirstClick } from 'https://strudel.cc/strudel.mjs';
132
-
133
- // Make Strudel available globally
134
- window.strudel = { repl, controls, mini, initAudioOnFirstClick };
135
- window.strudelReady = true;
136
-
137
- console.log('Strudel.js loaded successfully!');
138
- updateStatus('šŸŽµ Strudel.js ready! Generate code and play!', 'white');
139
- </script>
140
 
141
  <script>
142
  let isPlaying = false;
143
- let currentPattern = null;
144
  let strudelInitialized = false;
 
145
 
146
  function getCurrentCode() {
147
- // Get code from the textarea - try multiple selectors
148
- const selectors = [
149
- 'textarea[data-testid*="code"]',
150
- '.code-container textarea',
151
- 'textarea',
152
- 'code',
153
- '[data-testid="code"] textarea'
154
- ];
155
 
156
- for (let selector of selectors) {
157
- const element = document.querySelector(selector);
158
- if (element && (element.value || element.textContent)) {
159
- const code = element.value || element.textContent;
160
- if (code && !code.includes('Please describe') && code.includes('cpm')) {
161
- return code;
162
- }
 
163
  }
164
  }
 
165
  return '';
166
  }
167
 
@@ -171,6 +175,7 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
171
  status.textContent = message;
172
  status.style.color = color;
173
  }
 
174
  }
175
 
176
  function updatePlayButton(playing) {
@@ -180,36 +185,37 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
180
  }
181
  }
182
 
183
- async function initializeStrudel() {
184
- if (strudelInitialized) return true;
185
-
186
  try {
187
- // Wait for Strudel to load
188
- let attempts = 0;
189
- while (!window.strudelReady && attempts < 50) {
190
- await new Promise(resolve => setTimeout(resolve, 100));
191
- attempts++;
 
 
 
192
  }
193
 
194
- if (!window.strudel) {
195
- throw new Error('Strudel failed to load');
 
 
 
 
 
196
  }
197
-
198
- // Initialize audio on first click
199
- await window.strudel.initAudioOnFirstClick();
200
- strudelInitialized = true;
201
- updateStatus('šŸŽµ Audio ready! Generate code and play!', '#ccffcc');
202
- return true;
203
  } catch (error) {
204
- console.error('Strudel initialization failed:', error);
205
  updateStatus('āš ļø Audio init failed - using demo mode', '#ffcccc');
206
- return false;
207
  }
208
  }
209
 
210
  async function togglePlay() {
211
  if (isPlaying) {
212
- pausePlay();
213
  } else {
214
  await startPlay();
215
  }
@@ -218,92 +224,87 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
218
  async function startPlay() {
219
  const code = getCurrentCode();
220
 
221
- if (!code || code.trim() === '' || code.includes('Please describe')) {
222
- updateStatus('No code to play! Generate some first.', '#ffcccc');
223
  return;
224
  }
225
 
226
  try {
227
- // Initialize Strudel if needed
228
- const initialized = await initializeStrudel();
229
-
230
- if (!initialized || !window.strudel) {
231
- // Fallback to demo mode
232
- updateStatus('šŸŽ® Demo: Playing ' + code.split('\\n')[0] + '...', '#ffffcc');
233
- isPlaying = true;
234
- updatePlayButton(true);
235
-
236
- setTimeout(() => {
237
- stopPlay();
238
- updateStatus('Demo playback finished!', 'white');
239
- }, 8000);
240
- return;
241
- }
242
-
243
- // Stop any current pattern
244
- if (currentPattern) {
245
- currentPattern.stop();
246
- }
247
-
248
- updateStatus('šŸŽµ Evaluating code...', '#ffffcc');
249
-
250
- // Clean the code (remove comments)
251
- const cleanCode = code
252
- .split('\\n')
253
- .filter(line => !line.trim().startsWith('//'))
254
- .join('\\n')
255
- .trim();
256
 
257
- console.log('Playing code:', cleanCode);
258
-
259
- // Evaluate the Strudel pattern
260
- const pattern = window.strudel.repl.evaluate(cleanCode);
261
-
262
- if (pattern && typeof pattern.play === 'function') {
263
- currentPattern = pattern;
264
- await pattern.play();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
- isPlaying = true;
267
- updatePlayButton(true);
268
- updateStatus('šŸŽµ Playing your music! šŸŽ¶', '#ccffcc');
269
  } else {
270
- throw new Error('Invalid pattern - check your Strudel syntax');
 
 
271
  }
272
 
 
 
 
 
 
 
 
 
 
 
 
273
  } catch (error) {
274
  console.error('Playback error:', error);
275
- updateStatus('āŒ Error: ' + error.message, '#ffcccc');
276
- isPlaying = false;
277
- updatePlayButton(false);
 
 
 
278
 
279
- // Try demo mode as fallback
280
  setTimeout(() => {
281
- updateStatus('šŸŽ® Falling back to demo mode...', '#ffffcc');
282
- isPlaying = true;
283
- updatePlayButton(true);
284
-
285
- setTimeout(() => {
286
- stopPlay();
287
- updateStatus('Demo playback finished!', 'white');
288
- }, 5000);
289
- }, 1000);
290
- }
291
- }
292
-
293
- function pausePlay() {
294
- if (currentPattern && typeof currentPattern.stop === 'function') {
295
- currentPattern.stop();
296
  }
297
-
298
- isPlaying = false;
299
- updatePlayButton(false);
300
- updateStatus('āøļø Paused', '#ffffcc');
301
  }
302
 
303
  function stopPlay() {
304
- if (currentPattern && typeof currentPattern.stop === 'function') {
305
- currentPattern.stop();
306
- currentPattern = null;
 
 
 
 
 
307
  }
308
 
309
  isPlaying = false;
@@ -311,8 +312,11 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
311
  updateStatus('ā¹ļø Stopped', 'white');
312
  }
313
 
314
- // Add hover effects to buttons
315
  document.addEventListener('DOMContentLoaded', function() {
 
 
 
316
  const buttons = document.querySelectorAll('#player button');
317
  buttons.forEach(btn => {
318
  btn.addEventListener('mouseenter', function() {
@@ -325,15 +329,21 @@ with gr.Blocks(title="šŸŽµ Strudel Generator") as app:
325
  });
326
  });
327
 
328
- // Initialize on first user interaction
329
- document.addEventListener('click', initializeStrudel, { once: true });
 
 
 
 
 
 
 
 
330
  });
331
 
332
- // Handle page visibility changes
333
- document.addEventListener('visibilitychange', function() {
334
- if (document.hidden && isPlaying) {
335
- pausePlay();
336
- }
337
  });
338
  </script>
339
  """)
 
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);
 
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
 
 
175
  status.textContent = message;
176
  status.style.color = color;
177
  }
178
+ console.log('Status:', message);
179
  }
180
 
181
  function updatePlayButton(playing) {
 
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
  }
 
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;
 
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() {
 
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
  """)