wishartgroup commited on
Commit
d56f673
·
verified ·
1 Parent(s): ea29fbd

Update float_streamer.py

Browse files
Files changed (1) hide show
  1. float_streamer.py +46 -13
float_streamer.py CHANGED
@@ -52,6 +52,9 @@ class FloatStreamer:
52
 
53
  self.ready = False
54
  self.current_dampening = 0.35
 
 
 
55
 
56
  def initialize(self, model, device, opt, ref_image_tensor, wav2vec_preprocessor):
57
  self.model = model
@@ -112,8 +115,6 @@ class FloatStreamer:
112
 
113
  speech_array, sr = librosa.load(audio_path, sr=self.sampling_rate)
114
 
115
- # BUG FIX: ONLY pad with silence if this is the very last sentence of the entire response.
116
- # Otherwise, the avatar's mouth will awkwardly clamp shut between every sentence.
117
  if is_last:
118
  pad_samples = int(0.5 * self.sampling_rate)
119
  speech_array = np.concatenate([speech_array, np.zeros(pad_samples, dtype=speech_array.dtype)])
@@ -147,7 +148,6 @@ class FloatStreamer:
147
  }
148
  self._speech_queue.put(chunk_data)
149
 
150
- # BUG FIX: ONLY tell the streamer to transition back to the Idle phase if this is the final sentence.
151
  if is_last:
152
  self._speech_queue.put({"type": "speech_end"})
153
 
@@ -195,13 +195,25 @@ class FloatStreamer:
195
  cfg = self._idle_cfg_scale
196
  if cfg > 1.0: self._idle_cfg_scale = max(1.0, cfg - 0.35)
197
 
 
 
 
 
 
 
 
 
 
 
 
198
  self._generate_chunk(
199
  wa=self._silence_wa, we=self._silence_we, actual_frames=self.frames_per_chunk,
200
- a_cfg_scale=cfg, e_cfg_scale=1.0, is_speech=False, nfe=3,
 
201
  )
202
 
203
  @torch.no_grad()
204
- def _generate_chunk(self, wa, we, actual_frames=None, a_cfg_scale=None, e_cfg_scale=None, is_speech=False, nfe=None, speech_start_event=None):
205
  if actual_frames is None: actual_frames = self.frames_per_chunk
206
  if a_cfg_scale is None: a_cfg_scale = self.opt.a_cfg_scale
207
  if e_cfg_scale is None: e_cfg_scale = self.opt.e_cfg_scale
@@ -237,15 +249,36 @@ class FloatStreamer:
237
  self.prev_x = sample[:, -self.num_prev_frames:].clone()
238
  self.prev_wa = wa[:, -self.num_prev_frames:].clone()
239
 
240
- target_dampening = 1.0 if is_speech else 0.35
241
-
242
- if abs(self.current_dampening - target_dampening) > 0.01:
243
- damp_curve = torch.linspace(self.current_dampening, target_dampening, sample.shape[1], device=self.device)
244
- damp_curve = damp_curve.view(1, -1, 1)
245
- sample_display = sample * damp_curve
246
- self.current_dampening = target_dampening
 
 
 
 
 
 
 
 
247
  else:
248
- sample_display = sample * target_dampening
 
 
 
 
 
 
 
 
 
 
 
 
 
249
 
250
  t_dec = time.time()
251
  frames_pushed = 0
 
52
 
53
  self.ready = False
54
  self.current_dampening = 0.35
55
+
56
+ # Global counter to keep sine waves continuous across chunks
57
+ self._idle_frame_counter = 0
58
 
59
  def initialize(self, model, device, opt, ref_image_tensor, wav2vec_preprocessor):
60
  self.model = model
 
115
 
116
  speech_array, sr = librosa.load(audio_path, sr=self.sampling_rate)
117
 
 
 
118
  if is_last:
119
  pad_samples = int(0.5 * self.sampling_rate)
120
  speech_array = np.concatenate([speech_array, np.zeros(pad_samples, dtype=speech_array.dtype)])
 
148
  }
149
  self._speech_queue.put(chunk_data)
150
 
 
151
  if is_last:
152
  self._speech_queue.put({"type": "speech_end"})
153
 
 
195
  cfg = self._idle_cfg_scale
196
  if cfg > 1.0: self._idle_cfg_scale = max(1.0, cfg - 0.35)
197
 
198
+ # Ported from batch_idle.py: Recreate the lively "breathing" using a continuous sine wave!
199
+ dampening = torch.zeros(1, self.frames_per_chunk, 1, device=self.device)
200
+ damp_mid = 0.50
201
+ damp_amp = 0.15
202
+
203
+ for t in range(self.frames_per_chunk):
204
+ global_t = self._idle_frame_counter + t
205
+ dampening[0, t, 0] = damp_mid + damp_amp * math.sin(global_t * 0.06)
206
+
207
+ self._idle_frame_counter += self.frames_per_chunk
208
+
209
  self._generate_chunk(
210
  wa=self._silence_wa, we=self._silence_we, actual_frames=self.frames_per_chunk,
211
+ a_cfg_scale=cfg, e_cfg_scale=1.0, is_speech=False, nfe=3,
212
+ dynamic_dampening=dampening
213
  )
214
 
215
  @torch.no_grad()
216
+ def _generate_chunk(self, wa, we, actual_frames=None, a_cfg_scale=None, e_cfg_scale=None, is_speech=False, nfe=None, speech_start_event=None, dynamic_dampening=None):
217
  if actual_frames is None: actual_frames = self.frames_per_chunk
218
  if a_cfg_scale is None: a_cfg_scale = self.opt.a_cfg_scale
219
  if e_cfg_scale is None: e_cfg_scale = self.opt.e_cfg_scale
 
249
  self.prev_x = sample[:, -self.num_prev_frames:].clone()
250
  self.prev_wa = wa[:, -self.num_prev_frames:].clone()
251
 
252
+ # ---- FLUID DAMPENING LOGIC ----
253
+ if is_speech:
254
+ target_dampening = 1.0
255
+ if isinstance(self.current_dampening, torch.Tensor):
256
+ # Transitioning from organic idle wave -> full speech
257
+ start_val = self.current_dampening[0, -1, 0].item()
258
+ damp_curve = torch.linspace(start_val, 1.0, sample.shape[1], device=self.device).view(1, -1, 1)
259
+ sample_display = sample * damp_curve
260
+ elif abs(self.current_dampening - target_dampening) > 0.01:
261
+ # Transitioning from flat float -> float
262
+ damp_curve = torch.linspace(self.current_dampening, target_dampening, sample.shape[1], device=self.device).view(1, -1, 1)
263
+ sample_display = sample * damp_curve
264
+ else:
265
+ sample_display = sample * target_dampening
266
+ self.current_dampening = 1.0
267
  else:
268
+ # Applying organic breathing curve from batch_idle.py
269
+ if dynamic_dampening is not None:
270
+ if isinstance(self.current_dampening, float):
271
+ # Transitioning from speech -> down to the organic idle wave
272
+ fade = torch.linspace(1.0, 0.0, sample.shape[1], device=self.device).view(1, -1, 1)
273
+ damp_curve = self.current_dampening * fade + dynamic_dampening * (1.0 - fade)
274
+ sample_display = sample * damp_curve
275
+ else:
276
+ # Continuous organic idle wave
277
+ sample_display = sample * dynamic_dampening
278
+ self.current_dampening = dynamic_dampening
279
+ else:
280
+ sample_display = sample * 0.35
281
+ self.current_dampening = 0.35
282
 
283
  t_dec = time.time()
284
  frames_pushed = 0