morfeo 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/python/musica.py CHANGED
@@ -305,7 +305,44 @@ def momento(en, ev, si, m):
305
305
  return ev(si, base) + ajuste
306
306
 
307
307
 
308
- def mix(vid, style, outdir, TIM, SPEC, durs, ev):
308
+ def cama(nombre, N, rng):
309
+ """Sonido de fondo de un ambiente 3D (bucle suave, sin melodía): lluvia, zumbido de tele, arcade."""
310
+ t = np.arange(N) / SR
311
+ zumbido = 0.012 * (np.sin(2 * np.pi * 60 * t) + 0.5 * np.sin(2 * np.pi * 120 * t))
312
+ def lluvia(vol):
313
+ x = lp(hp(rng.standard_normal(N), 900), 6000) * vol * (0.85 + 0.15 * np.sin(2 * np.pi * 0.07 * t))
314
+ for _ in range(int(N / SR * 14)): # gotas sueltas en el vidrio
315
+ g = int(rng.random() * (N - SR // 20)); n = int(0.012 * SR)
316
+ x[g:g + n] += vol * 1.5 * hp(rng.standard_normal(n), 2500) * np.exp(-np.arange(n) / (0.002 * SR))
317
+ return x
318
+ if nombre == "cuarto-gamer":
319
+ x = lluvia(0.05) + zumbido
320
+ for _ in range(int(N / SR / 2.5)): # el juego de la tele: blips lejanos
321
+ add(x, 0.012 * lp(_tono(nf(72 + int(rng.random() * 12)), 0.12, 20), 2500), rng.random() * (N / SR - 0.2))
322
+ return x
323
+ if nombre == "sala":
324
+ murmullo = lp(hp(rng.standard_normal(N), 250), 1400) * 0.035 * (0.6 + 0.4 * np.abs(np.sin(2 * np.pi * 0.9 * t + np.sin(2 * np.pi * 0.23 * t) * 3)))
325
+ return lluvia(0.03) + murmullo + zumbido
326
+ if nombre == "arcade":
327
+ x = lp(rng.standard_normal(N), 700) * 0.05 + zumbido
328
+ for _ in range(int(N / SR * 3)): # maquinitas sonando por todos lados
329
+ f = nf(70 + int(rng.random() * 20)); d = 0.06 + rng.random() * 0.1
330
+ n = int(d * SR); tt = np.arange(n) / SR
331
+ b = np.sign(np.sin(2 * np.pi * f * tt * (1 + 0.5 * tt / d))) * np.exp(-tt / d * 3)
332
+ add(x, 0.012 * lp(b, 4000), rng.random() * (N / SR - d))
333
+ return x
334
+ return np.zeros(N)
335
+
336
+
337
+ def ambiente_de(v):
338
+ """Nombre del ambiente del video (capa `ambiente` del mundo) si su sonido no está apagado."""
339
+ for c in (v.get("mundo") or []):
340
+ if isinstance(c, dict) and c.get("tipo") == "ambiente" and c.get("sonido", True) is not False:
341
+ return c.get("nombre")
342
+ return None
343
+
344
+
345
+ def mix(vid, style, outdir, TIM, SPEC, durs, ev, ambiente=None):
309
346
  """Mezcla voz + música (con ducking) + efectos y escribe mix.wav. style=None: sin música."""
310
347
  dur = sum(durs); N = int(dur * SR); rng = np.random.default_rng(11)
311
348
  music = musica_de(vid, style, dur, N)
@@ -343,6 +380,10 @@ def mix(vid, style, outdir, TIM, SPEC, durs, ev):
343
380
  v = np.zeros(N); v[: min(N, len(voice))] = voice[:N]
344
381
  w = int(0.15 * SR); envv = np.convolve(np.abs(v), np.ones(w) / w, mode="same")
345
382
  music *= 1 - 0.6 * np.clip(envv / 0.05, 0, 1)
346
- out = 1.3 * v + 0.22 * music + 0.6 * sfx
383
+ fondo = cama(ambiente, N, np.random.default_rng(23)) if ambiente else np.zeros(N)
384
+ fondo *= 1 - 0.45 * np.clip(envv / 0.05, 0, 1)
385
+ if len(fondo) > SR: # entra y sale suave
386
+ fondo[:SR // 2] *= np.linspace(0, 1, SR // 2); fondo[-SR:] *= np.linspace(1, 0, SR)
387
+ out = 1.3 * v + 0.22 * music + 0.6 * sfx + fondo
347
388
  out = np.tanh(out * 1.1) * 0.89
348
389
  sf.write(os.path.join(outdir, "mix.wav"), np.stack([out, out], 1).astype(np.float32), SR)
@@ -250,7 +250,7 @@ def preparar(job):
250
250
  return seg["speech"] * 0.5
251
251
 
252
252
  durs = [seg["dur"] + (0.6 if i == len(TIM) - 1 else 0) for i, seg in enumerate(TIM)]
253
- musica.mix(vid, v.get("music"), outdir, TIM, spec, durs, ev) # -> mix.wav (voz + música con ducking + efectos)
253
+ musica.mix(vid, v.get("music"), outdir, TIM, spec, durs, ev, ambiente=musica.ambiente_de(v)) # -> mix.wav (voz + música con ducking + efectos)
254
254
 
255
255
  escenas = []
256
256
  for si, (seg, sp) in enumerate(zip(TIM, spec)):