forked from ares-emulator/ares
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsdl.cpp
114 lines (91 loc) · 3.2 KB
/
sdl.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <SDL3/SDL.h>
struct AudioSDL : AudioDriver {
AudioSDL& self = *this;
AudioSDL(Audio& super) : AudioDriver(super) {}
~AudioSDL() { terminate(); }
auto create() -> bool override {
super.setChannels(2);
super.setFrequency(48000);
super.setLatency(20);
return initialize();
}
auto driver() -> string override { return "SDL"; }
auto ready() -> bool override { return _ready; }
auto hasBlocking() -> bool override { return true; }
auto hasDynamic() -> bool override { return true; }
double bitsPerSample = 0;
auto hasFrequencies() -> vector<u32> override {
return {44100, 48000, 96000};
}
auto hasLatencies() -> vector<u32> override {
return {10, 20, 40, 60, 80, 100};
}
auto setFrequency(u32 frequency) -> bool override { return initialize(); }
auto setLatency(u32 latency) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override { clear(); return true; }
auto clear() -> void override {
if(!ready()) return;
SDL_ClearAudioStream(_stream);
}
auto output(const f64 samples[]) -> void override {
if(!ready()) return;
if(self.blocking) {
auto bytesRemaining = SDL_GetAudioStreamAvailable(_stream);
while(bytesRemaining > _bufferSize) {
//wait for audio to drain
auto bytesToWait = bytesRemaining - _bufferSize;
auto bytesPerSample = bitsPerSample / 8.0;
auto samplesRemaining = bytesToWait / bytesPerSample;
auto secondsRemaining = samplesRemaining / frequency;
usleep(secondsRemaining * 1000000);
bytesRemaining = SDL_GetAudioStreamAvailable(_stream);
}
}
std::unique_ptr<f32[]> output = std::make_unique<f32[]>(channels);
for(auto n : range(channels)) output[n] = samples[n];
SDL_PutAudioStreamData(_stream, &output[0], channels * sizeof(f32));
}
auto level() -> f64 override {
return SDL_GetAudioStreamAvailable(_stream) / ((f64)_bufferSize);
}
private:
auto initialize() -> bool {
terminate();
#if defined(PLATFORM_WINDOWS)
timeBeginPeriod(1);
#endif
SDL_InitSubSystem(SDL_INIT_AUDIO);
SDL_AudioSpec spec;
spec.format = SDL_AUDIO_F32;
spec.channels = 2;
spec.freq = frequency;
auto desired_samples = (latency * frequency) / 1000.0f;
string desired_samples_string = (string)desired_samples;
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, desired_samples_string);
SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
_device = SDL_GetAudioStreamDevice(stream);
SDL_ResumeAudioDevice(_device);
_stream = stream;
frequency = spec.freq;
channels = spec.channels;
int bufferFrameSize;
SDL_GetAudioDeviceFormat(_device, &spec, &bufferFrameSize);
bitsPerSample = SDL_AUDIO_BITSIZE(spec.format);
_bufferSize = bufferFrameSize * channels * 4;
_ready = true;
clear();
return true;
}
auto terminate() -> void {
#if defined(PLATFORM_WINDOWS)
timeEndPeriod(1);
#endif
_ready = false;
SDL_CloseAudioDevice(_device);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
bool _ready = false;
SDL_AudioDeviceID _device = 0;
SDL_AudioStream *_stream;
u32 _bufferSize = 0;
};