我编写了一个函数来使用 portaudio 和 sndfile 播放声音文件。不幸的是,音质很糟糕。声音更像是嘶嘶声。以下是我正在使用的函数的源代码。
#define _GLIBCXX_USE_C99_MATH 1
#include "PlaySound_config.h"
#include <boost/predef.h>
#if !defined(USE_PORTAUDIO) // {
# define USE_PORTAUDIO 0
# if (! BOOST_OS_CYGWIN && ! BOOST_OS_WINDOWS) // {
# undef USE_PORTAUDIO
# define USE_PORTAUDIO 1
# endif // }
#endif // }
#if (PLAY_SOUND_HAVE_PORTAUDIO_H && PLAY_SOUND_HAVE_SNDFILE_H && PLAY_SOUND_HAVE_SNDFILE_HH && USE_PORTAUDIO) // {
#if (PLAY_SOUND_HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <sndfile.hh>
#include <cmath>
#include <fstream>
#include <iostream>
#include <vector>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/format.hpp>
#include "PlaySound.h"
#include "PlaySoundStrings.h"
void SoundWarning(const std::string& message)
{
std::cerr << message << std::endl;
}
bool PlaySoundFile(const std::string& soundFile, unsigned long /* volume */)
{
const int MAX_CHANNELS = 1;
const double SAMPLE_RATE = 11025.0;
const unsigned long FRAMES_PER_BUFFER = 1024;
const size_t BUFFER_LEN = 1024;
using boost::format;
using boost::io::group;
std::string message;
if (soundFile.empty())
{
errno = EINVAL;
message = playSoundStrings[error_invalid_argument];
SoundWarning(message);
return false;
}
boost::filesystem::path soundFilePath(soundFile);
if (! boost::filesystem::exists(soundFilePath))
{
errno = EINVAL;
message = str(format(playSoundStrings[error_file_does_not_exist]) % soundFile.c_str());
SoundWarning(message);
return false;
}
PaError paError = Pa_Initialize();
if (paError != paNoError)
{
message = str(format(playSoundStrings[error_pa_initialize_failed]) % Pa_GetErrorText(paError));
SoundWarning(message);
return false;
}
SNDFILE* sndFile;
SF_INFO sfInfo;
sndFile = sf_open(soundFile.c_str(), SFM_READ, &sfInfo);
if (! sndFile)
{
message = str(format(playSoundStrings[error_sf_open_failed]) % soundFile.c_str() % sf_strerror(nullptr));
SoundWarning(message);
Pa_Terminate();
return false;
}
if (sfInfo.channels > MAX_CHANNELS)
{
message = str(format(playSoundStrings[error_too_many_channels]) % sfInfo.channels % MAX_CHANNELS);
SoundWarning(message);
Pa_Terminate();
return false;
}
PaStream* stream = nullptr;
PaStreamParameters paStreamParameters;
paStreamParameters.device = Pa_GetDefaultOutputDevice();
paStreamParameters.channelCount = sfInfo.channels;
paStreamParameters.sampleFormat = paInt16;
paStreamParameters.suggestedLatency = Pa_GetDeviceInfo(paStreamParameters.device)->defaultLowOutputLatency;
paStreamParameters.hostApiSpecificStreamInfo = nullptr;
paError = Pa_OpenStream(
&stream, nullptr, &paStreamParameters,
SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff,
nullptr, nullptr);
if (paError != paNoError || ! stream)
{
message = str(format(playSoundStrings[error_pa_open_stream_failed]) % Pa_GetErrorText(paError));
SoundWarning(message);
Pa_Terminate();
return false;
}
paError = Pa_StartStream(stream);
if (paError != paNoError)
{
message = str(format(playSoundStrings[error_pa_start_stream_failed]) % Pa_GetErrorText(paError));
SoundWarning(message);
Pa_Terminate();
return false;
}
sf_count_t readCount = 0;
double data[BUFFER_LEN];
while ((readCount = sf_read_double(sndFile, data, BUFFER_LEN)))
{
paError = Pa_WriteStream(stream, data, BUFFER_LEN);
if (paError != paNoError)
{
message = str(format(playSoundStrings[error_pa_write_stream_failed]) % Pa_GetErrorText(paError));
SoundWarning(message);
break;
}
}
paError = Pa_CloseStream(stream);
if (paError != paNoError)
{
message = str(format(playSoundStrings[error_pa_close_stream_failed]) % Pa_GetErrorText(paError));
SoundWarning(message);
Pa_Terminate();
return false;
}
Pa_Terminate();
return true;
}
我在文章什么是轻量级跨平台WAV播放库?但样本不完整。它似乎只会播放文件的前五秒。我想播放整个文件。
知道我做错了什么吗?
此代码是我的PlaySound项目的一部分。