#pragma once
#include "../System/IOPorts/spu_io.hpp"

namespace JabyEngine {
    namespace SPU {
        using SPU_IO_Values::operator""_vol;
        
        using SRAMAdr      = SPU_IO_Values::SRAMAdr;
        using SimpleVolume = SPU_IO_Values::SimpleVolume;
        using SweepVolume  = SPU_IO_Values::SweepVolume;
        
        struct Voice {
            size_t get_id() const {
                return reinterpret_cast<size_t>(this);
            }

            SRAMAdr allocate(size_t size);
            SRAMAdr allocate(SPU_IO_Values::SampleRate frequency, size_t size);
            void    deallocate();

            void set_sample_rate(SPU_IO_Values::SampleRate frequency) {
                SPU_IO::Voice[Voice::get_id()].sampleRate.write(frequency);
            }

            void set_volume(SimpleVolume left, SimpleVolume right) {
                SPU_IO::Voice[Voice::get_id()].volumeLeft.write(SweepVolume::create(left));
                SPU_IO::Voice[Voice::get_id()].volumeRight.write(SweepVolume::create(right));
            }

            void play() {
                SPU_IO::Key::On.write(SPU_IO_Values::KeyOn::for_specific(Voice::get_id()));
            }

            void play_if_end() {
                if(Voice::is_end()) {
                    Voice::play();
                }
            }

            void stop() {
                SPU_IO::Key::Off.write(SPU_IO_Values::KeyOff::for_specific(Voice::get_id()));
            }

            bool is_end() const {
                return SPU_IO::Voice[Voice::get_id()].adsr_volume.read() == SimpleVolume::mute();
            }
        };

        static auto& voice = __declare_io_port_array(Voice, SPU_IO::VoiceCount, 0x0);
    }
}