/[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 1862 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2007 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 * 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 /**
79 * 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 * 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 private:
99 static float* pCentsToFreqTable;
100
101 static float* InitCentsToFreqTable();
102 };
103
104 /** @brief Real Time Math
105 *
106 * 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 */
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 #if CONFIG_ASM && ARCH_X86
118 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 #endif // CONFIG_ASM && ARCH_X86
128 default: {
129 return (int) a;
130 }
131 }
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 #if CONFIG_ASM && ARCH_X86
142 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 #endif // CONFIG_ASM && ARCH_X86
153 default: {
154 return (float) a;
155 }
156 }
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 #if CONFIG_ASM && ARCH_X86
169 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 #endif // CONFIG_ASM && ARCH_X86
181 default: {
182 return (a + b);
183 }
184 }
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 #if CONFIG_ASM && ARCH_X86
194 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 #endif // CONFIG_ASM && ARCH_X86
206 default: {
207 return (a - b);
208 }
209 }
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 #if CONFIG_ASM && ARCH_X86
219 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 #endif // CONFIG_ASM && ARCH_X86
231 default: {
232 return (a * b);
233 }
234 }
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 #if CONFIG_ASM && ARCH_X86
244 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 #endif // CONFIG_ASM && ARCH_X86
256 default: {
257 return (a / b);
258 }
259 }
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 #if CONFIG_ASM && ARCH_X86
269 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 #endif // CONFIG_ASM && ARCH_X86
281 default: {
282 return std::min(a, b);
283 }
284 }
285 }
286
287 template<class T_a, class T_b> inline static T_a Min(const T_a a, const T_b b) {
288 return (b < a) ? b : a;
289 }
290
291 inline static float Max(const float a, const float b) {
292 switch (IMPL) {
293 #if CONFIG_ASM && ARCH_X86
294 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 #endif // CONFIG_ASM && ARCH_X86
306 default: {
307 return std::max(a, b);
308 }
309 }
310 }
311
312 template<class T_a, class T_b> inline static T_a Max(const T_a a, const T_b b) {
313 return (b > a) ? b : a;
314 }
315
316 inline static float Fmodf(const float &a, const float &b) {
317 switch (IMPL) {
318 #if CONFIG_ASM && ARCH_X86
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 #endif // CONFIG_ASM && ARCH_X86
338 default: {
339 return fmodf(a, b);
340 }
341 }
342 }
343 };
344
345 /// convenience typedef for using the default implementation (which is CPP)
346 typedef __RTMath<> RTMath;
347
348 #endif // __RT_MATH_H__

  ViewVC Help
Powered by ViewVC