| 1 | /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ |
| 2 | /* If you are missing that file, acquire a complete release at teeworlds.com. */ |
| 3 | #ifndef ENGINE_CLIENT_SOUND_H |
| 4 | #define ENGINE_CLIENT_SOUND_H |
| 5 | |
| 6 | #include <base/lock.h> |
| 7 | |
| 8 | #include <engine/sound.h> |
| 9 | |
| 10 | #include <SDL_audio.h> |
| 11 | |
| 12 | #include <atomic> |
| 13 | |
| 14 | struct CSample |
| 15 | { |
| 16 | int m_Index; |
| 17 | int m_NextFreeSampleIndex; |
| 18 | |
| 19 | short *m_pData; |
| 20 | int m_NumFrames; |
| 21 | int m_Rate; |
| 22 | int m_Channels; |
| 23 | int m_LoopStart; |
| 24 | int m_LoopEnd; |
| 25 | int m_PausedAt; |
| 26 | |
| 27 | float TotalTime() const |
| 28 | { |
| 29 | return m_NumFrames / (float)m_Rate; |
| 30 | } |
| 31 | |
| 32 | bool IsLoaded() const |
| 33 | { |
| 34 | return m_pData != nullptr; |
| 35 | } |
| 36 | }; |
| 37 | |
| 38 | struct CChannel |
| 39 | { |
| 40 | int m_Vol; |
| 41 | int m_Pan; |
| 42 | }; |
| 43 | |
| 44 | struct CVoice |
| 45 | { |
| 46 | CSample *m_pSample; |
| 47 | CChannel *m_pChannel; |
| 48 | int m_Age; // increases when reused |
| 49 | int m_Tick; |
| 50 | int m_Vol; // 0 - 255 |
| 51 | int m_Flags; |
| 52 | vec2 m_Position; |
| 53 | float m_Falloff; // [0.0, 1.0] |
| 54 | |
| 55 | int m_Shape; |
| 56 | union |
| 57 | { |
| 58 | ISound::CVoiceShapeCircle m_Circle; |
| 59 | ISound::CVoiceShapeRectangle m_Rectangle; |
| 60 | }; |
| 61 | }; |
| 62 | |
| 63 | class CSound : public IEngineSound |
| 64 | { |
| 65 | enum |
| 66 | { |
| 67 | NUM_SAMPLES = 512, |
| 68 | NUM_VOICES = 256, |
| 69 | NUM_CHANNELS = 16, |
| 70 | }; |
| 71 | |
| 72 | bool m_SoundEnabled = false; |
| 73 | SDL_AudioDeviceID m_Device = 0; |
| 74 | CLock m_SoundLock; |
| 75 | |
| 76 | CSample m_aSamples[NUM_SAMPLES] GUARDED_BY(m_SoundLock) = {{.m_Index: 0}}; |
| 77 | int m_FirstFreeSampleIndex GUARDED_BY(m_SoundLock) = 0; |
| 78 | |
| 79 | CVoice m_aVoices[NUM_VOICES] GUARDED_BY(m_SoundLock) = {{.m_pSample: nullptr}}; |
| 80 | CChannel m_aChannels[NUM_CHANNELS] GUARDED_BY(m_SoundLock) = {{.m_Vol: 255, .m_Pan: 0}}; |
| 81 | int m_NextVoice GUARDED_BY(m_SoundLock) = 0; |
| 82 | uint32_t m_MaxFrames = 0; |
| 83 | |
| 84 | // This is not an std::atomic<vec2> as this would require linking with |
| 85 | // libatomic with clang x86 as there is no native support for this. |
| 86 | std::atomic<float> m_ListenerPositionX = 0.0f; |
| 87 | std::atomic<float> m_ListenerPositionY = 0.0f; |
| 88 | std::atomic<int> m_SoundVolume = 100; |
| 89 | int m_MixingRate = 48000; |
| 90 | |
| 91 | class IEngineGraphics *m_pGraphics = nullptr; |
| 92 | IStorage *m_pStorage = nullptr; |
| 93 | |
| 94 | int *m_pMixBuffer = nullptr; |
| 95 | |
| 96 | CSample *AllocSample() REQUIRES(!m_SoundLock); |
| 97 | void RateConvert(CSample &Sample) const; |
| 98 | |
| 99 | // pContextName used for error |
| 100 | bool DecodeOpus(CSample &Sample, const void *pData, unsigned DataSize, const char *pContextName) const; |
| 101 | bool DecodeWV(CSample &Sample, const void *pData, unsigned DataSize, const char *pContextName) const; |
| 102 | |
| 103 | void UpdateVolume(); |
| 104 | |
| 105 | public: |
| 106 | int Init() override REQUIRES(!m_SoundLock); |
| 107 | int Update() override; |
| 108 | void Shutdown() override REQUIRES(!m_SoundLock); |
| 109 | |
| 110 | bool IsSoundEnabled() override { return m_SoundEnabled; } |
| 111 | |
| 112 | int LoadOpus(const char *pFilename, int StorageType = IStorage::TYPE_ALL) override REQUIRES(!m_SoundLock); |
| 113 | int LoadWV(const char *pFilename, int StorageType = IStorage::TYPE_ALL) override REQUIRES(!m_SoundLock); |
| 114 | int LoadOpusFromMem(const void *pData, unsigned DataSize, bool ForceLoad, const char *pContextName) override REQUIRES(!m_SoundLock); |
| 115 | int LoadWVFromMem(const void *pData, unsigned DataSize, bool ForceLoad, const char *pContextName) override REQUIRES(!m_SoundLock); |
| 116 | void UnloadSample(int SampleId) override REQUIRES(!m_SoundLock); |
| 117 | |
| 118 | float GetSampleTotalTime(int SampleId) override REQUIRES(!m_SoundLock); // in s |
| 119 | float GetSampleCurrentTime(int SampleId) override REQUIRES(!m_SoundLock); // in s |
| 120 | void SetSampleCurrentTime(int SampleId, float Time) override REQUIRES(!m_SoundLock); |
| 121 | |
| 122 | void SetChannel(int ChannelId, float Vol, float Pan) override REQUIRES(!m_SoundLock); |
| 123 | void SetListenerPosition(vec2 Position) override; |
| 124 | |
| 125 | void SetVoiceVolume(CVoiceHandle Voice, float Volume) override REQUIRES(!m_SoundLock); |
| 126 | void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) override REQUIRES(!m_SoundLock); |
| 127 | void SetVoicePosition(CVoiceHandle Voice, vec2 Position) override REQUIRES(!m_SoundLock); |
| 128 | void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) override REQUIRES(!m_SoundLock); // in s |
| 129 | |
| 130 | void SetVoiceCircle(CVoiceHandle Voice, float Radius) override REQUIRES(!m_SoundLock); |
| 131 | void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) override REQUIRES(!m_SoundLock); |
| 132 | |
| 133 | CVoiceHandle Play(int ChannelId, int SampleId, int Flags, float Volume, vec2 Position) REQUIRES(!m_SoundLock); |
| 134 | CVoiceHandle PlayAt(int ChannelId, int SampleId, int Flags, float Volume, vec2 Position) override REQUIRES(!m_SoundLock); |
| 135 | CVoiceHandle Play(int ChannelId, int SampleId, int Flags, float Volume) override REQUIRES(!m_SoundLock); |
| 136 | void Pause(int SampleId) override REQUIRES(!m_SoundLock); |
| 137 | void Stop(int SampleId) override REQUIRES(!m_SoundLock); |
| 138 | void StopAll() override REQUIRES(!m_SoundLock); |
| 139 | void StopVoice(CVoiceHandle Voice) override REQUIRES(!m_SoundLock); |
| 140 | bool IsPlaying(int SampleId) override REQUIRES(!m_SoundLock); |
| 141 | |
| 142 | int MixingRate() const override { return m_MixingRate; } |
| 143 | void Mix(short *pFinalOut, unsigned Frames) override REQUIRES(!m_SoundLock); |
| 144 | |
| 145 | void PauseAudioDevice() override; |
| 146 | void UnpauseAudioDevice() override; |
| 147 | }; |
| 148 | |
| 149 | #endif |
| 150 | |