/[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 1862 - (hide annotations) (download) (as text)
Wed Mar 11 19:03:37 2009 UTC (15 years, 1 month ago) by persson
File MIME type: text/x-c++hdr
File size: 12930 byte(s)
* allow gig files to use unlimited downward pitch shifting
* added a limit check for upward pitch shifting

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 1212 * Copyright (C) 2005 - 2007 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 328 * Highly accurate time stamp.
48     */
49     typedef uint32_t time_stamp_t;
50    
51     /**
52     * We read the processor's cycle count register as a reference
53     * for the real time. These are of course only abstract values
54     * with arbitrary time entity, but that's not a problem as long
55     * as we calculate relatively.
56     */
57     static time_stamp_t CreateTimeStamp();
58    
59     /**
60 schoenebeck 53 * Calculates the frequency ratio for a pitch value given in cents
61     * (assuming equal tempered scale of course, divided into 12
62     * semitones per octave and 100 cents per semitone).
63     *
64 schoenebeck 554 * Note: CONFIG_MAX_PITCH (defined in config.h) has to be defined to an
65 schoenebeck 53 * appropriate value, otherwise the behavior of this function is
66 schoenebeck 554 * undefined, but most probably if CONFIG_MAX_PITCH is too small, the
67 schoenebeck 53 * application will crash due to segmentation fault here.
68     *
69     * @param cents - pitch value in cents (+1200 cents means +1 octave)
70     * @returns frequency ratio (e.g. +2.0 for +1 octave)
71     */
72     inline static double CentsToFreqRatio(double Cents) {
73 schoenebeck 319 int index_int = (int) (Cents); // integer index
74 schoenebeck 53 float index_fract = Cents - index_int; // fractional part of index
75     return pCentsToFreqTable[index_int] + index_fract * (pCentsToFreqTable[index_int+1] - pCentsToFreqTable[index_int]);
76     }
77    
78 schoenebeck 829 /**
79 persson 1862 * 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     /**
91 schoenebeck 829 * 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 schoenebeck 319 private:
99     static float* pCentsToFreqTable;
100    
101     static float* InitCentsToFreqTable();
102     };
103    
104 schoenebeck 563 /** @brief Real Time Math
105 schoenebeck 319 *
106 schoenebeck 563 * This is a template which provides customized methods for the desired low
107     * level implementation. The ASM_X86_MMX_SSE implementation of each method
108     * for example doesn't use 387 FPU instruction. This is needed for MMX
109     * algorithms which do not allow mixed MMX and 387 instructions.
110 schoenebeck 319 */
111     template<implementation_t IMPL = CPP>
112     class __RTMath : public RTMathBase {
113     public:
114     // conversion using truncate
115     inline static int Int(const float a) {
116     switch (IMPL) {
117 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
118 schoenebeck 319 case ASM_X86_MMX_SSE: {
119     int ret;
120     asm (
121     "cvttss2si %1, %0 # convert to int\n\t"
122     : "=r" (ret)
123     : "m" (a)
124     );
125     return ret;
126     }
127 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
128 persson 685 default: {
129     return (int) a;
130     }
131 schoenebeck 319 }
132     }
133    
134     //for doubles and everything else except floats
135     template<class T_a> inline static int Int(const T_a a) {
136     return (int) a;
137     }
138    
139     inline static float Float(const int a) {
140     switch (IMPL) {
141 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
142 schoenebeck 319 case ASM_X86_MMX_SSE: {
143     float ret;
144     asm (
145     "cvtsi2ss %1, %%xmm0 # convert to float\n\t"
146     "movss %%xmm0,%0 # output\n\t"
147     : "=m" (ret)
148     : "r" (a)
149     );
150     return ret;
151     }
152 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
153 persson 685 default: {
154     return (float) a;
155     }
156 schoenebeck 319 }
157     }
158    
159     #if 0
160     //for everything except ints
161     template<class T_a> inline static float Float(T_a a) {
162     return (float) a;
163     }
164     #endif
165    
166     inline static float Sum(const float& a, const float& b) {
167     switch (IMPL) {
168 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
169 schoenebeck 319 case ASM_X86_MMX_SSE: {
170     float ret;
171     asm (
172     "movss %1, %%xmm0 # load a\n\t"
173     "addss %2, %%xmm0 # a + b\n\t"
174     "movss %%xmm0, %0 # output\n\t"
175     : "=m" (ret)
176     : "m" (a), "m" (b)
177     );
178     return ret;
179     }
180 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
181 persson 685 default: {
182     return (a + b);
183     }
184 schoenebeck 319 }
185     }
186    
187     template<class T_a, class T_b> inline static T_a Sum(const T_a a, const T_b b) {
188     return (a + b);
189     }
190    
191     inline static float Sub(const float& a, const float& b) {
192     switch (IMPL) {
193 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
194 schoenebeck 319 case ASM_X86_MMX_SSE: {
195     float ret;
196     asm (
197     "movss %1, %%xmm0 # load a\n\t"
198     "subss %2, %%xmm0 # a - b\n\t"
199     "movss %%xmm0, %0 # output\n\t"
200     : "=m" (ret)
201     : "m" (a), "m" (b)
202     );
203     return ret;
204     }
205 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
206 persson 685 default: {
207     return (a - b);
208     }
209 schoenebeck 319 }
210     }
211    
212     template<class T_a, class T_b> inline static T_a Sub(const T_a a, const T_b b) {
213     return (a - b);
214     }
215    
216     inline static float Mul(const float a, const float b) {
217     switch (IMPL) {
218 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
219 schoenebeck 319 case ASM_X86_MMX_SSE: {
220     float ret;
221     asm (
222     "movss %1, %%xmm0 # load a\n\t"
223     "mulss %2, %%xmm0 # a * b\n\t"
224     "movss %%xmm0, %0 # output\n\t"
225     : "=m" (ret)
226     : "m" (a), "m" (b)
227     );
228     return ret;
229     }
230 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
231 persson 685 default: {
232     return (a * b);
233     }
234 schoenebeck 319 }
235     }
236    
237     template<class T_a, class T_b> inline static T_a Mul(const T_a a, const T_b b) {
238     return (a * b);
239     }
240    
241     inline static float Div(const float a, const float b) {
242     switch (IMPL) {
243 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
244 schoenebeck 319 case ASM_X86_MMX_SSE: {
245     float ret;
246     asm (
247     "movss %1, %%xmm0 # load a\n\t"
248     "divss %2, %%xmm0 # a / b\n\t"
249     "movss %%xmm0, %0 # output\n\t"
250     : "=m" (ret)
251     : "m" (a), "m" (b)
252     );
253     return ret;
254     }
255 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
256 persson 685 default: {
257     return (a / b);
258     }
259 schoenebeck 319 }
260     }
261    
262     template<class T_a, class T_b> inline static T_a Div(const T_a a, const T_b b) {
263     return (a / b);
264     }
265    
266     inline static float Min(const float a, const float b) {
267     switch (IMPL) {
268 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
269 schoenebeck 319 case ASM_X86_MMX_SSE: {
270     float ret;
271     asm (
272     "movss %1, %%xmm0 # load a\n\t"
273     "minss %2, %%xmm0 # Minimum(a, b)\n\t"
274     "movss %%xmm0, %0 # output\n\t"
275     : "=m" (ret)
276     : "m" (a), "m" (b)
277     );
278     return ret;
279     }
280 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
281 persson 685 default: {
282 wylder 818 return std::min(a, b);
283 persson 685 }
284 schoenebeck 319 }
285     }
286    
287     template<class T_a, class T_b> inline static T_a Min(const T_a a, const T_b b) {
288 schoenebeck 53 return (b < a) ? b : a;
289     }
290    
291 schoenebeck 319 inline static float Max(const float a, const float b) {
292     switch (IMPL) {
293 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
294 schoenebeck 319 case ASM_X86_MMX_SSE: {
295     float ret;
296     asm (
297     "movss %1, %%xmm0 # load a\n\t"
298     "maxss %2, %%xmm0 # Maximum(a, b)\n\t"
299     "movss %%xmm0, %0 # output\n\t"
300     : "=m" (ret)
301     : "m" (a), "m" (b)
302     );
303     return ret;
304     }
305 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
306 persson 685 default: {
307 wylder 818 return std::max(a, b);
308 persson 685 }
309 schoenebeck 319 }
310     }
311    
312     template<class T_a, class T_b> inline static T_a Max(const T_a a, const T_b b) {
313 schoenebeck 53 return (b > a) ? b : a;
314     }
315    
316 schoenebeck 319 inline static float Fmodf(const float &a, const float &b) {
317     switch (IMPL) {
318 schoenebeck 617 #if CONFIG_ASM && ARCH_X86
319 schoenebeck 319 case ASM_X86_MMX_SSE: {
320     float ret;
321     asm (
322     "movss %1, %%xmm0 # load a\n\t"
323     "movss %2, %%xmm1 # load b\n\t"
324     "movss %%xmm0,%%xmm2\n\t"
325     "divss %%xmm1, %%xmm2 # xmm2 = a / b\n\t"
326     "cvttss2si %%xmm2, %%ecx #convert to int\n\t"
327     "cvtsi2ss %%ecx, %%xmm2 #convert back to float\n\t"
328     "mulss %%xmm1, %%xmm2 # xmm2 = b * int(a/b)\n\t"
329     "subss %%xmm2, %%xmm0 #sub a\n\t"
330     "movss %%xmm0, %0 # output\n\t"
331     : "=m" (ret)
332     : "m" (a), "m" (b)
333     : "%ecx"
334     );
335     return ret;
336     }
337 schoenebeck 617 #endif // CONFIG_ASM && ARCH_X86
338 persson 685 default: {
339     return fmodf(a, b);
340     }
341 schoenebeck 319 }
342     }
343 schoenebeck 53 };
344    
345 schoenebeck 319 /// convenience typedef for using the default implementation (which is CPP)
346     typedef __RTMath<> RTMath;
347    
348 schoenebeck 53 #endif // __RT_MATH_H__

  ViewVC Help
Powered by ViewVC