Skip to content

Commit 8cbdfd6

Browse files
committed
Revert "Cleanup."
This reverts commit 3bf6f3a.
1 parent 3bf6f3a commit 8cbdfd6

File tree

433 files changed

+362542
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

433 files changed

+362542
-1
lines changed

website/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ GENERATED_INTERPRETER_DIR := $(PWD)/../liquidsoap/_build/default/src/js
66
NODE := $(shell which node)
77

88
# Versions for which documentation should be built and included
9-
VERSIONS := dev 1.4.4 2.1.4 2.2.5 2.3.0 2.3.1
9+
VERSIONS := dev 1.4.4 2.1.4 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1
1010
DEFAULT_VERSION := 2.3.1
1111
# DEFAULT_VERSION := dev
1212

website/content/doc-2.2.0/beets.md

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Integrating a music library: an example with Beets
2+
3+
Liquidsoap's native sources can read from files and folders,
4+
but if your radio uses an important music library
5+
(more than a thousand tracks)
6+
sorting by folders may not be enough.
7+
You will also need to adjust the playout gain per track (ReplayGain).
8+
In that case you would better have a music library
9+
queried by Liquidsoap.
10+
In this section we'll do this with [Beets](http://beets.io/).
11+
Beets holds your music catalog,
12+
cleans tracks' tags before importing,
13+
can compute each track's ReplayGain,
14+
and most importantly has a command-line interface we can leverage from Liquidsoap.
15+
The following examples may also inspire you to integrate another library or your own scripts.
16+
17+
After installing Beets,
18+
enable the `random` plug-in
19+
(see [Beets documentation on plug-ins](https://beets.readthedocs.io/en/stable/plugins/index.html#using-plugins)).
20+
To enable gain normalization, install and configure the
21+
[`replaygain`](https://beets.readthedocs.io/en/stable/plugins/replaygain.html) plug-in.
22+
To easily add single tracks to you library,
23+
you might also be interested in the
24+
[drop2beets](https://github.com/martinkirch/drop2beets#drop2beets) plug-in.
25+
The following examples suppose you defined a `BEET` constant,
26+
which contains the complete path to your `beet` executable (on UNIX systems, find it with `which beet`). For example:
27+
28+
```
29+
BEET = "/home/radio/.local/bin/beet"
30+
```
31+
32+
Before creating a Liquidsoap source,
33+
let's see why Beets queries are interesting for a radio.
34+
35+
## Beets queries
36+
37+
Queries are parameters that you usually provide to the `beet ls` command :
38+
Beets will find matching tracks.
39+
The `random` plug-in works the same, except that it returns only one track matching the query
40+
(see [the plug-in's documentation](https://beets.readthedocs.io/en/stable/plugins/random.html)).
41+
Once your library is imported,
42+
you can try the following queries on the command line
43+
by typing `beet ls [query]` or `beet random [query]`.
44+
To test quickly, add the `-t 60` option to `beet random`
45+
so it will select an hour worth of tracks matching your query.
46+
47+
Without selectors, queries search in a track’s title, artist, album name,
48+
album artist, genre and comments. Typing an artist name or a complete title
49+
usually match the exact track, and you could do a lovely playlist just by querying `love`.
50+
51+
But in a radio you'll usually query on other fields.
52+
You can select tracks by genre with the `genre:` selector.
53+
Be careful that `genre:Rock` also matches `Indie Rock`, `Punk Rock`, etc.
54+
To select songs having english lyrics, use `language:eng`.
55+
Or pick 80s songs with `year:1980..1990`.
56+
57+
Beets also holds internal meta-data, like `added`:
58+
the date and time when you imported each song.
59+
You can use it to query tracks inserted over the past month with `added:-1m..`.
60+
Or you can query track imported more than a year ago with `added:..-1y`.
61+
Beets also lets you
62+
[set your own tags](https://beets.readthedocs.io/en/stable/guides/advanced.html#store-any-data-you-like).
63+
64+
You can use the `info` plug-in to see everything Beets knows about title(s) matching a query
65+
by typing `beet info -l [query]`.
66+
See also [the Beets' documentation](https://beets.readthedocs.io/en/stable/reference/query.html)
67+
for more details on queries operators.
68+
All these options should allow you to create both general and specialiazed Liquidsoap sources.
69+
70+
## A source querying each next track from Beets
71+
72+
As of Liquidsoap 2.x we can create a function that creates a dynamic source,
73+
given its `id` and a Beet query.
74+
We rely on `request.dynamic` to call `beet random`
75+
(with `-f '$path'` option so beets only returns the matching track's path)
76+
every time the source must prepare a new track:
77+
78+
```liquidsoap
79+
def beets(id, query) =
80+
beets_src =
81+
request.dynamic(id=id, retry_delay=1., {
82+
request.create(
83+
string.trim(
84+
process.read("#{BEET} random -f '$path' #{query}")
85+
)
86+
)
87+
})
88+
(beets_src:source)
89+
end
90+
91+
all_music = beets("all_music", "")
92+
recent_music = beets("recent_music", "added:-1m..")
93+
rock_music = beets("rock_music", "genre:Rock")
94+
```
95+
96+
Note that
97+
98+
- `query` can be empty, it will match all tracks in the library.
99+
- we set `retry_delay` to a second, to avoid looping on `beet` calls if something goes wrong.
100+
- The final type hint (`:source`) will avoid false typing errors when the source is integrated in complex operators.
101+
102+
## Applying ReplayGain
103+
104+
When the [`replaygain` plug-in](https://beets.readthedocs.io/en/stable/plugins/replaygain.html)
105+
is enabled, all tracks will have an additional metadata field called `replaygain_track_gain`.
106+
Check that Beet is configured to
107+
[write ID3 tags](https://beets.readthedocs.io/en/stable/reference/config.html#importer-options)
108+
so Liquidsoap will be able to read this metadata -
109+
your Beet configuration should include something like:
110+
111+
```
112+
import:
113+
write: yes
114+
```
115+
116+
Then we only need to add `amplify` to our source creation function. In the example below we also add `blank.eat`, to automatically cut silence at the beginning or end of tracks.
117+
118+
```liquidsoap
119+
def beets(id, query) =
120+
beets_src =
121+
blank.eat(id="#{id}_", start_blank=true, max_blank=1.0, threshold=-45.0,
122+
amplify(override="replaygain_track_gain", 1.0,
123+
request.dynamic(id=id, retry_delay=1., {
124+
request.create(
125+
string.trim(
126+
process.read("#{BEET} random -f '$path' #{query}")
127+
)
128+
)
129+
})
130+
)
131+
)
132+
(beets_src:source)
133+
end
134+
```
135+
136+
This is the recommended Beets integration ;
137+
such source will provide music continuously,
138+
at a regular volume.
139+
140+
## Beets as a requests protocol
141+
142+
If you're queueing tracks with `request.queue`,
143+
you may prefer to integrate Beets as a protocol.
144+
In that case,
145+
the list of paths returned by `beet random -f '$path'` fits directly
146+
what's needed by protocol resolution:
147+
148+
```liquidsoap
149+
def beets_protocol(~rlog,~maxtime,arg) =
150+
timeout = maxtime - time()
151+
command = "#{BEET} random -f '$path' #{arg}"
152+
p = process.run(timeout=timeout, command)
153+
if p.status == "exit" and p.status.code == 0 then
154+
[string.trim(p.stdout)]
155+
else
156+
rlog("Failed to execute #{command}: #{p.status} (#{p.status.code}) #{p.stderr}")
157+
[]
158+
end
159+
end
160+
protocol.add("beets", beets_protocol,
161+
syntax = "same arguments as beet's random module, see https://beets.readthedocs.io/en/stable/reference/query.html"
162+
)
163+
```
164+
165+
Once this is done,
166+
you can push a beets query from [the telnet server](server.html):
167+
if you created `request.queue(id="userrequested")`,
168+
the server command
169+
`userrequested.push beets:All along the watchtower`
170+
will push the Jimi Hendrix's song.
171+
172+
With this method, you can benefit from replay gain metadata too, by wrapping
173+
the recipient queue in an `amplify` operator, like
174+
175+
```liquidsoap
176+
userrequested = amplify(override="replaygain_track_gain", 1.0,
177+
request.queue(id="userrequested")
178+
)
179+
```

website/content/doc-2.2.0/blank.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Blank detection
2+
3+
[Liquidsoap](index.html) has three operators for dealing with blanks.
4+
5+
On GeekRadio, we play many files, some of which include bonus tracks, which
6+
means that they end with a very long blank and then a little extra music. It's
7+
annoying to get that on air. The `blank.skip` operator skips the
8+
current track when a too long blank is detected, which avoids that. The typical
9+
usage is simple:
10+
11+
```liquidsoap
12+
# Wrap it with a blank skipper
13+
source = blank.skip(source)
14+
```
15+
16+
At [RadioPi](http://www.radiopi.org/) they have another problem: sometimes they
17+
have technical problems, and while they think they are doing a live show,
18+
they're making noise only in the studio, while only blank is on air; sometimes,
19+
the staff has so much fun (or is it something else ?) doing live shows that they
20+
leave at the end of the show without thinking to turn off the live, and the
21+
listeners get some silence again. To avoid that problem we made the
22+
`blank.strip` operators which hides the stream when it's too blank
23+
(i.e. declare it as unavailable), which perfectly suits the typical setup used
24+
for live shows:
25+
26+
```liquidsoap
27+
interlude = single("/path/to/sorryfortheblank.ogg")
28+
# After 5 sec of blank the microphone stream is ignored,
29+
# which causes the stream to fallback to interlude.
30+
# As soon as noise comes back to the microphone the stream comes
31+
# back to the live -- thanks to track_sensitive=false.
32+
stream = fallback(track_sensitive=false,
33+
[ blank.strip(max_blank=5.,live) , interlude ])
34+
35+
# Put that stream to a local file
36+
output.file(%vorbis, "/tmp/hop.ogg", stream)
37+
```
38+
39+
If you don't get the difference between these two operators, you should learn
40+
more about liquidsoap's notion of [source](sources.html).
41+
42+
Finally, if you need to do some custom action when there's too much blank, we
43+
have `blank.detect`:
44+
45+
```liquidsoap
46+
def handler()
47+
system("/path/to/your/script to do whatever you want")
48+
end
49+
source = blank.detect(handler,source)
50+
```

website/content/doc-2.2.0/book.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# The Liquidsoap book
2+
3+
Together with the release of Liquidsoap 2.0, we have written _the Liquidsoap
4+
book_ which covers in details the language and the process of building a
5+
radio. It complements the online documentation by providing a homogeneous and
6+
progressive presentation of Liquidsoap.
7+
8+
[![The Liquidsoap book](/assets/img/book.svg){height=600px}](https://www.amazon.com/dp/B095PVTYR3)
9+
10+
It can be [ordered from Amazon](https://www.amazon.com/dp/B095PVTYR3)
11+
(or [read online](http://www.liquidsoap.info/book/book.pdf)).

website/content/doc-2.2.0/build.md

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Building Liquidsoap
2+
3+
## Forewords
4+
5+
Installing liquidsoap can be a difficult task. The software relies on a up-to date
6+
OCaml compiler, as well as a bunch of OCaml modules and, for most of them, corresponding
7+
C library dependencies.
8+
9+
Our recommended way of installing liquidsoap is via [opam](http://opam.ocaml.org/). `opam` can take
10+
care of installing the correct OCaml compiler, optional and required dependencies as well as system-specific
11+
package dependencies.
12+
13+
The `opam` method is described in details in the [documentation](doc/content/install.md).
14+
We recommend that any interested user head over to this link to install the software via `opam`.
15+
16+
The remainder of this document describes how to compile liquidsoap locally for developers.
17+
18+
## Overview
19+
20+
Liquidsoap is compiled using [dune](https://dune.readthedocs.io/en/stable/), which is the most popular
21+
OCaml build system at the moment. `dune` is tightly integrated with `opam` so, even if you are installing
22+
from source using `dune`, `opam` remains an important tool.
23+
24+
Generally speaking, compiling from source may require the latest version of the liquidsoap code as well as its
25+
dependencies. Some of its dependencies are optional and can be ignored at first and some are not.
26+
27+
Keep in mind that, although `opam` is generally aware of required minimal version for dependencies, `dune` is not.
28+
If a dependency is outdated, `dune` compilation will simply fail, at which point your may have to figure out if
29+
you need to update a dependency.
30+
31+
Each branch of liquidsoap is compiled using [github actions](https://github.com/savonet/liquidsoap/actions). When trying
32+
to build a specific branch, if the CI passes with it then, most likely, you are missing a dependency or it is not
33+
the latest version.
34+
35+
## `opam` pinning
36+
37+
`opam` pinning is a mechanism to update `opam` with the latest version of a package, even before it is published to
38+
the official opam repository. This is the easiest way to update a dependency to its latest version.
39+
40+
You can pin directly from a local git repository checkout:
41+
42+
```shell
43+
git clone https://github.com/savonet/ocaml-metadata.git
44+
cd ocaml-metadata
45+
opam pin -ny .
46+
```
47+
48+
You can also pin directly using a git url:
49+
50+
```shell
51+
opam pin -ny git+https://github.com/savonet/ocaml-cry
52+
```
53+
54+
See `opam pin --help` for more defails about the available options.
55+
56+
## Dependencies
57+
58+
The best way to figure out what dependencies are required or optional and their versions is to use the latest `opam`
59+
package. Since `liquidsoap` development is using `dune` and `opam`, the dependencies are kept in sync via the
60+
local liquidsoap opam package(s) and this serves as the de-facto list of dependencies and their versions.
61+
62+
First, you should pin the latest liquidsoap code:
63+
64+
```shell
65+
opam pin -ny git+https://github.com/savonet/liquidsoap
66+
```
67+
68+
Then, ask `opam` to list all the dependencies for `liquidsoap`:
69+
70+
```shell
71+
opam info liquidsoap
72+
opam info liquidsoap-core
73+
opam info liquidsoa-lang
74+
```
75+
76+
This should give you a (long!) list of all dependencies. Then, you can query `opam` to see
77+
what each dependency does. This is particularly useful for optional dependencies on `liquidsoap-core`
78+
which provide opt-in features. For instance `opam info soundtouch` will let you know that this
79+
package provides functions for changing pitch and timestretching audio data.
80+
81+
Lastly, there are two types of dependencies:
82+
83+
- Dependencies maintained by us
84+
- Dependencies not maintained by us
85+
86+
For dependencies not maintained by us, most of the time, we rely on the latest published version. Very rarely should you
87+
have to fetch/pin the latest version of these dependencies.
88+
89+
For dependencies maintained by us, we may break their API during our development cycle and you maybe have to fetch/pin
90+
the latest version when compilign the latest `liquidsoap` code. You may also have to check out a specific
91+
branch when compiling `liquidsoap` from a specific development branch when the changes in the liquidsoap code are paired with
92+
changes in one of our dependencies. Typically, this happens a lof with the `ffmpeg` binding.
93+
94+
## Compiling
95+
96+
Once you have all dependencies installed, you should be able to compile via:
97+
98+
```shell
99+
dune build
100+
```
101+
102+
If an error occurs, you may need to see if you need to update a dependency. Hopefully, with a short iteration of this cycle,
103+
you will end up with a successful build!
104+
105+
Once you have a successful build, you can also use the top-level `liquidsoap` script. This script builds the latest code and
106+
executes it right away. It works as if you were calling the `liquidsoap` binary after installing it:
107+
108+
```shell
109+
./liquidsoap -h output.ao
110+
```
111+
112+
From here, you can start changing code, testing script etc. Happy hacking!

0 commit comments

Comments
 (0)