Navigation Voice¶
In this guide you will learn how to change the navigation turn-by-turn
instructions guidance voice language you hear during a real or simulated navigation;
RoutingService
is used to compute a route and NavigationService
to start a real or simulated navigation on that route.
Setting and changing the voice¶
First, get an API key token, see the Getting Started guide.
Qt should be installed to continue.The Maps SDK for Qt should be installed, see the Setup Maps SDK for Qt guide.
Overview¶
Each language for the voice instructions is in a separate file which has to be downloaded prior to starting real or simulated navigation along a route. This example includes 9 languages for demonstration purposes.
Before running this example, please do the following 3 steps:
copy the
.speech
files from the directory of this example to theData/AudioRes/
directory, located within your GeneralMagic/MagicLane QML SDK install directory; in this example, the absolute path of the QML SDK install directory is/home/user/myGMsdk/
so the absolute path of theData/AudioRes/
directory is/home/user/myGMsdk/Data/AudioRes/
edit the absolute paths of the
.speech
files inmain.qml
in thevoiceFullPathArray
item to match the absolute paths of these files in theData/AudioRes/
directory;edit the
main.cpp
of this example to update the following line with the absolute pathname which containsData/AudioRes/
in your QML SDK install directory:
qputenv("GENERAL_MAGIC_RESOURCES_PATH", "/home/user/myGMsdk/");
The above line should be before the following line:
engine.load(url);
The voice for navigation instructions is set from QML like this:
ServicesManager.settings.setVoiceByPath("/home/user/myGMsdk/Data/AudioRes/eng_ZAF_Kayla.mp3_112128000.speech")
Please see the ContentDownload
example for the complete list of voices
available for download, which is much more extensive, and includes
both a male and a female voice for each language.
How it works
In Qt, go to the File menu and select Open File or Project…
then browse to the NavigationVoice example folder and open NavigationVoice.pro
You may want to have a look at Setting your API Key to see how to open and configure a project and set your API Key.
Defining A Route¶
When the example is started, a preset route with several turns (to exercise
the voice instructions) is computed automatically by routingService.update()
in the Component.onCompleted
block.
1RoutingService {
2 id: routingService
3 type: Route.Type.Fastest
4 transportMode: Route.TransportMode.Car
5 waypoints: LandmarkList {
6 Landmark {
7 name: "start"
8 coordinates: Coordinates {
9 latitude: 48.52564
10 longitude: 7.73589
11 }
12 }
13 Landmark {
14 name: "waypoint1"
15 coordinates: Coordinates {
16 latitude: 48.52568
17 longitude: 7.73546
18 }
19 }
A RoutingService
is defined to compute and render a route.
The waypoints causing the turns are specified as a LandmarkList
where each
Landmark
contains a longitude
and a latitude
coordinate.
1NavigationService {
2 id: navigation
3 route: mapView.routeCollection.mainRoute
4 simulation: true // change it to false (default) to perform real turn by turn navigation
5 onActiveChanged: {
6 if (active) {
7 mapView.startFollowingPosition();
8 mapView.routeCollection.clear(true /*keepMainRoute*/);
9 }
10 }
A NavigationService
is defined to simulate navigation along the route,
so simulation
is set to true.
The onActiveChanged
signal is caught, so that when navigation is started,
follow position is also activated, so the camera follows the green position
indicator arrow along the route.
1MapView {
2 id: mapView
3 anchors.fill: parent
4 viewAngle: 25
5 cursorVisibility: false
6 onRouteSelected: {
7 routeCollection.mainRoute = route;
8 centerOnRoute(route);
9 console.log("Route selected, centering:" + route.summary);
10 }
The MapView
element displays the interactive map, and catches the
onRouteSelected
signal to set the main route and to center it in the
viewport using centerOnRoute()
Display Turn Indicators¶
1Rectangle {
2 color: Qt.rgba(.8, 1, 1, 0.6)
3 visible: navigation.active
4 anchors.top: parent.top
5 anchors.left: parent.left
6 anchors.right: parent.right
7 height: 96
8 RowLayout {
9 anchors.fill: parent
10 anchors.margins: 10
11 DynamicIconView {
12 id: iconLeft
13 Layout.fillHeight: true
14 Layout.maximumWidth: height
15 width: height
16 arrowInner: "blue"
17 arrowOuter: "cyan"
18 slotInner: "yellow"
19 slotOuter: "red"
20 iconSource: navigation.currentInstruction.nextTurnDynamicIcon
21 }
22 Label {
23 Layout.fillWidth: true
24 font.pixelSize: 16
25
26 text: navigation.currentInstruction.nextStreetName
27 + " (" + distance(navigation.currentInstruction.distanceToNextTurn) + ")";
28 }
29 DynamicIconView {
30 id: iconRight
31 Layout.fillHeight: true
32 Layout.maximumWidth: height
33 width: height
34 arrowInner: "yellow"
35 arrowOuter: "cyan"
36 slotInner: "red"
37 slotOuter: "magenta"
38 iconSource: navigation.currentInstruction.nextNextTurnDynamicIcon
39 }
40 Label {
41 font.pixelSize: 16
42 text: distance(navigation.currentInstruction.distanceToNextNextTurn)
43 }
44 }
45}
Turn indicators, rendered using DynamicIconView
for visualizing the voice instructions, are shown on a panel at the top
with transparency, so the map is also visible through the panel.
Simulate Navigation¶
1Button {
2 enabled: mapView.routeCollection.mainRoute.valid
3 text: navigation.active ? "Stop simulation" : "Start simulation"
4 background: Rectangle {
5 opacity: parent.hovered ? 1 : 0.5
6 color: enabled ? parent.down ? "#aa00aa" :
7 (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
8 }
9 palette { buttonText: "#ffffff"; }
10 onClicked: {
11 navigation.active = !navigation.active
12 }
13}
The button to start or stop navigation toggles navigation.active
causing simulated navigation to start or stop.
Follow Position¶
1Button {
2 anchors.right: parent.right
3 anchors.bottom: parent.bottom
4 text: qsTr("Follow position")
5 enabled: !mapView.followingPosition
6 background: Rectangle {
7 opacity: parent.hovered ? 1 : 0.5
8 color: enabled ? parent.down ? "#aa00aa" :
9 (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
10 }
11 palette { buttonText: "#ffffff"; }
12 onClicked: mapView.followingPosition = true
13}
The follow position button is active if the map was panned during the real or simulated navigation, to enable resuming follow position, that is, cause the camera to resume following the green arrow position tracker indicator on the map.
Change Navigation Voice¶
1Item {
2 id: voiceFullPathArray
3 property int maxElements: 0
4 property int currentVoiceIndex: 0
5 property var voices: [
6 "/home/user/myGMsdk/Data/AudioRes/eng_ZAF_Kayla.mp3_112128000.speech",
7 "/home/user/myGMsdk/Data/AudioRes/spa_MEX_Sofía.mp3_392929280.speech",
8 "/home/user/myGMsdk/Data/AudioRes/arb_SAU_Nadia.mp3_27955200.speech",
9 "/home/user/myGMsdk/Data/AudioRes/hin_IND_Alok.mp3_181903370.speech",
10 "/home/user/myGMsdk/Data/AudioRes/cmn_CHN_Cheng.mp3_64512000.speech",
11 "/home/user/myGMsdk/Data/AudioRes/por_BRA_Júlia.mp3_336322560.speech",
12 "/home/user/myGMsdk/Data/AudioRes/deu_DEU_Hannah.mp3_86712320.speech",
13 "/home/user/myGMsdk/Data/AudioRes/rus_RUS_Sofiya.mp3_363100160.speech",
14 "/home/user/myGMsdk/Data/AudioRes/ron_ROU_Andreea.mp3_352604160.speech"
15 ]
16 Component.onCompleted: {
17 voiceFullPathArray.maxElements = voiceFullPathArray.voices.length;
18 ServicesManager.settings.setVoiceByPath(voiceFullPathArray.voices[voiceFullPathArray.currentVoiceIndex])
19 }
20}
During real or simulated navigation, it is possible to change the instruction guidance voice
to any other voice that is already downloaded, using ServicesManager.settings.setVoiceByPath()
and specifying the full path of the voice which must be located and configured in
Data/AudioRes/
as described above.
1Button {
2 text: "Voice " + voiceFullPathArray.currentVoiceIndex + ", click for next voice"
3 background: Rectangle {
4 opacity: parent.hovered ? 1 : 0.5
5 color: enabled ? parent.down ? "#aa00aa" :
6 (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
7 }
8 palette { buttonText: "#ffffff"; }
9 onClicked: {
10 voiceFullPathArray.currentVoiceIndex += 1;
11 if ( voiceFullPathArray.currentVoiceIndex >= voiceFullPathArray.maxElements )
12 voiceFullPathArray.currentVoiceIndex = 0;
13 ServicesManager.settings.setVoiceByPath(voiceFullPathArray.voices[voiceFullPathArray.currentVoiceIndex])
14 }
15}
This button selects the next voice from the array of voices configured above, cycling through all of them as it is clicked repeatedly. The new voice applies to the next instruction.