liquidsoap-prettier 1.8.2 → 1.8.3

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.
Files changed (67) hide show
  1. package/.github/workflows/check-formatting.yml +32 -0
  2. package/README.md +31 -5
  3. package/package.json +1 -1
  4. package/src/cli.js +104 -9
  5. package/tests/liq/audio.liq +460 -0
  6. package/tests/liq/autocue.liq +1081 -0
  7. package/tests/liq/clock.liq +14 -0
  8. package/tests/liq/cron.liq +74 -0
  9. package/tests/liq/error.liq +48 -0
  10. package/tests/liq/extra/audio.liq +677 -0
  11. package/tests/liq/extra/audioscrobbler.liq +482 -0
  12. package/tests/liq/extra/deprecations.liq +976 -0
  13. package/tests/liq/extra/externals.liq +196 -0
  14. package/tests/liq/extra/fades.liq +260 -0
  15. package/tests/liq/extra/file.liq +66 -0
  16. package/tests/liq/extra/http.liq +160 -0
  17. package/tests/liq/extra/interactive.liq +917 -0
  18. package/tests/liq/extra/metadata.liq +75 -0
  19. package/tests/liq/extra/native.liq +201 -0
  20. package/tests/liq/extra/openai.liq +150 -0
  21. package/tests/liq/extra/server.liq +177 -0
  22. package/tests/liq/extra/source.liq +476 -0
  23. package/tests/liq/extra/spinitron.liq +272 -0
  24. package/tests/liq/extra/telnet.liq +266 -0
  25. package/tests/liq/extra/video.liq +59 -0
  26. package/tests/liq/extra/visualization.liq +68 -0
  27. package/tests/liq/fades.liq +941 -0
  28. package/tests/liq/ffmpeg.liq +605 -0
  29. package/tests/liq/file.liq +387 -0
  30. package/tests/liq/getter.liq +74 -0
  31. package/tests/liq/hls.liq +329 -0
  32. package/tests/liq/http.liq +1048 -0
  33. package/tests/liq/http_codes.liq +447 -0
  34. package/tests/liq/icecast.liq +58 -0
  35. package/tests/liq/io.liq +106 -0
  36. package/tests/liq/liquidsoap.liq +31 -0
  37. package/tests/liq/list.liq +440 -0
  38. package/tests/liq/log.liq +47 -0
  39. package/tests/liq/lufs.liq +295 -0
  40. package/tests/liq/math.liq +23 -0
  41. package/tests/liq/medialib.liq +752 -0
  42. package/tests/liq/metadata.liq +253 -0
  43. package/tests/liq/nfo.liq +258 -0
  44. package/tests/liq/null.liq +71 -0
  45. package/tests/liq/playlist.liq +1347 -0
  46. package/tests/liq/predicate.liq +106 -0
  47. package/tests/liq/process.liq +93 -0
  48. package/tests/liq/profiler.liq +5 -0
  49. package/tests/liq/protocols.liq +1139 -0
  50. package/tests/liq/ref.liq +28 -0
  51. package/tests/liq/replaygain.liq +135 -0
  52. package/tests/liq/request.liq +467 -0
  53. package/tests/liq/resolvers.liq +33 -0
  54. package/tests/liq/runtime.liq +70 -0
  55. package/tests/liq/server.liq +99 -0
  56. package/tests/liq/settings.liq +41 -0
  57. package/tests/liq/socket.liq +33 -0
  58. package/tests/liq/source.liq +362 -0
  59. package/tests/liq/sqlite.liq +161 -0
  60. package/tests/liq/stdlib.liq +172 -0
  61. package/tests/liq/string.liq +476 -0
  62. package/tests/liq/switches.liq +197 -0
  63. package/tests/liq/testing.liq +37 -0
  64. package/tests/liq/thread.liq +161 -0
  65. package/tests/liq/tracks.liq +100 -0
  66. package/tests/liq/utils.liq +81 -0
  67. package/tests/liq/video.liq +918 -0
