OpenAL仅呈现一个“凸起”,但没有错误。到底是怎么回事?

时间:2019-07-12 13:01:36

标签: java audio lwjgl openal

我试图在OpenAL中制作一个简单的声音播放器作为学习练习。我浏览了几个示例和教程,结果总是一样:没有声音,没有错误。我已经读过OpenAL Documentation,但从未提及过类似的内容。

我最终认为我可能没有安装OpenAL,这很有趣,但我没有。因此,安装后,我也没有声音,也没有错误。

然后我以为我的缓冲区填充不正确,因此我尝试仅使用Java库来播放它。事实证明,它完全可以播放!

[经过大量测试,已编辑]

现在我有音频,但是在调用alSourcePlay之后(有时在应用程序结束时)只是一个“凸起”。如果我使用AL_FORMAT_STEREO8或AL_FORMAT_MONO8而不是16位格式,则会发生这种情况。我想这是格式的问题,但是如果使用其他正确的格式,则什么也不会发生。甚至没有“颠簸”。

我只是不知道有什么问题。我必须承认,这是我第一次使用OpenAL。有关OpenAL故障排除的信息很少,似乎主要关注OpenGL和Vulkan。

这是我到目前为止编写的代码。我正在使用LWJGL访问OpenAL和Java 8。

 public class ErrorController : Controller
{
    public ActionResult Index()
    {
        ViewBag.statusCode = System.Web.HttpContext.Current.Response.StatusCode;

        return View();
    }
}

AutoByteBuffer


import static org.lwjgl.openal.AL10.AL_BUFFER;
import static org.lwjgl.openal.AL10.AL_FORMAT_MONO16;
import static org.lwjgl.openal.AL10.AL_FORMAT_MONO8;
import static org.lwjgl.openal.AL10.AL_FORMAT_STEREO16;
import static org.lwjgl.openal.AL10.AL_FORMAT_STEREO8;
import static org.lwjgl.openal.AL10.AL_GAIN;
import static org.lwjgl.openal.AL10.AL_INVALID_ENUM;
import static org.lwjgl.openal.AL10.AL_INVALID_VALUE;
import static org.lwjgl.openal.AL10.AL_NO_ERROR;
import static org.lwjgl.openal.AL10.AL_OUT_OF_MEMORY;
import static org.lwjgl.openal.AL10.AL_PITCH;
import static org.lwjgl.openal.AL10.AL_POSITION;
import static org.lwjgl.openal.AL10.AL_VELOCITY;
import static org.lwjgl.openal.AL10.alBufferData;
import static org.lwjgl.openal.AL10.alDeleteBuffers;
import static org.lwjgl.openal.AL10.alDeleteSources;
import static org.lwjgl.openal.AL10.alGenBuffers;
import static org.lwjgl.openal.AL10.alGenSources;
import static org.lwjgl.openal.AL10.alGetError;
import static org.lwjgl.openal.AL10.alListener3f;
import static org.lwjgl.openal.AL10.alSource3f;
import static org.lwjgl.openal.AL10.alSourcePlay;
import static org.lwjgl.openal.AL10.alSourcef;
import static org.lwjgl.openal.AL10.alSourcei;
import static org.lwjgl.openal.ALC10.alcCloseDevice;
import static org.lwjgl.openal.ALC10.alcCreateContext;
import static org.lwjgl.openal.ALC10.alcMakeContextCurrent;
import static org.lwjgl.openal.ALC10.alcOpenDevice;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import org.lwjgl.openal.AL;
import org.lwjgl.openal.ALC;
import org.lwjgl.openal.ALC10;
import org.lwjgl.openal.ALCCapabilities;

import dev.ckitty.engine.kc.io.AutoByteBuffer;
import dev.ckitty.engine.kc.io.FileLoader;
import dev.ckitty.engine.kc.main.Engine;
import dev.ckitty.engine.kc.utils.Util;

public class AudioMaster {

    private long device, context;
    private int buffer, source;

    public AudioMaster() {
        init();
        load();
        source();

        Engine.log("Playing!");
        play();
        Util.waitSec(10);

        deinit();
    }

