All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.com.lehaine.littlekt.audio.OpenALAudioClip.kt Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
package com.lehaine.littlekt.audio

import com.lehaine.littlekt.log.Logger
import org.lwjgl.openal.AL10.*
import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/**
 * @author Colton Daily
 * @date 12/19/2021
 */
class OpenALAudioClip(
    private val context: OpenALAudioContext,
    pcm: ByteArray,
    val channels: Int,
    val sampleRate: Int
) : AudioClip {

    private var bufferID = -1

    override var volume: Float = 1f
    override val duration: Duration

    private val NO_DEVICE get() = context.NO_DEVICE

    init {
        if (NO_DEVICE) {
            logger.error { "Unable to retrieve audio device!" }
        }
        val bytes = pcm.size - (pcm.size % (if (channels > 1) 4 else 2))
        val samples = bytes / (2 * channels)
        duration = (samples / sampleRate.toDouble()).seconds

        val buffer = ByteBuffer.allocateDirect(bytes).apply {
            order(ByteOrder.nativeOrder())
            put(pcm, 0, bytes)
            flip()
        }
        if (bufferID == -1) {
            bufferID = alGenBuffers()
            alBufferData(
                bufferID,
                (if (channels > 1) AL_FORMAT_STEREO16 else AL_FORMAT_MONO16),
                buffer.asShortBuffer(),
                sampleRate
            )
        }
    }


    override fun play(volume: Float, loop: Boolean) = withDevice {
        val sourceId = context.obtainSource()

        if (sourceId == -1) return

        alSourcei(sourceId, AL_BUFFER, bufferID)
        alSourcei(sourceId, AL_LOOPING, if (loop) AL_TRUE else AL_FALSE)
        alSourcef(sourceId, AL_GAIN, volume)
        alSourcePlay(sourceId)
    }

    override fun stop() = withDevice {
        context.stopSourceViaBufferID(bufferID)
    }

    override fun resume() = withDevice {
        context.resumeSourceViaBufferID(bufferID)
    }

    override fun pause() = withDevice {
        context.pauseSourceViaBufferID(bufferID)
    }

    override fun dispose() = withDevice {
        if (bufferID == -1) return

        context.disposeSourceViaBufferID(bufferID)
        bufferID = -1
    }


    private inline fun withDevice(block: () -> Unit) {
        if (NO_DEVICE) return
        block()
    }

    companion object {
        private val logger = Logger()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy