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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 53 by schoenebeck, Mon Apr 26 17:15:51 2004 UTC revision 2931 by schoenebeck, Sat Jul 9 14:38:33 2016 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck         *   *   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  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 24  Line 25 
25  #define __RT_MATH_H__  #define __RT_MATH_H__
26    
27  #include <math.h>  #include <math.h>
28  #include "global.h"  #include <stdint.h>
29    #include "global_private.h"
30    
31  /// Needed for calculating frequency ratio used to pitch a sample  /// Needed for calculating frequency ratio used to pitch a sample
32  #define TWELVEHUNDREDTH_ROOT_OF_TWO     1.000577789506555  #define TWELVEHUNDREDTH_ROOT_OF_TWO     1.000577789506555
33    
34  /** Real Time Math  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.   * Math functions for real time operation. This base class contains all
42     * non-template methods.
43   */   */
44  class RTMath {  class RTMathBase {
45      public:      public:
46          /**          /**
47           * Converts a double to integer type.           * Highly accurate time stamp.
48           */           */
49          inline static int DoubleToInt(double f) {          typedef uint32_t time_stamp_t;
50              #if ARCH_X86  
51              int i;          /**
52              __asm__ ("fistl %0" : "=m"(i) : "st"(f - 0.5) );           * We read the processor's cycle count register as a reference
53              return i;           * for the real time. These are of course only abstract values
54              #else           * with arbitrary time entity, but that's not a problem as long
55              return (int) f;           * as we calculate relatively.
56              #endif // ARCH_X86           */
57          }          static time_stamp_t CreateTimeStamp();
58    
59          /**          /**
60           * Calculates the frequency ratio for a pitch value given in cents           * Calculates the frequency ratio for a pitch value given in cents
61           * (assuming equal tempered scale of course, divided into 12           * (assuming equal tempered scale of course, divided into 12
62           * semitones per octave and 100 cents per semitone).           * semitones per octave and 100 cents per semitone).
63           *           *
64           * Note: MAX_PITCH (defined in global.h) has to be defined to an           * Note: CONFIG_MAX_PITCH (defined in config.h) has to be defined to an
65           * appropriate value, otherwise the behavior of this function is           * appropriate value, otherwise the behavior of this function is
66           * undefined, but most probably if MAX_PITCH is too small, the           * undefined, but most probably if CONFIG_MAX_PITCH is too small, the
67           * application will crash due to segmentation fault here.           * application will crash due to segmentation fault here.
68           *           *
69           * @param cents - pitch value in cents (+1200 cents means +1 octave)           * @param cents - pitch value in cents (+1200 cents means +1 octave)
70           * @returns  frequency ratio (e.g. +2.0 for +1 octave)           * @returns  frequency ratio (e.g. +2.0 for +1 octave)
71           */           */
72          inline static double CentsToFreqRatio(double Cents) {          inline static double CentsToFreqRatio(double Cents) {
73              int   index_int   = DoubleToInt(Cents); // integer index              int   index_int   = (int) (Cents);      // integer index
74              float index_fract = Cents - index_int;  // fractional part of index              float index_fract = Cents - index_int;  // fractional part of index
75              return pCentsToFreqTable[index_int] + index_fract * (pCentsToFreqTable[index_int+1] - pCentsToFreqTable[index_int]);              return pCentsToFreqTable[index_int] + index_fract * (pCentsToFreqTable[index_int+1] - pCentsToFreqTable[index_int]);
76          }          }
77    
78          template<class T_a, class T_b> inline static T_a Min(T_a a, T_b b) {          /**
79              return (b < a) ? b : a;           * Slower version of CentsToFreqRatio, for big values.
80             *
81             * @param cents - pitch value in cents (+1200 cents means +1 octave)
82             * @returns  frequency ratio (e.g. +2.0 for +1 octave)
83             */
84            static double CentsToFreqRatioUnlimited(double Cents) {
85                int octaves = int(Cents / 1200);
86                double x = CentsToFreqRatio(Cents - octaves * 1200);
87                return  octaves < 0 ? x / (1 << -octaves) : x * (1 << octaves);
88          }          }
89    
90          template<class T_a, class T_b> inline static T_a Max(T_a a, T_b b) {          /**
91              return (b > a) ? b : a;           * Inverse function to CentsToFreqRatio(). This function is a bit
92             * slow, so it should not be called too frequently.
93             */
94            static double FreqRatioToCents(double FreqRatio) {
95                return log(FreqRatio) / log(TWELVEHUNDREDTH_ROOT_OF_TWO);
96            }
97    
98            /**
99             * Calculates the line ratio value representation (linear scale)
100             * of the @a decibel value provided (exponential scale).
101             *
102             * The context of audio acoustic sound pressure levels is assumed, and
103             * hence the field version of the dB unit is used here (which uses a
104             * linear factor of 20). This function is a bit slow, so it should
105             * not be called too frequently.
106             *
107             * @param decibel - sound pressure level in dB
108             * @returns linear ratio of the supplied dB value
109             */
110            static float DecibelToLinRatio(float decibel) {
111                return powf(10.f, decibel / 20.f);
112            }
113    
114            /**
115             * Calculates the relatively summed average of a set of values.
116             *
117             * @param current - the current avaerage value of all previously summed values
118             * @param sample - new value to be applied as summed average to the existing values
119             * @param n - amount of sample values applied so far
120             * @returns new average value of all summed values (including the new @a sample)
121             */
122            inline static float RelativeSummedAvg(float current, float sample, int n) {
123                return current + (sample - current) / float(n);
124          }          }
125    
126      private:      private:
         static float  CentsToFreqTable[MAX_PITCH * 1200 * 2 + 1];  
127          static float* pCentsToFreqTable;          static float* pCentsToFreqTable;
128    
129          static float* InitCentsToFreqTable();          static float* InitCentsToFreqTable();
130  };  };
131    
132    /** @brief Real Time Math
133     *
134     * This is a template which provides customized methods for the desired low
135     * level implementation. The ASM_X86_MMX_SSE implementation of each method
136     * for example doesn't use 387 FPU instruction. This is needed for MMX
137     * algorithms which do not allow mixed MMX and 387 instructions.
138     */
139    template<implementation_t IMPL = CPP>
140    class __RTMath : public RTMathBase {
141        public:
142            // conversion using truncate
143            inline static int Int(const float a) {
144                switch (IMPL) {
145                    #if CONFIG_ASM && ARCH_X86
146                    case ASM_X86_MMX_SSE: {
147                        int ret;
148                        asm (
149                            "cvttss2si %1, %0  # convert to int\n\t"
150                            : "=r" (ret)
151                            : "m" (a)
152                        );
153                        return ret;
154                    }
155                    #endif // CONFIG_ASM && ARCH_X86
156                    default: {
157                        return (int) a;
158                    }
159                }
160            }
161    
162            //for doubles and everything else except floats
163            template<class T_a> inline static int Int(const T_a a) {
164                return (int) a;
165            }
166    
167            inline static float Float(const int a) {
168                switch (IMPL) {
169                    #if CONFIG_ASM && ARCH_X86
170                    case ASM_X86_MMX_SSE: {
171                        float ret;
172                        asm (
173                            "cvtsi2ss %1, %%xmm0  # convert to float\n\t"
174                            "movss    %%xmm0,%0   # output\n\t"
175                            : "=m" (ret)
176                            : "r" (a)
177                        );
178                        return ret;
179                    }
180                    #endif // CONFIG_ASM && ARCH_X86
181                    default: {
182                        return (float) a;
183                    }
184                }
185            }
186    
187    #if 0
188            //for everything except ints
189            template<class T_a> inline static float Float(T_a a) {
190                return (float) a;
191            }
192    #endif
193    
194            inline static float Sum(const float& a, const float& b) {
195                switch (IMPL) {
196                    #if CONFIG_ASM && ARCH_X86
197                    case ASM_X86_MMX_SSE: {
198                        float ret;
199                        asm (
200                            "movss    %1, %%xmm0  # load a\n\t"
201                            "addss    %2, %%xmm0  # a + b\n\t"
202                            "movss    %%xmm0, %0  # output\n\t"
203                            : "=m" (ret)
204                            : "m" (a), "m" (b)
205                        );
206                        return ret;
207                    }
208                    #endif // CONFIG_ASM && ARCH_X86
209                    default: {
210                        return (a + b);
211                    }
212                }
213            }
214    
215            template<class T_a, class T_b> inline static T_a Sum(const T_a a, const T_b b) {
216                return (a + b);
217            }
218    
219            inline static float Sub(const float& a, const float& b) {
220                switch (IMPL) {
221                    #if CONFIG_ASM && ARCH_X86
222                    case ASM_X86_MMX_SSE: {
223                        float ret;
224                        asm (
225                            "movss    %1, %%xmm0  # load a\n\t"
226                            "subss    %2, %%xmm0  # a - b\n\t"
227                            "movss    %%xmm0, %0  # output\n\t"
228                            : "=m" (ret)
229                            : "m" (a), "m" (b)
230                        );
231                        return ret;
232                    }
233                    #endif // CONFIG_ASM && ARCH_X86
234                    default: {
235                        return (a - b);
236                    }
237                }
238            }
239    
240            template<class T_a, class T_b> inline static T_a Sub(const T_a a, const T_b b) {
241                return (a - b);
242            }
243    
244            inline static float Mul(const float a, const float b) {
245                switch (IMPL) {
246                    #if CONFIG_ASM && ARCH_X86
247                    case ASM_X86_MMX_SSE: {
248                        float ret;
249                        asm (
250                            "movss    %1, %%xmm0  # load a\n\t"
251                            "mulss    %2, %%xmm0  # a * b\n\t"
252                            "movss    %%xmm0, %0  # output\n\t"
253                            : "=m" (ret)
254                            : "m" (a), "m" (b)
255                        );
256                        return ret;
257                    }
258                    #endif // CONFIG_ASM && ARCH_X86
259                    default: {
260                        return (a * b);
261                    }
262                }
263            }
264    
265            template<class T_a, class T_b> inline static T_a Mul(const T_a a, const T_b b) {
266                return (a * b);
267            }
268    
269            inline static float Div(const float a, const float b) {
270                switch (IMPL) {
271                    #if CONFIG_ASM && ARCH_X86
272                    case ASM_X86_MMX_SSE: {
273                        float ret;
274                        asm (
275                            "movss    %1, %%xmm0  # load a\n\t"
276                            "divss    %2, %%xmm0  # a / b\n\t"
277                            "movss    %%xmm0, %0  # output\n\t"
278                            : "=m" (ret)
279                            : "m" (a), "m" (b)
280                        );
281                        return ret;
282                    }
283                    #endif // CONFIG_ASM && ARCH_X86
284                    default: {
285                        return (a / b);
286                    }
287                }
288            }
289    
290            template<class T_a, class T_b> inline static T_a Div(const T_a a, const T_b b) {
291                return (a / b);
292            }
293    
294            inline static float Min(const float a, const float b) {
295                switch (IMPL) {
296                    #if CONFIG_ASM && ARCH_X86
297                    case ASM_X86_MMX_SSE: {
298                        float ret;
299                        asm (
300                            "movss    %1, %%xmm0  # load a\n\t"
301                            "minss    %2, %%xmm0  # Minimum(a, b)\n\t"
302                            "movss    %%xmm0, %0  # output\n\t"
303                            : "=m" (ret)
304                            : "m" (a), "m" (b)
305                        );
306                        return ret;
307                    }
308                    #endif // CONFIG_ASM && ARCH_X86
309                    default: {
310                        return std::min(a, b);
311                    }
312                }
313            }
314    
315            template<class T_a, class T_b> inline static T_a Min(const T_a a, const T_b b) {
316                return (b < a) ? b : a;
317            }
318    
319            inline static float Max(const float a, const float b) {
320                switch (IMPL) {
321                    #if CONFIG_ASM && ARCH_X86
322                    case ASM_X86_MMX_SSE: {
323                        float ret;
324                        asm (
325                            "movss    %1, %%xmm0  # load a\n\t"
326                            "maxss    %2, %%xmm0  # Maximum(a, b)\n\t"
327                            "movss    %%xmm0, %0  # output\n\t"
328                            : "=m" (ret)
329                            : "m" (a), "m" (b)
330                        );
331                        return ret;
332                    }
333                    #endif // CONFIG_ASM && ARCH_X86
334                    default: {
335                        return std::max(a, b);
336                    }
337                }
338            }
339    
340            template<class T_a, class T_b> inline static T_a Max(const T_a a, const T_b b) {
341                return (b > a) ? b : a;
342            }
343    
344            inline static float Fmodf(const float &a, const float &b) {
345                switch (IMPL) {
346                    #if CONFIG_ASM && ARCH_X86
347                    case ASM_X86_MMX_SSE: {
348                        float ret;
349                        asm (
350                            "movss    %1, %%xmm0  # load a\n\t"
351                            "movss    %2, %%xmm1  # load b\n\t"
352                            "movss    %%xmm0,%%xmm2\n\t"
353                            "divss    %%xmm1, %%xmm2  # xmm2 = a / b\n\t"
354                            "cvttss2si %%xmm2, %%ecx  #convert to int\n\t"
355                            "cvtsi2ss %%ecx, %%xmm2  #convert back to float\n\t"
356                            "mulss    %%xmm1, %%xmm2  # xmm2 = b * int(a/b)\n\t"
357                            "subss    %%xmm2, %%xmm0  #sub a\n\t"
358                            "movss    %%xmm0, %0  # output\n\t"
359                            : "=m" (ret)
360                            : "m" (a), "m" (b)
361                            : "%ecx"
362                        );
363                        return ret;
364                    }
365                    #endif // CONFIG_ASM && ARCH_X86
366                    default: {
367                        return fmodf(a, b);
368                    }
369                }
370            }
371    };
372    
373    /// convenience typedef for using the default implementation (which is CPP)
374    typedef __RTMath<> RTMath;
375    
376  #endif // __RT_MATH_H__  #endif // __RT_MATH_H__

Legend:
Removed from v.53  
changed lines
  Added in v.2931

  ViewVC Help
Powered by ViewVC