PX4 Firmware
PX4 Autopilot Software http://px4.io
tunes.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2017 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file tunes.cpp
36  */
37 
38 #include "tunes.h"
39 
40 #include <px4_platform_common/log.h>
41 #include <math.h>
42 #include <ctype.h>
43 #include <errno.h>
44 
45 #define TUNE_CONTINUE 1
46 #define TUNE_ERROR -1
47 #define TUNE_STOP 0
48 
49 #define BEAT_TIME_CONVERSION_MS (60 * 1000 * 4)
50 #define BEAT_TIME_CONVERSION_US BEAT_TIME_CONVERSION_MS * 1000
51 #define BEAT_TIME_CONVERSION BEAT_TIME_CONVERSION_US
52 
53 // semitone offsets from C for the characters 'A'-'G'
54 const uint8_t Tunes::_note_tab[] = {9, 11, 0, 2, 4, 5, 7};
55 
56 Tunes::Tunes(unsigned default_note_length, NoteMode default_note_mode,
57  unsigned default_octave, unsigned default_tempo):
58  _default_note_length(default_note_length),
59  _default_note_mode(default_note_mode),
60  _default_octave(default_octave),
61  _default_tempo(default_tempo)
62 {
63  reset(false);
64 }
65 
66 void Tunes::reset(bool repeat_flag)
67 {
68  // reset pointer
69  if (!repeat_flag) {
70  _tune = nullptr;
71  _next_tune = nullptr;
72 
73  } else {
75  _next_tune = _tune;
76  }
77 
78  // reset music parameter
83 }
84 
86 {
87  // Sanity check
88  if (tune_control.tune_id >= _default_tunes_size) {
89  return -EINVAL;
90  }
91 
92  // Accept new tune or a stop?
93  if (_tune == nullptr || // No tune is currently being played
94  tune_control.tune_override || // Override interrupts everything
96 
97  // Check if this exact tune is already being played back
98  if (tune_control.tune_id != static_cast<int>(TuneID::CUSTOM) &&
99  _tune == _default_tunes[tune_control.tune_id]) {
100  return OK; // Nothing to do
101  }
102 
103  // Reset repeat flag. Can jump to true again while tune is being parsed later
104  _repeat = false;
105 
106  // Reset octave, tempo etc.
107  reset(_repeat);
108 
109  // Volume will remain valid for the entire tune, unless interrupted.
110  if (tune_control.volume <= tune_control_s::VOLUME_LEVEL_MAX) {
111  _volume = tune_control.volume;
112 
113  } else {
114  _volume = tune_control_s::VOLUME_LEVEL_MAX;
115  }
116 
117 
118  // Special treatment for custom tunes
119  if (tune_control.tune_id == static_cast<int>(TuneID::CUSTOM)) {
120  _using_custom_msg = true;
121  _frequency = (unsigned)tune_control.frequency;
122  _duration = (unsigned)tune_control.duration;
123  _silence = (unsigned)tune_control.silence;
124 
125  } else {
126  _using_custom_msg = false;
127  _tune = _default_tunes[tune_control.tune_id];
129  _next_tune = _tune;
130  }
131 
132  _current_tune_id = tune_control.tune_id;
133  }
134 
135  return OK;
136 }
137 
138 void Tunes::set_string(const char *const string, uint8_t volume)
139 {
140  // Only play new tune if nothing is being played currently.
141  if (_tune == nullptr) {
142  // Set tune string the first time.
143  _tune = string;
144  _tune_start_ptr = string;
145  _next_tune = _tune;
146 
147  if (volume <= tune_control_s::VOLUME_LEVEL_MAX) {
148  _volume = volume;
149 
150  } else {
151  _volume = tune_control_s::VOLUME_LEVEL_MAX;
152  }
153  }
154 }
155 
156 int Tunes::get_next_note(unsigned &frequency, unsigned &duration,
157  unsigned &silence, uint8_t &volume)
158 {
159  int ret = get_next_note(frequency, duration, silence);
160 
161  // Check if note should not be heard -> adjust volume to 0 to be safe.
162  if (frequency == 0 || duration == 0) {
163  volume = 0;
164 
165  } else {
166  volume = _volume;
167  }
168 
169  return ret;
170 }
171 
172 int Tunes::get_next_note(unsigned &frequency, unsigned &duration,
173  unsigned &silence)
174 {
175  // Return the values for frequency and duration if the custom msg was received.
176  if (_using_custom_msg) {
177  _using_custom_msg = false;
178  duration = _duration;
179  frequency = _frequency;
180  silence = _silence;
181  return TUNE_CONTINUE;
182  }
183 
184  // Make sure we still have a tune.
185  if ((_next_tune == nullptr) || (_tune == nullptr)) {
186  return tune_error();
187  }
188 
189  // Parse characters out of the string until we have resolved a note.
190  unsigned note = 0;
191  unsigned note_length = _note_length;
192 
193  while (note == 0) {
194  // we always need at least one character from the string.
195  int c = next_char();
196 
197  if (c == 0) {
198  silence = 0;
199  return tune_end();
200  }
201 
202  _next_tune++;
203 
204  switch (c) {
205  case 'L': // Select note length.
207 
208  if (_note_length < 1) {
209  return tune_error();
210  }
211 
212  break;
213 
214  case 'O': // Select octave.
215  _octave = next_number();
216 
217  if (_octave > 6) {
218  _octave = 6;
219  }
220 
221  break;
222 
223  case '<': // Decrease octave.
224  if (_octave > 0) {
225  _octave--;
226  }
227 
228  break;
229 
230  case '>': // Increase octave.
231  if (_octave < 6) {
232  _octave++;
233  }
234 
235  break;
236 
237  case 'M': // Select inter-note gap.
238  c = next_char();
239 
240  if (c == 0) {
241  return tune_error();
242  }
243 
244  _next_tune++;
245 
246  switch (c) {
247  case 'N':
249  break;
250 
251  case 'L':
253  break;
254 
255  case 'S':
257  break;
258 
259  case 'F':
260  _repeat = false;
261  break;
262 
263  case 'B':
264  _repeat = true;
265  break;
266 
267  default:
268  return tune_error();
269  }
270 
271  break;
272 
273  case 'P': // Pause for a note length.
274  frequency = 0;
275  duration = 0;
276  silence = rest_duration(next_number(), next_dots());
277  return TUNE_CONTINUE;
278 
279  case 'T': { // Change tempo.
280  unsigned nt = next_number();
281 
282  if ((nt >= 32) && (nt <= 255)) {
283  _tempo = nt;
284 
285  } else {
286  return tune_error();
287  }
288 
289  break;
290  }
291 
292  case 'N': // Play an arbitrary note.
293  note = next_number();
294 
295  if (note > 84) {
296  return tune_error();
297  }
298 
299  if (note == 0) {
300  // This is a rest - pause for the current note length.
301  silence = rest_duration(_note_length, next_dots());
302  return TUNE_CONTINUE;
303  }
304 
305  break;
306 
307  case 'A'...'G': // Play a note in the current octave.
308  note = _note_tab[c - 'A'] + (_octave * 12) + 1;
309  c = next_char();
310 
311  switch (c) {
312  case '#': // Up a semitone.
313  case '+':
314  if (note < 84) {
315  note++;
316  }
317 
318  _next_tune++;
319  break;
320 
321  case '-': // Down a semitone.
322  if (note > 1) {
323  note--;
324  }
325 
326  _next_tune++;
327  break;
328 
329  default:
330  // 0 / No next char here is OK.
331  break;
332  }
333 
334  // Shorthand length notation.
335  note_length = next_number();
336 
337  if (note_length == 0) {
338  note_length = _note_length;
339  }
340 
341  break;
342 
343  default:
344  return tune_error();
345  }
346  }
347 
348  // Compute the duration of the note and the following silence (if any).
349  duration = note_duration(silence, note_length, next_dots());
350 
351  // Compute the note frequency.
352  frequency = note_to_frequency(note);
353  return TUNE_CONTINUE;
354 }
355 
357 {
358  // Restore intial parameters.
359  reset(_repeat);
360 
361  // Stop or restart the tune.
362  if (_repeat) {
363  return TUNE_CONTINUE;
364 
365  } else {
366  return TUNE_STOP;
367  }
368 }
369 
371 {
372  // The tune appears to be bad (unexpected EOF, bad character, etc.).
373  _repeat = false; // Don't loop on error.
374  reset(_repeat);
375  return TUNE_ERROR;
376 }
377 
378 uint32_t Tunes::note_to_frequency(unsigned note) const
379 {
380  // Compute the frequency (Hz).
381  return (unsigned)(880.0f * powf(2.0f, ((int)note - 46) / 12.0f));
382 }
383 
384 unsigned Tunes::note_duration(unsigned &silence, unsigned note_length, unsigned dots) const
385 {
386  unsigned whole_note_period = BEAT_TIME_CONVERSION / _tempo;
387 
388  if (note_length == 0) {
389  note_length = 1;
390  }
391 
392  unsigned note_period = whole_note_period / note_length;
393 
394  switch (_note_mode) {
395  case NoteMode::NORMAL:
396  silence = note_period / 8;
397  break;
398 
399  case NoteMode::STACCATO:
400  silence = note_period / 4;
401  break;
402 
403  case NoteMode::LEGATO:
404  default:
405  silence = 0;
406  break;
407  }
408 
409  note_period -= silence;
410 
411  unsigned dot_extension = note_period / 2;
412 
413  while (dots--) {
414  note_period += dot_extension;
415  dot_extension /= 2;
416  }
417 
418  return note_period;
419 }
420 
421 unsigned Tunes::rest_duration(unsigned rest_length, unsigned dots) const
422 {
423  unsigned whole_note_period = BEAT_TIME_CONVERSION / _tempo;
424 
425  if (rest_length == 0) {
426  rest_length = 1;
427  }
428 
429  unsigned rest_period = whole_note_period / rest_length;
430 
431  unsigned dot_extension = rest_period / 2;
432 
433  while (dots--) {
434  rest_period += dot_extension;
435  dot_extension /= 2;
436  }
437 
438  return rest_period;
439 }
440 
442 {
443  while (isspace(*_next_tune)) {
444  _next_tune++;
445  }
446 
447  return toupper(*_next_tune);
448 }
449 
451 {
452  unsigned number = 0;
453  int next_character;
454 
455  for (;;) {
456  next_character = next_char();
457 
458  if (!isdigit(next_character)) {
459  return number;
460  }
461 
462  _next_tune++;
463  number = (number * 10) + (next_character - '0');
464  }
465 }
466 
468 {
469  unsigned dots = 0;
470 
471  while (next_char() == '.') {
472  _next_tune++;
473  dots++;
474  }
475 
476  return dots;
477 }
#define TUNE_CONTINUE
Definition: tunes.cpp:45
Tunes(unsigned default_note_length=TUNE_DEFAULT_NOTE_LENGTH, NoteMode default_note_mode=NoteMode::NORMAL, unsigned default_octave=TUNE_DEFAULT_OCTAVE, unsigned default_tempo=TUNE_DEFAULT_TEMPO)
Constructor with the default parameters set to: default_tempo: TUNE_DEFAULT_TEMPO default_octave: TUN...
Definition: tunes.cpp:56
int get_next_note(unsigned &frequency, unsigned &duration, unsigned &silence)
Get next note in the current tune, which has been provided by either set_control or play_string...
Definition: tunes.cpp:172
int next_char()
Find the next character in the string, discard any whitespace.
Definition: tunes.cpp:441
NoteMode _note_mode
Definition: tunes.h:208
unsigned int _silence
Definition: tunes.h:214
static const uint8_t _note_tab[]
Definition: tunes.h:192
unsigned int _default_tempo
Definition: tunes.h:205
NoteMode
Definition: tunes.h:59
unsigned int _frequency
Definition: tunes.h:213
unsigned note_duration(unsigned &silence, unsigned note_length, unsigned dots) const
Calculate the duration in microseconds of play and silence for a note given the current tempo...
Definition: tunes.cpp:384
#define TUNE_STOP
Definition: tunes.cpp:47
unsigned next_dots()
Consume dot characters from the string.
Definition: tunes.cpp:467
bool _using_custom_msg
Definition: tunes.h:217
uint8_t tune_override
Definition: tune_control.h:62
static const bool _default_tunes_interruptable[]
Definition: tunes.h:190
uint16_t frequency
Definition: tune_control.h:60
uint32_t duration
Definition: tune_control.h:58
const char * _tune_start_ptr
pointer to repeat tune
Definition: tunes.h:196
unsigned int _tempo
Definition: tunes.h:210
uint8_t _volume
Definition: tunes.h:215
void reset(bool repeat_flag)
Reset the tune parameters.
Definition: tunes.cpp:66
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
int set_control(const tune_control_s &tune_control)
Set tune to be played using the message.
Definition: tunes.cpp:85
static const char *const _default_tunes[]
Definition: tunes.h:189
unsigned next_number()
Extract a number from the string, consuming all the digit characters.
Definition: tunes.cpp:450
const char * _tune
current tune string
Definition: tunes.h:195
NoteMode _default_note_mode
Definition: tunes.h:203
uint32_t note_to_frequency(unsigned note) const
Convert note to frequency.
Definition: tunes.cpp:378
int tune_end()
Definition: tunes.cpp:356
unsigned int _default_octave
Definition: tunes.h:204
unsigned int _note_length
Definition: tunes.h:207
int _current_tune_id
Definition: tunes.h:198
unsigned int _default_note_length
Definition: tunes.h:202
#define OK
Definition: uavcan_main.cpp:71
const char * _next_tune
next note in the string
Definition: tunes.h:194
int tune_error()
Definition: tunes.cpp:370
static tune_control_s tune_control
#define TUNE_ERROR
Definition: tunes.cpp:46
static const unsigned int _default_tunes_size
Definition: tunes.h:191
unsigned int _duration
Definition: tunes.h:212
unsigned rest_duration(unsigned rest_length, unsigned dots) const
Calculate the duration in microseconds of a rest corresponding to a given note length.
Definition: tunes.cpp:421
#define BEAT_TIME_CONVERSION
Definition: tunes.cpp:51
uint8_t tune_id
Definition: tune_control.h:61
void set_string(const char *const string, uint8_t volume)
Set tune to be played using a string.
Definition: tunes.cpp:138
uint32_t silence
Definition: tune_control.h:59
bool _repeat
if true, tune restarts at end
Definition: tunes.h:200
unsigned int _octave
Definition: tunes.h:209
uint8_t volume
Definition: tune_control.h:63