    public void init() {
        device = alcOpenDevice((ByteBuffer) null);
        if (device == 0)
            throw new IllegalStateException("Failed to open the default device.");

        ALCCapabilities deviceCaps = ALC.createCapabilities(device);

        context = alcCreateContext(device, (IntBuffer) null);
        if (context == 0)
            throw new IllegalStateException("Failed to create an OpenAL context.");

        alcMakeContextCurrent(context);
        Engine.log(erroralc());

        AL.createCapabilities(deviceCaps);
        Engine.log(error());
    }

    public void load() {
        AutoByteBuffer abb = new AutoByteBuffer();
        AudioFormat format = null;

        try {
            InputStream is = FileLoader.Internal.getInputStream("/kc/audios/LFZ - Popsicle.wav");
            BufferedInputStream bis = new BufferedInputStream(is);
            AudioInputStream ais = AudioSystem.getAudioInputStream(bis);
            abb.put(ais);
            format = ais.getFormat();

            ais.close();
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        buffer = alGenBuffers();
        int samplerate = (int) format.getSampleRate();
        alBufferData(buffer, AL_FORMAT_STEREO8, abb.flip(), samplerate);
    }

    public void source() {
        source = alGenSources();
        Engine.log(error());
        alSourcef(source, AL_GAIN, 1f);
        alSourcef(source, AL_PITCH, 1f);
        alSource3f(source, AL_POSITION, 0f, 0f, 0f);
        alSourcei(source, AL_BUFFER, buffer);
    }

    public void play() {
        alListener3f(AL_POSITION, 0, 0, 0);
        alListener3f(AL_VELOCITY, 0, 0, 0);



        Engine.log("PLAYING");
        alSourcePlay(source);
    }

    public String erroralc() {
        switch (ALC10.alcGetError(device)) {
          case AL_NO_ERROR: return "ALC_NO_ERROR";
          case AL_INVALID_ENUM: return "ALC_INVALID_ENUM";
          case AL_INVALID_VALUE: return "ALC_INVALID_VALUE";
          case AL_OUT_OF_MEMORY: return "ALC_OUT_OF_MEMORY";
          /* ... */
          default:
            return "Unknown error code";
        }
    }

    public String error() {
        switch (alGetError()) {
          case AL_NO_ERROR: return "AL_NO_ERROR";
          case AL_INVALID_ENUM: return "AL_INVALID_ENUM";
          case AL_INVALID_VALUE: return "AL_INVALID_VALUE";
          case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY";
          /* ... */
          default:
            return "Unknown error code";
        }
    }

    public void deinit() {
        alDeleteSources(source);
        alDeleteBuffers(buffer);
        alcCloseDevice(device);
    }

}

控制台输出


import java.io.InputStream;
import java.nio.ByteBuffer;

public class AutoByteBuffer {

    private byte[] array = new byte[0];
    private int index;

    public void put(InputStream is) {
        int n;
        byte[] data = new byte[1024];
        try {
            while ((n = is.read(data)) != -1)
                put(data, 0, n);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void put(byte[] src) {
        put(src, 0, src.length);
    }

    public void put(byte[] src, int off, int length) {
        resize(src.length);
        for (int i = 0; i < length; i++) {
            array[index++] = src[off + i];
        }
    }

    protected void resize(int bytes) {
        Math.addExact(index, bytes);
        if (index + bytes >= array.length) {
            int newsize = (int) ((index + bytes) * 1.5 + 0.5);
            if (newsize < index + bytes)
                throw new RuntimeException("Could not store enough memory!");

            byte[] copy = new byte[newsize];
            System.arraycopy(array, 0, copy, 0, index);
            array = copy;
        }
    }

    public ByteBuffer flip() {
        ByteBuffer buffer = ByteBuffer.allocate(index);
        buffer.put(array, 0, index);
        buffer.flip();
        return buffer;
    }

}

1 个答案:

答案 0 :(得分:0)

我仍然不知道发生了什么,但是我如何遵循this教程。花花公子告诉我们使用this代码来加载wav文件,并且看起来一切正常!我的理论是行之有效的,因为它使用LWJGL缓冲区而不是Java缓冲区。查看LWJGL的来源,这似乎很重要,因为它试图获取缓冲区的内存地址。而且,当然,如果LWJGL是创建缓冲区的那个,它将确切知道它在哪里。