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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3575 - (hide annotations) (download) (as text)
Wed Aug 28 11:12:04 2019 UTC (4 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 17747 byte(s)
NKSP: Added some initial floating point test cases.

* RTMath: Implemented floating point comparison methods
  fEqual32(float,float) and fEqual64(double,double)
  which take the expected floating point tolerances
  into account.

* NKSP: Allow built-in exit() function to potentially
  accept real type argument as well.

* NKSP: Added real number test cases for built-in
  functions exit(), int_to_real(), real(), real_to_int()
  and int(), as well as for the plus, minus and negate
  language operators.

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3575 * Copyright (C) 2005 - 2019 Christian Schoenebeck *
7 schoenebeck 53 * *
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 schoenebeck 328 #include <stdint.h>
29 schoenebeck 1424 #include "global_private.h"
30 schoenebeck 53
31     /// Needed for calculating frequency ratio used to pitch a sample
32     #define TWELVEHUNDREDTH_ROOT_OF_TWO 1.000577789506555
33    
34 schoenebeck 319 enum implementation_t {
35 schoenebeck 361 CPP,
36     ASM_X86_MMX_SSE
37 schoenebeck 319 };
38    
39 schoenebeck 563 /** @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 schoenebeck 319 class RTMathBase {
45 schoenebeck 53 public:
46     /**
47 schoenebeck 2942 * High resolution time stamp.
48 schoenebeck 328 */
49     typedef uint32_t time_stamp_t;
50    
51 schoenebeck 2942 typedef uint64_t usecs_t;
52    
53 schoenebeck 328 /**
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 schoenebeck 2942 *
59     * @see unsafeMicroSeconds()
60 schoenebeck 328 */
61     static time_stamp_t CreateTimeStamp();
62    
63     /**
64 schoenebeck 53 * 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 schoenebeck 554 * Note: CONFIG_MAX_PITCH (defined in config.h) has to be defined to an
69 schoenebeck 53 * appropriate value, otherwise the behavior of this function is
70 schoenebeck 554 * undefined, but most probably if CONFIG_MAX_PITCH is too small, the
71 schoenebeck 53 * 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 schoenebeck 319 int index_int = (int) (Cents); // integer index
78 schoenebeck 53 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 schoenebeck 829 /**
83 persson 1862 * 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 schoenebeck 829 * 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 schoenebeck 2931 /**
103 schoenebeck 3193 * Calculates the linear ratio value representation (linear scale)
104 schoenebeck 2931 * 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 schoenebeck 3193 * @see LinRatioToDecibel() as inverse function
114 schoenebeck 2931 */
115     static float DecibelToLinRatio(float decibel) {
116     return powf(10.f, decibel / 20.f);
117     }
118    
119     /**
120 schoenebeck 3193 * Calculates the decibel value (exponential scale) of the @a linear
121     * ratio value representation (linear scale) provided.
122     *
123     * The context of audio acoustic sound pressure levels is assumed, and
124     * hence the field version of the dB unit is used here (which uses a
125     * linear factor of 20). This function is a bit slow, so it should
126     * not be called too frequently.
127     *
128     * @param linear - sound pressure level as linear ratio value (linear scale)
129     * @returns dB value representation
130     * @see DecibelToLinRatio() as inverse function
131     */
132     static float LinRatioToDecibel(float linear) {
133     return 20.f * log10f(linear);
134     }
135    
136     /**
137 schoenebeck 2931 * Calculates the relatively summed average of a set of values.
138     *
139     * @param current - the current avaerage value of all previously summed values
140     * @param sample - new value to be applied as summed average to the existing values
141     * @param n - amount of sample values applied so far
142     * @returns new average value of all summed values (including the new @a sample)
143     */
144 schoenebeck 3054 template<typename T_int>
145     inline static float RelativeSummedAvg(float current, float sample, T_int n) {
146 schoenebeck 2931 return current + (sample - current) / float(n);
147     }
148    
149 schoenebeck 2942 /**
150     * Clock source to use for getting the current time.
151     */
152     enum clock_source_t {
153     real_clock, ///< Use this to measure time that passed in reality (no matter if process got suspended).
154     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).
155     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).
156     };
157    
158     /**
159     * Returns a time stamp of the current time in microseconds (in
160     * probably real-time @b unsafe way). There is no guarantee about
161     * what the returned amount of microseconds relates to (i.e.
162     * microseconds since epoch, microseconds since system uptime, ...).
163     * So you should only use it to calculate time differences between
164     * values taken with this method.
165     *
166     * @b CAUTION: This method may not @b NOT be real-time safe! On some
167     * systems it could be RT safe, but there is no guarantee whatsoever!
168     * So this method should only be used for debugging, benchmarking and
169     * other developing purposes !
170     *
171     * For creating time stamps in real-time context, use
172     * CreateTimeStamp() instead.
173     *
174     * @param source - the actual clock to use for getting the current
175     * time, note that the various clock sources may not
176     * be implemented on all systems
177     * @returns time stamp in microseconds
178     *
179     * @see CreateTimeStamp()
180     */
181     static usecs_t unsafeMicroSeconds(clock_source_t source);
182    
183 schoenebeck 3575 /**
184     * 'Equalness' comparison between two 32 bit floating point numbers
185     * (that is of single precision data type).
186     *
187     * This methods deals with the expected tolerance of the floating point
188     * representation.
189     *
190     * @return true if the two numbers can be expected to be equal
191     */
192     static bool fEqual32(float a, float b);
193    
194     /**
195     * 'Equalness' comparison between two 64 bit floating point numbers
196     * (that is of double precision data type).
197     *
198     * This methods deals with the expected tolerance of the floating point
199     * representation.
200     *
201     * @return true if the two numbers can be expected to be equal
202     */
203     static bool fEqual64(double a, double b);
204    
205 schoenebeck 319 private:
206     static float* pCentsToFreqTable;
207    
208     static float* InitCentsToFreqTable();
209     };
210    
211 schoenebeck 563 /** @brief Real Time Math
212 schoenebeck 319 *
213 schoenebeck 563 * This is a template which provides customized methods for the desired low
214     * level implementation. The ASM_X86_MMX_SSE implementation of each method
215     * for example doesn't use 387 FPU instruction. This is needed for MMX
216     * algorithms which do not allow mixed MMX and 387 instructions.
217 schoenebeck 319 */
218     template<implementation_t IMPL = CPP>
219     class __RTMath : public RTMathBase {
220     public:
221     // conversion using truncate
222     inline static int Int(const float a) {
223     switch (IMPL) {
224 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
225 schoenebeck 319 case ASM_X86_MMX_SSE: {
226     int ret;
227     asm (
228     "cvttss2si %1, %0 # convert to int\n\t"
229     : "=r" (ret)
230     : "m" (a)
231     );
232     return ret;
233     }
234 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
235 persson 685 default: {
236     return (int) a;
237     }
238 schoenebeck 319 }
239     }
240    
241     //for doubles and everything else except floats
242     template<class T_a> inline static int Int(const T_a a) {
243     return (int) a;
244     }
245    
246     inline static float Float(const int a) {
247     switch (IMPL) {
248 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
249 schoenebeck 319 case ASM_X86_MMX_SSE: {
250     float ret;
251     asm (
252     "cvtsi2ss %1, %%xmm0 # convert to float\n\t"
253     "movss %%xmm0,%0 # output\n\t"
254     : "=m" (ret)
255     : "r" (a)
256     );
257     return ret;
258     }
259 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
260 persson 685 default: {
261     return (float) a;
262     }
263 schoenebeck 319 }
264     }
265    
266     #if 0
267     //for everything except ints
268     template<class T_a> inline static float Float(T_a a) {
269     return (float) a;
270     }
271     #endif
272    
273     inline static float Sum(const float& a, const float& b) {
274     switch (IMPL) {
275 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
276 schoenebeck 319 case ASM_X86_MMX_SSE: {
277     float ret;
278     asm (
279     "movss %1, %%xmm0 # load a\n\t"
280     "addss %2, %%xmm0 # a + b\n\t"
281     "movss %%xmm0, %0 # output\n\t"
282     : "=m" (ret)
283     : "m" (a), "m" (b)
284     );
285     return ret;
286     }
287 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
288 persson 685 default: {
289     return (a + b);
290     }
291 schoenebeck 319 }
292     }
293    
294     template<class T_a, class T_b> inline static T_a Sum(const T_a a, const T_b b) {
295     return (a + b);
296     }
297    
298     inline static float Sub(const float& a, const float& b) {
299     switch (IMPL) {
300 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
301 schoenebeck 319 case ASM_X86_MMX_SSE: {
302     float ret;
303     asm (
304     "movss %1, %%xmm0 # load a\n\t"
305     "subss %2, %%xmm0 # a - b\n\t"
306     "movss %%xmm0, %0 # output\n\t"
307     : "=m" (ret)
308     : "m" (a), "m" (b)
309     );
310     return ret;
311     }
312 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
313 persson 685 default: {
314     return (a - b);
315     }
316 schoenebeck 319 }
317     }
318    
319     template<class T_a, class T_b> inline static T_a Sub(const T_a a, const T_b b) {
320     return (a - b);
321     }
322    
323     inline static float Mul(const float a, const float b) {
324     switch (IMPL) {
325 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
326 schoenebeck 319 case ASM_X86_MMX_SSE: {
327     float ret;
328     asm (
329     "movss %1, %%xmm0 # load a\n\t"
330     "mulss %2, %%xmm0 # a * b\n\t"
331     "movss %%xmm0, %0 # output\n\t"
332     : "=m" (ret)
333     : "m" (a), "m" (b)
334     );
335     return ret;
336     }
337 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
338 persson 685 default: {
339     return (a * b);
340     }
341 schoenebeck 319 }
342     }
343    
344     template<class T_a, class T_b> inline static T_a Mul(const T_a a, const T_b b) {
345     return (a * b);
346     }
347    
348     inline static float Div(const float a, const float b) {
349     switch (IMPL) {
350 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
351 schoenebeck 319 case ASM_X86_MMX_SSE: {
352     float ret;
353     asm (
354     "movss %1, %%xmm0 # load a\n\t"
355     "divss %2, %%xmm0 # a / b\n\t"
356     "movss %%xmm0, %0 # output\n\t"
357     : "=m" (ret)
358     : "m" (a), "m" (b)
359     );
360     return ret;
361     }
362 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
363 persson 685 default: {
364     return (a / b);
365     }
366 schoenebeck 319 }
367     }
368    
369     template<class T_a, class T_b> inline static T_a Div(const T_a a, const T_b b) {
370     return (a / b);
371     }
372    
373     inline static float Min(const float a, const float b) {
374     switch (IMPL) {
375 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
376 schoenebeck 319 case ASM_X86_MMX_SSE: {
377     float ret;
378     asm (
379     "movss %1, %%xmm0 # load a\n\t"
380     "minss %2, %%xmm0 # Minimum(a, b)\n\t"
381     "movss %%xmm0, %0 # output\n\t"
382     : "=m" (ret)
383     : "m" (a), "m" (b)
384     );
385     return ret;
386     }
387 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
388 persson 685 default: {
389 wylder 818 return std::min(a, b);
390 persson 685 }
391 schoenebeck 319 }
392     }
393    
394     template<class T_a, class T_b> inline static T_a Min(const T_a a, const T_b b) {
395 schoenebeck 53 return (b < a) ? b : a;
396     }
397    
398 schoenebeck 319 inline static float Max(const float a, const float b) {
399     switch (IMPL) {
400 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
401 schoenebeck 319 case ASM_X86_MMX_SSE: {
402     float ret;
403     asm (
404     "movss %1, %%xmm0 # load a\n\t"
405     "maxss %2, %%xmm0 # Maximum(a, b)\n\t"
406     "movss %%xmm0, %0 # output\n\t"
407     : "=m" (ret)
408     : "m" (a), "m" (b)
409     );
410     return ret;
411     }
412 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
413 persson 685 default: {
414 wylder 818 return std::max(a, b);
415 persson 685 }
416 schoenebeck 319 }
417     }
418    
419     template<class T_a, class T_b> inline static T_a Max(const T_a a, const T_b b) {
420 schoenebeck 53 return (b > a) ? b : a;
421     }
422    
423 schoenebeck 319 inline static float Fmodf(const float &a, const float &b) {
424     switch (IMPL) {
425 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
426 schoenebeck 319 case ASM_X86_MMX_SSE: {
427     float ret;
428     asm (
429     "movss %1, %%xmm0 # load a\n\t"
430     "movss %2, %%xmm1 # load b\n\t"
431     "movss %%xmm0,%%xmm2\n\t"
432     "divss %%xmm1, %%xmm2 # xmm2 = a / b\n\t"
433     "cvttss2si %%xmm2, %%ecx #convert to int\n\t"
434     "cvtsi2ss %%ecx, %%xmm2 #convert back to float\n\t"
435     "mulss %%xmm1, %%xmm2 # xmm2 = b * int(a/b)\n\t"
436     "subss %%xmm2, %%xmm0 #sub a\n\t"
437     "movss %%xmm0, %0 # output\n\t"
438     : "=m" (ret)
439     : "m" (a), "m" (b)
440     : "%ecx"
441     );
442     return ret;
443     }
444 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
445 persson 685 default: {
446     return fmodf(a, b);
447     }
448 schoenebeck 319 }
449     }
450 schoenebeck 53 };
451    
452 schoenebeck 319 /// convenience typedef for using the default implementation (which is CPP)
453     typedef __RTMath<> RTMath;
454    
455 schoenebeck 53 #endif // __RT_MATH_H__

  ViewVC Help
Powered by ViewVC