Im probably doing something stupid but I am not getting any form of data from libsndfile when I'm using it in a sound system that I'm developing. sf_read_floatf returns greater than zero but looking at the buffer itself it's just zeroed out data. I'm also using libsamplerate but at the moment I have both samplerates of the audio file and port audio the same for testing.
Port Audio Constructor:
PortAudioSystem::PortAudioSystem(double sampleRate, PaDeviceIndex device, void * hostApiSpecificStreamInfo) {
this->m_masterVol = this->m_musicVol = this->m_sfxVol = 1.0f;
this->m_deltaTime = 0.0f;
this->audioStream = nullptr;
this->_hasPaError = false;
this->m_sampleRate = sampleRate;
PaStreamParameters streamParams;
streamParams.device = device; //set device to use
streamParams.hostApiSpecificStreamInfo = hostApiSpecificStreamInfo;
streamParams.sampleFormat = paFloat32; // 32bit float format
streamParams.suggestedLatency = 0.2; //200 ms ought to satisfy even the worst sound card
streamParams.channelCount = 2; //number of channels (1: mono, 2: left/right, etc)
int err = 0;
err = Pa_OpenStream(
&this->audioStream,
0, // no input
&streamParams,
sampleRate,
paFramesPerBufferUnspecified, // let portaudio choose the buffersize
paNoFlag,/* no special modes (clip off, dither off) */
PortAudioSystem::paCallbackCommon,
this
);
if (err != paNoError) {
pushPaError(err, Pa_GetErrorText(err));
this->audioStream = nullptr;
}
int src_err;
this->m_srcState = src_new(SRC_SINC_FASTEST,2,&src_err); //create a new sample rate converter
if (this->m_srcState == NULL) {
//src_error(this->m_srcState);
this->pushPaError(src_err, src_strerror(src_err));
}
this->m_nextPlayID = 0;
}
Port Audio Callback:
int PortAudioSystem::paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
this->m_deltaTime = (float)((double)framesPerBuffer / this->m_sampleRate); //get delta time based on sample rate and number of frames per buffer
if (this->m_playingAudioFiles.size() == 0) return paContinue; //if we dont have any playing audio files, skip.
AudioFrame::_2 *outFrame = (AudioFrame::_2*)outputBuffer; //convert the port audio buffer to an audio frame buffer.
//zero out the output buffer.
for (unsigned long zeroI = 0; zeroI < framesPerBuffer; zeroI++) {
outFrame[zeroI].left = 0.0f;
outFrame[zeroI].right = 0.0f;
}
//for (PlayingAudioFile playingfile : this->m_playingAudioFiles) playingfile.audioFile->Seek(playingfile.currentFrame); //seek to the current position of the file
AudioFrame::_2 *framesOut = new AudioFrame::_2[framesPerBuffer]; //create a buffer for frames out.
//float * fFramesOut = new float[framesPerBuffer * 2]; //create a float buffer for frames out (*2 for left and right channel)
//prep common data for sample rate conversion.
SRC_DATA src_data;
src_data.output_frames = framesPerBuffer; //set output frames to be the max output frames to have.
src_data.end_of_input = 0; //we are not at the end of the file (change for specific audio file system [function?]).
src_data.data_out = (float *)framesOut; //set our output frames to be the buffer that we created.
flow.lock(); //mutex lock
for (std::pair<long, PlayingAudioFile> entry : this->m_playingAudioFiles){ //for each playing audio file
if (entry.second.paused) continue; //if the audio file is paused, skip it.
PlayingAudioFile& playingfile = entry.second;
playingfile.audioFile->Seek(playingfile.currentFrame); //seek to the current position of the file
src_data.src_ratio = this->m_sampleRate / playingfile.audioFile->GetSampleRate(); //get the ratio of the sample rate conversion
if (src_data.src_ratio == 1) { //if we are 1 to 1, dont do sample rate conversion.
src_data.input_frames_used = src_data.output_frames_gen = (long)playingfile.audioFile->GetFrames(framesPerBuffer, (float *)framesOut);
} else { //otherwise convert to port audio system's sample rate.
//adjust the number of frames to read based on ratio.
long long framesToRead//;
/*if (fmod((double)framesPerBuffer, src_data.src_ratio) == 0) framesToRead = framesPerBuffer;
else framesToRead*/ = (framesPerBuffer / ((long long)src_data.src_ratio));// + 2;
AudioFrame::_2* framesIn = new AudioFrame::_2[framesToRead]; //create a buffer for frames in.
//float * fFramesIn = new float[framesToRead * 2]; //create a float buffer to read in frames. (*2 for left and right audio channel)
src_data.data_in = (float *)framesIn; //set the frame in buffer
src_data.input_frames = (long)playingfile.audioFile->GetFrames(framesToRead, (float *)framesIn); //read the frames; //set the number of frames that were read
if (src_data.input_frames == 0) {
delete[] framesIn; //free up the frame in buffer to prevent memory leaks.
continue; //if we have no data, skip
}
src_reset(this->m_srcState); //reset the sample rate conversion state
int src_err = src_process(this->m_srcState, &src_data); //convert the sample rate
if (src_err != 0) this->pushPaError(src_err, src_strerror(src_err)); //if we have an error, push it back.
delete[] framesIn; //free up the frame in buffer
}
//AudioFrame::_2* framesOut = (AudioFrame::_2*) fFramesOut; //convert the float buffer to an audio frame buffer for easier access to the channels
for (unsigned long outFrameI = 0; outFrameI < src_data.output_frames_gen; outFrameI++) { //for each frame (based on how many frames were generated from conversion [possibly under framesPerBuffer])
//individual frame data;
AudioFrame::_2 frame = framesOut[outFrameI];
//adjust volume from master volume
frame.left *= this->m_masterVol;
frame.right *= this->m_masterVol;
//adjust volume
switch (playingfile.channel) { //based on sound channel
case eAT_Music: //if we are a music channel
frame.left *= this->m_musicVol;
frame.right *= this->m_musicVol;
break;
case eAT_SFX: //if we are a sfx channel
frame.left *= this->m_sfxVol;
frame.right *= this->m_sfxVol;
break;
}
if (frame.left != 0.0f){ //make sure we have data.
if (outFrame[outFrameI].left == 0.0f) { //if the output frame has no data
outFrame[outFrameI].left = frame.left; //set the audio
} else { //if the output frame has data
outFrame[outFrameI].left += frame.left; //mix the channels
outFrame[outFrameI].left /= 2; //ghetto way of making sure we dont clip?
}
}
if (frame.right != 0.0f){ //make sure we have data.
if (outFrame[outFrameI].right == 0.0f) { //if the output frame has no data
outFrame[outFrameI].right = frame.right; //set the audio
} else { //if the output frame has data
outFrame[outFrameI].right += frame.right; //mix the channels
outFrame[outFrameI].right /= 2; //ghetto way of making sure we dont clip?
}
}
}
playingfile.currentFrame += src_data.input_frames_used; //update the current position time based on how many frames were converted;
if (playingfile.currentFrame >= playingfile.endFrame && !playingfile.loop) { //if we are finnished playing.
//mark for removal.
m_stoppedAudioFiles.push_back(entry.first);
} else {
//loop the file
playingfile.currentFrame = playingfile.startFrame;
}
}
delete [] framesOut;
//removed stopped audio files.
while (m_stoppedAudioFiles.size() > 0) {
this->m_playingAudioFiles.erase(m_stoppedAudioFiles.back());
m_stoppedAudioFiles.pop_back();
}
flow.unlock(); //mutex unlock
return paContinue; //continue playback
}
AudioFile_Libsnd:
bool AudioFile_Libsnd::Seek(long long position){
if (!this->_hasSfError) {
if (sf_seek(this->sndFile, position, SF_SEEK_SET) == -1) {
int err = sf_error(this->sndFile);
pushSfError(err, sf_error_number(err));
return false;
}
return true;
}
return false;
}
long long AudioFile_Libsnd::GetFrames(long long framesToRead, float buff[]){
if (this->_hasSfError) return 0;
long long framesRead = sf_readf_float(this->sndFile, buff, framesToRead);
return framesRead;
}
bool AudioFile_Libsnd::GetFrame(float* frame) {
return sf_readf_float(this->sndFile, frame, 1) == 1;
}
AudioFrame::_2:
struct _2 {
float left;
float right;
_2() : left(0.0f), right(0.0f) {}
};
PlayingAudioFile:
struct PlayingAudioFile {
IAudioFile* audioFile;
long long currentFrame;
long long startFrame;
long long endFrame;
bool loop;
bool paused;
EAudioChannel channel;
};
I know the whole code is kind of long but I currently don't know what I'm doing wrong... I believe that I am constructing the buffers correctly but I have tried pure float pointers, both array defined and created with new and that didn't work. I have also tried going frame by frame with a for loop and saving it into a single float but that apparently threw me a stack around variable was corrupt error... Any help would be appreciated.
Fixed it. I was doing stupid. This is the culprit right here:
changed the "else" to "else if (playingsource.currentFrame >= playingsource.endFrame && playingsource.loop)" because it was setting the current frame to the starting frame every time