thecollabagepatch commited on
Commit
5ae6d86
·
1 Parent(s): aa3931e

another failure at getting rid of these silence dips. reverting

Browse files
Files changed (1) hide show
  1. jam_worker.py +38 -98
jam_worker.py CHANGED
@@ -117,8 +117,6 @@ class JamWorker(threading.Thread):
117
  self._spool = np.zeros((0, 2), dtype=np.float32) # (S,2) target SR
118
  self._spool_written = 0 # absolute frames written into spool
119
 
120
- self._pending_overlap_model = None
121
-
122
  # bar clock: start with offset 0; if you have a downbeat estimator, set base later
123
  self._bar_clock = BarClock(self.params.target_sr, self.params.bpm, self.params.beats_per_bar, base_offset_samples=0)
124
 
@@ -422,106 +420,48 @@ class JamWorker(threading.Thread):
422
 
423
  # ---------- core streaming helpers ----------
424
 
425
- def _append_model_chunk_and_spool(self, wav: au.Waveform) -> None:
426
- """
427
- Emit crossfaded overlaps into the *output spool* (target SR).
428
- We hold the previous tail (model-rate), mix it with the current head (equal-power),
429
- append that mixed overlap to the spool, then append the current body.
430
- The current tail is kept pending for the next call.
431
- """
432
-
433
-
434
- # ---- unpack model-rate samples ----
435
  s = wav.samples.astype(np.float32, copy=False)
436
  if s.ndim == 1:
437
- s = s[:, None] # (S,1) -> (S,1); downstream expects 2D
438
- n_samps, n_ch = s.shape
439
- sr_model = self._model_sr
440
-
441
- # crossfade length (in model samples)
442
- try:
443
- xfade_s = float(self.mrt.config.crossfade_length)
444
- except Exception:
445
- xfade_s = 0.0
446
- xfade_n = int(round(max(0.0, xfade_s) * float(sr_model)))
447
-
448
- # trivial cases
449
- if n_samps == 0:
450
- return
451
- if xfade_n <= 0:
452
- # No crossfade configured -> just emit whole thing
453
- y = (s if self._rs is None else self._rs.process(s, final=False))
454
- self._spool = np.concatenate([self._spool, y], axis=0) if self._spool.size else y
455
- self._spool_written += y.shape[0]
456
- # For continuity tracking of model stream:
457
- self._model_stream = s if self._model_stream is None else np.concatenate([self._model_stream, s], axis=0)
458
- return
459
-
460
- # If the chunk is too short to hold a full overlap, accumulate into pending and wait
461
- if n_samps <= xfade_n:
462
- tail = s # keep most recent xfade_n samples
463
- self._pending_overlap_model = tail if self._pending_overlap_model is None \
464
- else np.concatenate([self._pending_overlap_model, tail], axis=0)[-xfade_n:]
465
- # Keep model stream continuity too
466
- self._model_stream = s if self._model_stream is None else np.concatenate([self._model_stream, s], axis=0)
467
- return
468
-
469
- # ---- split current chunk into head / body / tail at model rate ----
470
- head = s[:xfade_n, :]
471
- body = s[xfade_n:-xfade_n, :] if n_samps >= (2 * xfade_n) else None
472
- tail = s[-xfade_n:, :]
473
-
474
- # === First call path (no previous tail to mix) ===
475
- if self._pending_overlap_model is None or self._pending_overlap_model.shape[0] != xfade_n:
476
- # Model-stream continuity (drop preroll like before, so future mixes line up)
477
- new_part_for_stream = s[xfade_n:] if xfade_n < n_samps else s[:0]
478
- self._model_stream = new_part_for_stream.copy() if self._model_stream is None \
479
- else np.concatenate([self._model_stream, new_part_for_stream], axis=0)
480
-
481
- # Emit only the body (if present); DO NOT emit tail yet
482
- if body is not None and body.size:
483
- y_body = body if self._rs is None else self._rs.process(body, final=False)
484
- if y_body.size:
485
- self._spool = np.concatenate([self._spool, y_body], axis=0) if self._spool.size else y_body
486
- self._spool_written += y_body.shape[0]
487
-
488
- # Hold tail for next head
489
- self._pending_overlap_model = tail.copy()
490
  return
491
 
