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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 714 - (hide annotations) (download)
Sat Jul 23 21:55:38 2005 UTC (18 years, 9 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 schoenebeck 714 /*
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