@@ -0,0 +1,941 @@
1
+ fade = ()
2
+
3
+ let settings.fade =
4
+ settings.make.void(
5
+ "Settings for the fade in/out operators"
6
+ )
7
+
8
+ let settings.fade.in =
9
+ settings.make.void(
10
+ "Settings for fade.in operators"
11
+ )
12
+
13
+ let settings.fade.in.duration =
14
+ settings.make(
15
+ description="Default fade.in duration",
16
+ 3.
17
+ )
18
+
19
+ let settings.fade.in.type =
20
+ settings.make(
21
+ description="Default fade.in type",
22
+ "lin"
23
+ )
24
+
25
+ let settings.fade.in.curve =
26
+ settings.make(
27
+ description="Default fade.in curve",
28
+ 10.
29
+ )
30
+
31
+ let settings.fade.out =
32
+ settings.make.void(
33
+ "Settings for fade.out operators"
34
+ )
35
+
36
+ let settings.fade.out.duration =
37
+ settings.make(
38
+ description="Default fade.out duration",
39
+ 3.
40
+ )
41
+
42
+ let settings.fade.out.type =
43
+ settings.make(
44
+ description="Default fade.out type",
45
+ "lin"
46
+ )
47
+
48
+ let settings.fade.out.curve =
49
+ settings.make(
50
+ description="Default fade.out curve",
51
+ 10.
52
+ )
53
+
54
+ # Make a fade function based on a source's clock.
55
+ # @category Source / Fade
56
+ # @param ~curve Fade curve for `"log"` and `"exp"` shapes. If `null`, depends on the type of fade. \
57
+ # The higher the value, the shaper the curve.
58
+ # @param ~type Fade shape. One of: `"sin"`, `"exp"`, `"log"`, `"lin"`
59
+ # @param ~start Start value.
60
+ # @param ~stop Stop value.
61
+ # @param ~delay Initial delay before starting fade.
62
+ # @param ~duration Duration in seconds.
63
+ # @param ~on_done Function to execute when the fade is finished
64
+ def mkfade(
65
+ ~curve=null,
66
+ ~type="lin",
67
+ ~start=0.,
68
+ ~stop=1.,
69
+ ~delay=0.,
70
+ ~duration=3.,
71
+ ~on_done={()},
72
+ s
73
+ ) =
74
+ def log(x) =
75
+ log(label="mkfade", x)
76
+ end
77
+
78
+ # Shape functions must map 0. -> 0. and 1. -> 1.
79
+ pi = acos(-1.)
80
+
81
+ def sin_shape(x) =
82
+ (1. + sin((x - 0.5) * pi)) / 2.
83
+ end
84
+
85
+ exp_curve = curve ?? 3.
86
+ m = exp(exp_curve - 1.) - exp(-1.)
87
+
88
+ def exp_shape(x) =
89
+ (exp((exp_curve * x) - 1.) - exp(-1.)) / m
90
+ end
91
+
92
+ ln_curve = curve ?? 10.
93
+ m = ln(1. + ln_curve)
94
+
95
+ def log_shape(x) =
96
+ ln(1. + ln_curve * x) / m
97
+ end
98
+
99
+ def lin_shape(x) =
100
+ x
101
+ end
102
+
103
+ shape =
104
+ if
105
+ type == "sin"
106
+ then
107
+ sin_shape
108
+ elsif
109
+ type == "exp"
110
+ then
111
+ exp_shape
112
+ elsif
113
+ type == "log"
114
+ then
115
+ log_shape
116
+ elsif
117
+ type == "lin"
118
+ then
119
+ lin_shape
120
+ else
121
+ log(
122
+ "Invalid type #{type}, using \"lin\""
123
+ )
124
+ lin_shape
125
+ end
126
+
127
+ start_time = ref(-1.)
128
+ increasing_fade = start <= stop
129
+
130
+ def fade() =
131
+ if start_time() < 0. then start_time := source.time(s) end
132
+
133
+ t = source.time(s) - start_time() - delay
134
+ if
135
+ 0. < duration and t <= 0.
136
+ then
137
+ start
138
+ elsif
139
+ t >= duration
140
+ then
141
+ on_done()
142
+ stop
143
+ else
144
+ if
145
+ increasing_fade
146
+ then
147
+ start + shape(t / duration) * (stop - start)
148
+ else
149
+ stop + shape(1. - t / duration) * (start - stop)
150
+ end
151
+ end
152
+ end
153
+
154
+ fade
155
+ end
156
+
157
+ # Scale source during fading.
158
+ # @category Source / Fade
159
+ # @flag hidden
160
+ def fade.scale(~id="fade.scale", x, s) =
161
+ amplify(id=id, override=null, x, s)
162
+ end
163
+
164
+ # Fade the end of tracks.
165
+ # @category Source / Fade
166
+ # @param ~id Force the value of the source ID.
167
+ # @param ~duration Duration of the fading. This value can be set on a per-file basis using the metadata field passed as override. Defaults to `settings.fade.out.curve` if `null`.
168
+ # @param ~delay Initial delay before starting fade. Defaults to `settings.fade.out.delay` if `null`.
169
+ # @param ~curve Fade curve. Defaults to `settings.fade.out.curve` if `null`.
170
+ # @param ~override_duration Metadata field which, if present and containing a float, overrides the 'duration' parameter for the current track.
171
+ # @param ~override_type Metadata field which, if present and correct, overrides the 'type' parameter for the current track.
172
+ # @param ~override_curve Metadata field which, if presents and correct, overrides the `curve` parameter for the current track. Use `"default"` \
173
+ # to set to default value.
174
+ # @param ~override_delay Metadata field which, if presents and correct, overrides the initial fade delay.
175
+ # @param ~persist_overrides Keep duration and type overrides on track change.
176
+ # @param ~track_sensitive Be track sensitive (if `false` we only fade ou once at the beginning of the track).
177
+ # @param ~initial_metadata Initial metadata.
178
+ # @param ~type Fader shape. One of: "lin"", "sin", "log" or "exp". Defaults to `settings.fade.out.type` if `null`.
179
+ def fade.out(
180
+ ~id="fade.out",
181
+ ~duration=null,
182
+ ~delay=0.,
183
+ ~curve=null,
184
+ ~override_duration="liq_fade_out",
185
+ ~override_type="liq_fade_out_type",
186
+ ~override_curve="liq_fade_out_curve",
187
+ ~override_delay="liq_fade_out_delay",
188
+ ~persist_overrides=false,
189
+ ~track_sensitive=false,
190
+ ~initial_metadata=[],
191
+ ~type=null,
192
+ s
193
+ ) =
194
+ def log(~level=4, x) =
195
+ log(label=source.id(s), level=level, x)
196
+ end
197
+
198
+ fn = ref(fun () -> 1.)
199
+ original_type = type ?? settings.fade.out.type()
200
+ type = ref(original_type)
201
+ original_curve = (curve ?? settings.fade.out.curve() : float?)
202
+ curve = ref(original_curve)
203
+ original_duration = duration ?? settings.fade.out.duration()
204
+ duration = ref(original_duration)
205
+ original_delay = delay
206
+ delay = ref(original_delay)
207
+ start_time = ref(-1.)
208
+ started = ref(false)
209
+ last_metadata = ref(initial_metadata)
210
+
211
+ def start_fade(d, _) =
212
+ curve_log =
213
+ if null.defined(curve()) then string(null.get(curve())) else "default" end
214
+
215
+ start_time := source.time(s)
216
+ let (delay, duration) =
217
+ if
218
+ d < delay() + duration()
219
+ then
220
+ if
221
+ d < duration()
222
+ then
223
+ (0., d)
224
+ else
225
+ (max(0., d - duration()), duration())
226
+ end
227
+ else
228
+ (delay(), duration())
229
+ end
230
+
231
+ log(
232
+ "Fading out with type: #{type()}, curve: #{curve_log}, delay: #{delay}s, \
233
+ duration: #{duration}s and #{d}s remaining."
234
+ )
235
+
236
+ fn :=
237
+ mkfade(
238
+ start=1.,
239
+ stop=0.,
240
+ type=type(),
241
+ curve=curve(),
242
+ delay=delay,
243
+ duration=duration,
244
+ s
245
+ )
246
+ started := true
247
+ end
248
+
249
+ def apply() =
250
+ fn = fn()
251
+ fn()
252
+ end
253
+
254
+ def stop_fade(_) =
255
+ if
256
+ started()
257
+ then
258
+ fn := fun () -> 1.
259
+ started := false
260
+ end
261
+ end
262
+
263
+ def update_fade(m) =
264
+ if
265
+ m[override_duration] != ""
266
+ then
267
+ old_duration = duration()
268
+ duration := float_of_string(default=duration(), m[override_duration])
269
+
270
+ if
271
+ duration() != old_duration
272
+ then
273
+ log(
274
+ "New fade out duration: #{duration()}s."
275
+ )
276
+ end
277
+ end
278
+
279
+ if
280
+ m[override_delay] != ""
281
+ then
282
+ old_delay = delay()
283
+ delay := float_of_string(default=0., m[override_delay])
284
+
285
+ if
286
+ delay() != old_delay
287
+ then
288
+ log(
289
+ "New fade out delay: #{delay()}s."
290
+ )
291
+ end
292
+ end
293
+
294
+ if
295
+ m[override_curve] != ""
296
+ then
297
+ old_curve = curve()
298
+
299
+ if
300
+ m[override_curve] == "default"
301
+ then
302
+ curve := null
303
+ else
304
+ try
305
+ curve := float_of_string(m[override_curve])
306
+ catch _ do
307
+ curve := null
308
+ end
309
+ end
310
+
311
+ if
312
+ curve() != old_curve
313
+ then
314
+ log(
315
+ "New fade out curve: #{curve()}."
316
+ )
317
+ end
318
+ end
319
+
320
+ if
321
+ m[override_type] != ""
322
+ then
323
+ old_type = type()
324
+ type := m[override_type]
325
+
326
+ if
327
+ type() != old_type
328
+ then
329
+ log(
330
+ "New fade out type: #{type()}."
331
+ )
332
+ end
333
+ end
334
+ end
335
+
336
+ update_fade(last_metadata())
337
+
338
+ def reset_overrides(_) =
339
+ if
340
+ not persist_overrides
341
+ then
342
+ log(
343
+ "Setting fade out to default duration: #{original_duration}s, delay: #{
344
+ original_delay
345
+ }s, type: #{original_type}, curve: #{original_curve}"
346
+ )
347
+ duration := original_duration
348
+ delay := original_delay
349
+ type := original_type
350
+ curve := original_curve
351
+ end
352
+ end
353
+
354
+ s = source.methods(s)
355
+ s.on_track(synchronous=true, reset_overrides)
356
+ s.on_metadata(synchronous=true, update_fade)
357
+ if track_sensitive then s.on_track(synchronous=true, stop_fade) end
358
+
359
+ d = source.dynamic(memoize({s}))
360
+
361
+ if
362
+ track_sensitive
363
+ then
364
+ d.on_position(
365
+ synchronous=true,
366
+ remaining=true,
367
+ position=duration,
368
+ start_fade
369
+ )
370
+ else
371
+ d.on_frame(
372
+ synchronous=true,
373
+ before=false,
374
+ memoize({start_fade(source.remaining(s), [])})
375
+ )
376
+ end
377
+
378
+ # Make sure we generate a frame before starting the fade
379
+ # to ensure that we catch all the initial metadata.
380
+ d.on_frame(
381
+ synchronous=true,
382
+ before=true,
383
+ memoize({if s.is_ready() then s.generate_frame() end})
384
+ )
385
+
386
+ fade.scale(id=id, apply, d).{
387
+ fade_duration = {duration()},
388
+ fade_type = {type()}
389
+ }
390
+ end
391
+
392
+ # Fade when the metadata trigger is received and then skip.
393
+ # @flag extra
394
+ # @category Source / Fade
395
+ # @flag extra
396
+ # @param ~id Force the value of the source ID.
397
+ # @param ~duration Duration of the fading. This value can be set on a per-file basis using the metadata field passed as override.
398
+ # @param ~delay Initial delay before starting fade.
399
+ # @param ~curve Fade curve. Default if `null`.
400
+ # @param ~override_duration Metadata field which, if present and containing a float, overrides the 'duration' parameter for the current track.
401
+ # @param ~override_type Metadata field which, if present and correct, overrides the 'type' parameter for the current track.
402
+ # @param ~override_curve Metadata field which, if presents and correct, overrides the `curve` parameter for the current track. Use `"default"` \
403
+ # to set to default value.
404
+ # @param ~override_skip Metadata field which, when present and set to "true", will trigger the fade
405
+ # @param ~persist_overrides Keep duration and type overrides on track change.
406
+ # @param ~initial_metadata Initial metadata.
407
+ # @param ~type Fader shape (lin|sin|log|exp): linear, sinusoidal, logarithmic or exponential.
408
+ def fade.skip(
409
+ ~id="fade.skip",
410
+ ~duration=5.,
411
+ ~delay=0.,
412
+ ~curve=null,
413
+ ~override_duration="liq_fade_skip",
414
+ ~override_type="liq_fade_skip_type",
415
+ ~override_curve="liq_fade_skip_curve",
416
+ ~persist_overrides=false,
417
+ ~override_skip="liq_skip_meta",
418
+ ~initial_metadata=[],
419
+ ~type="lin",
420
+ s
421
+ ) =
422
+ def log(x) =
423
+ log(label=source.id(s), level=4, x)
424
+ end
425
+
426
+ fn = ref(fun () -> 1.)
427
+ original_type = type
428
+ type = ref(type)
429
+ original_curve = curve
430
+ curve = ref(curve)
431
+ original_duration = duration
432
+ duration = ref(duration)
433
+ original_delay = delay
434
+ delay = ref(original_delay)
435
+ last_metadata = ref(initial_metadata)
436
+
437
+ def apply() =
438
+ fn = fn()
439
+ fn()
440
+ end
441
+
442
+ def stop_fade(_) =
443
+ fn := fun () -> 1.
444
+ end
445
+
446
+ def skip() =
447
+ log(
448
+ "Fade finished executing. Calling skip now"
449
+ )
450
+ source.skip(s)
451
+ end
452
+
453
+ def update_fade(m) =
454
+ if
455
+ m[override_skip] == "true"
456
+ then
457
+ remaining = source.remaining(s)
458
+ duration = if remaining < duration() then remaining else duration() end
459
+ log(
460
+ "Skip fade executed for: #{duration}s"
461
+ )
462
+ fn :=
463
+ mkfade(
464
+ start=1.,
465
+ stop=0.,
466
+ type=type(),
467
+ curve=curve(),
468
+ duration=duration,
469
+ delay=delay(),
470
+ on_done=skip,
471
+ s
472
+ )
473
+ end
474
+
475
+ if
476
+ m[override_duration] != ""
477
+ then
478
+ old_duration = duration()
479
+ duration := float_of_string(default=duration(), m[override_duration])
480
+
481
+ if
482
+ duration() != old_duration
483
+ then
484
+ log(
485
+ "New fade skip duration: #{duration()}s."
486
+ )
487
+ end
488
+ end
489
+
490
+ if
491
+ m[override_curve] != ""
492
+ then
493
+ old_curve = curve()
494
+
495
+ if
496
+ m[override_curve] == "default"
497
+ then
498
+ curve := null
499
+ else
500
+ try
501
+ curve := float_of_string(m[override_curve])
502
+ catch _ do
503
+ curve := null
504
+ end
505
+ end
506
+
507
+ if
508
+ curve() != old_curve
509
+ then
510
+ log(
511
+ "New fade skip curve: #{curve()}."
512
+ )
513
+ end
514
+ end
515
+
516
+ if
517
+ m[override_type] != ""
518
+ then
519
+ old_type = type()
520
+ type := m[override_type]
521
+
522
+ if
523
+ type() != old_type
524
+ then
525
+ log(
526
+ "New fade skip type: #{type()}."
527
+ )
528
+ end
529
+ end
530
+ end
531
+
532
+ update_fade(last_metadata())
533
+
534
+ def reset_overrides(_) =
535
+ if
536
+ not persist_overrides
537
+ then
538
+ log(
539
+ "Setting fade skip to default duration: #{original_duration}s, delay: #{
540
+ original_delay
541
+ }s, type: #{original_type}, curve: #{original_curve}"
542
+ )
543
+ duration := original_duration
544
+ type := original_type
545
+ curve := original_curve
546
+ end
547
+ end
548
+
549
+ s = source.methods(s)
550
+ s.on_track(synchronous=true, reset_overrides)
551
+ s.on_metadata(synchronous=true, update_fade)
552
+ s.on_track(synchronous=true, stop_fade)
553
+
554
+ fade.scale(id=id, apply, s).{
555
+ fade_duration = {duration()},
556
+ fade_type = {type()}
557
+ }
558
+ end
559
+
560
+ # Fade the beginning of tracks.
561
+ # @category Source / Fade
562
+ # @param ~id Force the value of the source ID.
563
+ # @param ~duration Duration of the fading. This value can be set on a per-file basis using the metadata field passed as override. Defaults to `settings.fade.in.duration` if `null`.
564
+ # @param ~delay Initial delay before starting fade.
565
+ # @param ~curve Fade curve. Defaults to `settings.fade.in.curve` if `null`.
566
+ # @param ~override_duration Metadata field which, if present and containing a float, overrides the 'duration' parameter for the current track.
567
+ # @param ~override_type Metadata field which, if present and correct, overrides the 'type' parameter for the current track.
568
+ # @param ~override_curve Metadata field which, if presents and correct, overrides the `curve` parameter for the current track. Use `"default"` \
569
+ # to set to default value.
570
+ # @param ~override_delay Metadata field which, if presents and correct, overrides the initial fade delay.
571
+ # @param ~persist_overrides Keep duration and type overrides on track change.
572
+ # @param ~track_sensitive Be track sensitive (if `false` we only fade in once at the beginning of the track).
573
+ # @param ~initial_metadata Initial metadata.
574
+ # @param ~type Fader shape. One of: "lin"", "sin", "log" or "exp". Defaults to `settings.fade.in.type` if `null`.
575
+ def fade.in(
576
+ ~id="fade.in",
577
+ ~duration=null,
578
+ ~delay=0.,
579
+ ~curve=null,
580
+ ~override_duration="liq_fade_in",
581
+ ~override_type="liq_fade_in_type",
582
+ ~override_curve="liq_fade_in_curve",
583
+ ~override_delay="liq_fade_in_delay",
584
+ ~persist_overrides=false,
585
+ ~track_sensitive=false,
586
+ ~initial_metadata=[],
587
+ ~type=null,
588
+ s
589
+ ) =
590
+ def log(~level=4, x) =
591
+ log(label=source.id(s), level=level, x)
592
+ end
593
+
594
+ fn = ref(fun () -> 0.)
595
+ original_duration = duration ?? settings.fade.in.duration()
596
+ duration = ref(original_duration)
597
+ original_delay = delay
598
+ delay = ref(original_delay)
599
+ original_type = type ?? settings.fade.in.type()
600
+ type = ref(original_type)
601
+ original_curve = curve ?? settings.fade.in.curve()
602
+ curve = ref(curve)
603
+ last_metadata = ref(initial_metadata)
604
+
605
+ def apply() =
606
+ fn = fn()
607
+ fn()
608
+ end
609
+
610
+ def start_fade(_) =
611
+ curve_log =
612
+ if null.defined(curve()) then string(null.get(curve())) else "default" end
613
+
614
+ duration =
615
+ if
616
+ source.remaining(s) < duration()
617
+ then
618
+ source.remaining(s)
619
+ else
620
+ duration()
621
+ end
622
+
623
+ log(
624
+ "Fading in with type: #{type()}, curve: #{curve_log}, delay: #{delay()}s \
625
+ and duration: #{duration}s."
626
+ )
627
+
628
+ # Note: delay here must match the add delay via blank to make the curve also match
629
+ fn :=
630
+ mkfade(
631
+ start=0.,
632
+ stop=1.,
633
+ type=type(),
634
+ curve=curve(),
635
+ delay=delay(),
636
+ duration=duration,
637
+ s
638
+ )
639
+ end
640
+
641
+ def update_fade(m) =
642
+ if
643
+ m[override_duration] != ""
644
+ then
645
+ old_duration = duration()
646
+ duration := float_of_string(default=duration(), m[override_duration])
647
+
648
+ if
649
+ duration() != old_duration
650
+ then
651
+ log(
652
+ "New fade in duration: #{duration()}s."
653
+ )
654
+ end
655
+ end
656
+
657
+ if
658
+ m[override_delay] != ""
659
+ then
660
+ old_delay = delay()
661
+ delay := float_of_string(default=0., m[override_delay])
662
+
663
+ if
664
+ delay() != old_delay
665
+ then
666
+ log(
667
+ "New fade in delay: #{delay()}s."
668
+ )
669
+ end
670
+ end
671
+
672
+ if
673
+ m[override_curve] != ""
674
+ then
675
+ old_curve = curve()
676
+
677
+ if
678
+ m[override_curve] == "default"
679
+ then
680
+ curve := null
681
+ else
682
+ try
683
+ curve := float_of_string(m[override_curve])
684
+ catch _ do
685
+ curve := null
686
+ end
687
+ end
688
+
689
+ if
690
+ curve() != old_curve
691
+ then
692
+ log(
693
+ "New fade in curve: #{curve()}."
694
+ )
695
+ end
696
+ end
697
+
698
+ if
699
+ m[override_type] != ""
700
+ then
701
+ old_type = type()
702
+ type := m[override_type]
703
+
704
+ if
705
+ type() != old_type
706
+ then
707
+ log(
708
+ "New fade in type: #{type()}."
709
+ )
710
+ end
711
+ end
712
+ end
713
+
714
+ update_fade(last_metadata())
715
+
716
+ def reset_overrides(_) =
717
+ if
718
+ not persist_overrides
719
+ then
720
+ log(
721
+ "Setting fade in to default duration: #{original_duration}s, delay: #{
722
+ original_delay
723
+ }s, type: #{original_type}, curve: #{original_curve}"
724
+ )
725
+ duration := original_duration
726
+ delay := original_delay
727
+ type := original_type
728
+ curve := original_curve
729
+ end
730
+ end
731
+
732
+ s = source.methods(s)
733
+ s.on_track(synchronous=true, reset_overrides)
734
+ s.on_metadata(synchronous=true, update_fade)
735
+
736
+ # Register start_fade on the inner source so it fires before the amplify
737
+ # operator processes the new track head.
738
+ if track_sensitive then s.on_track(synchronous=true, start_fade) end
739
+
740
+ # Initial duration for fade.in should be computed after fetching the initial
741
+ # frame from s to make sure any initial metadata is taken into account
742
+ prepare = ref(fun (_) -> ())
743
+ s =
744
+ source.dynamic(
745
+ memoize(
746
+ fun () ->
747
+ begin
748
+ prepare = prepare()
749
+ prepare(s)
750
+ if s.is_active() then s.generate_frame() end
751
+ delay = delay()
752
+ if
753
+ delay > 0.
754
+ then
755
+ effective_source = source.methods(source.effective(s))
756
+ if
757
+ s.is_active()
758
+ then
759
+ log(
760
+ level=2,
761
+ "Active source #{effective_source.id()} is faded in after an \
762
+ initial delay of #{delay}s. This will result is initial data \
763
+ loss since the source will be animated while the delay \
764
+ expires."
765
+ )
766
+ end
767
+ sequence(merge=true, [blank(duration=delay), s])
768
+ else
769
+ s
770
+ end
771
+ end
772
+ )
773
+ )
774
+
775
+ s = fade.scale(id=id, apply, s)
776
+
777
+ if
778
+ not track_sensitive
779
+ then
780
+ s.on_frame(synchronous=true, before=false, memoize({start_fade([])}))
781
+ end
782
+ s.{fade_duration = {duration()}, fade_delay = {delay()}, fade_type = {type()}}
783
+ end
784
+
785
+ # Simple transition for crossfade
786
+ # @category Source / Fade
787
+ # @param ~log Logging utility
788
+ # @param ~fade_in Fade-in duration, if any.
789
+ # @param ~fade_out Fade-out duration, if any.
790
+ # @param ~initial_fade_in_metadata Initial fade-in metadata
791
+ # @param ~initial_fade_out_metadata Initial fade-out metadata
792
+ # @param ~ending_map Optional mapping for the ending track
793
+ # @param ~starting_map Optional mapping for the starting track
794
+ # @param a Ending track
795
+ # @param b Starting track
796
+ def cross.simple(
797
+ ~log=(fun (s) -> log(label="cross.simple", level=3, s)),
798
+ ~fade_in=3.,
799
+ ~fade_out=3.,
800
+ ~initial_fade_in_metadata=[],
801
+ ~initial_fade_out_metadata=[],
802
+ ~ending_map=fun (s) -> s,
803
+ ~starting_map=fun (s) -> s,
804
+ a,
805
+ b
806
+ ) =
807
+ fade_out_start_next =
808
+ if
809
+ list.assoc.mem("liq_fade_out_start_next", initial_fade_out_metadata)
810
+ then
811
+ float_of_string(initial_fade_out_metadata["liq_fade_out_start_next"])
812
+ else
813
+ 0.
814
+ end
815
+
816
+ fade_in_delay =
817
+ if
818
+ list.assoc.mem("liq_fade_in_delay", initial_fade_in_metadata)
819
+ then
820
+ float_of_string(initial_fade_in_metadata["liq_fade_in_delay"])
821
+ else
822
+ fade_out_start_next
823
+ end
824
+
825
+ fade_in_delay =
826
+ if
827
+ source.duration(b) < source.duration(a)
828
+ then
829
+ delay = source.duration(a) - source.duration(b)
830
+ log(
831
+ "Adding #{delay} of fade_in_delay to match ending source"
832
+ )
833
+ fade_in_delay + delay
834
+ else
835
+ fade_in_delay
836
+ end
837
+
838
+ def fade.out(s) =
839
+ fade.out(
840
+ type="sin",
841
+ persist_overrides=true,
842
+ duration=fade_out,
843
+ initial_metadata=initial_fade_out_metadata,
844
+ s
845
+ )
846
+ end
847
+
848
+ def fade.in(s) =
849
+ fade.in(
850
+ type="sin",
851
+ persist_overrides=true,
852
+ duration=fade_in,
853
+ initial_metadata=[
854
+ ...list.assoc.remove("liq_fade_in_delay", initial_fade_in_metadata),
855
+ ("liq_fade_in_delay", "#{fade_in_delay}")
856
+ ],
857
+ s
858
+ )
859
+ end
860
+
861
+ add = fun (a, b) -> add(normalize=false, [starting_map(b), ending_map(a)])
862
+ add(fade.out(a), fade.in(b))
863
+ end
864
+
865
+ # @docof cross
866
+ # @param ~deduplicate Crossfade transitions can generate duplicate metadata. When `true`, the operator \
867
+ # removes duplicate metadata from the returned source.
868
+ def replaces cross(%argsof(cross), ~deduplicate=true, transition, s) =
869
+ if
870
+ not deduplicate
871
+ then
872
+ cross(%argsof(cross), transition, s)
873
+ else
874
+ s = cross(%argsof(cross[!id]), transition, s)
875
+ dedup = metadata.deduplicate(s)
876
+
877
+ dedup.{
878
+ buffered = s.buffered,
879
+ duration = s.duration,
880
+ cross_duration = s.cross_duration
881
+ }
882
+ end
883
+ end
884
+
885
+ # Crossfade between tracks, taking the respective volume levels into account in
886
+ # the choice of the transition.
887
+ # @category Source / Fade
888
+ # @argsof cross[id,duration,override_duration,persist_override,width]
889
+ # @param ~deduplicate Crossfade transitions can generate duplicate metadata. When `true`, the operator \
890
+ # removes duplicate metadata from the returned source.
891
+ # @param s The input source.
892
+ def crossfade(
893
+ %argsof(cross[id,duration,override_duration,persist_override,width]),
894
+ ~fade_in=3.,
895
+ ~fade_out=3.,
896
+ ~deduplicate=true,
897
+ s
898
+ ) =
899
+ id = string.id.default(default="crossfade", id)
900
+
901
+ def log(~level=3, x) =
902
+ log(label=id, level=level, x)
903
+ end
904
+
905
+ def transition(a, b) =
906
+ list.iter(
907
+ fun (x) ->
908
+ log(
909
+ level=4,
910
+ "Before: #{x}"
911
+ ),
912
+ a.metadata
913
+ )
914
+
915
+ list.iter(
916
+ fun (x) ->
917
+ log(
918
+ level=4,
919
+ "After : #{x}"
920
+ ),
921
+ b.metadata
922
+ )
923
+
924
+ cross.simple(
925
+ log=log,
926
+ fade_in=fade_in,
927
+ fade_out=fade_out,
928
+ initial_fade_in_metadata=b.metadata,
929
+ initial_fade_out_metadata=a.metadata,
930
+ a.source,
931
+ b.source
932
+ )
933
+ end
934
+
935
+ cross(
936
+ %argsof(cross[id,duration,override_duration,persist_override,width]),
937
+ deduplicate=deduplicate,
938
+ transition,
939
+ s
940
+ )
941
+ end