0

I seem to have pretty weird error with my callback function that I am trying to parse to my function that calls it..

record.h

#pragma once
#include <iostream>
#include "portaudio.h"
#include <algorithm>
#define SAMPLE_RATE (44100)

typedef double SAMPLE;
#define NUM_SECONDS 30

#define NUM_CHANNELS  2
#define SAMPLE_SILENCE 0.0f
#define PA_SAMPLE_TYPE  paFloat32
#define FRAMES_PER_BUFFER (512)


typedef struct
{
    int     frameIndex;
    int     maxFrameindex;
    SAMPLE  *recordedSamples;
}
paTestData;

class record {
public:
    record();
    void start_record();
    int recordCallback(const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer,
                       const PaStreamCallbackTimeInfo* timeInfo,
                       PaStreamCallbackFlags statusFlags, void *userData);
private:
    PaStreamParameters  inputParameters,
                        outputParameters;
    PaStream*           stream;
    PaError             err = paNoError;
    paTestData          data;
    int                 totalFrames;
    int                 numSamples;
    int                 numBytes;
    SAMPLE              max, val;
    double              average;
};

record.cpp

#include "record.h"


record::record()
{
    std::cout << "Record object made" << std::endl;
    std::cout << Pa_GetVersion() << std::endl;
    this->data.maxFrameindex = this->totalFrames = NUM_SECONDS * SAMPLE_RATE;
    this->data.frameIndex = 0;
    this->numSamples = this->totalFrames * NUM_CHANNELS;
    numBytes = numSamples * sizeof(SAMPLE);
    data.recordedSamples = (SAMPLE *) malloc( numBytes ); /* From now on, recordedSamples is initialised. */
    if( data.recordedSamples == NULL )
    {
        std::cout << "Could not allocate record array" << std::endl;
        exit(1);
    }

    std::fill_n(this->data.recordedSamples,numSamples,0);
    int err = Pa_Initialize();

    if( err != paNoError )
    {
        std::cout << "Error" << std::endl;
        printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
    }
    else
    {
       printf(  "PortAudio init: %s\n", Pa_GetErrorText( err ) );
    }

    this->inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */


    if (this->inputParameters.device == paNoDevice) {
        std::cout << "Error: No default input device" << std::endl;
        exit(1);
    }

    this->inputParameters.channelCount = 2;                    /* stereo input */
    this->inputParameters.sampleFormat = PA_SAMPLE_TYPE;
    this->inputParameters.suggestedLatency = Pa_GetDeviceInfo( this->inputParameters.device )->defaultLowInputLatency;
    this->inputParameters.hostApiSpecificStreamInfo = NULL;

}

int record::recordCallback(const void *inputBuffer, void *outputBuffer,
                           unsigned long framesPerBuffer,
                           const PaStreamCallbackTimeInfo* timeInfo,
                           PaStreamCallbackFlags statusFlags, void *userData)
{
    this->data = (paTestData&) userData;
    const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
    SAMPLE *wptr = &this->data.recordedSamples[this->data.frameIndex * NUM_CHANNELS];
    long framesToCalc;
    long i;
    int finished;
    unsigned long framesLeft = this->data.maxFrameindex - this->data.frameIndex;

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

    if( framesLeft < framesPerBuffer )
    {
        framesToCalc = framesLeft;
        finished = paComplete;
    }
    else
    {
        framesToCalc = framesPerBuffer;
        finished = paContinue;
    }

    if( inputBuffer == NULL )
    {
        for(int i=0; i<framesToCalc; i++ )
        {
            *wptr++ = SAMPLE_SILENCE;  /* left */
            if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE;  /* right */
        }
    }
    else
    {
        for(int i=0; i<framesToCalc; i++ )
        {
            *wptr++ = *rptr++;  /* left */
            if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++;  /* right */
        }
    }
    this->data.frameIndex += framesToCalc;
    return finished;
}

void record::start_record()
{

    err = Pa_OpenStream(
              &this->stream,
              &this->inputParameters,
              NULL,                  /* &outputParameters, */
              SAMPLE_RATE,
              FRAMES_PER_BUFFER,
              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
              recordCallback,
              &data );
    if( err != paNoError )
    {
        std::cout << "Something wrong  - open_stream check" << std::endl;
        exit(1);
    }

    if( this->stream )
    {
        this->err = Pa_StartStream( this->stream );
        if( err != paNoError )
        {
            std::cout << "Something wrong in stream check" << std::endl;
            exit(1);
        }

        std::cout << "Waiting for playback to finish" << std::endl;

        while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
        {
            Pa_Sleep(100);
        }
        if( err < 0 )
        {
            std::cout << "error check with isStreamActive - something wrong" << std::endl;
            exit(1);
        }

        err = Pa_CloseStream( stream );
        if( err != paNoError )
        {
            std::cout << "error check with close_stream- something wrong" << std::endl;
            exit(1);
        }


        std::cout << "Everythin done!" << std::endl;
    }


}

error:

record/record.cpp:107:21: error: cannot convert ‘record::recordCallback’ from type ‘int (record::)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*) {aka int (record::)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, long unsigned int, void*)}’ to type ‘int (*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*) {aka int (*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, long unsigned int, void*)}’
               &data );
                     ^
make[2]: *** [src/include/record/CMakeFiles/record.dir/record.cpp.o] Error 1
make[1]: *** [src/include/record/CMakeFiles/record.dir/all] Error 2
make: *** [all] Error 2

It program written here is a bit of a copy of this github code post, where I tried to format it a bit c++ style. the problem seem to be with the start_recording() function, in which I parse the callback function RecordCallback() to the function Pa_OpenStream().. For some reason is it seen that as a type conversion, but even the error message states that both versions are identical, which make me question... why does it think it is a type conversion, and how do fix it?

Lamda
  • 914
  • 3
  • 13
  • 39
  • A non-`static` member function pointer is not a non-member function pointer. You are trying to use a non-`static` member function when a pointer to a non-member function is expected. Please remember that there is an implicit `this` in a non-`static` member function. – R Sahu Nov 01 '17 at 21:43
  • so parsing `this->callback()` work? – Lamda Nov 01 '17 at 21:52
  • 1
    You can make the function call `this->callback()`, but you can't pass `this->callback` as a function pointer where a non-member function pointer is expected. – R Sahu Nov 01 '17 at 21:55
  • Ahh.. that makes sense. So I guess I have to define my callback outside the class, as the library (portaudio) seem to have this limitation.. no way to get around it? – Lamda Nov 01 '17 at 22:02
  • 1
    You can pass `this` as the user data pointer to the callback, then in the callback recover the `this` pointer from it and use that to call the callback within the class. – 1201ProgramAlarm Nov 01 '17 at 22:04
  • @1201ProgramAlarm not sure I understand.. If the callback is defined outside the class scope, how do I then have access to the class variable using `this` ? – Lamda Nov 01 '17 at 22:07
  • Something like `record *pThis = (record *) userData; pThis->realCallback(parameters);` – 1201ProgramAlarm Nov 01 '17 at 22:09
  • Not sure I understand.. you make an instance of the class, and then define the callback function, within the instance/class.. was is not basically that which caused this error in the first place? – Lamda Nov 01 '17 at 22:15
  • I guess my problem now is, since my callback function is defined within the class, it alters the member variables of its instance. but since I need to define my callback function outside the class scope, I don't have access to the member variable of the instance, forcing me to make all the variables global.. Not wanted.. Any suggestions?@1201ProgramAlarm – Lamda Nov 01 '17 at 22:20

0 Answers0