Program Listing for File audio_source.hpp

Return to documentation for file (/home/runner/work/Legion-Engine/Legion-Engine/legion/engine/audio/components/audio_source.hpp)

#pragma once
#if !defined(DOXY_EXCLUDE)
#include <AL/al.h>
#include <AL/alc.h>
#endif
#include <audio/data/audio_segment.hpp>

namespace legion::audio
{
    struct audio_source
    {
        friend class AudioSystem;
    public:
        enum sound_properties
        {
            pitch = 1 << 0,
            gain = 1 << 1,
            playState = 1 << 2,
            doRewind = 1 << 3,
            audioHandle = 1 << 4,
            rollOffFactor = 1 << 5,
            looping = 1 << 6
        };

        enum playstate
        {
            stopped,
            playing,
            paused,
        };

        void setPitch(float pitch) noexcept
        {
            m_changes |= sound_properties::pitch; // set b0
            m_pitch = legion::math::max(0.0f, pitch);
        }
        float getPitch() const noexcept { return m_pitch; }
        void setGain(float gain) noexcept
        {
            m_changes |= sound_properties::gain; // set b1
            m_gain = legion::math::max(0.0f, gain);
        }
        float getGain() const noexcept { return m_gain; }

        void setRollOffFactor(float factor) noexcept
        {
            m_changes = sound_properties::rollOffFactor;
            m_rolloffFactor = factor;
        }

        void disableSpatialAudio() noexcept
        {
            setRollOffFactor(0.0f);
        }

        void enableSpatialAudio() noexcept
        {
            setRollOffFactor(1.0f);
        }

        void play() noexcept
        {
            // If the file is already playing or if the file will be played on next update > return
            if (m_nextPlayState == playstate::playing) return;
            m_changes |= sound_properties::playState;
            m_nextPlayState = playstate::playing;
            // Do not set playstate to playing - audiosystem will set it accordingly
        }

        void pause() noexcept
        {
            // If the file is already playing or if the file will be played on next update > return
            if (m_nextPlayState == playstate::paused) return;
            m_changes |= sound_properties::playState;
            m_nextPlayState = playstate::paused;
            // Do not set playstate to paused - audiosystem will set it accordingly
        }

        void stop() noexcept
        {
            // If the file is already playing or if the file will be played on next update > return
            if (m_nextPlayState == playstate::stopped) return;
            m_changes |= sound_properties::playState;
            m_nextPlayState = playstate::stopped;
            // Do not set playstate to stopped - audiosystem will set it accordingly
        }

        bool isPlaying() const noexcept
        {
            return m_playState == playstate::playing;
        }

        bool isPaused() const noexcept
        {
            return m_playState == playstate::paused;
        }

        bool isStopped() const noexcept
        {
            return m_playState == playstate::stopped;
        }

        void setAudioHandle(audio_segment_handle handle) noexcept
        {
            if (handle == m_audio_handle) return;
            m_changes |= sound_properties::audioHandle;
            m_audio_handle = handle;
        }

        void rewind() noexcept
        {
            m_changes |= sound_properties::doRewind;
        }

        audio_segment_handle getAudioHandle() const noexcept
        {
            return m_audio_handle;
        }

        int getChannels() const
        {
            async::readonly_guard guard(m_audio_handle.get().first);
            return m_audio_handle.get().second.channels;
        }

        bool isStereo() const noexcept
        {
            return getChannels() == 2;
        }
        bool isMono() const noexcept
        {
            return getChannels() == 1;
        }

        void setLooping(bool state = false) noexcept
        {
            if (state != m_looping) {
                m_looping = state;
                m_changes |= looping;
            }
        }

        bool isLooping() const noexcept
        {
            return m_looping;
        }


        operator ALuint() const
        {
            return m_sourceId;
        }

    private:
        void clearChanges()
        {
            m_changes ^= m_changes; // Reset
            // The next play state also needs to be reset to be able to properly switch play states
            m_nextPlayState = m_playState;
        }

        ALuint m_sourceId;
        audio_segment_handle m_audio_handle = invalid_audio_segment_handle;

        float m_pitch = 1.0f;
        float m_gain = 1.0f;

        bool m_looping = false;

        playstate m_playState = playstate::stopped;
        playstate m_nextPlayState = playstate::stopped;

        float m_rolloffFactor;

        // Byte to keep track of changes made to audio source
        // For all the values > see enum sound_properties
        // b0 - pitch
        // b1 - gain
        // b2 - play state
        // b3 - rewind (doRewind)
        // b4 - audio handle
        // b5 - roll off factor 3D
        byte m_changes = 0;
    };
}