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 | #include "AudioSettings.hxx" |
19 | #include "Settings.hxx" |
20 | |
21 | namespace { |
22 | uInt32 lboundInt(int x, int defaultValue) |
23 | { |
24 | return x <= 0 ? defaultValue : x; |
25 | } |
26 | |
27 | AudioSettings::Preset normalizedPreset(int numericPreset) |
28 | { |
29 | return ( |
30 | numericPreset >= static_cast<int>(AudioSettings::Preset::custom) && |
31 | numericPreset <= static_cast<int>(AudioSettings::Preset::ultraQualityMinimalLag) |
32 | ) ? static_cast<AudioSettings::Preset>(numericPreset) : AudioSettings::DEFAULT_PRESET; |
33 | } |
34 | |
35 | AudioSettings::ResamplingQuality normalizeResamplingQuality(int numericResamplingQuality) |
36 | { |
37 | return ( |
38 | numericResamplingQuality >= static_cast<int>(AudioSettings::ResamplingQuality::nearestNeightbour) && |
39 | numericResamplingQuality <= static_cast<int>(AudioSettings::ResamplingQuality::lanczos_3) |
40 | ) ? static_cast<AudioSettings::ResamplingQuality>(numericResamplingQuality) : AudioSettings::DEFAULT_RESAMPLING_QUALITY; |
41 | } |
42 | } |
43 | |
44 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
45 | AudioSettings::AudioSettings(Settings& settings) |
46 | : mySettings(settings), |
47 | myIsPersistent(true) |
48 | { |
49 | setPreset(normalizedPreset(mySettings.getInt(SETTING_PRESET))); |
50 | } |
51 | |
52 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
53 | void AudioSettings::normalize(Settings& settings) |
54 | { |
55 | int settingPreset = settings.getInt(SETTING_PRESET); |
56 | Preset preset = normalizedPreset(settingPreset); |
57 | if (static_cast<int>(preset) != settingPreset) settings.setValue(SETTING_PRESET, static_cast<int>(DEFAULT_PRESET)); |
58 | |
59 | switch (settings.getInt(SETTING_SAMPLE_RATE)) { |
60 | case 44100: |
61 | case 48000: |
62 | case 96000: |
63 | break; |
64 | |
65 | default: |
66 | settings.setValue(SETTING_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); |
67 | break; |
68 | } |
69 | |
70 | switch (settings.getInt(SETTING_FRAGMENT_SIZE)) { |
71 | case 128: |
72 | case 256: |
73 | case 512: |
74 | case 1024: |
75 | case 2048: |
76 | case 4096: |
77 | break; |
78 | |
79 | default: |
80 | settings.setValue(SETTING_FRAGMENT_SIZE, DEFAULT_FRAGMENT_SIZE); |
81 | break; |
82 | } |
83 | |
84 | int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE); |
85 | if (settingBufferSize < 0 || settingBufferSize > MAX_BUFFER_SIZE) settings.setValue(SETTING_BUFFER_SIZE, DEFAULT_BUFFER_SIZE); |
86 | |
87 | int settingHeadroom = settings.getInt(SETTING_HEADROOM); |
88 | if (settingHeadroom < 0 || settingHeadroom > MAX_HEADROOM) settings.setValue(SETTING_HEADROOM, DEFAULT_HEADROOM); |
89 | |
90 | int settingResamplingQuality = settings.getInt(SETTING_RESAMPLING_QUALITY); |
91 | ResamplingQuality resamplingQuality = normalizeResamplingQuality(settingResamplingQuality); |
92 | if (static_cast<int>(resamplingQuality) != settingResamplingQuality) |
93 | settings.setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(DEFAULT_RESAMPLING_QUALITY)); |
94 | |
95 | int settingVolume = settings.getInt(SETTING_VOLUME); |
96 | if (settingVolume < 0 || settingVolume > 100) settings.setValue(SETTING_VOLUME, DEFAULT_VOLUME); |
97 | } |
98 | |
99 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
100 | AudioSettings::Preset AudioSettings::preset() |
101 | { |
102 | updatePresetFromSettings(); |
103 | return myPreset; |
104 | } |
105 | |
106 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
107 | uInt32 AudioSettings::sampleRate() |
108 | { |
109 | updatePresetFromSettings(); |
110 | return customSettings() ? lboundInt(mySettings.getInt(SETTING_SAMPLE_RATE), DEFAULT_SAMPLE_RATE) : myPresetSampleRate; |
111 | } |
112 | |
113 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
114 | uInt32 AudioSettings::fragmentSize() |
115 | { |
116 | updatePresetFromSettings(); |
117 | return customSettings() ? lboundInt(mySettings.getInt(SETTING_FRAGMENT_SIZE), DEFAULT_FRAGMENT_SIZE) : myPresetFragmentSize; |
118 | } |
119 | |
120 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
121 | uInt32 AudioSettings::bufferSize() |
122 | { |
123 | updatePresetFromSettings(); |
124 | // 0 is a valid value -> keep it |
125 | return customSettings() ? lboundInt(mySettings.getInt(SETTING_BUFFER_SIZE), 0) : myPresetBufferSize; |
126 | } |
127 | |
128 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
129 | uInt32 AudioSettings::headroom() |
130 | { |
131 | updatePresetFromSettings(); |
132 | // 0 is a valid value -> keep it |
133 | return customSettings() ? lboundInt(mySettings.getInt(SETTING_HEADROOM), 0) : myPresetHeadroom; |
134 | } |
135 | |
136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
137 | AudioSettings::ResamplingQuality AudioSettings::resamplingQuality() |
138 | { |
139 | updatePresetFromSettings(); |
140 | return customSettings() ? normalizeResamplingQuality(mySettings.getInt(SETTING_RESAMPLING_QUALITY)) : myPresetResamplingQuality; |
141 | } |
142 | |
143 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
144 | bool AudioSettings::stereo() const |
145 | { |
146 | // 0 is a valid value -> keep it |
147 | return mySettings.getBool(SETTING_STEREO); |
148 | } |
149 | |
150 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
151 | uInt32 AudioSettings::volume() const |
152 | { |
153 | // 0 is a valid value -> keep it |
154 | return lboundInt(mySettings.getInt(SETTING_VOLUME), 0); |
155 | } |
156 | |
157 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
158 | bool AudioSettings::enabled() const |
159 | { |
160 | return mySettings.getBool(SETTING_ENABLED); |
161 | } |
162 | |
163 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
164 | uInt32 AudioSettings::dpcPitch() const |
165 | { |
166 | return lboundInt(mySettings.getInt(SETTING_DPC_PITCH), 10000); |
167 | } |
168 | |
169 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
170 | void AudioSettings::setPreset(AudioSettings::Preset preset) |
171 | { |
172 | if (preset == myPreset) return; |
173 | myPreset = preset; |
174 | |
175 | switch (myPreset) { |
176 | case Preset::custom: |
177 | break; |
178 | |
179 | case Preset::lowQualityMediumLag: |
180 | myPresetSampleRate = 44100; |
181 | myPresetFragmentSize = 1024; |
182 | myPresetBufferSize = 6; |
183 | myPresetHeadroom = 5; |
184 | myPresetResamplingQuality = ResamplingQuality::nearestNeightbour; |
185 | break; |
186 | |
187 | case Preset::highQualityMediumLag: |
188 | myPresetSampleRate = 44100; |
189 | myPresetFragmentSize = 1024; |
190 | myPresetBufferSize = 6; |
191 | myPresetHeadroom = 5; |
192 | myPresetResamplingQuality = ResamplingQuality::lanczos_2; |
193 | break; |
194 | |
195 | case Preset::highQualityLowLag: |
196 | myPresetSampleRate = 48000; |
197 | myPresetFragmentSize = 512; |
198 | myPresetBufferSize = 3; |
199 | myPresetHeadroom = 2; |
200 | myPresetResamplingQuality = ResamplingQuality::lanczos_2; |
201 | break; |
202 | |
203 | case Preset::ultraQualityMinimalLag: |
204 | myPresetSampleRate = 96000; |
205 | myPresetFragmentSize = 128; |
206 | myPresetBufferSize = 0; |
207 | myPresetHeadroom = 0; |
208 | myPresetResamplingQuality = ResamplingQuality::lanczos_3; |
209 | break; |
210 | |
211 | default: |
212 | throw runtime_error("invalid preset" ); |
213 | } |
214 | |
215 | if (myIsPersistent) mySettings.setValue(SETTING_PRESET, static_cast<int>(myPreset)); |
216 | } |
217 | |
218 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
219 | void AudioSettings::setSampleRate(uInt32 sampleRate) |
220 | { |
221 | if (!myIsPersistent) return; |
222 | |
223 | mySettings.setValue(SETTING_SAMPLE_RATE, sampleRate); |
224 | normalize(mySettings); |
225 | } |
226 | |
227 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
228 | void AudioSettings::setFragmentSize(uInt32 fragmentSize) |
229 | { |
230 | if (!myIsPersistent) return; |
231 | |
232 | mySettings.setValue(SETTING_FRAGMENT_SIZE, fragmentSize); |
233 | normalize(mySettings); |
234 | } |
235 | |
236 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
237 | void AudioSettings::setBufferSize(uInt32 bufferSize) |
238 | { |
239 | if (!myIsPersistent) return; |
240 | |
241 | mySettings.setValue(SETTING_BUFFER_SIZE, bufferSize); |
242 | normalize(mySettings); |
243 | } |
244 | |
245 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
246 | void AudioSettings::setHeadroom(uInt32 headroom) |
247 | { |
248 | if (!myIsPersistent) return; |
249 | |
250 | mySettings.setValue(SETTING_HEADROOM, headroom); |
251 | normalize(mySettings); |
252 | } |
253 | |
254 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
255 | void AudioSettings::setResamplingQuality(AudioSettings::ResamplingQuality resamplingQuality) |
256 | { |
257 | if (!myIsPersistent) return; |
258 | |
259 | mySettings.setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(resamplingQuality)); |
260 | normalize(mySettings); |
261 | } |
262 | |
263 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
264 | void AudioSettings::setStereo(bool allROMs) |
265 | { |
266 | if(!myIsPersistent) return; |
267 | |
268 | mySettings.setValue(SETTING_STEREO, allROMs); |
269 | } |
270 | |
271 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
272 | void AudioSettings::setDpcPitch(uInt32 pitch) |
273 | { |
274 | if (!myIsPersistent) return; |
275 | |
276 | mySettings.setValue(SETTING_DPC_PITCH, pitch); |
277 | } |
278 | |
279 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
280 | void AudioSettings::setVolume(uInt32 volume) |
281 | { |
282 | if (!myIsPersistent) return; |
283 | |
284 | mySettings.setValue(SETTING_VOLUME, volume); |
285 | normalize(mySettings); |
286 | } |
287 | |
288 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
289 | void AudioSettings::setEnabled(bool isEnabled) |
290 | { |
291 | if (!myIsPersistent) return; |
292 | |
293 | mySettings.setValue(SETTING_ENABLED, isEnabled); |
294 | } |
295 | |
296 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
297 | void AudioSettings::setPersistent(bool isPersistent) |
298 | { |
299 | myIsPersistent = isPersistent; |
300 | } |
301 | |
302 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
303 | bool AudioSettings::customSettings() const |
304 | { |
305 | return myPreset == Preset::custom; |
306 | } |
307 | |
308 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
309 | void AudioSettings::updatePresetFromSettings() |
310 | { |
311 | if (!myIsPersistent) return; |
312 | |
313 | setPreset(normalizedPreset(mySettings.getInt(SETTING_PRESET))); |
314 | } |
315 | |