// Note: this function will have half-buffer phase shift effect
void processInput(short *input, short *output, short channel)
{
    int i;

    // Read in the input buffer
    for (i = 0; i < ARRAY_SIZE; i++)
    {
        inputBuffer[channel][ARRAY_SIZE + i] = input[i];
    }

    // Apply windows to the midpoint buffer and input buffer
    applyWindow(inputBuffer[channel] + (ARRAY_SIZE / 2), windowedCrossSampleArray[channel]);
    applyWindow(inputBuffer[channel] + ARRAY_SIZE, windowedInputArray[channel]);

    frequencyScale(windowedCrossSampleArray[channel], frequencyScaledSamples[channel][1], ARRAY_SIZE, frequencyScalars);

    frequencyScale(windowedInputArray[channel], frequencyScaledSamples[channel][2], ARRAY_SIZE, frequencyScalars);

    // Sum overlaps to produce the output array
    for (i = 0; i < ARRAY_SIZE / 2; i++)
    {
        output[i] = frequencyScaledSamples[channel][FSS_PREVIOUS_INPUT][ARRAY_SIZE / 2 + i] + frequencyScaledSamples[channel][FSS_CROSS_INPUT][i];
    }

    for (i = ARRAY_SIZE / 2; i < ARRAY_SIZE; i++)
    {
        // float -> short conversion should be handled automatically
        output[i] = frequencyScaledSamples[channel][FSS_CROSS_INPUT][i] + frequencyScaledSamples[channel][FSS_THIS_INPUT][i - (ARRAY_SIZE / 2)];
    }

    // Store input and scaled version of input for use in next iteration
    for (i = 0; i < ARRAY_SIZE; i++)
    {
        inputBuffer[channel][i] = inputBuffer[channel][i + ARRAY_SIZE];
        frequencyScaledSamples[channel][FSS_PREVIOUS_INPUT][i] = frequencyScaledSamples[channel][FSS_THIS_INPUT][i];
    }

    /*
    for (i = 0; i < ARRAY_SIZE / 2; i++)
    {
        printf("%d, %d\n", input[i], output[i + ARRAY_SIZE / 2]);
    }
    printf("\n\n");
    */
    
}
Example #2
0
void RealtimeAnalyser::doFFTAnalysis() {
  DCHECK(isMainThread());

  // Unroll the input buffer into a temporary buffer, where we'll apply an
  // analysis window followed by an FFT.
  size_t fftSize = this->fftSize();

  AudioFloatArray temporaryBuffer(fftSize);
  float* inputBuffer = m_inputBuffer.data();
  float* tempP = temporaryBuffer.data();

  // Take the previous fftSize values from the input buffer and copy into the
  // temporary buffer.
  unsigned writeIndex = m_writeIndex;
  if (writeIndex < fftSize) {
    memcpy(tempP, inputBuffer + writeIndex - fftSize + InputBufferSize,
           sizeof(*tempP) * (fftSize - writeIndex));
    memcpy(tempP + fftSize - writeIndex, inputBuffer,
           sizeof(*tempP) * writeIndex);
  } else {
    memcpy(tempP, inputBuffer + writeIndex - fftSize, sizeof(*tempP) * fftSize);
  }

  // Window the input samples.
  applyWindow(tempP, fftSize);

  // Do the analysis.
  m_analysisFrame->doFFT(tempP);

  float* realP = m_analysisFrame->realData();
  float* imagP = m_analysisFrame->imagData();

  // Blow away the packed nyquist component.
  imagP[0] = 0;

  // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT
  // scaling factor).
  const double magnitudeScale = 1.0 / fftSize;

  // A value of 0 does no averaging with the previous result.  Larger values
  // produce slower, but smoother changes.
  double k = m_smoothingTimeConstant;
  k = std::max(0.0, k);
  k = std::min(1.0, k);

  // Convert the analysis data from complex to magnitude and average with the
  // previous result.
  float* destination = magnitudeBuffer().data();
  size_t n = magnitudeBuffer().size();
  for (size_t i = 0; i < n; ++i) {
    std::complex<double> c(realP[i], imagP[i]);
    double scalarMagnitude = abs(c) * magnitudeScale;
    destination[i] = float(k * destination[i] + (1 - k) * scalarMagnitude);
  }
}
Example #3
0
void RealtimeAnalyser::doFFTAnalysis()
{    
    ASSERT(isMainThread());

    // Unroll the input buffer into a temporary buffer, where we'll apply an analysis window followed by an FFT.
    size_t fftSize = this->fftSize();
    
    AudioFloatArray temporaryBuffer(fftSize);
    float* inputBuffer = m_inputBuffer.data();
    float* tempP = temporaryBuffer.data();

    // Take the previous fftSize values from the input buffer and copy into the temporary buffer.
    // FIXME : optimize with memcpy().
    unsigned writeIndex = m_writeIndex;
    for (unsigned i = 0; i < fftSize; ++i)
        tempP[i] = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize];
    
    // Window the input samples.
    applyWindow(tempP, fftSize);
    
    // Do the analysis.
    m_analysisFrame->doFFT(tempP);

    size_t n = DefaultFFTSize / 2;

    float* realP = m_analysisFrame->realData();
    float* imagP = m_analysisFrame->imagData();

    // Blow away the packed nyquist component.
    imagP[0] = 0.0f;
    
    // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor).
    const double MagnitudeScale = 1.0 / DefaultFFTSize;

    // A value of 0 does no averaging with the previous result.  Larger values produce slower, but smoother changes.
    double k = m_smoothingTimeConstant;
    k = max(0.0, k);
    k = min(1.0, k);    
    
    // Convert the analysis data from complex to magnitude and average with the previous result.
    float* destination = magnitudeBuffer().data();
    for (unsigned i = 0; i < n; ++i) {
        Complex c(realP[i], imagP[i]);
        double scalarMagnitude = abs(c) * MagnitudeScale;        
        destination[i] = float(k * destination[i] + (1.0 - k) * scalarMagnitude);
    }
}
Example #4
0
File: main.c Project: jake-g/tuner
/* -- main function -- */
int main( int argc, char **argv ) {
    PaStreamParameters inputParameters;
    float a[2], b[3], mem1[4], mem2[4];
    float data[FFT_SIZE];
    float datai[FFT_SIZE];
    float window[FFT_SIZE];
    float freqTable[FFT_SIZE];
    char * noteNameTable[FFT_SIZE];
    float notePitchTable[FFT_SIZE];
    void * fft = NULL;
    PaStream *stream = NULL;
    PaError err = 0;
    struct sigaction action;

    // add signal listen so we know when to exit:
    action.sa_handler = signalHandler;
    sigemptyset (&action.sa_mask);
    action.sa_flags = 0;

    sigaction (SIGINT, &action, NULL);
    sigaction (SIGHUP, &action, NULL);
    sigaction (SIGTERM, &action, NULL);

    // build the window, fft, etc
    /*
       buildHanWindow( window, 30 );
       for( int i=0; i<30; ++i ) {
          for( int j=0; j<window[i]*50; ++j )
             printf( "*" );
          printf("\n");
       }
       exit(0);
    */
    buildHanWindow( window, FFT_SIZE );
    fft = initfft( FFT_EXP_SIZE );
    computeSecondOrderLowPassParameters( SAMPLE_RATE, 330, a, b );
    mem1[0] = 0;
    mem1[1] = 0;
    mem1[2] = 0;
    mem1[3] = 0;
    mem2[0] = 0;
    mem2[1] = 0;
    mem2[2] = 0;
    mem2[3] = 0;
    //freq/note tables
    for( int i=0; i<FFT_SIZE; ++i ) {
        freqTable[i] = ( SAMPLE_RATE * i ) / (float) ( FFT_SIZE );
    }
    for( int i=0; i<FFT_SIZE; ++i ) {
        noteNameTable[i] = NULL;
        notePitchTable[i] = -1;
    }
    for( int i=0; i<127; ++i ) {
        float pitch = ( 440.0 / 32.0 ) * pow( 2, (i-9.0)/12.0 ) ;
        if( pitch > SAMPLE_RATE / 2.0 )
            break;
        //find the closest frequency using brute force.
        float min = 1000000000.0;
        int index = -1;
        for( int j=0; j<FFT_SIZE; ++j ) {
            if( fabsf( freqTable[j]-pitch ) < min ) {
                min = fabsf( freqTable[j]-pitch );
                index = j;
            }
        }
        noteNameTable[index] = NOTES[i%12];
        notePitchTable[index] = pitch;
        //printf( "%f %d %s\n", pitch, index, noteNameTable[index] );
    }



    // initialize portaudio
    err = Pa_Initialize();
    if( err != paNoError ) goto error;

    inputParameters.device = Pa_GetDefaultInputDevice();
    inputParameters.channelCount = 1;
    inputParameters.sampleFormat = paFloat32;
    inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
    inputParameters.hostApiSpecificStreamInfo = NULL;

    printf( "Opening %s\n",
            Pa_GetDeviceInfo( inputParameters.device )->name );

    err = Pa_OpenStream( &stream,
                         &inputParameters,
                         NULL, //no output
                         SAMPLE_RATE,
                         FFT_SIZE,
                         paClipOff,
                         NULL,
                         NULL );
    if( err != paNoError ) goto error;

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

    // this is the main loop where we listen to and
    // process audio.
    while( running )
    {
        // read some data
        err = Pa_ReadStream( stream, data, FFT_SIZE );
        if( err ) goto error; //FIXME: we don't want to err on xrun

        // low-pass
        //for( int i=0; i<FFT_SIZE; ++i )
        //   printf( "in %f\n", data[i] );
        for( int j=0; j<FFT_SIZE; ++j ) {
            data[j] = processSecondOrderFilter( data[j], mem1, a, b );
            data[j] = processSecondOrderFilter( data[j], mem2, a, b );
        }
        // window
        applyWindow( window, data, FFT_SIZE );

        // do the fft
        for( int j=0; j<FFT_SIZE; ++j )
            datai[j] = 0;
        applyfft( fft, data, datai, false );

        //find the peak
        float maxVal = -1;
        int maxIndex = -1;
        for( int j=0; j<FFT_SIZE/2; ++j ) {
            float v = data[j] * data[j] + datai[j] * datai[j] ;
            /*
                     printf( "%d: ", j*SAMPLE_RATE/(2*FFT_SIZE) );
                     for( int i=0; i<sqrt(v)*100000000; ++i )
                        printf( "*" );
                     printf( "\n" );
            */
            if( v > maxVal ) {
                maxVal = v;
                maxIndex = j;
            }
        }
        float freq = freqTable[maxIndex];
        //find the nearest note:
        int nearestNoteDelta=0;
        while( true ) {
            if( nearestNoteDelta < maxIndex && noteNameTable[maxIndex-nearestNoteDelta] != NULL ) {
                nearestNoteDelta = -nearestNoteDelta;
                break;
            } else if( nearestNoteDelta + maxIndex < FFT_SIZE && noteNameTable[maxIndex+nearestNoteDelta] != NULL ) {
                break;
            }
            ++nearestNoteDelta;
        }
        char * nearestNoteName = noteNameTable[maxIndex+nearestNoteDelta];
        float nearestNotePitch = notePitchTable[maxIndex+nearestNoteDelta];
        float centsSharp = 1200 * log( freq / nearestNotePitch ) / log( 2.0 );

        // now output the results:
        printf("\033[2J\033[1;1H"); //clear screen, go to top left
        fflush(stdout);

        printf( "Tuner listening. Control-C to exit.\n" );
        printf( "%f Hz, %d : %f\n", freq, maxIndex, maxVal*1000 );
        printf( "Nearest Note: %s\n", nearestNoteName );
        if( nearestNoteDelta != 0 ) {
            if( centsSharp > 0 )
                printf( "%f cents sharp.\n", centsSharp );
            if( centsSharp < 0 )
                printf( "%f cents flat.\n", -centsSharp );
        } else {
            printf( "in tune!\n" );
        }
        printf( "\n" );
        int chars = 30;
        if( nearestNoteDelta == 0 || centsSharp >= 0 ) {
            for( int i=0; i<chars; ++i )
                printf( " " );
        } else {
            for( int i=0; i<chars+centsSharp; ++i )
                printf( " " );
            for( int i=chars+centsSharp<0?0:chars+centsSharp; i<chars; ++i )
                printf( "=" );
        }
        printf( " %2s ", nearestNoteName );
        if( nearestNoteDelta != 0 )
            for( int i=0; i<chars && i<centsSharp; ++i )
                printf( "=" );
        printf("\n");
    }
    err = Pa_StopStream( stream );
    if( err != paNoError ) goto error;

    // cleanup
    destroyfft( fft );
    Pa_Terminate();

    return 0;
error:
    if( stream ) {
        Pa_AbortStream( stream );
        Pa_CloseStream( stream );
    }
    destroyfft( fft );
    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 1;
}