]> Repos - portaudio/commitdiff
Use Interpolating sine lookup to eliminate differences in math lib performance
authorphilburk <philburk@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 28 Mar 2002 18:15:43 +0000 (18:15 +0000)
committerphilburk <philburk@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 28 Mar 2002 18:15:43 +0000 (18:15 +0000)
between hosts.

pa_tests/patest_maxsines.c

index 646a77f47f7dd842b45cbc7629781df486d914ae..4a5c26b927abd78bb04b83f3c120b3120e42c3b9 100644 (file)
 #include "portaudio.h"
 
 #define MAX_SINES     (500)
+#define MAX_USAGE     (0.8)
 #define SAMPLE_RATE   (44100)
+#define FREQ_TO_PHASE_INC(freq)   (freq/(float)SAMPLE_RATE)
+
+#define MIN_PHASE_INC  FREQ_TO_PHASE_INC(200.0f)
+#define MAX_PHASE_INC  (MIN_PHASE_INC * (1 << 5))
+
 #define FRAMES_PER_BUFFER  (512)
 #ifndef M_PI
 #define M_PI  (3.14159265)
 #endif
 #define TWOPI (M_PI * 2.0)
 
+#define TABLE_SIZE   (512)
+
 typedef struct paTestData
 {
     int numSines;
+    float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */
     double phases[MAX_SINES];
 }
 paTestData;
 
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+    float fIndex = phase*TABLE_SIZE;
+    int   index = (int) fIndex;
+    float fract = fIndex - index;
+    float lo = data->sine[index];
+    float hi = data->sine[index+1];
+    float val = lo + fract*(hi-lo);
+    return val;
+}
+
 /* This routine will be called by the PortAudio engine when audio is needed.
 ** It may called at interrupt level on some machines so don't do anything
 ** that could mess up the system like calling malloc() or free().
@@ -65,33 +89,39 @@ static int patestCallback(   void *inputBuffer, void *outputBuffer,
     paTestData *data = (paTestData*)userData;
     float *out = (float*)outputBuffer;
     float outSample;
+    float scaler;
+    int numForScale;
     unsigned long i;
     int j;
     int finished = 0;
     (void) outTime; /* Prevent unused variable warnings. */
     (void) inputBuffer;
 
+/* Detemine amplitude scaling factor */
+    numForScale = data->numSines;
+    if( numForScale < 8 ) numForScale = 8;  /* prevent pops at beginning */
+    scaler = 1.0f / numForScale;
+    
     for( i=0; i<framesPerBuffer; i++ )
     {
         float output = 0.0;
-        double phaseInc = 0.02;
+        double phaseInc = MIN_PHASE_INC;
         double phase;
         for( j=0; j<data->numSines; j++ )
         {
             /* Advance phase of next oscillator. */
             phase = data->phases[j];
             phase += phaseInc;
-            if( phase > TWOPI ) phase -= TWOPI;
+            if( phase >= 1.0 ) phase -= 1.0;
 
-            phaseInc *= 1.02;
-            if( phaseInc > 0.5 ) phaseInc *= 0.5;
-
-            /* This is not a very efficient way to calc sines. */
-            output += (float) sin( phase );
+            output += LookupSine(data, phase); 
             data->phases[j] = phase;
+            
+            phaseInc *= 1.02;
+            if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC;
         }
 
-        outSample = (float) (output / data->numSines);
+        outSample = (float) (output * scaler);
         *out++ = outSample; /* Left */
         *out++ = outSample; /* Right */
     }
@@ -102,12 +132,19 @@ static int patestCallback(   void *inputBuffer, void *outputBuffer,
 int main(void);
 int main(void)
 {
+       int i;
     PortAudioStream *stream;
     PaError err;
     paTestData data = {0};
     double load;
     printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
     /* initialise sinusoidal wavetable */
+    for( i=0; i<TABLE_SIZE; i++ )
+    {
+        data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+    }
+    data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point */
 
     err = Pa_Initialize();
     if( err != paNoError ) goto error;
@@ -131,6 +168,7 @@ int main(void)
     err = Pa_StartStream( stream );
     if( err != paNoError ) goto error;
 
+/* Play an increasing number of sine waves until we hit MAX_USAGE */
     do
     {
         data.numSines++;
@@ -140,7 +178,7 @@ int main(void)
         printf("numSines = %d, CPU load = %f\n", data.numSines, load );
         fflush( stdout );
     }
-    while( (load < 0.8) && (data.numSines < MAX_SINES) );
+    while( (load < MAX_USAGE) && (data.numSines < MAX_SINES) );
 
     err = Pa_StopStream( stream );
     if( err != paNoError ) goto error;