2017-11-04 13 views
2

私は現在記録しているアプリケーションでportaudioを使っていますが、サンプルを収集する際に問題があるようです。私が見ることができるのは、格納されているサンプルが1つだけであり、変数NUM_OF_SECONDSが30秒に設定されていても、コールバックは1回だけ呼び出されていることです。portaudioは1つのサンプルしか取っていませんか?

私は現在何がテストできるのか、どのようにこれをデバッグできるのかというアイデアが不足しているので、私はここで問題をデバッグする方法を提案していますか?

main.cppに:

#include <record.h> 

int main() 
{ 
    record somethis; 
    somethis.start_record(); 
    return 0; 
} 

record.h

#pragma once 
#include <iostream> // Functionality: COUT 
#include "portaudio.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <chrono> //Functionality: Sleep 
#include <thread> //Functionality: Sleep 
#include <algorithm> //Functionality: fill_n 
#define SAMPLE_RATE (44100) 

typedef float SAMPLE; 

#define NUM_SECONDS 30 
#define NUM_CHANNELS 2 
#define SAMPLE_SILENCE 0.0f 
#define PA_SAMPLE_TYPE paFloat32 
#define FRAMES_PER_BUFFER (512) 
#define TRUE (1==1) 
#define FALSE (!TRUE) 
#define WRITE_TO_FILE TRUE 


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

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

    static int recordCallbackSub(const void *inputBuffer, void *outputBuffer, 
         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, 
         PaStreamCallbackFlags statusFlags, void *userData) 
    { 
     auto pThis = reinterpret_cast<record*>(userData); // get back the this pointer. 
     return pThis->recordCallback(inputBuffer, outputBuffer,framesPerBuffer, timeInfo,statusFlags, nullptr); 

    } 
}; 

record.cpp

#include "record.h" 


record::record() 
{ 
    std::cout << "Record object made" << std::endl; 
    std::cout << "Portaudio Version: " << 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); 
    this->data.recordedSamples = new SAMPLE[numSamples]; /* From now on, recordedSamples is initialised. */ 
    if(this->data.recordedSamples == NULL) 
    { 
     std::cout << "Could not allocate record array" << std::endl; 
     exit(1); 
    } 

    for(int i=0; i<numSamples; i++) 
    { 
     this->data.recordedSamples[i] = 0; 

    } 

    int err = Pa_Initialize(); 

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

    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 = 1;     /* stereo input */ 
    this->inputParameters.sampleFormat = PA_SAMPLE_TYPE; 
    this->inputParameters.suggestedLatency = Pa_GetDeviceInfo(this->inputParameters.device)->defaultLowInputLatency; 
    this->inputParameters.hostApiSpecificStreamInfo = NULL; 

    std::cout << "Device name: " <<Pa_GetDeviceInfo(this->inputParameters.device)->name << std::endl; 
    std::cout << "Max inputChannels: " <<Pa_GetDeviceInfo(this->inputParameters.device)->maxInputChannels << std::endl; 

} 

