1 | //============================================================================ |
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #ifdef SOUND_SUPPORT |
19 | |
20 | #ifndef SOUND_SDL2_HXX |
21 | #define SOUND_SDL2_HXX |
22 | |
23 | class OSystem; |
24 | class AudioQueue; |
25 | class EmulationTiming; |
26 | class AudioSettings; |
27 | |
28 | #include "SDL_lib.hxx" |
29 | |
30 | #include "bspf.hxx" |
31 | #include "Sound.hxx" |
32 | #include "audio/Resampler.hxx" |
33 | |
34 | /** |
35 | This class implements the sound API for SDL. |
36 | |
37 | @author Stephen Anthony and Christian Speckner (DirtyHairy) |
38 | */ |
39 | class SoundSDL2 : public Sound |
40 | { |
41 | public: |
42 | /** |
43 | Create a new sound object. The init method must be invoked before |
44 | using the object. |
45 | */ |
46 | SoundSDL2(OSystem& osystem, AudioSettings& audioSettings); |
47 | |
48 | /** |
49 | Destructor |
50 | */ |
51 | virtual ~SoundSDL2(); |
52 | |
53 | public: |
54 | /** |
55 | Enables/disables the sound subsystem. |
56 | |
57 | @param enable Either true or false, to enable or disable the sound system |
58 | */ |
59 | void setEnabled(bool enable) override; |
60 | |
61 | /** |
62 | Initializes the sound device. This must be called before any |
63 | calls are made to derived methods. |
64 | */ |
65 | void open(shared_ptr<AudioQueue> audioQueue, EmulationTiming* emulationTiming) override; |
66 | |
67 | /** |
68 | Should be called to close the sound device. Once called the sound |
69 | device can be started again using the open method. |
70 | */ |
71 | void close() override; |
72 | |
73 | /** |
74 | Set the mute state of the sound object. While muted no sound is played. |
75 | |
76 | @param state Mutes sound if true, unmute if false |
77 | |
78 | @return The previous (old) mute state |
79 | */ |
80 | bool mute(bool state) override; |
81 | |
82 | /** |
83 | Toggles the sound mute state. While muted no sound is played. |
84 | |
85 | @return The previous (old) mute state |
86 | */ |
87 | bool toggleMute() override; |
88 | |
89 | /** |
90 | Sets the volume of the sound device to the specified level. The |
91 | volume is given as a percentage from 0 to 100. Values outside |
92 | this range indicate that the volume shouldn't be changed at all. |
93 | |
94 | @param percent The new volume percentage level for the sound device |
95 | */ |
96 | void setVolume(uInt32 percent) override; |
97 | |
98 | /** |
99 | Adjusts the volume of the sound device based on the given direction. |
100 | |
101 | @param direction Increase or decrease the current volume by a predefined |
102 | amount based on the direction (1 = increase, -1 = decrease) |
103 | */ |
104 | void adjustVolume(Int8 direction) override; |
105 | |
106 | /** |
107 | This method is called to provide information about the sound device. |
108 | */ |
109 | string about() const override; |
110 | |
111 | protected: |
112 | /** |
113 | Invoked by the sound callback to process the next sound fragment. |
114 | The stream is 16-bits (even though the callback is 8-bits), since |
115 | the TIASnd class always generates signed 16-bit stereo samples. |
116 | |
117 | @param stream Pointer to the start of the fragment |
118 | @param length Length of the fragment |
119 | */ |
120 | void processFragment(float* stream, uInt32 length); |
121 | |
122 | private: |
123 | /** |
124 | The actual sound device is opened only when absolutely necessary. |
125 | Typically this will only happen once per program run, but it can also |
126 | happen dynamically when changing sample rate and/or fragment size. |
127 | */ |
128 | bool openDevice(); |
129 | |
130 | void initResampler(); |
131 | |
132 | private: |
133 | // Indicates if the sound device was successfully initialized |
134 | bool myIsInitializedFlag; |
135 | |
136 | // Current volume as a percentage (0 - 100) |
137 | uInt32 myVolume; |
138 | float myVolumeFactor; |
139 | |
140 | // Audio specification structure |
141 | SDL_AudioSpec myHardwareSpec; |
142 | |
143 | SDL_AudioDeviceID myDevice; |
144 | |
145 | shared_ptr<AudioQueue> myAudioQueue; |
146 | |
147 | EmulationTiming* myEmulationTiming; |
148 | |
149 | Int16* myCurrentFragment; |
150 | bool myUnderrun; |
151 | |
152 | unique_ptr<Resampler> myResampler; |
153 | |
154 | AudioSettings& myAudioSettings; |
155 | |
156 | string myAboutString; |
157 | |
158 | private: |
159 | // Callback function invoked by the SDL Audio library when it needs data |
160 | static void callback(void* udata, uInt8* stream, int len); |
161 | |
162 | // Following constructors and assignment operators not supported |
163 | SoundSDL2() = delete; |
164 | SoundSDL2(const SoundSDL2&) = delete; |
165 | SoundSDL2(SoundSDL2&&) = delete; |
166 | SoundSDL2& operator=(const SoundSDL2&) = delete; |
167 | SoundSDL2& operator=(SoundSDL2&&) = delete; |
168 | }; |
169 | |
170 | #endif |
171 | |
172 | #endif // SOUND_SUPPORT |
173 | |