-
Notifications
You must be signed in to change notification settings - Fork 0
/
audio.cpp
128 lines (98 loc) · 3.18 KB
/
audio.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "audio.h"
SDL_AudioDeviceID Audio::device;
SDL_AudioSpec Audio::spec;
double Audio::frequency;
double Audio::volume;
int Audio::pos;
int (*Audio::calcOffset)(int sample, int channel);
void (*Audio::writeData)(uint8_t* ptr, double data);
int calcOffsets16(int sample, int channel) {
return (sample * sizeof(int16_t) * Audio::spec.channels) + (channel * sizeof(int16_t));
}
int calcOffsetf32(int sample, int channel) {
return (sample * sizeof(float) * Audio::spec.channels) + (channel * sizeof(float));
}
void writeDatas16(uint8_t* ptr, double data) {
int16_t* ptrTyped = (int16_t*) ptr;
double range = (double) INT16_MAX - (double) INT16_MIN;
double dataScaled = data * range / 2.0;
*ptrTyped = data;
}
void writeDataf32(uint8_t* ptr, double data) {
float* ptrTyped = (float*) ptr;
*ptrTyped = data;
}
double Audio::getData() {
double sampleRate = (double) spec.freq;
double period = sampleRate / frequency;
if (pos % (int) period == 0) {
pos = 0;
}
double angularFreq = (1.0 / period) * 2.0 * M_PI;
double amplitude = volume;
return sin((double) pos * angularFreq) * amplitude;
}
void Audio::callback(void* userdata, uint8_t* stream, int len) {
for (int sample = 0; sample < spec.samples; ++sample) {
double data = getData();
pos++;
for (int channel = 0; channel < spec.channels; ++channel) {
int offset = calcOffset(sample, channel);
uint8_t* ptrData = stream + offset;
writeData(ptrData, data);
}
}
}
void Audio::open() {
SDL_AudioSpec desired;
SDL_zero(desired);
desired.freq = 44100;
desired.format = AUDIO_F32;
desired.samples = 512;
desired.channels = 1;
desired.callback = Audio::callback;
device = SDL_OpenAudioDevice(NULL, 0, &desired, &spec, 0);
if (device == 0) {
throw std::runtime_error("AUDIO DEVICE CREATION FAILED.");
} else {
std::string formatName;
switch (spec.format) {
case AUDIO_S16:
writeData = writeDatas16;
calcOffset = calcOffsets16;
formatName = "AUDIO_S16";
break;
case AUDIO_F32:
writeData = writeDataf32;
calcOffset = calcOffsetf32;
formatName = "AUDIO_F32";
break;
default:
throw std::runtime_error("UNSUPPORTED AUDIO FORMAT.");
}
std::cout << "[Beeper] frequency: " << spec.freq << std::endl;
std::cout << "[Beeper] format: " << formatName << std::endl;
std::cout
<< "[Beeper] channels: "
<< (int)(spec.channels)
<< std::endl;
std::cout << "[Beeper] samples: " << spec.samples << std::endl;
std::cout << "[Beeper] padding: " << spec.padding << std::endl;
std::cout << "[Beeper] size: " << spec.size << std::endl;
}
}
void Audio::close() {
SDL_CloseAudioDevice(device);
}
void Audio::setFreq(double freq) {
frequency = freq;
}
void Audio::setVol(double vol) {
volume = vol;
}
void Audio::play() {
SDL_PauseAudioDevice(device, 0);
}
void Audio::stop() {
SDL_PauseAudioDevice(device, 1);
}