int record::recordCallback(const void *inputBuffer, void *outputBuffer, 
          unsigned long framesPerBuffer, 
          const PaStreamCallbackTimeInfo* timeInfo, 
          PaStreamCallbackFlags statusFlags, void *userData) 
{ 
    std::cout << "Callback called" << std::endl; 
    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 */ 
       &record::recordCallbackSub, 
       this); 
    if(err != paNoError) 
    { 
     std::cout << "Something wrong - open_stream check" << std::endl; 
     std::cout << "PortAudio error: "<< Pa_GetErrorText(err) << std::endl; 
     exit(1); 
    } 

    this->err = Pa_StartStream(this->stream); 

    if(err != paNoError) 
    { 
     std::cout << "Something wrong in stream check" << std::endl; 
     std::cout << "PortAudio error: "<< Pa_GetErrorText(err) << std::endl; 
     exit(1); 
    } 

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

    while((err = Pa_IsStreamActive(stream)) == 1) 
    { 
     Pa_Sleep(1000); 
     printf("index = %d\n", this->data.frameIndex); fflush(stdout); 

    } 
    if(err < 0) 
    { 
     std::cout << "error check with isStreamActive - something wrong" << std::endl; 
     std::cout << "PortAudio error: "<< Pa_GetErrorText(err) << std::endl; 
     exit(1); 
    } 

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

    std::cout << "Number of entries: " << sizeof(this->data.recordedSamples)/sizeof(this->data.recordedSamples[0]) << std::endl; 

    /* Measure maximum peak amplitude. */ 
    max = 0; 
    average = 0.0; 
    for(int i=0; i<numSamples; i++) 
    { 

     val = this->data.recordedSamples[i]; 
     std::cout << "i: " << i << " : "<< val << std::endl; 
     std::this_thread::sleep_for(std::chrono::milliseconds(100)); 

     if(val < 0) val = -val; /* ABS */ 
     if(val > max) 
     { 
      max = val; 
     } 
     average += val; 
    } 

    average = average/(double)numSamples; 

    std::cout<<"sample max amplitude = " << max << std::endl; 
    std::cout<<"sample average = " << average << std::endl; 

    if (WRITE_TO_FILE) 
    { 
     FILE *fid; 
     fid = fopen("recorded.wav", "wb"); 
     if(fid == NULL) 
     { 
      printf("Could not open file."); 
     } 
     else 
     { 
      fwrite(data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid); 
      fclose(fid); 
      printf("Wrote data to 'recorded.raw'\n"); 
     } 
    } 



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



} 

更新:

ここ

コードです

私はいくつかのデバッグ通知から、コールバックは一度しか呼び出されておらず、返った後はストリームが非アクティブになるため、コールバック関数を呼び出すことが不可能になります。ストリームが非アクティブになるのはなぜですか?

+0

質問を回答できるのは、その中に含まれている情報のみにしてください。 – bolov

+0

あなたはどの言語を書いていますか?質問に答えるために外部リンクを訪問する必要はありませんか?それは 'C'か' C++ 'ですか?選択してください。 – bolov

+0

コードを追加してタグを変更しました@bolov – Lamda

答えて

2

あなたの最初のコールバック

static int recordCallbackSub(const void *inputBuffer, void *outputBuffer, 
        unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, 
        PaStreamCallbackFlags statusFlags, void *userData) 
{ 
    auto pThis = reinterpret_cast<record*>(userData); // get back the this pointer. 
    return pThis->recordCallback(inputBuffer, outputBuffer,framesPerBuffer, timeInfo,statusFlags, nullptr); 

} 

はあなたの2番目のコールバックnullptrに設定userDataパラメータと

int record::recordCallback(const void *inputBuffer, void *outputBuffer, 
          unsigned long framesPerBuffer, 
          const PaStreamCallbackTimeInfo* timeInfo, 
          PaStreamCallbackFlags statusFlags, void *userData) 
{ 
    std::cout << "Callback called" << std::endl; 
    this->data = (paTestData&) userData; 

    .... 
} 

を呼び出します。 nullptrpaTestData&にキャストし、dataメンバー変数を結果に設定します。これは意図していないと思われます。

this->data = (paTestData&) userData;行を削除してください。

+0

これは修正されたようです。私はportaudioが提供したpaex_record.cサンプルスクリプトを使用していました。私は/まだ、userDataが実際に何をしているかについて少しは確信していましたか? – Lamda

+1

userDataパラメータは、Port AudioのようなC APIのかなり一般的な機能です。その目的は、ユーザー定義の任意の情報をコールバックに渡すことです。クラスへのポインタを 'recordCallbackSub'関数に渡して、静的関数からメンバ関数に渡すことができます。 'void * userData'パラメータがなければ、これは単純には不可能です。 paex_record.cの例では、このメカニズムを使用してデータ構造体をコールバックに渡していますが、すでにクラス内にあるため、代わりにメンバー変数を直接使用することができます。 – t0m

関連する問題