Passed
Push — master ( 6237c6...c7dfb9 )
by Maximilian
01:02
created

SsmlGenerator::sayWithAmazonEffect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
3
namespace MaxBeckers\AmazonAlexa\Helper;
4
5
use MaxBeckers\AmazonAlexa\Exception\InvalidSsmlException;
6
7
/**
8
 * @author Maximilian Beckers <[email protected]>
9
 */
10
class SsmlGenerator implements SsmlTypes
11
{
12
    /**
13
     * @var string[]
14
     */
15
    private $parts = [];
16
17
    /**
18
     * Clear the current ssml parts.
19
     */
20
    public function clear()
21
    {
22
        $this->parts = [];
23
    }
24
25
    /**
26
     * @return string
27
     */
28
    public function getSsml()
29
    {
30
        return sprintf('<speak>%s</speak>', implode(' ', $this->parts));
31
    }
32
33
    /**
34
     * Say a default text.
35
     *
36
     * @param string $text
37
     */
38
    public function say(string $text)
39
    {
40
        $this->parts[] = $text;
41
    }
42
43
    /**
44
     * Play audio in output.
45
     * For more specifications of the mp3 file @see https://developer.amazon.com/de/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html#audio.
46
     *
47
     * @param string $mp3Url
48
     *
49
     * @throws InvalidSsmlException
50
     */
51
    public function playMp3(string $mp3Url)
52
    {
53
        if (1 !== preg_match('/^(https:\/\/.*\.mp3.*)$/i', $mp3Url) && 0 !== strpos($mp3Url, 'soundbank://')) {
54
            throw new InvalidSsmlException(sprintf('"%s" in not a valid mp3 url!', $mp3Url));
55
        }
56
        $this->parts[] = sprintf('<audio src="%s" />', $mp3Url);
57
    }
58
59
    /**
60
     * Make a pause (or remove with none/x-weak).
61
     * Possible values @see https://developer.amazon.com/de/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html#break.
62
     *
63
     * @param string $strength
64
     *
65
     * @throws InvalidSsmlException
66
     */
67
    public function pauseStrength(string $strength)
68
    {
69
        if (!in_array($strength, self::BREAK_STRENGTHS, true)) {
70
            throw new InvalidSsmlException(sprintf('Break strength must be one of "%s"!', implode(',', self::BREAK_STRENGTHS)));
71
        }
72
        $this->parts[] = sprintf('<break strength="%s" />', $strength);
73
    }
74
75
    /**
76
     * Make a pause with duration time as string in seconds(s) or milliseconds(ms).
77
     * For example '10s' or '10000ms' to break 10 seconds.
78
     *
79
     * @param string $time
80
     *
81
     * @throws InvalidSsmlException
82
     */
83
    public function pauseTime(string $time)
84
    {
85
        if (1 !== preg_match('/^(\d+(s|ms))$/i', $time)) {
86
            throw new InvalidSsmlException('Time must be seconds or milliseconds!');
87
        }
88
        $this->parts[] = sprintf('<break time="%s" />', $time);
89
    }
90
91
    /**
92
     * Say a text with effect.
93
     *
94
     * @param string $text
95
     * @param string $effect
96
     *
97
     * @throws InvalidSsmlException
98
     */
99
    public function sayWithAmazonEffect(string $text, string $effect = self::AMAZON_EFFECT_WHISPERED)
100
    {
101
        if (!in_array($effect, self::AMAZON_EFFECTS, true)) {
102
            throw new InvalidSsmlException(sprintf('Amazon:effect name must be one of "%s"!', implode(',', self::AMAZON_EFFECTS)));
103
        }
104
        $this->parts[] = sprintf('<amazon:effect name="%s">%s</amazon:effect>', $effect, $text);
105
    }
106
107
    /**
108
     * Whisper a text.
109
     *
110
     * @param string $text
111
     */
112
    public function whisper(string $text)
113
    {
114
        $this->sayWithAmazonEffect($text, self::AMAZON_EFFECT_WHISPERED);
115
    }
116
117
    /**
118
     * Say with emphasis.
119
     *
120
     * @param string $text
121
     * @param string $level
122
     *
123
     * @throws InvalidSsmlException
124
     */
125
    public function emphasis(string $text, string $level)
126
    {
127
        if (!in_array($level, self::EMPHASIS_LEVELS, true)) {
128
            throw new InvalidSsmlException(sprintf('Emphasis level must be one of "%s"!', implode(',', self::EMPHASIS_LEVELS)));
129
        }
130
        $this->parts[] = sprintf('<emphasis level="%s">%s</emphasis>', $level, $text);
131
    }
132
133
    /**
134
     * Say a text pronounced in the given language.
135
     *
136
     * @param string $language
137
     * @param string $text
138
     *
139
     * @throws InvalidSsmlException
140
     */
141
    public function pronounceInLanguage(string $language, string $text)
142
    {
143
        if (!in_array($language, self::LANGUAGE_LIST, true)) {
144
            throw new InvalidSsmlException(sprintf('Language must be one of "%s"!', implode(',', self::LANGUAGE_LIST)));
145
        }
146
        $this->parts[] = sprintf('<lang xml:lang="%s">%s</lang>', $language, $text);
147
    }
148
149
    /**
150
     * Say a paragraph.
151
     *
152
     * @param string $paragraph
153
     */
154
    public function paragraph(string $paragraph)
155
    {
156
        $this->parts[] = sprintf('<p>%s</p>', $paragraph);
157
    }
158
159
    /**
160
     * Say a text with a phoneme.
161
     *
162
     * @param string $alphabet
163
     * @param string $ph
164
     * @param string $text
165
     *
166
     * @throws InvalidSsmlException
167
     */
168
    public function phoneme(string $alphabet, string $ph, string $text)
169
    {
170
        if (!in_array($alphabet, self::PHONEME_ALPHABETS, true)) {
171
            throw new InvalidSsmlException(sprintf('Phoneme alphabet must be one of "%s"!', implode(',', self::PHONEME_ALPHABETS)));
172
        }
173
        $this->parts[] = sprintf('<phoneme alphabet="%s" ph="%s">%s</phoneme>', $alphabet, $ph, $text);
174
    }
175
176
    /**
177
     * Say a text with a prosody.
178
     *
179
     * There are three different modes of prosody: volume, pitch, and rate.
180
     * For more details @see https://developer.amazon.com/de/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html#prosody
181
     *
182
     * @param string $mode
183
     * @param string $value
184
     * @param string $text
185
     *
186
     * @throws InvalidSsmlException
187
     */
188
    public function prosody(string $mode, string $value, string $text)
189
    {
190
        if (!isset(self::PROSODIES[$mode])) {
191
            throw new InvalidSsmlException(sprintf('Prosody mode must be one of "%s"!', implode(',', array_keys(self::PROSODIES))));
192
        }
193
        // todo validate value for mode
194
        $this->parts[] = sprintf('<prosody %s="%s">%s</prosody>', $mode, $value, $text);
195
    }
196
197
    /**
198
     * Say a sentence.
199
     *
200
     * @param string $text
201
     */
202
    public function sentence(string $text)
203
    {
204
        $this->parts[] = sprintf('<s>%s</s>', $text);
205
    }
206
207
    /**
208
     * Say a text with interpretation.
209
     *
210
     * @param string $interpretAs
211
     * @param string $text
212
     * @param string $format
213
     *
214
     * @throws InvalidSsmlException
215
     */
216
    public function sayAs(string $interpretAs, string $text, string $format = '')
217
    {
218
        if (!in_array($interpretAs, self::SAY_AS_INTERPRET_AS, true)) {
219
            throw new InvalidSsmlException(sprintf('Interpret as attribute must be one of "%s"!', implode(',', self::SAY_AS_INTERPRET_AS)));
220
        }
221
        if ($format) {
222
            $this->parts[] = sprintf('<say-as interpret-as="%s" format="%s">%s</say-as>', $interpretAs, $format, $text);
223
        } else {
224
            $this->parts[] = sprintf('<say-as interpret-as="%s">%s</say-as>', $interpretAs, $text);
225
        }
226
    }
227
228
    /**
229
     * Say an alias.
230
     * For example replace the abbreviated chemical elements with the full words.
231
     *
232
     * @param string $alias
233
     * @param string $text
234
     */
235
    public function alias(string $alias, string $text)
236
    {
237
        $this->parts[] = sprintf('<sub alias="%s">%s</sub>', $alias, $text);
238
    }
239
240
    /**
241
     * Say a text with the voice of the given person.
242
     *
243
     * @param string $voice
244
     * @param string $text
245
     *
246
     * @throws InvalidSsmlException
247
     */
248
    public function sayWithVoice(string $voice, string $text)
249
    {
250
        if (!in_array($voice, self::VOICES, true)) {
251
            throw new InvalidSsmlException(sprintf('Voice must be one of "%s"!', implode(',', self::VOICES)));
252
        }
253
        $this->parts[] = sprintf('<voice name="%s">%s</voice>', $voice, $text);
254
    }
255
256
    /**
257
     * Say a word with defined word's parts to speach.
258
     *
259
     * @param string $role
260
     * @param string $text
261
     *
262
     * @throws InvalidSsmlException
263
     */
264
    public function word(string $role, string $text)
265
    {
266
        if (!in_array($role, self::INTERPRET_WORDS, true)) {
267
            throw new InvalidSsmlException(sprintf('Interpret as attribute must be one of "%s"!', implode(',', self::INTERPRET_WORDS)));
268
        }
269
        $this->parts[] = sprintf('<w role="%s">%s</w>', $role, $text);
270
    }
271
}
272