Skip to content

Commit c33d22b

Browse files
committed
Add Guidelines and Readme cleanup
Add Guidelines and assets Remove documentation from Readme and refer GitHub page CI scripts cleanup
1 parent 1f6b431 commit c33d22b

12 files changed

+232
-366
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[submodule "modules/asio-standalone"]
22
path = modules/asio-standalone
3-
url = git@github.com:chriskohlhoff/asio.git
3+
url = https://github.com/chriskohlhoff/asio.git
44
[submodule "modules/catch"]
55
path = modules/catch
66
url = https://github.com/philsquared/Catch.git

Ableton Link Guidelines.pdf

285 KB
Binary file not shown.

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Contributing
2+
3+
Unfortunately we can not accept pull requests at the moment.
4+
5+
If you found errors or have suggestions for improvements please open an issue.
6+
When reporting errors please provide a detailed description and code examples if
7+
possible.

README.md

Lines changed: 13 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ can join or leave without disrupting the session.
1010
# License
1111

1212
Ableton Link is dual [licensed][license] under GNU GPL version 2 and a proprietary license.
13+
If you would like to incorporate Link into a proprietary software application,
14+
please contact <[email protected]>.
1315

1416
# Building and Running Link Examples
1517

@@ -27,13 +29,17 @@ unit-tests and the example applications.
2729
$ mkdir build
2830
$ cd build
2931
$ cmake ..
32+
$ cmake --build .
3033
```
3134

3235
In order to build the GUI example application **QLinkHut**, the [Qt][qt] installation
3336
path must be set in the system PATH and `LINK_BUILD_QT_EXAMPLES` must be set:
3437

3538
```
39+
$ mkdir build
40+
$ cd build
3641
$ cmake -DLINK_BUILD_QT_EXAMPLES=ON ..
42+
$ cmake --build .
3743
```
3844

3945
The output binaries for the example applications and the unit-tests will be placed in a
@@ -106,158 +112,12 @@ information on the LinkKit SDK for iOS.
106112

107113
# Documentation
108114

109-
The [Link.hpp](include/ableton/Link.hpp) header contains the full Link public interface.
110-
See the LinkHut and QLinkHut projects for an example usage of the `Link` type.
111-
112-
## Link Concepts
113-
114-
Link is different from other approaches to synchronizing electronic instruments that you
115-
may be familiar with. It is not designed to orchestrate multiple instruments so that they
116-
play together in lock-step along a shared timeline. In fact, Link-enabled apps each have
117-
their own independent timelines. The Link library maintains a temporal relationship
118-
between these independent timelines that provides the experience of playing in time
119-
without the timelines being identical.
120-
121-
Playing "in time" is an intentionally vague term that might have different meanings for
122-
different musical contexts and different applications. As a developer, you must decide
123-
the most natural way to map your application's musical concepts onto Link's
124-
synchronization model. For this reason, it's important to gain an intuitive understanding
125-
of how Link synchronizes **tempo**, **beat**, and **phase**.
126-
127-
### Tempo Synchronization
128-
129-
Tempo is a well understood parameter that represents the velocity of a beat timeline with
130-
respect to real time, giving it a unit of beats/time. Tempo synchronization is achieved
131-
when the beat timelines of all participants in a session are advancing at the same rate.
132-
133-
With Link, any participant can propose a change to the session tempo at any time. No
134-
single participant is responsible for maintaining the shared session tempo. Rather, each
135-
participant chooses to adopt the last tempo value that they've seen proposed on the
136-
network. This means that it is possible for participants' tempi to diverge during periods
137-
of tempo modification (especially during simultaneous modification by multiple
138-
participants), but this state is only temporary. The session will converge quickly to a
139-
common tempo after any modification. The Link approach to tempo relies on group
140-
adaptation to changes made by independent, autonomous actors - much like a group of
141-
traditional instrumentalists playing together.
142-
143-
### Beat Alignment
144-
145-
It's conceivable that for certain musical situations, participants would wish to only
146-
synchronize tempo and not other musical parameters. But for the vast majority of cases,
147-
playing with synchronized tempo in the absence of beat alignment would not be perceived
148-
as playing "in time." In this scenario, participants' beat timelines would advance at the
149-
same rate, but the relationship between values on those beat timelines would be undefined.
150-
151-
In most cases, we want to provide a stronger timing property for a session than just
152-
tempo synchronization - we also want beat alignment. When a session is in a state of beat
153-
alignment, an integral value on any participant's beat timeline corresponds to an
154-
integral value on all other participants' beat timelines. This property says nothing
155-
about the magnitude of beat values on each timeline, which can be different, just that
156-
any two timelines must only differ by an integral offset. For example, beat 1 on one
157-
participant's timeline might correspond to beat 3 or beat 4 on another's, but it cannot
158-
correspond to beat 3.5.
159-
160-
Note that in order for a session to maintain a state of beat alignment, it must have
161-
synchronized tempo.
162-
163-
### Phase Synchronization
164-
165-
Beat alignment is a necessary condition for playing "in time" in most circumstances, but
166-
it's often not enough. When working with bars or loops, a user may expect that the beat
167-
position within such a construct (the phase) be synchronized, resulting in alignment of
168-
bar or loop boundaries across participants.
169-
170-
In order to enable the desired bar and loop alignment, an application provides a quantum
171-
value to Link that specifies, in beats, the desired unit of phase synchronization. Link
172-
guarantees that session participants with the same quantum value will be phase aligned,
173-
meaning that if two participants have a 4 beat quantum, beat 3 on one participant's
174-
timeline could correspond to beat 11 on another's, but not beat 12. It also guarantees
175-
the expected relationship between sessions in which one participant has a multiple of
176-
another's quantum. So if one app has an 8-beat loop with a quantum of 8 and another has a
177-
4-beat loop with a quantum of 4, then the beginning of an 8-beat loop will always
178-
correspond to the beginning of a 4-beat loop, whereas a 4-beat loop may align with the
179-
beginning or the middle of an 8-beat loop.
180-
181-
Specifying the quantum value and the handling of phase synchronization is the aspect of
182-
Link integration that leads to the greatest diversity of approaches among developers.
183-
There's no one-size-fits-all recommendation about how to do this, it is very
184-
application-specific. Some applications have a constant quantum that never changes.
185-
Others allow it to change to match a changing value in their app, such as loop length or
186-
time signature. In Ableton Live, it is directly tied to the "Global Quantization"
187-
control, so it may be useful to explore how different values affect the behavior of Live
188-
in order to gain intuition about the quantum.
189-
190-
In order to maintain phase synchronization, the vast majority of Link-enabled
191-
applications (including Live) perform a quantized launch when the user starts transport.
192-
This means that the user sees some sort of count-in animation or flashing play button
193-
until starting at the next quantum boundary. This is a very satisfying interaction
194-
because it allows multiple users on different devices to start exactly together just by
195-
pressing play at roughly the same time. We strongly recommend that developers implement
196-
quantized launching in Link-enabled applications.
197-
198-
## Link API
199-
200-
### Timeline
201-
202-
In Link, a timeline is represented as a triple of `(beat, time, tempo)`, which defines a
203-
bijection between the sets of all beat and time values. Converting between beats and time
204-
is the most basic service that Link provides to integrating applications - an application
205-
will generally want to know what beat value corresponds to a given moment in time. The
206-
timeline implements this and all other timing-related queries and modifications available
207-
to Link clients.
208-
209-
Of course, tempo and beat/time mapping may change over time. A timeline value only
210-
represents a snapshot of the state of the system at a particular moment. Link provides
211-
clients the ability to 'capture' such a snapshot. This is the only mechanism for
212-
obtaining a timeline value.
213-
214-
Once a timeline value is captured, clients may query its properties or modify it by
215-
changing its tempo or its beat/time mapping. Modifications to the captured timeline are
216-
*not* propagated to the Link session automatically - clients must 'commit' the modified
217-
timeline back to Link for it to take effect.
218-
219-
A major benefit of the capture-commit model for timelines is that a captured timeline can
220-
be known to have a consistent value for the duration of a computation in which it is
221-
used. If clients queried timing information from the Link object directly without
222-
capturing a timeline, the results could be inconsistent during the course of a
223-
computation because of asynchronous changes coming from other participants in the Link
224-
session.
225-
226-
### Timelines and Threads
227-
228-
Audio application developers know that the thread that computes and fills audio buffers
229-
has special timing constraints that must be managed carefully. It's usually necessary to
230-
query Link timing data while computing audio, so the Link API provides a realtime-safe
231-
timeline capture/commit function pair. This allows clients to query and modify the Link
232-
timeline directly from the audio callback. It's important that this audio-thread specific
233-
interface *only* be used from the audio thread.
234-
235-
It is also often convenient to be able to access the current Link timeline from the main
236-
thread or other application threads, for example when rendering the current beat time in
237-
a GUI. For this reason, Link also provides a timeline capture/commit function pair to be
238-
used on application threads. These versions must not be used from the audio thread as
239-
they may block.
240-
241-
While it is possible to commit timeline modifications from an application thread, this
242-
should generally be avoided by clients that implement a custom audio callback and use
243-
Link from the audio thread. Because of the real-time constraints in the audio thread,
244-
changes made to the Link timeline from an application thread are processed asynchronously
245-
and are not immediately visible to the audio thread. The same is true for changes made
246-
from the audio thread - the new timeline will eventually be visible to the application
247-
thread, but clients cannot rely on exactly when. It's especially important to take this
248-
into account when combining Link timeline modifications with other cross-thread
249-
communication mechanisms employed by the application. For example, if a timeline is
250-
committed from an application thread and in the next line an atomic flag is set, the
251-
audio thread will almost certainly observe the flag being set before observing the new
252-
timeline value.
253-
254-
In order to avoid these complexities, it is recommended that applications that implement
255-
a custom audio callback only modify the Link timeline from the audio thread. Application
256-
threads may query the timeline but should not modify it. This approach also leads to
257-
better timing accuracy because timeline changes can be specified to occur at buffer
258-
boundaries or even at specific samples, which is not possible from an application thread.
259-
260-
### Time and Clocks
115+
An overview of Link concepts can be found at http://ableton.github.io/link. Those that
116+
are new to Link should start there. The [Link.hpp](include/ableton/Link.hpp) header
117+
contains the full Link public interface. See the LinkHut and QLinkHut projects in this
118+
repo for an example usage of the `Link` type.
119+
120+
## Time and Clocks
261121

262122
Link works by calculating a relationship between the system clocks of devices in a session.
263123
Since the mechanism for obtaining a system time value and the unit of these values differ
@@ -294,7 +154,7 @@ the various [platforms](examples/linkaudio) used in the examples to see how this
294154
in practice. Note that for Windows-based systems, we recommend using the [ASIO][asio]
295155
audio driver.
296156

297-
### Latency Compensation
157+
## Latency Compensation
298158

299159
As discussed in the previous section, the system time that a client is provided in an
300160
audio callback either represents the time at which the buffer will be submitted to the

assets/Ableton_Link_Badge-Black.eps

979 KB
Binary file not shown.

assets/Ableton_Link_Badge-White.eps

971 KB
Binary file not shown.
1.3 MB
Binary file not shown.
1.27 MB
Binary file not shown.

ci/build.py

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,72 @@
11
#!/usr/bin/env python
22

3-
from distutils.spawn import find_executable
4-
from subprocess import call
5-
63
import argparse
74
import logging
85
import os
9-
import shutil
106
import sys
117

8+
from distutils.spawn import find_executable
9+
from subprocess import call
10+
1211

1312
def parse_args():
14-
arg_parser = argparse.ArgumentParser()
13+
arg_parser = argparse.ArgumentParser()
1514

16-
arg_parser.add_argument(
17-
'--cmake',
18-
default=find_executable("cmake"),
19-
help='Path to CMake executable (default: %(default)s)')
15+
arg_parser.add_argument(
16+
'--cmake',
17+
default=find_executable("cmake"),
18+
help='Path to CMake executable (default: %(default)s)')
2019

21-
arg_parser.add_argument(
22-
'-c', '--configuration',
23-
help='Build configuration to use (not supported by IDE generators)')
20+
arg_parser.add_argument(
21+
'-c', '--configuration',
22+
help='Build configuration to use (not supported by IDE generators)')
2423

25-
arg_parser.add_argument(
26-
'-a', '--arguments',
27-
help='Arguments to pass to builder')
24+
arg_parser.add_argument(
25+
'-a', '--arguments',
26+
help='Arguments to pass to builder')
2827

29-
return arg_parser.parse_args(sys.argv[1:])
28+
return arg_parser.parse_args(sys.argv[1:])
3029

3130

3231
def build_cmake_args(args, build_dir):
33-
if args.cmake is None:
34-
logging.error('CMake not found, please use the --cmake option')
35-
return None
32+
if args.cmake is None:
33+
logging.error('CMake not found, please use the --cmake option')
34+
return None
3635

37-
cmake_args = []
38-
cmake_args.append(args.cmake)
39-
cmake_args.append('--build')
40-
cmake_args.append(build_dir)
36+
cmake_args = []
37+
cmake_args.append(args.cmake)
38+
cmake_args.append('--build')
39+
cmake_args.append(build_dir)
4140

42-
if args.configuration is not None:
43-
cmake_args.append('--config')
44-
cmake_args.append(args.configuration)
41+
if args.configuration is not None:
42+
cmake_args.append('--config')
43+
cmake_args.append(args.configuration)
4544

46-
if args.arguments is not None:
47-
cmake_args.append('--')
48-
for arg in args.arguments.split():
49-
cmake_args.append(arg)
45+
if args.arguments is not None:
46+
cmake_args.append('--')
47+
for arg in args.arguments.split():
48+
cmake_args.append(arg)
5049

51-
return cmake_args
50+
return cmake_args
5251

5352

5453
def build(args):
55-
scripts_dir = os.path.dirname(os.path.realpath(__file__))
56-
root_dir = os.path.join(scripts_dir, os.pardir)
57-
build_dir = os.path.join(root_dir, 'build')
58-
if not os.path.exists(build_dir):
59-
logging.error('Build directory not found, did you forget to run the configure.py script?')
60-
return 2
54+
scripts_dir = os.path.dirname(os.path.realpath(__file__))
55+
root_dir = os.path.join(scripts_dir, os.pardir)
56+
build_dir = os.path.join(root_dir, 'build')
57+
if not os.path.exists(build_dir):
58+
logging.error(
59+
'Build directory not found, did you forget to run the configure.py script?')
60+
return 2
6161

62-
cmake_args = build_cmake_args(args, build_dir)
63-
if cmake_args is None:
64-
return 1
62+
cmake_args = build_cmake_args(args, build_dir)
63+
if cmake_args is None:
64+
return 1
6565

66-
logging.info('Running CMake')
67-
return call(cmake_args)
66+
logging.info('Running CMake')
67+
return call(cmake_args)
6868

6969

7070
if __name__ == '__main__':
71-
logging.basicConfig(format='%(message)s', level=logging.INFO, stream=sys.stdout)
72-
sys.exit(build(parse_args()))
71+
logging.basicConfig(format='%(message)s', level=logging.INFO, stream=sys.stdout)
72+
sys.exit(build(parse_args()))

0 commit comments

Comments
 (0)