Skip to content

Commit 52d4ac7

Browse files
authored
docs: Guide Updates and Media Sync Editor (#137)
2 parents 001c98d + d635754 commit 52d4ac7

37 files changed

Lines changed: 839 additions & 251 deletions

docs/alphatex/percussion.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
---
22
title: Percussion
3-
since: 1.4.0-alpha.1026
3+
since: 1.4.0
44
---
55

66
import { SinceBadge } from '@site/src/components/SinceBadge';
77

8-
<SinceBadge since="1.4.0-alpha.1026" />
8+
<SinceBadge since="1.4.0" />
99

1010
import { AlphaTexSample } from '@site/src/components/AlphaTexSample';
1111

docs/getting-started/configuration-web.mdx

Lines changed: 5 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ Simply create a div container where you want alphaTab to be located on your page
1313
to the available width of the div when using the page layout. If you prefer a fixed layout simply set a fixed width on the div via CSS
1414
and no resizes to alphaTab will happen either.
1515

16-
If jQuery is detected on the page you can use the jQuery plugin to interact with alphaTab. Otherwise alphaTab is initailized using a special `API`
17-
object. The main namespace `alphaTab` contains every class and enum exposed by the API. The main api is the `alphaTab.AlphaTabApi`
18-
class:
16+
The main namespace `alphaTab` and its sub-namespaces like `model` or `midi` contain all types and functionalities by alphaTab. The main api is the `alphaTab.AlphaTabApi`
17+
class which can be used to initialize and interface with alphaTab:
1918

2019
```html
2120
<div id="alphaTab"></div>
@@ -27,78 +26,20 @@ const api = new alphaTab.AlphaTabApi(element);
2726

2827
## Settings
2928

30-
There are 2 main ways to initialize alphaTab: either via a settings object or via data attributes.
31-
Depending on the technologies used in your project either the direct code initialization or the data attributes might be easier to use.
32-
33-
The data attributes might be more suitable for server side rendering technologies where settings are provided from a backend infrastructure
34-
during page rendering. When printing the main alphaTab div element to the DOM you can pass on any settings you might want to have.
35-
36-
When using client side frontend frameworks like Angular, React or even plain JavaScript it might be more suitable to initialize alphaTab
37-
via a settings object.
38-
39-
Both systems can be combined while the data attributes will overrule the JSON settings.
40-
The full list of settings can be found in the [API Reference](/docs/reference/settings).
41-
42-
import Tabs from '@theme/Tabs';
43-
import TabItem from '@theme/TabItem';
44-
45-
<Tabs
46-
defaultValue="js"
47-
values={[
48-
{ label: 'Settings Object', value: 'js', },
49-
{ label: 'jQuery', value: 'jq', },
50-
{ label: 'Data Attributes', value: 'html', },
51-
]
52-
}>
53-
<TabItem value="js">
54-
5529
The settings object is passed to the constructor of the API object as second parameter:
5630

5731
```js
5832
const api = new alphaTab.AlphaTabApi(element, {
5933
// any settings go here
6034
});
61-
```
62-
63-
</TabItem>
64-
<TabItem value="jq">
6535

66-
AlphaTab is initialized via the `$.alphaTab()` plugin. The first parameter is the settings object and the API object will be returned.
67-
68-
```js
69-
const api = $('#alphaTab').alphaTab();
7036
```
7137

72-
</TabItem>
73-
<TabItem value="html">
74-
75-
Data Attributes will only allow configuration, you still need to manually initailize alphaTab with one of the other variants.
76-
But the settings parameter can be simply left out.
77-
78-
```html
79-
<div id="alphaTab" data-layout-mode="horizontal"></div>
80-
```
81-
```js
82-
const api = new alphaTab.AlphaTabApi(element);
83-
```
84-
85-
</TabItem>
86-
</Tabs>
87-
8838
## Events
8939

90-
Events of alphaTab can be either subscribed on the API object directly, or via the DOM element to which alphaTab is attached.
40+
Events of alphaTab should be either subscribed on the API object.
9141
Please refer to the [API Reference](/docs/reference/api) to find a full list of events available.
9242

93-
<Tabs
94-
defaultValue="js"
95-
values={[
96-
{ label: 'API Object', value: 'js', },
97-
{ label: 'DOM events', value: 'html', }
98-
]
99-
}>
100-
<TabItem value="js">
101-
10243
Each event has an `.on(handler)` and `.off(handler)` function to subscribe or unsubscribe.
10344

10445
```js
@@ -108,35 +49,12 @@ api.scoreLoaded.on( (score) => {
10849
});
10950
```
11051

111-
</TabItem>
112-
</Tabs>
113-
11452
## API
11553

116-
The main interaction with alphaTab happens through the API object or via jQuery plugin.
54+
The main interaction with alphaTab happens through the API object.
11755
Simply use any [available API](/docs/reference/api) to get/set details or trigger actions.
11856

119-
<Tabs
120-
defaultValue="js"
121-
values={[
122-
{ label: 'API Object', value: 'js', },
123-
{ label: 'jQuery API', value: 'jq', }
124-
]
125-
}>
126-
<TabItem value="js">
127-
12857
```js
12958
const api = new alphaTab.AlphaTabApi(element);
13059
api.tex('\title "Hello AlphaTab" . 1.1*4')
131-
```
132-
133-
</TabItem>
134-
<TabItem value="jq">
135-
136-
```js
137-
$(element).alphaTab('tex', '\title "Hello AlphaTab" . 1.1*4')
138-
```
139-
140-
</TabItem>
141-
142-
</Tabs>
60+
```

docs/guides/audio-video-sync.mdx

Lines changed: 178 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
title: Audio & Video Sync
33
---
44

5-
> [!WARNING]
6-
> This guide is still incomplete and is currently being extended.
7-
85
alphaTab can be synchronized with an external audio or video backing track. You can either use Guitar Pro 8 files with an audio track or synchronize alphaTab with an external media using the
96
[Media Sync Editor in the Playground](/docs/playground/playground.mdx).
107

@@ -34,6 +31,15 @@ Beside that you can load Guitar Pro 8 files and directly benefit from the enhanc
3431
### Custom External Media Player
3532

3633
alphaTab can be integrated with any external media system but it requires some implementation on the integrator side. To properly synchronize alphaTab and an external media source (audio or video) the `alphaTab.synth.IExternalMediaHandler` interface has to be implemented and provided to alphaTab.
34+
Beside that, alphaTab has to be informed about the time updates on the external media (e.g. during playback and seeking). This update should happen at a rate smaller than two subsequent notes. 50ms updates have shown to work well on even fast songs, but to save power and battery you might want to handle this dynamically.
35+
36+
The following example illustrates a full integration with a HTML Media Element like `<audio />` or `<video />`. This should be a good reference on how to implement the related sync with your media player.
37+
Most things should be quite obvious like syncing volume, playback speed and providing the time and duration.
38+
39+
import { ExternalMediaSample } from '@site/src/components/ExternalMediaSample';
40+
41+
<ExternalMediaSample />
42+
3743

3844
#### YouTube
3945

@@ -46,3 +52,172 @@ Some key reasons behind this is:
4652

4753
Nevertheless we want to give you some guidance on how to link alphaTab to YouTube. The following steps show how to use the [YouTube Player API Reference for iframe Embeds](https://developers.google.com/youtube/iframe_api_reference) together with alphaTab.
4854

55+
56+
```js
57+
// assuming a <div id="youtube"></div> somewhere
58+
59+
60+
//
61+
// 1. load the YouTube IFrame API. we use promises to have a bit better control over the initialization sequence
62+
63+
const playerElement = document.getElementById('youtube');
64+
65+
const tag = document.createElement('script');
66+
tag.src = "https://www.youtube.com/player_api";
67+
playerElement.parentNode.insertBefore(tag, playerElement);
68+
69+
const youtubeApiReady = Promise.withResolvers();
70+
window.onYouTubePlayerAPIReady = youtubeApiReady.resolve;
71+
72+
//
73+
// 2. Already initialize alphaTab
74+
75+
const api = new alphaTab.AlphaTabApi('#alphaTab', {
76+
core: {
77+
file: 'my-synced-file.gp'
78+
},
79+
player: {
80+
// set the external media mode
81+
playerMode: alphaTab.PlayerMode.EnabledExternalMedia
82+
}
83+
});
84+
window.at = at;
85+
86+
//
87+
// 3. Wait for the youtube API to be ready
88+
await youtubeApiReady.promise;
89+
90+
91+
//
92+
// 4. Setup the youtube player and wait for the video to be ready for playback
93+
const youtubePlayerReady = Promise.withResolvers();
94+
let currentTimeInterval = 0;
95+
const player = new YT.Player(playerElement, {
96+
height: '360',
97+
width: '640',
98+
videoId: 'your-video-id',
99+
playerVars: { 'autoplay': 0 }, // we do not want autoplay
100+
events: {
101+
'onReady': (e) => {
102+
youtubePlayerReady.resolve();
103+
},
104+
105+
// when the player state changes we update alphatab accordingly.
106+
'onStateChange': (e) => {
107+
//
108+
switch (e.data) {
109+
case YT.PlayerState.PLAYING:
110+
currentTimeInterval = window.setInterval(() => {
111+
api.player.output.updatePosition(player.getCurrentTime() * 1000)
112+
}, 50);
113+
api.play();
114+
break;
115+
case YT.PlayerState.ENDED:
116+
window.clearInterval(currentTimeInterval);
117+
api.stop();
118+
break;
119+
case YT.PlayerState.PAUSED:
120+
window.clearInterval(currentTimeInterval);
121+
api.pause();
122+
break;
123+
default:
124+
break;
125+
}
126+
},
127+
'onPlaybackRateChange': (e) => {
128+
api.playbackSpeed = e.data;
129+
},
130+
'onError': (e) => {
131+
youtubePlayerReady.reject(e);
132+
},
133+
}
134+
});
135+
136+
await youtubePlayerReady.promise;
137+
138+
//
139+
// 5. Setup the handler to let alphaTab control the youtube player when needed
140+
141+
// Setup alphaTab with youtube handler
142+
const alphaTabYoutubeHandler = {
143+
get backingTrackDuration() {
144+
return player.getDuration() * 1000;
145+
},
146+
get playbackRate() {
147+
return player.getPlaybackRate();
148+
},
149+
set playbackRate(value) {
150+
player.setPlaybackRate(value);
151+
},
152+
get masterVolume() {
153+
return player.getVolume() / 100;
154+
},
155+
set masterVolume(value) {
156+
player.setVolume(value * 100);
157+
},
158+
seekTo(time) {
159+
player.seekTo(time / 1000);
160+
},
161+
play() {
162+
player.playVideo();
163+
},
164+
pause() {
165+
player.pauseVideo();
166+
}
167+
};
168+
api.player.output.handler = alphaTabYoutubeHandler;
169+
```
170+
171+
As you can see it is again just a matter of passing the right calls and values back and forth just like with an `<audio />` element.
172+
173+
> [!WARNING]
174+
> The YouTube IFrame API has a quite nasty behavior when it comes to seeking: For some strange reason `seekTo` will start the playback of the video
175+
> depending on the state. The docs say:
176+
>
177+
> > `player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void`
178+
> >
179+
> > Seeks to a specified time in the video. If the player is paused when the function is called, it will remain paused. If the function is called from another state (playing, video cued, etc.), the player will play the video.
180+
>
181+
> alphaTab might initially do some seeking to the start position. This can cause the video to directly start playing which you might not want.
182+
> To workaround this problem you could adjust the handler to check the player state and react accordingly.
183+
184+
```js
185+
let initialSeek = -1;
186+
const alphaTabYoutubeHandler = {
187+
get backingTrackDuration() {
188+
return player.getDuration() * 1000;
189+
},
190+
get playbackRate() {
191+
return player.getPlaybackRate();
192+
},
193+
set playbackRate(value) {
194+
player.setPlaybackRate(value);
195+
},
196+
get masterVolume() {
197+
return player.getVolume() / 100;
198+
},
199+
set masterVolume(value) {
200+
player.setVolume(value * 100);
201+
},
202+
seekTo(time) {
203+
if (
204+
player.getPlayerState() !== YT.PlayerState.PAUSED &&
205+
player.getPlayerState() !== YT.PlayerState.PLAYING
206+
) {
207+
initialSeek = value / 1000;
208+
} else {
209+
player.seekTo(value / 1000);
210+
}
211+
},
212+
play() {
213+
player.playVideo();
214+
if (initialSeek >= 0) {
215+
player.seekTo(initialSeek);
216+
initialSeek = -1;
217+
}
218+
},
219+
pause() {
220+
player.pauseVideo();
221+
}
222+
};
223+
```

docs/guides/exporter.mdx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ import { SinceBadge } from '@site/src/components/SinceBadge';
1212
After alphaTab has loaded a full [`Score`](/docs/reference/score) object from any input source, it can also be exported again to one of the supported export formats.
1313
Supported export formats:
1414

15-
- Guitar Pro 7 (alphaTab.exporter.Gp7Exporter) <span className="badge badge--info">since 1.2.0-alpha.75</span>
16-
17-
:::note
18-
More exporters are planned for the 1.5 release unless special feature requests of users are incoming.
19-
:::
15+
- Guitar Pro 7 (alphaTab.exporter.Gp7Exporter) <span className="badge badge--info">since 1.2.0</span>
2016

2117
To export a `Score` object the corresponding exporter needs to be created and called. Then the resulting binary array can be used further to
2218
trigger a download, send it to a server, save it to a file etc.

0 commit comments

Comments
 (0)