即使我改变位置,OpenAL 源声音也没有改变

问题描述 投票:0回答:1

我正在尝试用 openal 实现空间声音,但是无论我如何改变源的位置,声音的音量都不会改变。这是一些示例代码:



#include <chrono>

#include <AL/al.h>
#include <AL/alc.h>
#include "stb_vorbis.c"


double timeDiff(std::chrono::steady_clock::time_point start, std::chrono::steady_clock::time_point stop) {
  auto dur = std::chrono::duration_cast<std::chrono::duration<double>>(stop - start);
  return dur.count();
}

int main(void) {
  auto audioDevice = alcOpenDevice(nullptr);
  auto alContext = alcCreateContext(audioDevice, nullptr);

  alcMakeContextCurrent(alContext);
  alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
  
  ALuint source = 0;
  alGenSources(1, &source);
  alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);

  // Added max distance and reference distance, thanks to paddy's comment
  alSourcef(source, AL_MAX_DISTANCE, 50.f);
  alSourcef(source, AL_REFERENCE_DISTANCE, 5.f);

  ALuint buffer = 0;
  alGenBuffers(1, &buffer);
  {

    int spacialAudioChannels = 0, sampleRate = 0;
    short* hData = nullptr;
    int samples = stb_vorbis_decode_filename("Cipher2.ogg", &spacialAudioChannels, &sampleRate, &hData);
    if (hData == nullptr) {
      printf("Failed to open file Cipher2.ogg");
      exit(EXIT_FAILURE);
    }
    auto alFormat = spacialAudioChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
    alBufferData(buffer, alFormat, hData, samples * sizeof(short), sampleRate);

    free(hData);
  }
  
  alSourcei(source, AL_BUFFER, buffer);
  alSourcePlay(source);
  
  auto startTime = std::chrono::steady_clock::now();

  while (timeDiff(startTime, std::chrono::steady_clock::now()) < 180.0) {
    double percentElasped = timeDiff(startTime, std::chrono::steady_clock::now()) / 180.0;

    float pos[] = { percentElasped * 100.f, 0.f, 0.f };
    alSourcefv(source, AL_POSITION, pos);
  }
}

我正在使用 stb vorbis 加载 ogg 文件。然后我计算已经过去的时间百分比,最后将源位置设置为该百分比。 这应该会产生声源远离听者的效果,并使声音随着时间的推移变得更安静。问题是音量保持不变。

c++ audio openal
1个回答
0
投票

我下载并安装了最新的 OpenAL SDK (Windows) 并复制了您的代码。我没有乱搞音频文件,而是生成了 5 秒单声道 440Hz 波形。这工作正常。

所以,我决定尝试立体声,发现它根本没有衰减。在阅读 alBufferData

documentation
时,我在备注部分看到以下评论:

包含多个数据通道的缓冲区 将在没有 3D 空间化的情况下播放。

我想说这可能是您问题的症结所在。您可能有一个立体声音频文件。尝试将其转换为单声道。

这是我的测试程序,它将音频源从最左移动到最右:

#include <cmath>
#include <chrono>
#include <vector>

#include "al.h"
#include "alc.h"

template <typename T, typename TimePoint>
T timeDiff(TimePoint start, TimePoint stop)
{
    auto dur = std::chrono::duration_cast<std::chrono::duration<T>>(stop - start);
    return dur.count();
}

std::vector<short> generateWave(int sampleRate, float durationSeconds, float frequencyHz, bool stereo)
{
    std::vector<short> samples;
    int numChannels = stereo + 1;
    int numSamples = static_cast<int>(sampleRate * durationSeconds) * numChannels;
    samples.reserve(numSamples);
    for (int t = 0; t < numSamples; t++)
    {
        double amplitude = sin(3.1415927 * 2.0 * frequencyHz * t / sampleRate / numChannels);
        samples.push_back(static_cast<short>(amplitude * 32767));
    }
    return samples;
}

int main()
{
    using Clock = std::chrono::steady_clock;

    const bool stereo = false;
    const int sampleRate = 44100;
    const float waveFrequencyHz = 440.f;
    const float playTimeSeconds = 5.f;
    const float maxDistance = 50.f;
    const float refDistance = 5.f;

    // Init device context
    auto audioDevice = alcOpenDevice(nullptr);
    auto alContext = alcCreateContext(audioDevice, nullptr);
    alcMakeContextCurrent(alContext);
    alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);

    // Create audio source
    ALuint source = 0;
    alGenSources(1, &source);
    alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);

    // Added max distance and reference distance, thanks to paddy's comment
    alSourcef(source, AL_MAX_DISTANCE, maxDistance);
    alSourcef(source, AL_REFERENCE_DISTANCE, refDistance);

    // Create audio buffer
    ALuint buffer = 0;
    alGenBuffers(1, &buffer);
    std::vector<short> samples = generateWave(sampleRate, playTimeSeconds, waveFrequencyHz, stereo);
    alBufferData(buffer, stereo ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, samples.data(), (ALsizei)samples.size() * sizeof(short), sampleRate);

    // Play audio source
    alSourcei(source, AL_BUFFER, buffer);
    alSourcePlay(source);

    // Animate the audio source from far-left to far-right
    auto startTime = Clock::now();
    for (float elapsed = 0; elapsed < playTimeSeconds; elapsed = timeDiff<float>(startTime, Clock::now()))
    {
        float t = elapsed / playTimeSeconds;
        float x = (t * 2.f - 1.f) * maxDistance;
        float pos[] = { x, 0, refDistance };  // offset z to avoid artifacts transitioning through origin
        alSourcefv(source, AL_POSITION, pos);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.