text: // Copyright: 2021 - 2022, Ziemas
  // SPDX-License-Identifier: ISC
  #pragma once
  #include <list>
  #include <memory>
  #include "common/common_types.h"
  #include "locator.h"
  #include "game/sound/common/synth.h"
  #include "game/sound/common/voice.h"
  
  namespace snd {
  
  enum class toneflag : u16 {
    out_reverb = 1,
    out_dry = 0x10,
  };
  
  struct Tone {
    /*   0 */ s8 Priority;
    /*   1 */ s8 Vol;
    /*   2 */ s8 CenterNote;
    /*   3 */ s8 CenterFine;
    /*   4 */ s16 Pan;
    /*   6 */ s8 MapLow;
    /*   7 */ s8 MapHigh;
    /*   8 */ s8 PBLow;
    /*   9 */ s8 PBHigh;
    /*   a */ s16 ADSR1;
    /*   c */ s16 ADSR2;
    /*   e */ s16 Flags;
    /*  10 */ /*void**/ u32 VAGInSR;
    ///*  14 */ u32 reserved1; confiscated
  
    // FIXME I'd rather restructure things than mess about like this.
    // If we have to edit the structs they should't be loaded like this
    /*  14 */ u32 BankID;
  };
  
  class vag_voice : public voice {
   public:
    vag_voice(Tone& t) : tone(t) {}
    Tone& tone;
    u8 group{0};
    vol_pair basevol{};
    s32 current_pm{0};
    s32 current_pb{0};
    s32 start_note{0};
    s32 start_fine{0};
    bool paused{false};
  };
  
  class voice_manager {
   public:
    voice_manager(synth& synth, locator& loc);
    void start_tone(std::shared_ptr<vag_voice> voice);
    void pause(std::shared_ptr<vag_voice> voice);
    void unpause(std::shared_ptr<vag_voice> voice);
    void set_pan_table(vol_pair* table) { m_pan_table = table; };
  
    vol_pair make_volume(int vol1, int pan1, int vol2, int pan2, int vol3, int pan3);
  
    // This is super silly, but it's what 989snd does
    vol_pair make_volume_b(int sound_vol,
                           int velocity_volume,
                           int pan,
                           int prog_vol,
                           int prog_pan,
                           int tone_vol,
                           int tone_pan);
  
    void set_master_vol(u8 group, s32 volume);
    void set_playback_mode(s32 mode) { m_stereo_or_mono = mode; }
    s16 adjust_vol_to_group(s16 involume, int group);
  
   private:
    synth& m_synth;
    locator& m_locator;
  
    std::list<std::weak_ptr<vag_voice>> m_voices;
    void clean_voices() {
      m_voices.remove_if([](auto& v) { return v.expired(); });
    }
  
    s32 m_stereo_or_mono{0};
  
    std::array<s32, 32> m_master_vol;
    std::array<s32, 32> m_group_duck;
  
    const vol_pair* m_pan_table{nullptr};
  };
  
  }  // namespace snd
  