Etterna 0.74.4
Loading...
Searching...
No Matches
RageSoundDriver.h
1#ifndef RAGE_SOUND_DRIVER
2#define RAGE_SOUND_DRIVER
3
4#include "RageUtil/Misc/RageThreads.h"
5#include "RageUtil/Misc/RageTimer.h"
6#include "RageUtil/Utils/RageUtil_CircularBuffer.h"
7#include "arch/RageDriver.h"
8
9class RageSoundBase;
10class RageTimer;
12static const int samples_per_block = 512;
13
15{
16 public:
17 /* Pass an empty string to get the default sound driver list. */
18 static RageSoundDriver* Create(const std::string& sDrivers);
19 static DriverList m_pDriverList;
20 static std::string GetDefaultSoundDriverList();
21
22 friend class RageSoundManager;
23
25 ~RageSoundDriver() override;
26
27 /* Initialize. On failure, an error message is returned. */
28 virtual std::string Init() { return std::string(); }
29
30 /* A RageSound calls this to request to be played.
31 * XXX: define what we should do when it can't be played (eg. out of
32 * channels) */
33 void StartMixing(RageSoundBase* pSound);
34
35 /* A RageSound calls this to request it not be played. When this function
36 * returns, snd is no longer valid; ensure no running threads are still
37 * accessing it before returning. This must handle gracefully the case
38 * where snd was not actually being played, though it may print a warning.
39 */
40 void StopMixing(RageSoundBase* pSound);
41
42 /* Pause or unpause the given sound. If the sound was stopped (not paused),
43 * return false and do nothing; otherwise return true and pause or unpause
44 * the sound. Unlike StopMixing, pausing and unpause a sound will not lose
45 * any buffered sound (but will not release any resources associated with
46 * playing the sound, either). */
47 bool PauseMixing(RageSoundBase* pSound, bool bStop);
48
49 /* Get the current hardware frame position, in the same time base as passed
50 * to RageSound::CommitPlayingPosition. */
51 int64_t GetHardwareFrame(RageTimer* pTimer) const;
52 virtual int64_t GetPosition() const = 0;
53
54 /* When a sound is finished playing (GetDataToPlay returns 0) and the sound
55 * has been completely flushed (so GetPosition is no longer meaningful),
56 * call RageSoundBase::SoundIsFinishedPlaying(). */
57
58 /* Optional, if needed: */
59 virtual void Update();
60
61 /* Sound startup latency--delay between Play() being called and actually
62 * hearing it. (This isn't necessarily the same as the buffer latency.) */
63 virtual float GetPlayLatency() const { return 0.0f; }
64
65 virtual int GetSampleRate() const { return 44100; }
66
67 protected:
68 /* Start the decoding. This should be called once the hardware is set up
69 * and GetSampleRate will return the correct value. */
70 void StartDecodeThread();
71
72 /* Call this before calling StartDecodeThread to set the desired decoding
73 * buffer size. This is the number of frames that Mix() will try to be able
74 * to return at once. This should generally be slightly larger than the
75 * sound writeahead, to allow filling the buffer after an underrun. The
76 * default is 4096 frames. */
77 void SetDecodeBufferSize(int frames);
78
79 /* Override this to set the priority of the decoding thread, which should be
80 * above normal priority but not realtime. */
81 virtual void SetupDecodingThread() {}
82
83 /*
84 * Read mixed data.
85 *
86 * pBuf: buffer to read into
87 * iFrames: number of frames (not samples) to read
88 * frameno: frame number at which this sound will be heard
89 * iCurrentFrame: frame number that is currently being heard
90 *
91 * iCurrentFrame is used for handling start timing.
92 *
93 * This function only mixes data; it will not lock any mutexes or do any
94 * file access, and is safe to call from a realtime thread.
95 */
96 void Mix(int16_t* pBuf,
97 int iFrames,
98 int64_t iFrameNumber,
99 int64_t iCurrentFrame);
100 void Mix(float* pBuf,
101 int iFrames,
102 int64_t iFrameNumber,
103 int64_t iCurrentFrame);
104
105 void MixDeinterlaced(float** pBufs,
106 int channels,
107 int iFrames,
108 int64_t iFrameNumber,
109 int64_t iCurrentFrame);
110
111 private:
112 /* This mutex is used for serializing with the decoder thread. Locking this
113 * mutex can take a while. */
114 RageMutex m_Mutex;
115
116 /* This mutex locks all sounds[] which are "available". (Other sound may
117 * safely be accessed, and sounds may be set to available, without locking
118 * this.) */
119 RageMutex m_SoundListMutex;
120
121 /*
122 * Thread safety and state transitions:
123 *
124 * AVAILABLE: The sound is available to play a new sound. The decoding and
125 * mixing threads will not touch a sound in this state.
126 *
127 * BUFFERING: The sound is stopped but StartMixing() is prebuffering. No
128 * other threads will touch a sound that is BUFFERING. This isn't necessary
129 * if only the main thread can call StartMixing().
130 *
131 * STOPPED: The sound is idle, but memory is still allocated for its buffer.
132 * Update() will deallocate memory and the sound will be changed to
133 * AVAILABLE.
134 *
135 * PLAYING: The sound is being decoded by the decoding thread, and played by
136 * the mixing thread. If the decoding thread hits EOF, the decoding thread
137 * will change the state to STOPPING.
138 *
139 * STOPPING: The sound is being played by the mixing thread. No new data
140 * will be decoded. Once the data buffer is empty (all sound has been
141 * played), Update() will change the sound to HALTING.
142 *
143 * HALTING: The main thread has called StopMixing or the data buffer is
144 * empty. The mixing thread will flush any remaining buffered data without
145 * playing it, and then move the sound to STOPPED.
146 *
147 * The mixing thread operates without any locks. This can lead to a little
148 * overlap. For example, if StopMixing() is called, moving the sound from
149 * PLAYING to HALTING, the mixing thread might be in the middle of mixing
150 * data. Although HALTING means "discard buffered data", some data will
151 * still be mixed. This is OK; the data is valid, and the flush will happen
152 * on the next iteration.
153 *
154 * The only state change made by the decoding thread is on EOF: the state is
155 * changed from PLAYING to STOPPING. This is done while m_Mutex is held, to
156 * prevent races with other threads.
157 *
158 * The only state change made by the mixing thread is from HALTING to
159 * STOPPED. This is done with no locks; no other thread can take a sound out
160 * of the HALTING state.
161 *
162 * Do not allocate or deallocate memory in the mixing thread since
163 * allocating memory involves taking a lock. Instead, push the deallocation
164 * to the main thread.
165 */
166 struct sound_block
167 {
168 float m_Buffer[samples_per_block];
169 float* m_BufferNext; // beginning of the unread data
170 int m_FramesInBuffer{ 0 }; // total number of frames at m_BufferNext
171 int64_t m_iPosition; // stream frame of m_BufferNext
172 sound_block()
173 : m_BufferNext(m_Buffer)
174 , m_iPosition(0)
175 {
176 }
177 };
178
179 struct Sound
180 {
181 Sound();
182 void Allocate(int iFrames);
183 void Deallocate();
184
185 RageSoundBase* m_pSound;
186 RageTimer m_StartTime;
187 CircBuf<sound_block> m_Buffer;
188
189 bool m_bPaused;
190
192 {
193 int iFrames;
194 int64_t iStreamFrame;
195 int64_t iHardwareFrame;
196 };
197
198 CircBuf<QueuedPosMap> m_PosMapQueue;
199
200 enum
201 {
202 AVAILABLE,
203 BUFFERING,
204 STOPPED, /* idle */
205
206 /* This state is set by the decoder thread, indicating that the
207 * sound has just reached EOF. Once the mixing thread finishes
208 * flushing buffer, it'll change to the STOPPING_FINISH state. */
209 STOPPING,
210
211 HALTING, /* stop immediately */
212 PLAYING
213 } m_State;
214 };
215
216 /* List of currently playing sounds: XXX no vector */
217 Sound m_Sounds[32];
218
219 int64_t ClampHardwareFrame(int64_t iHardwareFrame) const;
220 mutable int64_t m_iMaxHardwareFrame;
221
222 bool m_bShutdownDecodeThread;
223
224 static int DecodeThread_start(void* p);
225 void DecodeThread();
226 RageSoundMixBuffer& MixIntoBuffer(int iFrames,
227 int64_t iFrameNumber,
228 int64_t iCurrentFrame);
229 RageThread m_DecodeThread;
230
231 int GetDataForSound(Sound& s);
232};
233
234// Can't use Create##name because many of these have -sw suffixes.
235#define REGISTER_SOUND_DRIVER_CLASS2(name, x) \
236 static RegisterRageDriver register_##x( \
237 &RageSoundDriver::m_pDriverList, \
238 #name, \
239 CreateClass<RageSoundDriver_##x, RageDriver>)
240#define REGISTER_SOUND_DRIVER_CLASS(name) \
241 REGISTER_SOUND_DRIVER_CLASS2(name, name)
242
243#endif
Definition RageUtil_CircularBuffer.h:10
Definition RageDriver.h:7
Definition RageThreads.h:232
Definition RageSound.h:27
Definition RageSoundDriver.h:15
Definition RageSoundManager.h:18
Definition RageSoundMixBuffer.h:7
Thread, mutex, semaphore, and event classes.
Definition RageThreads.h:155
Definition RageTimer.h:9
Definition RageDriver.h:17
Definition RageSoundDriver.h:192