Makefile: remove spurious tab
[xcsoar.git] / src / Audio / VarioSynthesiser.cpp
blobb223d2ad1d0cf2cf8548d0c0290ddc6687998e21
1 /*
2 Copyright_License {
4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "VarioSynthesiser.hpp"
25 #include "Math/FastMath.h"
26 #include "Util/Clamp.hpp"
28 #include <algorithm>
30 /**
31 * The minimum and maximum vario range for the constants below [cm/s].
33 static constexpr int min_vario = -500, max_vario = 500;
35 unsigned
36 VarioSynthesiser::VarioToFrequency(int ivario)
38 return ivario > 0
39 ? (zero_frequency + (unsigned)ivario * (max_frequency - zero_frequency)
40 / (unsigned)max_vario)
41 : (zero_frequency - (unsigned)(ivario * (int)(zero_frequency - min_frequency) / min_vario));
44 void
45 VarioSynthesiser::SetVario(unsigned sample_rate, fixed vario)
47 const ScopeLock protect(mutex);
49 const int ivario = Clamp((int)(vario * 100), min_vario, max_vario);
51 if (dead_band_enabled && InDeadBand(ivario)) {
52 /* inside the "dead band" */
53 UnsafeSetSilence();
54 return;
57 /* update the ToneSynthesiser base class */
58 SetTone(sample_rate, VarioToFrequency(ivario));
60 if (ivario > 0) {
61 /* while climbing, the vario sound gets interrupted by silence
62 periodically */
64 const unsigned period_ms = sample_rate
65 * (min_period_ms + (max_vario - ivario)
66 * (max_period_ms - min_period_ms) / max_vario)
67 / 1000;
69 silence_count = period_ms / 3;
70 audible_count = period_ms - silence_count;
72 /* preserve the old "_remaining" values as much as possible, to
73 avoid chopping off the previous tone */
75 if (audible_remaining > audible_count)
76 audible_remaining = audible_count;
78 if (silence_remaining > silence_count)
79 silence_remaining = silence_count;
80 } else {
81 /* continuous tone while sinking */
82 audible_count = 1;
83 silence_count = 0;
87 void
88 VarioSynthesiser::SetSilence()
90 const ScopeLock protect(mutex);
91 UnsafeSetSilence();
94 void
95 VarioSynthesiser::UnsafeSetSilence()
97 audible_count = 0;
98 silence_count = 1;
100 if (audible_remaining > 0)
101 /* quit the current period as early as possible; the method
102 Synthesise() will take care for finishing the current sine
103 wave to avoid clicking noise */
104 audible_remaining = 1;
106 silence_remaining = 0;
110 void
111 VarioSynthesiser::Synthesise(int16_t *buffer, size_t n)
113 const ScopeLock protect(mutex);
115 assert(audible_count > 0 || silence_count > 0);
117 if (silence_count == 0) {
118 /* magic value for "continuous tone" */
119 ToneSynthesiser::Synthesise(buffer, n);
120 return;
123 while (n > 0) {
124 if (audible_remaining > 0) {
125 /* generate a period of audible tone */
127 unsigned o = silence_count > 0
128 ? std::min(n, audible_remaining)
129 : n;
130 ToneSynthesiser::Synthesise(buffer, o);
131 buffer += o;
132 n -= o;
133 audible_remaining -= o;
135 if (audible_remaining == 0 && silence_remaining > 0) {
136 /* finish the current sine wave to avoid clicking noise */
137 audible_remaining = ToZero();
138 if (audible_remaining == 0)
139 /* finished, we can now emit a period of silence */
140 Restart();
142 } else if (silence_remaining > 0) {
143 /* generate a period of silence (climbing) */
145 unsigned o = audible_count > 0
146 ? std::min(n, silence_remaining)
147 : n;
148 /* the "silence" PCM sample value is zero */
149 std::fill(buffer, buffer + o, 0);
150 buffer += o;
151 n -= o;
152 silence_remaining -= o;
153 } else {
154 /* period finished, begin next one */
156 audible_remaining = audible_count;
157 silence_remaining = silence_count;