2016-06-16 13 views
0

Ich arbeite an einer Sound-Anwendung mit PortAudio. Ich habe ein Array von Strukturen, die die Daten für einzelne Oszillatoren darstellen, die in die Haupt-Callback-Funktion übergeben werden.Summierung von Wellen in PortAudio Callback

Wenn ich versuche, zwei Wellen in einer einzigen Linie zu summieren und es zu spielen, funktioniert es, aber wenn ich es mit einer for-Schleife versuche, kann ich Oszillatoren willkürlich summieren, tut es nicht.

So funktioniert das:

*out = sinetable[(int)oscs[0].phase % TABLE_SIZE] * (oscs[0].amp/2) + sinetable[(int)oscs[1].phase % TABLE_SIZE] * (oscs[1].amp/2);

aber nicht:

for(int j = 0; j < 2; j++) 
    {  
    *out += sinetable[(int)oscs[j].phase % TABLE_SIZE] * (oscs[j].amp/2);      
    } 

Ich brauche nur einen Weg, um eine beliebige Anzahl von Oszillatoren zu summieren. Ich dachte, diese beiden Methoden wären gleichwertig, aber anscheinend nicht.

Jede Hilfe wird sehr geschätzt.

Edit: Der vollständige Code ist hier:

  #include <stdio.h> 
     #include <math.h> 
     #include "portaudio.h" 

     #define NUM_SECONDS (2) 
     #define SAMPLE_RATE (44100) 
     #define FRAMES_PER_BUFFER (0) // PA will select in it's own.. 

     #ifndef M_PI 
     #define M_PI (3.14159265) 
     #endif 

     #define TABLE_SIZE (4096) // < Hz/(sampling rate/table size) [line 53]] 
     float sinetable[TABLE_SIZE]; 

     typedef struct 
     { 
      float phase = 0; 
      float freq = 300; 
      float amp = 0.5; 
     } 
     Osc; 

     void initTable(){ 
      for(int i = 0; i < TABLE_SIZE; i++){ 

       sinetable[i] = sin(2 * M_PI * i/TABLE_SIZE); 
      } 
     } 

     /* 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(). 
     */ 
     static int patestCallback(const void *inputBuffer, void *outputBuffer, 
            unsigned long framesPerBuffer, 
            const PaStreamCallbackTimeInfo* timeInfo, 
            PaStreamCallbackFlags statusFlags, 
            void *userData) 
     { 
      Osc *oscs = (Osc*)userData; 
      float *out = (float*)outputBuffer; 
      unsigned long i; 

      (void) timeInfo; /* Prevent unused variable warnings. */ 
      (void) statusFlags; 
      (void) inputBuffer; 


      for(i=0; i<framesPerBuffer; i++) 
      { 

       /* 
       for(int j = 0; j < 2; j++){  //this won't work... 
       *out += sinetable[(int)oscs[j].phase % TABLE_SIZE] * (oscs[j].amp/2);      
       } 
       */ 
       // but this does: 
       *out = sinetable[(int)oscs[0].phase % TABLE_SIZE] * (oscs[0].amp/2) + sinetable[(int)oscs[1].phase % TABLE_SIZE] * (oscs[1].amp/2);   

       oscs[0].phase += oscs[0].freq/(SAMPLE_RATE/(float)TABLE_SIZE);   
       oscs[1].phase += oscs[1].freq/(SAMPLE_RATE/(float)TABLE_SIZE); 

       *out++; 
      } 

      return paContinue; 
     } 



     /* 
      * This routine is called by portaudio when playback is done. 
      */ 
     static void StreamFinished(void* userData) 
     { 
      Osc *oscs = (Osc *) userData; 
      // printf("Stream Completed: %s\n", oscs->message); 
     } 

     /*******************************************************************/ 
     int main(void); 
     int main(void) 
     { 
      PaStreamParameters outputParameters; 
      PaStream *stream; 
      PaError err; 
      Osc oscs[5]; 
      int i; 
      oscs[1].freq = 400; oscs[2].freq = 500; oscs[3].freq = 600; oscs[4].freq = 700; 

      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++) 
      { 
       sinetable[i] = 2* M_PI * (i/TABLE_SIZE); //using this global table   
      } 
      // oscs.phase = 0; 

      initTable(); 

      err = Pa_Initialize(); 
      if(err != paNoError) goto error; 

      outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 
      if (outputParameters.device == paNoDevice) { 
       fprintf(stderr,"Error: No default output device.\n"); 
       goto error; 
      } 
      outputParameters.channelCount = 1;  /* mono output */ 
      outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ 
      outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; 
      outputParameters.hostApiSpecificStreamInfo = NULL; 

      err = Pa_OpenStream(
         &stream, 
         NULL, /* no input */ 
         &outputParameters, 
         SAMPLE_RATE, 
         FRAMES_PER_BUFFER, 
         paClipOff,  /* we won't output out of range samples so don't bother clipping them */ 
         patestCallback, 
         &oscs); 
      if(err != paNoError) goto error; 

      // sprintf(oscs.message, "No Message"); 
      err = Pa_SetStreamFinishedCallback(stream, &StreamFinished); 
      if(err != paNoError) goto error; 

      err = Pa_StartStream(stream); 
      if(err != paNoError) goto error; 

      printf("Play for %d seconds.\n", NUM_SECONDS); 
      Pa_Sleep(NUM_SECONDS * 1000); 

      err = Pa_StopStream(stream); 
      if(err != paNoError) goto error; 

      err = Pa_CloseStream(stream); 
      if(err != paNoError) goto error; 

      Pa_Terminate(); 
      printf("Test finished.\n"); 

      return err; 
     error: 
      Pa_Terminate(); 
      fprintf(stderr, "An error occured while using the portaudio stream\n"); 
      fprintf(stderr, "Error number: %d\n", err); 
      fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err)); 
      return err; 
     } 

Antwort

2

Darf ich *out empfehlen Nullstellung vor Summieren?

*out = 0; 
for(int j = 0; j < 2; j++) 
{  
    *out += sinetable[(int)oscs[j].phase % TABLE_SIZE] * (oscs[j].amp/2);      
} 

Ansonsten, was war bei out wird dem += in der Summe durch aufzuwickeln.

*out = sinetable[(int)oscs[0].phase % TABLE_SIZE] * (oscs[0].amp/2) + 
     sinetable[(int)oscs[1].phase % TABLE_SIZE] * (oscs[1].amp/2); 

um diese bekommt, weil = überschreibt, was bei out war.

+0

Oh, ja, das funktioniert. Natürlich scheint es jetzt offensichtlich. :) – oraz