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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 717 - (show annotations) (download)
Sun Jul 24 10:26:17 2005 UTC (18 years, 9 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 /*
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 #include "../src/engines/common/LFOTriangleIntMath.h"
15 #include "../src/engines/common/LFOTriangleDiHarmonic.h"
16
17 // 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 // maximum value of the LFO output (also depends on SIGNED above)
45 #ifndef MAX
46 # define MAX 1.0f
47 #endif
48
49 // 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 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 // integer math solution
75 float int_math(sample_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
76 // pro forma
77 pIntLFO->trigger(frequency, start_level_max, 1200 /* max. internal depth */, 0, false, (unsigned int) SAMPLING_RATE);
78
79 clock_t stop_time;
80 clock_t start_time = clock();
81
82 for (int run = 0; run < RUNS; run++) {
83 pIntLFO->update(0); // pro forma
84 for (int i = 0; i < steps; ++i) {
85 pDestinationBuffer[i] = pIntLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load
86 }
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 // pro forma
171 pDiHarmonicLFO->trigger(frequency, start_level_max, 1200 /* max. internal depth */, 0, false, (unsigned int) SAMPLING_RATE);
172
173 clock_t stop_time;
174 clock_t start_time = clock();
175
176 for (int run = 0; run < RUNS; run++) {
177 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 }
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 #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 // 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 if (pIntLFO) delete pIntLFO;
262 if (pDiHarmonicLFO) delete pDiHarmonicLFO;
263
264 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