/[svn]/linuxsampler/trunk/benchmarks/triang.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/benchmarks/triang.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 714 - (show annotations) (download)
Sat Jul 23 21:55:38 2005 UTC (18 years, 8 months ago) by schoenebeck
File size: 9470 byte(s)
added benchmark to automatically detect the best triangle LFO
implementation (currently either an integer math solution or a
di-harmonic approximation), automatic detection can be overriden
with --enable-signed-triang-algo=x and --enable-unsigned-triang-algo=x
configure script argument though (mandatory for cross-compilation)
---
actual implementations of the new LFO solutions in LS will follow soon

1 /*
2 Triangle wave generator benchmark
3
4 This is a benchmark for comparison between a integer math, table lookup
5 and numeric sine wave harmonics solution.
6
7 Copyright (C) 2005 Christian Schoenebeck <cuse@users.sf.net>
8 */
9
10 #include <math.h>
11 #include <time.h>
12 #include <stdio.h>
13
14 // whether we should not show any messages on the console
15 #ifndef SILENT
16 # define SILENT 0
17 #endif
18
19 // set to 1 if you want to output the three calculated waves as RAW files
20 // you can e.g. open it as RAW file in Rezound
21 // (32 bit SP-FP PCM, mono, little endian, 44100kHz)
22 #ifndef OUTPUT_AS_RAW_WAVE
23 # define OUTPUT_AS_RAW_WAVE 0
24 #endif
25
26 // how many sample points should we calculate in one sequence
27 #ifndef STEPS
28 # define STEPS 16384
29 #endif
30
31 // how often should we repeat the benchmark loop of each solution
32 #ifndef RUNS
33 # define RUNS 1000
34 #endif
35
36 // whether the wave should have positive and negative range (signed -> 1) or just positive (unsigned -> 0)
37 #ifndef SIGNED
38 # define SIGNED 1
39 #endif
40
41 // pro forma
42 #ifndef SAMPLING_RATE
43 # define SAMPLING_RATE 44100.0f
44 #endif
45
46 // return value of this benchmark
47 // to indicate the best performing solution
48 #define INT_MATH_SOLUTION 2 /* we don't start with 1, as this is reserved for unknown errors */
49 #define DI_HARMONIC_SOLUTION 3
50 #define TABLE_LOOKUP_SOLUTION 4 /* table lookup solution is currently disabled in this benchmark, see below */
51 #define INVALID_RESULT -1
52
53 // we use 32 bit single precision floating point as sample point format
54 typedef float sample_t;
55
56 // integer math solution
57 float int_math(sample_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
58 // pro forma
59 const float r = frequency / SAMPLING_RATE; // frequency alteration quotient
60 unsigned int maxvalue = (unsigned int) -1; // all 0xFFFF...
61 #if SIGNED
62 const float normalizer = 1.0f / ((float) maxvalue / 4.0f);
63 #else // unsigned
64 const float normalizer = 1.0f / ((float) maxvalue / 2.0f);
65 #endif
66 const int c = (int) (maxvalue * r);
67 const int signshifts = (sizeof(int) * 8) - 1;
68
69 int iSign;
70
71 clock_t stop_time;
72 clock_t start_time = clock();
73
74 for (int run = 0; run < RUNS; run++) {
75 int iLevel = 0;
76 for (int i = 0; i < steps; ++i) {
77 iLevel += c;
78 iSign = (iLevel >> signshifts) | 1;
79 #if SIGNED
80 pDestinationBuffer[i] = (normalizer * (float) (iSign * iLevel) - 1.0f) * pAmp[i]; // * pAmp[i] just to simulate some memory load
81 #else // unsigned
82 pDestinationBuffer[i] = normalizer * (float) (iSign * iLevel) * pAmp[i]; // * pAmp[i] just to simulate some memory load
83 #endif
84 }
85 }
86
87 stop_time = clock();
88 float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
89 #if ! SILENT
90 printf("int math solution elapsed time: %1.0f ms\n", elapsed_time);
91 #endif
92
93 return elapsed_time;
94 }
95
96 // table lookup solution (currently disabled)
97 //
98 // This solution is not yet implemented in LinuxSampler yet and probably
99 // never will, I simply haven't found an architectures / system where this
100 // turned out to be the best solution and it introduces too many problems
101 // anyway. If you found an architecture where this seems to be the best
102 // solution, please let us know!
103 #if 0
104 float table_lookup(sample_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
105 // pro forma
106 const float r = frequency / SAMPLING_RATE; // frequency alteration quotient
107 #if SIGNED
108 float c = r * 4.0f;
109 #else
110 float c = r * 2.0f;
111 #endif
112 const int wl = (int) (SAMPLING_RATE / frequency); // wave length (in sample points)
113
114 // 'volatile' to avoid the cache to fudge the benchmark result
115 volatile float* pPrerenderingBuffer = new float[wl];
116
117 // prerendering of the triangular wave
118 {
119 float level = 0.0f;
120 for (int i = 0; i < wl; ++i) {
121 level += c;
122 #if SIGNED
123 if (level >= 1.0f) {
124 c = -c;
125 level = 1.0f;
126 }
127 else if (level <= -1.0f) {
128 c = -c;
129 level = -1.0f;
130 }
131 #else
132 if (level >= 1.0f) {
133 c = -c;
134 level = 1.0f;
135 }
136 else if (level <= 0.0f) {
137 c = -c;
138 level = 0.0f;
139 }
140 #endif
141 pPrerenderingBuffer[i] = level;
142 }
143 }
144
145 clock_t stop_time;
146 clock_t start_time = clock();
147
148 for (int run = 0; run < RUNS; run++) {
149 for (int i = 0; i < steps; ++i) {
150 pDestinationBuffer[i] = pPrerenderingBuffer[i % wl] * pAmp[i]; // * pAmp[i] just to simulate some memory load
151 }
152 }
153
154 stop_time = clock();
155 float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
156 #if ! SILENT
157 printf("Table lookup solution elapsed time: %1.0f ms\n", elapsed_time);
158 #endif
159
160 if (pPrerenderingBuffer) delete[] pPrerenderingBuffer;
161
162 return elapsed_time;
163 }
164 #endif
165
166 // numeric, di-harmonic solution
167 float numeric_di_harmonic_solution(sample_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
168 // we approximate the triangular wave by adding 2 harmonics
169 const float c1 = 2.0f * M_PI * frequency / SAMPLING_RATE;
170 const float phi1 = 0.0f; // phase displacement
171 const float c2 = 2.0f * M_PI * frequency / SAMPLING_RATE * 3.0f;
172 const float phi2 = 0.0f; // phase displacement
173
174 // amplitue for the 2nd harmonic (to approximate the triangular wave)
175 const float amp2 = 0.1f;
176
177 // initial values for real and imaginary part
178 float real1 = cos(phi1);
179 float imag1 = sin(phi1);
180 float real2 = cos(phi2);
181 float imag2 = sin(phi2);
182
183 clock_t stop_time;
184 clock_t start_time = clock();
185
186 for (int run = 0; run < RUNS; run++) {
187 for (int i = 0; i < steps; i++) {
188 #if SIGNED
189 pDestinationBuffer[i] = (real1 + real2 * amp2) * pAmp[i]; // * pAmp[i] just to simulate some memory load
190 #else // unsigned
191 pDestinationBuffer[i] = ((real1 + real2 * amp2) * 0.5f + 0.5f) * pAmp[i]; // * pAmp[i] just to simulate some memory load
192 #endif
193 real1 -= c1 * imag1;
194 imag1 += c1 * real1;
195 real2 -= c2 * imag2;
196 imag2 += c2 * real2;
197 }
198 }
199
200 stop_time = clock();
201 float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
202 #if ! SILENT
203 printf("Numeric harmonics solution elapsed time: %1.0f ms\n", elapsed_time);
204 #endif
205
206 return elapsed_time;
207 }
208
209 // output calculated values as RAW audio format (32 bit floating point, mono) file
210 void output_as_raw_file(const char* filename, sample_t* pOutputBuffer, int steps) {
211 FILE* file = fopen(filename, "w");
212 if (file) {
213 fwrite((void*) pOutputBuffer, sizeof(float), steps, file);
214 fclose(file);
215 } else {
216 fprintf(stderr, "Could not open %s\n", filename);
217 }
218 }
219
220 int main() {
221 const int steps = STEPS;
222 const int sinusoidFrequency = 100; // Hz
223
224 #if ! SILENT
225 # if SIGNED
226 printf("Signed triangular wave benchmark\n");
227 printf("--------------------------------\n");
228 # else
229 printf("Unsigned triangular wave benchmark\n");
230 printf("----------------------------------\n");
231 # endif
232 #endif
233
234 // output buffer for the calculated sinusoid wave
235 sample_t* pOutputBuffer = new sample_t[steps];
236 // just an arbitrary amplitude envelope to simulate a bit higher memory bandwidth
237 float* pAmplitude = new float[steps];
238
239 // pro forma - an arbitary amplitude envelope
240 for (int i = 0; i < steps; ++i)
241 pAmplitude[i] = (float) i / (float) steps;
242
243 // how long each solution took (in seconds)
244 float int_math_result, /*table_lookup_result,*/ numeric_di_harmonic_result;
245
246 int_math_result = int_math(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
247 #if OUTPUT_AS_RAW_WAVE
248 output_as_raw_file("bench_int_math.raw", pOutputBuffer, steps);
249 #endif
250 //table_lookup_result = table_lookup(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
251 //#if OUTPUT_AS_RAW_WAVE
252 // output_as_raw_file("bench_table_lookup.raw", pOutputBuffer, steps);
253 //#endif
254 numeric_di_harmonic_result = numeric_di_harmonic_solution(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
255 #if OUTPUT_AS_RAW_WAVE
256 output_as_raw_file("bench_numeric_harmonics.raw", pOutputBuffer, steps);
257 #endif
258
259 #if ! SILENT
260 printf("\nOK, 2nd try\n\n");
261 #endif
262
263 int_math_result += int_math(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
264 //table_lookup_result += table_lookup(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
265 numeric_di_harmonic_result += numeric_di_harmonic_solution(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
266
267 if (pAmplitude) delete[] pAmplitude;
268 if (pOutputBuffer) delete[] pOutputBuffer;
269
270 if (/*int_math_result <= table_lookup_result &&*/ int_math_result <= numeric_di_harmonic_result) return INT_MATH_SOLUTION;
271 if (/*numeric_di_harmonic_result <= table_lookup_result &&*/ numeric_di_harmonic_result <= int_math_result) return DI_HARMONIC_SOLUTION;
272 //if (table_lookup_result <= int_math_result && table_lookup_result <= numeric_di_harmonic_result) return TABLE_LOOKUP_SOLUTION;
273
274 return INVALID_RESULT; // error
275 }

  ViewVC Help
Powered by ViewVC