好的,這是我的問題。iOS OpenAL聲音不是位置
我正在開發一些幫助類,它爲我封裝了iOS上的OpenAL功能。要知道,它運行得很好,這意味着我可以播放多個聲音(同時)並配置增益和音調。
對我來說,下一步是添加位置聲音。我知道,我必須爲聽衆的位置和來源的位置(和速度,但這不是那麼重要,知道)使用屬性。
問題是,我實現了與互聯網上的教程相對應的所有內容,但聲音總是沒有衰減,所以它不是位置的。
我發現,有時這是由立體聲音頻文件引起的,所以現在我使用單聲道文件,但問題仍然存在。事實上,我從蘋果下載了這個example project。它適用於Mac OS並確實有效。所以我從他們的項目中拿出了聲音文件,然後用我自己的方式使用它們。所以聲音格式應該沒有問題。它仍然不播放位置。
所以我的問題是: 是否可以在iPhone上使用OpenAl播放聲音位置? 如果是的話,應該爲實現3D播放而設置的最低OpenAL屬性是什麼?也許我只是沒有設置一個需要的基本設置。
此外,我認爲模擬器是問題,但是當我在真正的iPhone上測試我的應用程序時,它也不起作用。
我會知道在這裏添加我目前的代碼,但我認爲這太直接找到bug了。我希望有人誰知道我的惱人問題的標準解決方案(其中,我認爲,會有一些小錯誤:d)
所以這裏的代碼:
監聽器:
class Listener {
private:
vec3 position;
vec3 velocity;
vec3 at;
vec3 up;
public:
Listener();
void setOrientation(vec3 at, vec3 up);
vec3 getPosition();
void setPosition(vec3 position);
vec3 getVelocity();
void setVelocity(vec3 velocity);
};
Listener::Listener() {
alListenerf(AL_GAIN, 0.5f);
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
}
void Listener::setOrientation(vec3 at, vec3 up)
{
printf("Listener Set Orientation\n");
ALfloat *orientation = (ALfloat*)malloc(6*sizeof(ALfloat));
orientation[0] = at.x;
orientation[1] = at.y;
orientation[2] = at.z;
orientation[3] = up.x;
orientation[4] = up.y;
orientation[5] = up.z;
alListenerfv(AL_ORIENTATION, orientation);
this->at = at;
this->up = up;
free(orientation);
}
vec3 Listener::getPosition()
{
return position;
}
void Listener::setPosition(vec3 position)
{
printf("Listener Set Position\n");
ALfloat *positionArray = (ALfloat*)malloc(3*sizeof(ALfloat));
positionArray[0] = position.x;
positionArray[1] = position.y;
positionArray[2] = position.z;
alListenerfv(AL_POSITION, positionArray);
this->position = position;
free(positionArray);
}
vec3 Listener::getVelocity()
{
return velocity;
}
void Listener::setVelocity(vec3 velocity)
{
printf("Listener Set Velocity\n");
ALfloat *velArray = (ALfloat*)malloc(3*sizeof(ALfloat));
velArray[0] = velocity.x;
velArray[1] = velocity.y;
velArray[2] = velocity.z;
alListenerfv(AL_VELOCITY, velArray);
this->velocity = velocity;
free(velArray);
}
樣品
class Sample {
private:
UInt32 usageCount; // Number of Screens using this sound
const char *filename; // The Filename, should be unique!
ALuint audioBuffer; // The sound buffer in which it is stored
public:
Sample(const char* filename);
Sample(std::string);
void load();
bool unload();
std::string getFilename();
ALuint getAudioBuffer();
};
Sample::Sample(const char* filename)
{
usageCount = 0;
this->filename = filename;
}
Sample::Sample(std::string filename)
{
usageCount = 0;
this->filename = filename.c_str();
}
void Sample::load()
{
ALenum format;
ALvoid* data;
ALsizei size;
ALsizei freq;
if (usageCount == 0) {
data = SampleLoader::GetOpenALAudioData(filename, &size, &format, &freq);
// Generate Buffer
alGenBuffers(1, &audioBuffer);
// Fill Buffer With Data
alBufferData(audioBuffer, format, data, size, freq);
// Free Audio Data
if (data)
{
free(data);
data = NULL;
}
}
usageCount++;
}
// returns true, if usageCount got zero
bool Sample::unload()
{
if (usageCount == 1) {
// Delete Buffer
alDeleteBuffers(1, &audioBuffer);
return true;
}
usageCount--;
return false;
}
std::string Sample::getFilename()
{
std::string strFilename = std::string(filename);
return strFilename;
}
ALuint Sample::getAudioBuffer()
{
return audioBuffer;
}
來源
class Source {
vec3 position;
vec3 velocity;
vec3 direction;
ALfloat gain;
ALfloat pitch;
ALuint sourceID;
Sample *sample;
public:
void load();
void unload();
ALboolean isPlaying();
void play();
void repeat();
void stop();
void updateSample(Sample *sample);
void updatePosition(vec3 position);
void updateVelocity(vec3 velocity);
void updateDirection(vec3 direcation);
void updateOrienation(vec3 position, vec3 velocity, vec3 direction);
void updateGain(ALfloat gain);
void updatePitch(ALfloat pitch);
};
void Source::load()
{
alGenSources(1, &sourceID);
position = vec3(0.0f, 0.0f, 0.0f);
velocity = vec3(0.0f, 0.0f, 0.0f);
direction = vec3(0.0f, 0.0f, 0.0f);
alSourcefv(sourceID, AL_POSITION, value_ptr(position));
alSourcefv(sourceID, AL_VELOCITY, value_ptr(velocity));
alSourcefv(sourceID, AL_DIRECTION, value_ptr(direction));
gain = 0.5f;
pitch = 1.0f;
alSourcef(sourceID, AL_GAIN, gain);
alSourcef(sourceID, AL_PITCH, pitch);
}
void Source::unload()
{
alDeleteSources(1, &sourceID);
}
ALboolean Source::isPlaying()
{
ALint sourceState;
alGetSourcei(sourceID, AL_SOURCE_STATE, &sourceState);
return (sourceState == AL_PLAYING);
}
void Source::play()
{
alSourcei(sourceID, AL_LOOPING, AL_FALSE);
alSourcePlay(sourceID);
}
void Source::repeat()
{
alSourcei(sourceID, AL_LOOPING, AL_TRUE);
alSourcePlay(sourceID);
}
void Source::stop()
{
alSourceStop(sourceID);
}
void Source::updateSample(Sample *sample)
{
alSourcei(sourceID, AL_BUFFER, sample->getAudioBuffer());
}
void Source::updatePosition(vec3 position)
{
alSource3f(sourceID, AL_POSITION, position.x, position.y, position.z);
}
void Source::updateVelocity(vec3 velocity)
{
alSourcefv(sourceID, AL_VELOCITY, value_ptr(velocity));
}
void Source::updateDirection(vec3 direction)
{
alSourcefv(sourceID, AL_DIRECTION, value_ptr(direction));
}
void Source::updateOrienation(vec3 position, vec3 velocity, vec3 direction)
{
alSourcefv(sourceID, AL_POSITION, value_ptr(position));
alSourcefv(sourceID, AL_VELOCITY, value_ptr(velocity));
alSourcefv(sourceID, AL_DIRECTION, value_ptr(direction));
}
void Source::updateGain(ALfloat gain)
{
alSourcef(sourceID, AL_GAIN, gain);
}
void Source::updatePitch(ALfloat pitch)
{
alSourcef(sourceID, AL_PITCH, pitch);
}
樣品加載函數,從項目從蘋果採取
void* SampleLoader::GetOpenALAudioData(const char* filename, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate)
{
OSStatus err = noErr;
SInt64 theFileLengthInFrames = 0;
AudioStreamBasicDescription theFileFormat;
UInt32 thePropertySize = sizeof(theFileFormat);
ExtAudioFileRef extRef = NULL;
void* theData = NULL;
AudioStreamBasicDescription theOutputFormat;
// Create Path
NSString *filenameString = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];
NSArray *components = [filenameString componentsSeparatedByString:@"."];
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:[components objectAtIndex:0] ofType:[components objectAtIndex:1]];
NSURL *audioFileURL = [NSURL fileURLWithPath:audioFilePath];
CFURLRef inFileURL = (__bridge CFURLRef)audioFileURL;
// Open a file with ExtAudioFileOpen()
err = ExtAudioFileOpenURL(inFileURL, &extRef);
if(err) {
printf("MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %d\n", (int)err);
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
// Get the audio data format
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
if(err) {
printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %d\n", (int)err);
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
if (theFileFormat.mChannelsPerFrame > 2) {
printf("MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n");
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
// Set the client format to 16 bit signed integer (native-endian) data
// Maintain the channel count and sample rate of the original source format
theOutputFormat.mSampleRate = theFileFormat.mSampleRate;
theOutputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame;
theOutputFormat.mFormatID = kAudioFormatLinearPCM;
theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame;
theOutputFormat.mFramesPerPacket = 1;
theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame;
theOutputFormat.mBitsPerChannel = 16;
theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
// Set the desired client (output) data format
err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
if(err) {
printf("MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %d\n", (int)err);
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
// Get the total frame count
thePropertySize = sizeof(theFileLengthInFrames);
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
if(err) {
printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %d\n", (int)err);
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
// Read all the data into memory
UInt32 theFramesToRead = (UInt32)theFileLengthInFrames;
UInt32 dataSize = theFramesToRead * theOutputFormat.mBytesPerFrame;;
theData = malloc(dataSize);
if (theData)
{
AudioBufferList theDataBuffer;
theDataBuffer.mNumberBuffers = 1;
theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame;
theDataBuffer.mBuffers[0].mData = theData;
// Read the data into an AudioBufferList
err = ExtAudioFileRead(extRef, &theFramesToRead, &theDataBuffer);
if(err == noErr)
{
// success
*outDataSize = (ALsizei)dataSize;
*outDataFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
*outSampleRate = (ALsizei)theOutputFormat.mSampleRate;
}
else
{
// failure
free (theData);
theData = NULL; // make sure to return NULL
printf("MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %d\n", (int)err);
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
}
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
SoundManager類
namespace SoundManager {
extern ALCdevice *openALDevice;
extern ALCcontext *openALContext;
extern std::vector<Sample*> samples;
void initialize();
void release();
Sample* manage(const char* filename);
Sample* manage(std::string filename);
void remove(Sample *sample);
}
namespace SoundManager {
ALCdevice *openALDevice;
ALCcontext *openALContext;
std::vector<Sample*> samples;
}
void AudioInterruptionListenerCallback(void* user_data, UInt32 interruption_state)
{
if (kAudioSessionBeginInterruption == interruption_state)
{
alcMakeContextCurrent(NULL);
}
else if (kAudioSessionEndInterruption == interruption_state)
{
AudioSessionSetActive(true);
alcMakeContextCurrent(SoundManager::openALContext);
}
}
void SoundManager::initialize()
{
AudioSessionInitialize(NULL, NULL, AudioInterruptionListenerCallback, NULL);
UInt32 session_category = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(session_category), &session_category);
AudioSessionSetActive(true);
// Open Device
openALDevice = alcOpenDevice(NULL);
// Create and activate context
openALContext = alcCreateContext(openALDevice, NULL);
alcMakeContextCurrent(openALContext);
}
void SoundManager::release()
{
// Give up Context and destroy it
alcMakeContextCurrent(NULL);
alcDestroyContext(openALContext);
// Close device
alcCloseDevice(openALDevice);
}
Sample* SoundManager::manage(const char* filename)
{
return manage(std::string(filename));
}
Sample* SoundManager::manage(std::string filename)
{
if (samples.size() >= kMaxNumberOfSamples) {
Engine::warning("Max number of samples reached! Release one first");
return NULL;
}
// If Sound is already managed, load the managed again
for (int i=0; i<samples.size(); i++) {
if (samples[i]->getFilename().compare(filename) == 0) {
printf("Already loaded\n");
samples[i]->load();
return samples[i];
}
}
// Otherwise load the new sound and manage it
printf("Load new sound\n");
Sample *sample = new Sample(filename);
sample->load();
samples.push_back(sample);
return sample;
}
void SoundManager::remove(Sample *sample)
{
for (int i=0; i<samples.size(); i++) {
if (samples[i]->getFilename().compare(sample->getFilename()) == 0) {
// If Sound isn't in use from anywhere else, unmanage it
if (samples[i]->unload()) {
samples.erase(std::remove(samples.begin(), samples.end(), sample), samples.end());
return;
}
}
}
Engine::warning("The sound to be removed wasn't managed!");
}
所以就在這裏,這是爲源,緩衝器和監聽器和一個管理者,所有的包裝類,其只是確保樣品只加載一次。所有這些都應用在屏幕類中,並在我的簡單引擎中呈現。它是獨立的,應該播放從左到右移動的聲音。但它不:
class SoundTestScreen : public Screen
{
private:
void initialize();
void load();
void unload();
void update(Time &time);
void draw(Time &time);
private:
Listener listener;
Sample *bubbles;
Source *bubbleSource;
double totalTime;
double lastPlayTime;
};
void SoundTestScreen::initialize()
{
listener.setPosition(vec3(0, 0, 0));
listener.setVelocity(vec3(0, 0, 0));
listener.setOrientation(vec3(0, 0, -1),vec3(0, 1, 0));
totalTime = 0;
lastPlayTime = 0;
// Create Sources to play the samples
bubbleSource = new Source();
}
void SoundTestScreen::load()
{
// Only load sample once
bubbles = SoundManager::manage("sound_electric.wav");
bubbleSource->load();
bubbleSource->updateSample(bubbles);
bubbleSource->updatePosition(vec3(0,0,0));
bubbleSource->repeat();
}
void SoundTestScreen::unload()
{
// Only unload sample once
SoundManager::remove(bubbles);
bubbleSource->unload();
}
void SoundTestScreen::update(Time &time)
{
bubbleSource->updatePosition(vec3(100*sinf(time.ElapsedTime),0,0));
}
void SoundTestScreen::draw(Time &time)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
這一切都只是一些基本的實現,但我真的不知道爲什麼聲音不位置。
我真的很希望有人能找到我的錯誤,這很煩人。
問候
編輯:
它的工作現在,只有一些小的錯誤,我現在糾正,但沒有找到很長一段時間。 我將這個代碼留給那些正在尋找一些iOS上的聲音系統的人來使用,這些聲音系統在互聯網上很少見。
謝謝你!即使根據您的示例重新編寫我的代碼後,iOS上不支持alut,我也會喜歡我的錯誤。它真的很笨,必須交換一個變量:D在Sample :: load()中,AL_FORMAT_STEREO16必須替換爲從前一個函數計算出來的'format'。這就是爲什麼它不是位置! – acloD128
哎呀!完全忘了ALUT和iOS。 –
謝謝:) – acloD128