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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 723 - (hide annotations) (download)
Sun Jul 24 20:01:39 2005 UTC (18 years, 8 months ago) by schoenebeck
File size: 10632 byte(s)
oops, don't bother the user with RAW files ;)

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

  ViewVC Help
Powered by ViewVC