Skip to content

Commit

Permalink
Rename map_metadata into metadata.map, add metadata.deduplicate, make…
Browse files Browse the repository at this point in the history
… sure crossfade transition sources do no re-send old source metadata.

Fixes: #2153
  • Loading branch information
smimram authored and toots committed Mar 23, 2022
1 parent 4781e84 commit de8359c
Show file tree
Hide file tree
Showing 18 changed files with 141 additions and 41 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Changed:
* Optimized memory usage when accessing ground terms.
* Allow crossfade duration getter to override duration at the
end of each track if duration isn't set via metadata.
* Make sure crossfade metadata are not duplicated (#2153)
* Renamed `map_metadata` into `metadata.map`, deprecated `map_metadata`.
* Enhanced remaining time when using `add` (#2255)

Fixed:
Expand Down
2 changes: 1 addition & 1 deletion doc/content/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ def source_tag(s,tag) =
def f(_)
[("source_tag",(tag:string))]
end
map_metadata(id=tag,insert_missing=true,f,s)
metadata.map(id=tag,insert_missing=true,f,s)
end
# Tag our sources
Expand Down
2 changes: 1 addition & 1 deletion doc/content/metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def append_title(m) =
end
# Apply map_metadata to s using append_title
s = map_metadata(append_title, s)
s = metadata.map(append_title, s)
```

The effect of `map_metadata` by default is to update the metadata with the
Expand Down
1 change: 1 addition & 0 deletions doc/content/migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ deprecated operatords. Here's a list of the most important ones:
* `empty` is replaced by: `source.fail`
* `file.unlink` is replaced by: `file.remove`
* `string.utf8.escape` is replaced by: `string.escape`
* `map_metadata` is replaced by: `metadata.map`

### Windows build

Expand Down
4 changes: 2 additions & 2 deletions doc/content/on2_part2.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ end
Finally, we apply `map_metadata` to the source, just after the `request.dynamic.list`
definition in `radio.liq`:
```liquidsoap
s = map_metadata(update_title,s)
s = metadata.map(update_title,s)
```

Solutions:
Expand Down Expand Up @@ -436,7 +436,7 @@ end
```
And, we add the following line in `radio.liq` after the `request.dynamic.list` line:
```liquidsoap
s = map_metadata(add_replaygain,s)
s = metadata.map(add_replaygain,s)
```
Finally, we add the `amplify` operator. We set the default amplification
to `1.`, i.e. no amplification, and tell the operator to update this value with
Expand Down
13 changes: 10 additions & 3 deletions libs/deprecations.liq
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,17 @@ def playlist.once(~id=null(),~random=false,~reload_mode="",
playlist(reload_mode=reload_mode, loop=false, id=id, mode=mode, prefetch=prefetch, check_next=filter, uri)
end

# Deprecated: this function has been replaced by `map_metadata`.
# Deprecated: use metadata.map
# @flag deprecated
def map_metadata(%argsof(metadata.map), fn, (s:source))
deprecated("map_metadata", "metadata.map")
metadata.map(%argsof(metadata.map), fn, s)
end

# Deprecated: this function has been replaced by `metadata.map`.
# @flag deprecated
def rewrite_metadata(l,~insert_missing=true,~update=true,~strip=false,s)
deprecated("rewrite_metadata", "map_metadata")
deprecated("rewrite_metadata", "metadata.map")
def map(m)
def apply(x)
label = fst(x)
Expand All @@ -107,7 +114,7 @@ def rewrite_metadata(l,~insert_missing=true,~update=true,~strip=false,s)
end
list.map(apply,l)
end
map_metadata(map,insert_missing=insert_missing,update=update,strip=strip,s)
metadata.map(map,insert_missing=insert_missing,update=update,strip=strip,s)
end

# Deprecated: this function will be removed in a future release
Expand Down
16 changes: 13 additions & 3 deletions libs/fades.liq
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,13 @@ end
# @param ~medium Smart crossfade: value, in dB, for medium sound level.
# @param ~margin Smart crossfade: margin to detect sources that have too different \
# sound level for crossing.
# @param ~deduplicate Crossfade transitions can generate duplicate metadata. When `true`, the operator \
# removes duplicate metadata from the returned source.
# @param s The input source.
def crossfade(~id=null(), ~duration=5.,~override_duration="liq_cross_duration",
~fade_in=3.,~fade_out=3.,~smart=false,
~default=(fun (a,b) -> (sequence([a, b]):source)),
~high=-15., ~medium=-32., ~margin=4.,
~high=-15., ~medium=-32., ~margin=4., ~deduplicate=true,
~minimum=(-1.),~width=2.,~conservative=true,s)
id = string.id.default(default="crossfade", id)
log = log(label=id)
Expand Down Expand Up @@ -389,8 +391,16 @@ def crossfade(~id=null(), ~duration=5.,~override_duration="liq_cross_duration",
simple_transition
end

cross(id=id, width=width, duration=duration, override_duration=override_duration,
conservative=conservative, minimum=minimum, transition, s)
let (cross_id, deduplicate_id) = deduplicate ? (null(), null(id)) : (null(id), null())

s = cross(id=cross_id, width=width, duration=duration, override_duration=override_duration,
conservative=conservative, minimum=minimum, transition, s)

if deduplicate then
metadata.deduplicate(id=deduplicate_id, s)
else
s
end
end

# Mixes two streams, with faded transitions between the state when only the
Expand Down
17 changes: 17 additions & 0 deletions libs/metadata.liq
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,20 @@ def metadata.json.parse(s) =
m = json.parse(default=[("invalid","invalid")], s)
if m == [("invalid","invalid")] then [] else m end
end

# Remove duplicate metadata in source
# @category Source / Track Processing
# @param ~id Source id
# @param s source
def metadata.deduplicate(~id=null("metadata.deduplicate"), s) =
last_meta = ref([])
def f(m) =
if m == !last_meta then
[]
else
last_meta := m
m
end
end
metadata.map(id=id, insert_missing=false, update=false, strip=true, f, s)
end
2 changes: 1 addition & 1 deletion libs/shoutcast.liq
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def output.shoutcast(
m
end
end
s = map_metadata(map,s)
s = metadata.map(map,s)

output.icecast(
%argsof(
Expand Down
2 changes: 1 addition & 1 deletion libs/source.liq
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ end
# Removes all metadata coming from a source.
# @category Source / Track Processing
def drop_metadata(s)
map_metadata(fun(_)->[],update=false,strip=true,insert_missing=false,s)
metadata.map(fun(_)->[],update=false,strip=true,insert_missing=false,s)
end

# Creates a source that plays only one track of the input source.
Expand Down
4 changes: 2 additions & 2 deletions src/operators/map_metadata.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ open Source

class map_metadata ~kind source rewrite_f insert_missing update strip =
object (self)
inherit operator ~name:"map_metadata" kind [source]
inherit operator ~name:"metadata.map" kind [source]
method stype = source#stype
method is_ready = source#is_ready
method remaining = source#remaining
Expand Down Expand Up @@ -69,7 +69,7 @@ class map_metadata ~kind source rewrite_f insert_missing update strip =
let register =
let kind = Lang.any in
let return_t = Lang.kind_type_of_kind_format kind in
Lang.add_operator "map_metadata"
Lang.add_operator "metadata.map"
[
( "",
Lang.fun_t
Expand Down
4 changes: 2 additions & 2 deletions tests/regression/AC5109.liq
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ s = sequence([s1,s2])

def transition(a, b) =
s1 = sine(duration=0.5)
s1 = map_metadata(fun (_) -> [("type", "s1")], s1)
s1 = metadata.map(fun (_) -> [("type", "s1")], s1)

s2 = sine(duration=0.5)
s2 = map_metadata(fun (_) -> [("type", "s2")], s2)
s2 = metadata.map(fun (_) -> [("type", "s2")], s2)
sequence([(a.source:source), (s1:source), (s2:source), (b.source:source)])
end

Expand Down
6 changes: 3 additions & 3 deletions tests/regression/GH1129.liq
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def m1(_) =
[("id","s1")]
end

s1 = map_metadata(id="s1",m1,s1)
s1 = metadata.map(id="s1",m1,s1)

s2_ready = ref(false)

Expand All @@ -25,15 +25,15 @@ def m2(_) =
[("id","s2")]
end

s2 = map_metadata(id="s2",m2,s2)
s2 = metadata.map(id="s2",m2,s2)

s3 = blank(id="s3",duration=0.04)

def m3(_) =
[("id","s3")]
end

s3 = map_metadata(id="s3",m3,s3)
s3 = metadata.map(id="s3",m3,s3)

def f(m) =
s2_ready := !s2_ready or m["id"] == "s3"
Expand Down
4 changes: 2 additions & 2 deletions tests/regression/GH1279.liq
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ def m1(_) =
[("id","s1")]
end

s1 = map_metadata(id="s1",m1,s1)
s1 = metadata.map(id="s1",m1,s1)

s2 = blank(duration=0.04)

def m2(_) =
[("id","s2")]
end

s2 = map_metadata(id="s2",m2,s2)
s2 = metadata.map(id="s2",m2,s2)

def f(m) =
selected := list.add(m["id"],!selected)
Expand Down
6 changes: 3 additions & 3 deletions tests/regression/GH1327.liq
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ def m1(_) =
[("id","s1")]
end

s1 = map_metadata(id="s1",m1,s1)
s1 = metadata.map(id="s1",m1,s1)

s2 = blank(duration=0.1)

def m2(_) =
[("id","s2")]
end

s2 = map_metadata(id="s2",m2,s2)
s2 = metadata.map(id="s2",m2,s2)

def f(m) =
selected := list.add(m["id"],!selected)
Expand All @@ -34,7 +34,7 @@ def m_noise(_) =
[("id","noise")]
end

noise = map_metadata(id="noise", m_noise, noise())
noise = metadata.map(id="noise", m_noise, noise())

ready = ref(false)

Expand Down
35 changes: 28 additions & 7 deletions tests/streams/cross.liq
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,44 @@
video.frame.rate.set(24)

a = sine(duration=5.,440.)
b = sine(880.)
a = metadata.map(update=false, (fun (_) -> [("title","a")]), a)

b = sine(duration=5.,880.)
b = metadata.map(update=false, (fun (_) -> [("title","b")]), b)

s = sequence([a,b])

def t(a, b)
log.important("Crossing!")
log.important("Levels: #{a.db_level} / #{b.db_level}")
log.important("Metadata: #{a.metadata} / #{b.metadata}")
add(normalize=false, [a.source, b.source])
sequence([a.source, b.source])
end

s = cross(duration=3., width=1., t, s)

output.dummy(fallible=true, s)
seen_a = ref(false)
seen_b = ref(false)

def check_duplicate(m) =
if m["title"] == "a" then
if !seen_a then test.fail() else seen_a := true end
end
if m["title"] == "b" then
if !seen_b then test.fail() else seen_b := true end
end
end

s.on_metadata(check_duplicate)

clock.assign_new(sync="none",[s])

def on_done () =
test.pass()
shutdown()
def on_stop () =
if !seen_a and !seen_b then
test.pass()
else
test.fail()
end
end

thread.run(delay=8., on_done)
output.dummy(fallible=true, on_stop=on_stop,s)
58 changes: 50 additions & 8 deletions tests/streams/crossfade.liq
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,58 @@

video.frame.rate.set(24)

a = sine(duration=5., 440.)
b = sine(880.)
a = sine(duration=20.,440.)
a = metadata.map(update=false, (fun (_) -> [("title","a1")]), a)

b = sine(duration=20.,880.)
b = metadata.map(update=false, (fun (_) -> [("title","b1")]), b)

s = sequence([a,b])

fa = crossfade(smart=true, deduplicate=true, s)

a = sine(duration=20.,440.)
a = metadata.map(update=false, (fun (_) -> [("title","a2")]), a)

b = sine(duration=20.,880.)
b = metadata.map(update=false, (fun (_) -> [("title","b2")]), b)

s = sequence([a,b])
s = crossfade(duration=3., s)

output.dummy(fallible=true, s)
fb = crossfade(smart=true, deduplicate=false, s)

s = sequence([merge_tracks(fa), fb])

dedup_a = ref(0)
dedup_b = ref(0)
dup_a = ref(0)
dup_b = ref(0)

def check_duplicate(m) =
if m["title"] == "a1" then
dedup_a := !dedup_a + 1
end
if m["title"] == "b1" then
dedup_b := !dedup_b + 1
end
if m["title"] == "a2" then
dup_a := !dup_a + 1
end
if m["title"] == "b2" then
dup_b := !dup_b + 1
end
end

s.on_metadata(check_duplicate)

clock.assign_new(sync="none",[s])

def on_done () =
test.pass()
shutdown()
def on_stop () =
if !dup_a == 2 and !dup_b == 2 and !dedup_a == 1 and !dedup_b == 1 then
test.pass()
else
test.fail()
end
end

thread.run(delay=8., on_done)
output.dummy(fallible=true, on_stop=on_stop,s)
4 changes: 2 additions & 2 deletions tests/streams/random.liq
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def m1(_) =
[("id","s1")]
end

s1 = map_metadata(m1,s1)
s1 = metadata.map(m1,s1)

s1_ready = ref(true)

Expand All @@ -29,7 +29,7 @@ def m2(_) =
[("id","s2")]
end

s2 = map_metadata(id="s2",m2,s2)
s2 = metadata.map(id="s2",m2,s2)

s2_ready = ref(false)

Expand Down

0 comments on commit de8359c

Please sign in to comment.