/
soundmanager.cpp
106 lines (101 loc) · 3.31 KB
/
soundmanager.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
#include "soundmanager.h"
SoundManager::SoundManager() {
configureSoundDevice();
buffer = new char[frames*4];
bufferIndex = 0;
}
void SoundManager::writeSample(int sample) { // returns frames written (usually zero)
lastSample = sample;
int rc = frames;
sample = sample > CEILING ? CEILING : sample;
sample = sample < -CEILING ? -CEILING : sample;
buffer[bufferIndex * 4] = sample & 255;
buffer[(bufferIndex * 4) + 2] = sample & 255;
buffer[(bufferIndex * 4) + 1] = sample >> 8;
buffer[(bufferIndex * 4) + 3] = sample >> 8;
bufferIndex++;
if(bufferIndex == frames) {
rc = snd_pcm_writei(handle, buffer, frames);
while(rc == -EPIPE) {
printf("error from writei: %s\n", snd_strerror(rc));
rc = snd_pcm_recover(handle, rc, 1);
if(rc != 0) {
fprintf(stderr, "Could not recover from underrun!\n");
exit(1);
}
rc = snd_pcm_writei(handle, buffer, frames);
}
if (rc < 0)
printf("error from writei: %s\n", snd_strerror(rc));
else if (rc != frames)
printf("short write, write %d frames\n", rc);
bufferIndex = 0;
}
}
void SoundManager::configureSoundDevice() {
unsigned int val;
int rc;
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
frames = 32;
hw_buffer = frames*16;
val = SAMPLE_RATE;
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr,
"unable to open pcm device: %s\n",
snd_strerror(rc));
exit(1);
}
snd_pcm_hw_params_alloca(&hw_params);
snd_pcm_hw_params_any(handle, hw_params);
snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, hw_params, 2);
snd_pcm_hw_params_set_rate_near(handle, hw_params, &val, 0);
while(val != SAMPLE_RATE) {
printf("unable to set sample rate, retrying: %s\n", snd_strerror(rc));
snd_pcm_hw_params_set_rate_near(handle, hw_params, &val, 0);
}
rc = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &hw_buffer);
if (rc < 0) {
fprintf(stderr, "unable to set buffer: %s\n", snd_strerror(rc));
exit(1);
}
hw_buffer /= 2;
rc = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &frames, 0);
if (rc < 0) {
fprintf(stderr, "unable to set period_size: %s\n", snd_strerror(rc));
exit(1);
}
rc = snd_pcm_hw_params(handle, hw_params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
snd_pcm_sw_params_alloca(&sw_params);
rc = snd_pcm_sw_params_set_start_threshold(handle, sw_params, hw_buffer-frames);
if (rc < 0) {
fprintf(stderr, "unable to set start threshold: %s\n", snd_strerror(rc));
exit(1);
}
rc = snd_pcm_sw_params_set_avail_min(handle, sw_params, 4);
if (rc < 0) {
fprintf(stderr, "unable to set avail min: %s\n", snd_strerror(rc));
exit(1);
}
rc = snd_pcm_sw_params(handle, sw_params);
if (rc < 0) {
fprintf(stderr, "unable to set sw parameters: %s\n", snd_strerror(rc));
exit(1);
}
if (rc < 0) {
fprintf(stderr, "unable to set sw parameters: %s\n", snd_strerror(rc));
exit(1);
}
}
SoundManager::~SoundManager() {
snd_pcm_drain(handle);
snd_pcm_close(handle);
delete[] buffer;
}