현재 녹음하는 응용 프로그램과 함께 portaudio를 사용하고 있는데 샘플을 수집하는 데 문제가있는 것 같습니다. 내가 볼 수있는 것은 단지 하나의 샘플 만 저장된다는 것이고, 콜백은 한번만 호출된다는 것인데, 변수 NUM_OF_SECONDS
이 30 초로 설정되어 있더라도.portaudio는 하나의 샘플만을 사용합니까?
현재 내가 테스트 할 수있는 아이디어가 부족하고 어떻게 디버깅 할 수 있습니까? 그래서 여기에 문제를 디버깅 할 수있는 방법을 제안했습니다.
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;
}
업데이트 :
,691 여기 코드입니다일부 디버깅 공지에서 콜백이 한 번만 호출되고 반환 된 후에는 스트림이 비활성 상태가되어 콜백 함수를 호출 할 수 없습니다. 스트림이 비활성 상태 인 이유는 무엇입니까?
질문에 답할 수있는 내용은 안에 포함 된 정보로만 작성하십시오. – bolov
당신은 어떤 언어로 글을 쓰고 있습니까? 질문에 대답하기 위해 외부 링크를 방문 할 필요는 없습니다. 그것은'C' 또는'C++'인가? 하나 골라주세요. – bolov
코드를 추가하고 태그를 변경했습니다. @bolov – Lamda