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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 717 - (hide annotations) (download)
Sun Jul 24 10:26:17 2005 UTC (18 years, 8 months ago) by schoenebeck
File size: 9098 byte(s)
Added "real" implementations of the triangle LFOs. Unfortunately
I introduced some bugs - the output results don't look like they should.
This has to be fixed.

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

  ViewVC Help
Powered by ViewVC