492
- # === Subsequent calls: we have a pending tail to mix with this head ===
493
- prev_tail = self._pending_overlap_model
494
-
495
- # Equal-power window
496
- t = np.linspace(0.0, np.pi / 2.0, xfade_n, endpoint=False, dtype=np.float32)[:, None]
497
- cosw = np.cos(t, dtype=np.float32)
498
- sinw = np.sin(t, dtype=np.float32)
499
-
500
- # Mixed overlap (model-rate)
501
- mixed = (prev_tail * cosw) + (head * sinw)
502
-
503
- # Update model stream exactly like before (for internal continuity)
504
- self._model_stream = (
505
- np.concatenate([self._model_stream[:-xfade_n], mixed, s[xfade_n:]], axis=0)
506
- if (self._model_stream is not None and self._model_stream.shape[0] >= xfade_n)
507
- else (mixed if self._model_stream is None else np.concatenate([self._model_stream, mixed, s[xfade_n:]], axis=0))
508
- )
509
-
510
- # ---- Emit to target-SR spool: mixed overlap FIRST, then body (if any) ----
511
- y_mixed = mixed if self._rs is None else self._rs.process(mixed, final=False)
512
- if y_mixed.size:
513
- self._spool = np.concatenate([self._spool, y_mixed], axis=0) if self._spool.size else y_mixed
514
- self._spool_written += y_mixed.shape[0]
515
-
516
- if body is not None and body.size:
517
- y_body = body if self._rs is None else self._rs.process(body, final=False)
518
- if y_body.size:
519
- self._spool = np.concatenate([self._spool, y_body], axis=0)
520
- self._spool_written += y_body.shape[0]
521
-
522
- # Keep the new tail for next time
523
- self._pending_overlap_model = tail.copy()
524
-
525
 
526
  def _should_generate_next_chunk(self) -> bool:
527
  # Allow running ahead relative to whichever is larger: last *consumed*
 
117
  self._spool = np.zeros((0, 2), dtype=np.float32) # (S,2) target SR
118
  self._spool_written = 0 # absolute frames written into spool
119
 
 
 
120
  # bar clock: start with offset 0; if you have a downbeat estimator, set base later
121
  self._bar_clock = BarClock(self.params.target_sr, self.params.bpm, self.params.beats_per_bar, base_offset_samples=0)
122
 
 
420
 
421
  # ---------- core streaming helpers ----------
422
 
423
+ def _append_model_chunk_and_spool(self, wav: au.Waveform):
424
+ """Crossfade into the model-rate stream and write the *non-overlapped*
425
+ tail to the target-SR spool."""
 
 
 
 
 
 
 
426
  s = wav.samples.astype(np.float32, copy=False)
427
  if s.ndim == 1:
428
+ s = s[:, None]
429
+ sr = self._model_sr
430
+ xfade_s = float(self.mrt.config.crossfade_length)
431
+ xfade_n = int(round(max(0.0, xfade_s) * sr))
432
+
433
+ if self._model_stream is None:
434
+ # first chunk: drop the preroll (xfade) then spool
435
+ new_part = s[xfade_n:] if xfade_n < s.shape[0] else s[:0]
436
+ self._model_stream = new_part.copy()
437
+ if new_part.size:
438
+ y = (new_part.astype(np.float32, copy=False)
439
+ if self._rs is None else
440
+ self._rs.process(new_part.astype(np.float32, copy=False), final=False))
441
+ self._spool = np.concatenate([self._spool, y], axis=0)
442
+ self._spool_written += y.shape[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  return
444
 
445
+ # crossfade into existing stream
446
+ if xfade_n > 0 and self._model_stream.shape[0] >= xfade_n and s.shape[0] >= xfade_n:
447
+ tail = self._model_stream[-xfade_n:]
448
+ head = s[:xfade_n]
449
+ t = np.linspace(0, np.pi/2, xfade_n, endpoint=False, dtype=np.float32)[:, None]
450
+ mixed = tail * np.cos(t) + head * np.sin(t)
451
+ self._model_stream = np.concatenate([self._model_stream[:-xfade_n], mixed, s[xfade_n:]], axis=0)
452
+ new_part = s[xfade_n:]
453
+ else:
454
+ self._model_stream = np.concatenate([self._model_stream, s], axis=0)
455
+ new_part = s
456
+
457
+ # spool only the *new* non-overlapped part
458
+ if new_part.size:
459
+ y = (new_part.astype(np.float32, copy=False)
460
+ if self._rs is None else
461
+ self._rs.process(new_part.astype(np.float32, copy=False), final=False))
462
+ if y.size:
463
+ self._spool = np.concatenate([self._spool, y], axis=0)
464
+ self._spool_written += y.shape[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
465
 
466
  def _should_generate_next_chunk(self) -> bool:
467
  # Allow running ahead relative to whichever is larger: last *consumed*