/[svn]/linuxsampler/trunk/src/common/RTMath.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/RTMath.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2942 - (show annotations) (download) (as text)
Wed Jul 13 15:51:06 2016 UTC (7 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 16095 byte(s)
* NKSP: Implemented built-in script variable "$KSP_TIMER".
* NKSP: Implemented built-in script variable "$NKSP_REAL_TIMER".
* NKSP: Implemented built-in script variable "$NKSP_PERF_TIMER".
* NKSP: Implemented built-in script variable "$ENGINE_UPTIME".
* Bumped version (2.0.0.svn14).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2016 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
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. *
17 * *
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, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef __RT_MATH_H__
25 #define __RT_MATH_H__
26
27 #include <math.h>
28 #include <stdint.h>
29 #include "global_private.h"
30
31 /// Needed for calculating frequency ratio used to pitch a sample
32 #define TWELVEHUNDREDTH_ROOT_OF_TWO 1.000577789506555
33
34 enum implementation_t {
35 CPP,
36 ASM_X86_MMX_SSE
37 };
38
39 /** @brief Real Time Math Base Class
40 *
41 * Math functions for real time operation. This base class contains all
42 * non-template methods.
43 */
44 class RTMathBase {
45 public:
46 /**
47 * High resolution time stamp.
48 */
49 typedef uint32_t time_stamp_t;
50
51 typedef uint64_t usecs_t;
52
53 /**
54 * We read the processor's cycle count register as a reference
55 * for the real time. These are of course only abstract values
56 * with arbitrary time entity, but that's not a problem as long
57 * as we calculate relatively.
58 *
59 * @see unsafeMicroSeconds()
60 */
61 static time_stamp_t CreateTimeStamp();
62
63 /**
64 * Calculates the frequency ratio for a pitch value given in cents
65 * (assuming equal tempered scale of course, divided into 12
66 * semitones per octave and 100 cents per semitone).
67 *
68 * Note: CONFIG_MAX_PITCH (defined in config.h) has to be defined to an
69 * appropriate value, otherwise the behavior of this function is
70 * undefined, but most probably if CONFIG_MAX_PITCH is too small, the
71 * application will crash due to segmentation fault here.
72 *
73 * @param cents - pitch value in cents (+1200 cents means +1 octave)
74 * @returns frequency ratio (e.g. +2.0 for +1 octave)
75 */
76 inline static double CentsToFreqRatio(double Cents) {
77 int index_int = (int) (Cents); // integer index
78 float index_fract = Cents - index_int; // fractional part of index
79 return pCentsToFreqTable[index_int] + index_fract * (pCentsToFreqTable[index_int+1] - pCentsToFreqTable[index_int]);
80 }
81
82 /**
83 * Slower version of CentsToFreqRatio, for big values.
84 *
85 * @param cents - pitch value in cents (+1200 cents means +1 octave)
86 * @returns frequency ratio (e.g. +2.0 for +1 octave)
87 */
88 static double CentsToFreqRatioUnlimited(double Cents) {
89 int octaves = int(Cents / 1200);
90 double x = CentsToFreqRatio(Cents - octaves * 1200);
91 return octaves < 0 ? x / (1 << -octaves) : x * (1 << octaves);
92 }
93
94 /**
95 * Inverse function to CentsToFreqRatio(). This function is a bit
96 * slow, so it should not be called too frequently.
97 */
98 static double FreqRatioToCents(double FreqRatio) {
99 return log(FreqRatio) / log(TWELVEHUNDREDTH_ROOT_OF_TWO);
100 }
101
102 /**
103 * Calculates the line ratio value representation (linear scale)
104 * of the @a decibel value provided (exponential scale).
105 *
106 * The context of audio acoustic sound pressure levels is assumed, and
107 * hence the field version of the dB unit is used here (which uses a
108 * linear factor of 20). This function is a bit slow, so it should
109 * not be called too frequently.
110 *
111 * @param decibel - sound pressure level in dB
112 * @returns linear ratio of the supplied dB value
113 */
114 static float DecibelToLinRatio(float decibel) {
115 return powf(10.f, decibel / 20.f);
116 }
117
118 /**
119 * Calculates the relatively summed average of a set of values.
120 *
121 * @param current - the current avaerage value of all previously summed values
122 * @param sample - new value to be applied as summed average to the existing values
123 * @param n - amount of sample values applied so far
124 * @returns new average value of all summed values (including the new @a sample)
125 */
126 inline static float RelativeSummedAvg(float current, float sample, int n) {
127 return current + (sample - current) / float(n);
128 }
129
130 /**
131 * Clock source to use for getting the current time.
132 */
133 enum clock_source_t {
134 real_clock, ///< Use this to measure time that passed in reality (no matter if process got suspended).
135 process_clock, ///< Use this to measure only the CPU execution time of the current process (if the process got suspended, the clock is paused as well).
136 thread_clock, ///< Use this to measure only the CPU execution time of the current thread (if the process got suspended or another thread is executed, the clock is paused as well).
137 };
138
139 /**
140 * Returns a time stamp of the current time in microseconds (in
141 * probably real-time @b unsafe way). There is no guarantee about
142 * what the returned amount of microseconds relates to (i.e.
143 * microseconds since epoch, microseconds since system uptime, ...).
144 * So you should only use it to calculate time differences between
145 * values taken with this method.
146 *
147 * @b CAUTION: This method may not @b NOT be real-time safe! On some
148 * systems it could be RT safe, but there is no guarantee whatsoever!
149 * So this method should only be used for debugging, benchmarking and
150 * other developing purposes !
151 *
152 * For creating time stamps in real-time context, use
153 * CreateTimeStamp() instead.
154 *
155 * @param source - the actual clock to use for getting the current
156 * time, note that the various clock sources may not
157 * be implemented on all systems
158 * @returns time stamp in microseconds
159 *
160 * @see CreateTimeStamp()
161 */
162 static usecs_t unsafeMicroSeconds(clock_source_t source);
163
164 private:
165 static float* pCentsToFreqTable;
166
167 static float* InitCentsToFreqTable();
168 };
169
170 /** @brief Real Time Math
171 *
172 * This is a template which provides customized methods for the desired low
173 * level implementation. The ASM_X86_MMX_SSE implementation of each method
174 * for example doesn't use 387 FPU instruction. This is needed for MMX
175 * algorithms which do not allow mixed MMX and 387 instructions.
176 */
177 template<implementation_t IMPL = CPP>
178 class __RTMath : public RTMathBase {
179 public:
180 // conversion using truncate
181 inline static int Int(const float a) {
182 switch (IMPL) {
183 #if CONFIG_ASM && ARCH_X86
184 case ASM_X86_MMX_SSE: {
185 int ret;
186 asm (
187 "cvttss2si %1, %0 # convert to int\n\t"
188 : "=r" (ret)
189 : "m" (a)
190 );
191 return ret;
192 }
193 #endif // CONFIG_ASM && ARCH_X86
194 default: {
195 return (int) a;
196 }
197 }
198 }
199
200 //for doubles and everything else except floats
201 template<class T_a> inline static int Int(const T_a a) {
202 return (int) a;
203 }
204
205 inline static float Float(const int a) {
206 switch (IMPL) {
207 #if CONFIG_ASM && ARCH_X86
208 case ASM_X86_MMX_SSE: {
209 float ret;
210 asm (
211 "cvtsi2ss %1, %%xmm0 # convert to float\n\t"
212 "movss %%xmm0,%0 # output\n\t"
213 : "=m" (ret)
214 : "r" (a)
215 );
216 return ret;
217 }
218 #endif // CONFIG_ASM && ARCH_X86
219 default: {
220 return (float) a;
221 }
222 }
223 }
224
225 #if 0
226 //for everything except ints
227 template<class T_a> inline static float Float(T_a a) {
228 return (float) a;
229 }
230 #endif
231
232 inline static float Sum(const float& a, const float& b) {
233 switch (IMPL) {
234 #if CONFIG_ASM && ARCH_X86
235 case ASM_X86_MMX_SSE: {
236 float ret;
237 asm (
238 "movss %1, %%xmm0 # load a\n\t"
239 "addss %2, %%xmm0 # a + b\n\t"
240 "movss %%xmm0, %0 # output\n\t"
241 : "=m" (ret)
242 : "m" (a), "m" (b)
243 );
244 return ret;
245 }
246 #endif // CONFIG_ASM && ARCH_X86
247 default: {
248 return (a + b);
249 }
250 }
251 }
252
253 template<class T_a, class T_b> inline static T_a Sum(const T_a a, const T_b b) {
254 return (a + b);
255 }
256
257 inline static float Sub(const float& a, const float& b) {
258 switch (IMPL) {
259 #if CONFIG_ASM && ARCH_X86
260 case ASM_X86_MMX_SSE: {
261 float ret;
262 asm (
263 "movss %1, %%xmm0 # load a\n\t"
264 "subss %2, %%xmm0 # a - b\n\t"
265 "movss %%xmm0, %0 # output\n\t"
266 : "=m" (ret)
267 : "m" (a), "m" (b)
268 );
269 return ret;
270 }
271 #endif // CONFIG_ASM && ARCH_X86
272 default: {
273 return (a - b);
274 }
275 }
276 }
277
278 template<class T_a, class T_b> inline static T_a Sub(const T_a a, const T_b b) {
279 return (a - b);
280 }
281
282 inline static float Mul(const float a, const float b) {
283 switch (IMPL) {
284 #if CONFIG_ASM && ARCH_X86
285 case ASM_X86_MMX_SSE: {
286 float ret;
287 asm (
288 "movss %1, %%xmm0 # load a\n\t"
289 "mulss %2, %%xmm0 # a * b\n\t"
290 "movss %%xmm0, %0 # output\n\t"
291 : "=m" (ret)
292 : "m" (a), "m" (b)
293 );
294 return ret;
295 }
296 #endif // CONFIG_ASM && ARCH_X86
297 default: {
298 return (a * b);
299 }
300 }
301 }
302
303 template<class T_a, class T_b> inline static T_a Mul(const T_a a, const T_b b) {
304 return (a * b);
305 }
306
307 inline static float Div(const float a, const float b) {
308 switch (IMPL) {
309 #if CONFIG_ASM && ARCH_X86
310 case ASM_X86_MMX_SSE: {
311 float ret;
312 asm (
313 "movss %1, %%xmm0 # load a\n\t"
314 "divss %2, %%xmm0 # a / b\n\t"
315 "movss %%xmm0, %0 # output\n\t"
316 : "=m" (ret)
317 : "m" (a), "m" (b)
318 );
319 return ret;
320 }
321 #endif // CONFIG_ASM && ARCH_X86
322 default: {
323 return (a / b);
324 }
325 }
326 }
327
328 template<class T_a, class T_b> inline static T_a Div(const T_a a, const T_b b) {
329 return (a / b);
330 }
331
332 inline static float Min(const float a, const float b) {
333 switch (IMPL) {
334 #if CONFIG_ASM && ARCH_X86
335 case ASM_X86_MMX_SSE: {
336 float ret;
337 asm (
338 "movss %1, %%xmm0 # load a\n\t"
339 "minss %2, %%xmm0 # Minimum(a, b)\n\t"
340 "movss %%xmm0, %0 # output\n\t"
341 : "=m" (ret)
342 : "m" (a), "m" (b)
343 );
344 return ret;
345 }
346 #endif // CONFIG_ASM && ARCH_X86
347 default: {
348 return std::min(a, b);
349 }
350 }
351 }
352
353 template<class T_a, class T_b> inline static T_a Min(const T_a a, const T_b b) {
354 return (b < a) ? b : a;
355 }
356
357 inline static float Max(const float a, const float b) {
358 switch (IMPL) {
359 #if CONFIG_ASM && ARCH_X86
360 case ASM_X86_MMX_SSE: {
361 float ret;
362 asm (
363 "movss %1, %%xmm0 # load a\n\t"
364 "maxss %2, %%xmm0 # Maximum(a, b)\n\t"
365 "movss %%xmm0, %0 # output\n\t"
366 : "=m" (ret)
367 : "m" (a), "m" (b)
368 );
369 return ret;
370 }
371 #endif // CONFIG_ASM && ARCH_X86
372 default: {
373 return std::max(a, b);
374 }
375 }
376 }
377
378 template<class T_a, class T_b> inline static T_a Max(const T_a a, const T_b b) {
379 return (b > a) ? b : a;
380 }
381
382 inline static float Fmodf(const float &a, const float &b) {
383 switch (IMPL) {
384 #if CONFIG_ASM && ARCH_X86
385 case ASM_X86_MMX_SSE: {
386 float ret;
387 asm (
388 "movss %1, %%xmm0 # load a\n\t"
389 "movss %2, %%xmm1 # load b\n\t"
390 "movss %%xmm0,%%xmm2\n\t"
391 "divss %%xmm1, %%xmm2 # xmm2 = a / b\n\t"
392 "cvttss2si %%xmm2, %%ecx #convert to int\n\t"
393 "cvtsi2ss %%ecx, %%xmm2 #convert back to float\n\t"
394 "mulss %%xmm1, %%xmm2 # xmm2 = b * int(a/b)\n\t"
395 "subss %%xmm2, %%xmm0 #sub a\n\t"
396 "movss %%xmm0, %0 # output\n\t"
397 : "=m" (ret)
398 : "m" (a), "m" (b)
399 : "%ecx"
400 );
401 return ret;
402 }
403 #endif // CONFIG_ASM && ARCH_X86
404 default: {
405 return fmodf(a, b);
406 }
407 }
408 }
409 };
410
411 /// convenience typedef for using the default implementation (which is CPP)
412 typedef __RTMath<> RTMath;
413
414 #endif // __RT_MATH_H__

  ViewVC Help
Powered by ViewVC