/[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 737 - (show annotations) (download) (as text)
Tue Aug 16 16:50:00 2005 UTC (18 years, 7 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 12378 byte(s)
added GCCs C++ language extension for Min and Max

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 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.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 * 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 * 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 * Note: CONFIG_MAX_PITCH (defined in config.h) has to be defined to an
65 * appropriate value, otherwise the behavior of this function is
66 * undefined, but most probably if CONFIG_MAX_PITCH is too small, the
67 * 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 int index_int = (int) (Cents); // integer index
74 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 private:
79 static float CentsToFreqTable[CONFIG_MAX_PITCH * 1200 * 2 + 1];
80 static float* pCentsToFreqTable;
81
82 static float* InitCentsToFreqTable();
83 };
84
85 /** @brief Real Time Math
86 *
87 * This is a template which provides customized methods for the desired low
88 * level implementation. The ASM_X86_MMX_SSE implementation of each method
89 * for example doesn't use 387 FPU instruction. This is needed for MMX
90 * algorithms which do not allow mixed MMX and 387 instructions.
91 */
92 template<implementation_t IMPL = CPP>
93 class __RTMath : public RTMathBase {
94 public:
95 // conversion using truncate
96 inline static int Int(const float a) {
97 switch (IMPL) {
98 #if CONFIG_ASM && ARCH_X86
99 case ASM_X86_MMX_SSE: {
100 int ret;
101 asm (
102 "cvttss2si %1, %0 # convert to int\n\t"
103 : "=r" (ret)
104 : "m" (a)
105 );
106 return ret;
107 }
108 #endif // CONFIG_ASM && ARCH_X86
109 default: {
110 return (int) a;
111 }
112 }
113 }
114
115 //for doubles and everything else except floats
116 template<class T_a> inline static int Int(const T_a a) {
117 return (int) a;
118 }
119
120 inline static float Float(const int a) {
121 switch (IMPL) {
122 #if CONFIG_ASM && ARCH_X86
123 case ASM_X86_MMX_SSE: {
124 float ret;
125 asm (
126 "cvtsi2ss %1, %%xmm0 # convert to float\n\t"
127 "movss %%xmm0,%0 # output\n\t"
128 : "=m" (ret)
129 : "r" (a)
130 );
131 return ret;
132 }
133 #endif // CONFIG_ASM && ARCH_X86
134 default: {
135 return (float) a;
136 }
137 }
138 }
139
140 #if 0
141 //for everything except ints
142 template<class T_a> inline static float Float(T_a a) {
143 return (float) a;
144 }
145 #endif
146
147 inline static float Sum(const float& a, const float& b) {
148 switch (IMPL) {
149 #if CONFIG_ASM && ARCH_X86
150 case ASM_X86_MMX_SSE: {
151 float ret;
152 asm (
153 "movss %1, %%xmm0 # load a\n\t"
154 "addss %2, %%xmm0 # a + b\n\t"
155 "movss %%xmm0, %0 # output\n\t"
156 : "=m" (ret)
157 : "m" (a), "m" (b)
158 );
159 return ret;
160 }
161 #endif // CONFIG_ASM && ARCH_X86
162 default: {
163 return (a + b);
164 }
165 }
166 }
167
168 template<class T_a, class T_b> inline static T_a Sum(const T_a a, const T_b b) {
169 return (a + b);
170 }
171
172 inline static float Sub(const float& a, const float& b) {
173 switch (IMPL) {
174 #if CONFIG_ASM && ARCH_X86
175 case ASM_X86_MMX_SSE: {
176 float ret;
177 asm (
178 "movss %1, %%xmm0 # load a\n\t"
179 "subss %2, %%xmm0 # a - b\n\t"
180 "movss %%xmm0, %0 # output\n\t"
181 : "=m" (ret)
182 : "m" (a), "m" (b)
183 );
184 return ret;
185 }
186 #endif // CONFIG_ASM && ARCH_X86
187 default: {
188 return (a - b);
189 }
190 }
191 }
192
193 template<class T_a, class T_b> inline static T_a Sub(const T_a a, const T_b b) {
194 return (a - b);
195 }
196
197 inline static float Mul(const float a, const float b) {
198 switch (IMPL) {
199 #if CONFIG_ASM && ARCH_X86
200 case ASM_X86_MMX_SSE: {
201 float ret;
202 asm (
203 "movss %1, %%xmm0 # load a\n\t"
204 "mulss %2, %%xmm0 # a * b\n\t"
205 "movss %%xmm0, %0 # output\n\t"
206 : "=m" (ret)
207 : "m" (a), "m" (b)
208 );
209 return ret;
210 }
211 #endif // CONFIG_ASM && ARCH_X86
212 default: {
213 return (a * b);
214 }
215 }
216 }
217
218 template<class T_a, class T_b> inline static T_a Mul(const T_a a, const T_b b) {
219 return (a * b);
220 }
221
222 inline static float Div(const float a, const float b) {
223 switch (IMPL) {
224 #if CONFIG_ASM && ARCH_X86
225 case ASM_X86_MMX_SSE: {
226 float ret;
227 asm (
228 "movss %1, %%xmm0 # load a\n\t"
229 "divss %2, %%xmm0 # a / b\n\t"
230 "movss %%xmm0, %0 # output\n\t"
231 : "=m" (ret)
232 : "m" (a), "m" (b)
233 );
234 return ret;
235 }
236 #endif // CONFIG_ASM && ARCH_X86
237 default: {
238 return (a / b);
239 }
240 }
241 }
242
243 template<class T_a, class T_b> inline static T_a Div(const T_a a, const T_b b) {
244 return (a / b);
245 }
246
247 inline static float Min(const float a, const float b) {
248 switch (IMPL) {
249 #if CONFIG_ASM && ARCH_X86
250 case ASM_X86_MMX_SSE: {
251 float ret;
252 asm (
253 "movss %1, %%xmm0 # load a\n\t"
254 "minss %2, %%xmm0 # Minimum(a, b)\n\t"
255 "movss %%xmm0, %0 # output\n\t"
256 : "=m" (ret)
257 : "m" (a), "m" (b)
258 );
259 return ret;
260 }
261 #endif // CONFIG_ASM && ARCH_X86
262 default: {
263 return (b < a) ? b : a;
264 }
265 }
266 }
267
268 template<class T_a, class T_b> inline static T_a Min(const T_a a, const T_b b) {
269 #if __GNUC__
270 return b <? a;
271 #else
272 return (b < a) ? b : a;
273 #endif
274 }
275
276 inline static float Max(const float a, const float b) {
277 switch (IMPL) {
278 #if CONFIG_ASM && ARCH_X86
279 case ASM_X86_MMX_SSE: {
280 float ret;
281 asm (
282 "movss %1, %%xmm0 # load a\n\t"
283 "maxss %2, %%xmm0 # Maximum(a, b)\n\t"
284 "movss %%xmm0, %0 # output\n\t"
285 : "=m" (ret)
286 : "m" (a), "m" (b)
287 );
288 return ret;
289 }
290 #endif // CONFIG_ASM && ARCH_X86
291 default: {
292 return (b > a) ? b : a;
293 }
294 }
295 }
296
297 template<class T_a, class T_b> inline static T_a Max(const T_a a, const T_b b) {
298 #if __GNUC__
299 return b >? a;
300 #else
301 return (b > a) ? b : a;
302 #endif
303 }
304
305 inline static float Fmodf(const float &a, const float &b) {
306 switch (IMPL) {
307 #if CONFIG_ASM && ARCH_X86
308 case ASM_X86_MMX_SSE: {
309 float ret;
310 asm (
311 "movss %1, %%xmm0 # load a\n\t"
312 "movss %2, %%xmm1 # load b\n\t"
313 "movss %%xmm0,%%xmm2\n\t"
314 "divss %%xmm1, %%xmm2 # xmm2 = a / b\n\t"
315 "cvttss2si %%xmm2, %%ecx #convert to int\n\t"
316 "cvtsi2ss %%ecx, %%xmm2 #convert back to float\n\t"
317 "mulss %%xmm1, %%xmm2 # xmm2 = b * int(a/b)\n\t"
318 "subss %%xmm2, %%xmm0 #sub a\n\t"
319 "movss %%xmm0, %0 # output\n\t"
320 : "=m" (ret)
321 : "m" (a), "m" (b)
322 : "%ecx"
323 );
324 return ret;
325 }
326 #endif // CONFIG_ASM && ARCH_X86
327 default: {
328 return fmodf(a, b);
329 }
330 }
331 }
332 };
333
334 /// convenience typedef for using the default implementation (which is CPP)
335 typedef __RTMath<> RTMath;
336
337 #endif // __RT_MATH_H__

  ViewVC Help
Powered by ViewVC