Etterna 0.74.4
Loading...
Searching...
No Matches
RageSound.h
1/* RageSound - High-level sound object. */
2
3#ifndef RAGE_SOUND_H
4#define RAGE_SOUND_H
5
6#include "RageSoundPosMap.h"
7#include "RageUtil/Misc/RageThreads.h"
8#include "RageUtil/Misc/RageTimer.h"
9#include "Etterna/Models/Lua/LuaReference.h"
10#include "fft.h"
11
12class RageSoundReader;
13struct lua_State;
14
15struct Butter
16{
17 RageTimer tm;
18 RageTimer hwTime;
19 RageTimer syncTime;
20 float hwPosition;
21 float syncPosition;
22 float acc;
23};
24
25/* Driver interface for sounds: this is what drivers see. */
27{
28 public:
29 virtual ~RageSoundBase() = default;
30 virtual void SoundIsFinishedPlaying() = 0;
31 virtual auto GetDataToPlay(float* buffer,
32 int size,
33 int64_t& iStreamFrame,
34 int& got_bytes) -> int = 0;
35 virtual void CommitPlayingPosition(int64_t iFrameno,
36 int64_t iPosition,
37 int iBytesRead) = 0;
38 [[nodiscard]] virtual auto GetStartTime() const -> RageTimer
39 {
40 return RageZeroTimer;
41 }
42 [[nodiscard]] virtual auto GetLoadedFilePath() const -> std::string = 0;
43};
44
51{
53
54 // The amount of data to play (or loop):
55 float m_StartSecond{ 0 };
56 float m_LengthSeconds{ -1 };
57
58 // Number of seconds to spend fading in.
59 float m_fFadeInSeconds{ 0 };
60
61 // Number of seconds to spend fading out.
62 float m_fFadeOutSeconds{ 0 };
63
64 float m_Volume{ 1.0F };
65 float m_fAttractVolume{ 1.0F }; // multiplies with m_Volume
66
67 /* Number of samples input and output when changing speed.
68 * Currently, this is either 1/1, 5/4 or 4/5. */
69 float m_fPitch{ 1.0F };
70 float m_fSpeed{ 1.0F };
71
72 // Accurate Sync (for now only useful for MP3s)
73 bool m_bAccurateSync{ false };
74
75 /* Optional driver feature: time to actually start playing sounds.
76 * If zero, or if not supported, the sound will start immediately. */
77 RageTimer m_StartTime;
78
81 {
86 M_AUTO
88 } StopMode{
89 M_AUTO
90 };
91
92 bool m_bIsCriticalSound{
93 false
94 }; // "is a sound that should be played even during attract"
95};
96
98{
100
101 /* If true, speed and pitch changes will be supported for this sound, at a
102 * small memory penalty if not used. */
103 bool m_bSupportRateChanging{ false };
104
105 // If true, panning will be supported for this sound.
106 bool m_bSupportPan{ false };
107};
108
109template <class T>
111{
112 public:
113 typedef T value_type;
114 MufftAllocator() noexcept {};
115
116 T* allocate(size_t n) { return static_cast<T*>(mufft_alloc(n * sizeof(T))); }
117 void deallocate(T* p, size_t n) { mufft_free(p); }
118
119 template<typename U>
120 MufftAllocator(const MufftAllocator<U>& other) throw(){};
121};
122
123struct cfloat
124{
125 float real;
126 float imag;
127};
128
130{
131 public:
132 RageSound();
133 ~RageSound() override;
134 RageSound(const RageSound& cpy);
135 auto operator=(const RageSound& cpy) -> RageSound&;
136
137 /* If bPrecache == true, we'll preload the entire file into memory if
138 * small enough. If this is done, a large number of copies of the sound
139 * can be played without much performance penalty. This is useful for
140 * efficiently playing keyed sounds, and for rapidly-repeating sound
141 * effects, such as the music wheel.
142 *
143 * If cache == false, we'll always stream the sound on demand, which
144 * makes loads much faster.
145 *
146 * If the file failed to load, false is returned, Error() is set
147 * and a null sample will be loaded. This makes failed loads nonfatal;
148 * they can be ignored most of the time, so we continue to work if a file
149 * is broken or missing.
150 */
151 auto Load(const std::string& sFile,
152 bool bPrecache,
153 const RageSoundLoadParams* pParams = nullptr) -> bool;
154
155 /* Using this version means the "don't care" about caching. Currently,
156 * this always will not cache the sound; this may become a preference. */
157 auto Load(const std::string& sFile) -> bool;
158
159 /* Load a RageSoundReader that you've set up yourself. Sample rate
160 * conversion will be set up only if needed. Doesn't fail. */
161 void LoadSoundReader(RageSoundReader* pSound);
162
163 // Get the loaded RageSoundReader. While playing, only properties can be
164 // set.
165 auto GetSoundReader() -> RageSoundReader* { return m_pSource; }
166
167 void Unload();
168 auto IsLoaded() const -> bool;
169 void DeleteSelfWhenFinishedPlaying();
170
171 void StartPlaying(float fGiven = 0, bool forcedTime = false);
172 void StopPlaying();
173
174 auto GetError() const -> std::string { return m_sError; }
175
176 void Play(bool is_action, const RageSoundParams* params = nullptr);
177 void PlayCopy(bool is_action,
178 const RageSoundParams* pParams = nullptr) const;
179 void Stop();
180
181 /* Cleanly pause or unpause the sound. If the sound wasn't already playing,
182 * return true and do nothing. */
183 auto Pause(bool bPause) -> bool;
184 bool m_bPaused{ false };
185
186 auto GetLengthSeconds() -> float;
187 auto GetPositionSeconds(bool* approximate = nullptr,
188 RageTimer* Timestamp = nullptr) -> float;
189 auto GetLoadedFilePath() const -> std::string override
190 {
191 return m_sFilePath;
192 }
193 auto IsPlaying() const -> bool { return m_bPlaying; }
194
195 auto GetPlaybackRate() const -> float;
196 auto GetStartTime() const -> RageTimer override;
197 void SetParams(const RageSoundParams& p);
198 auto GetParams() const -> const RageSoundParams& { return m_Param; }
199 auto SetProperty(const std::string& sProperty, float fValue) -> bool;
200 void SetStopModeFromString(const std::string& sStopMode);
201 void SetPositionSeconds(float fGiven);
202
203 void SetPlayBackCallback(const std::shared_ptr<LuaReference>& f,
204 unsigned int bufSize = 1024);
205 std::atomic<bool> pendingPlayBackCall{ false };
206 void ExecutePlayBackCallback(Lua* L);
207
208 // Lua
209 virtual void PushSelf(lua_State* L);
210
211 private:
212 mutable RageMutex m_Mutex;
213
214 RageSoundReader* m_pSource;
215
216 // We keep track of sound blocks we've sent out recently through
217 // GetDataToPlay.
218 pos_map_queue m_HardwareToStreamMap;
219 pos_map_queue m_StreamToSourceMap;
220
221 std::string m_sFilePath;
222
223 void ApplyParams();
224 RageSoundParams m_Param;
225
226 /* Current position of the output sound, in frames. If < 0, nothing will
227 * play until it becomes positive. */
228 int64_t m_iStreamFrame;
229
230 // For all operations related to sound play callbacks
231 std::mutex recentSamplesMutex;
232 unsigned int recentPCMSamplesBufferSize{ 1024 };
233 std::shared_ptr<LuaReference> soundPlayCallback;
234 std::vector<float, MufftAllocator<float>> recentPCMSamples;
235 std::vector<cfloat, MufftAllocator<cfloat>> fftBuffer;
236 mufft_plan_1d *fftPlan{ nullptr };
237
238 /* Hack: When we stop a playing sound, we can't ask the driver the position
239 * (we're not playing); and we can't seek back to the current playing
240 * position when we stop (too slow), but we want to be able to report the
241 * position we were at when we stopped without jumping to the last position
242 * we buffered. Keep track of the position after a seek or stop, so we can
243 * return a sane position when stopped, and when playing but pos_map hasn't
244 * yet been filled. */
245 int m_iStoppedSourceFrame{ 0 };
246 bool m_bPlaying{ false };
247 bool m_bDeleteWhenFinished{ false };
248
249 std::string m_sError;
250
251 Butter m_Pasteurizer{};
252
253 auto GetSourceFrameFromHardwareFrame(int64_t iHardwareFrame,
254 bool* bApproximate = nullptr) const
255 -> int;
256
257 auto SetPositionFrames(int frames = -1) -> bool;
258 auto GetStopMode() const -> RageSoundParams::StopMode_t; // resolves M_AUTO
259
260 void SoundIsFinishedPlaying() override; // called by sound drivers
261
262 public:
263 // These functions are called only by sound drivers.
264
265 /* Returns the number of bytes actually put into pBuffer. If 0 is returned,
266 * it signals the stream to stop; once it's flushed, SoundStopped will be
267 * called. Until then, SOUNDMAN->GetPosition can still be called; the sound
268 * is still playing. */
269 auto GetDataToPlay(float* pBuffer,
270 int iSize,
271 int64_t& iStreamFrame,
272 int& iBytesRead) -> int override;
273 void CommitPlayingPosition(int64_t iHardwareFrame,
274 int64_t iStreamFrame,
275 int iGotFrames) override;
276};
277
278#endif
Definition RageSound.h:111
Definition RageThreads.h:232
Definition RageSound.h:27
Definition RageSoundReader.h:7
Definition RageSound.h:130
Definition RageTimer.h:9
Definition RageSoundPosMap.h:8
Definition RageSound.h:16
Definition RageSound.h:98
The parameters to play a sound.
Definition RageSound.h:51
enum RageSoundParams::StopMode_t M_AUTO
How does the sound stop itself, if it does?
StopMode_t
How does the sound stop itself, if it does?
Definition RageSound.h:81
@ M_CONTINUE
Definition RageSound.h:84
@ M_LOOP
Definition RageSound.h:83
@ M_STOP
Definition RageSound.h:82
Definition RageSound.h:124