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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
|
/*
* These routines were extracted from the sound hack for olvwm3.3 by
* Andrew "Ender" Scherpbier (turtle@sciences.sdsu.edu, Andrew@SDSU.Edu)
* and modified by J.E. Sacco (jsacco @ssl.com) for tvtwm and twm. They
* were then slightly adapted for ctwm by Mark Boyns (boyns@sdsu.edu),
* and have since been reworked more.
*/
#include "ctwm.h"
#include <rplay.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "event_names.h"
#include "sound.h"
RPLAY **rp = NULL;
static int need_sound_init = 1;
static int sound_from_config = 0;
static int sound_fd = 0;
static int sound_state = 1;
#define HOSTNAME_LEN 200
static char hostname[HOSTNAME_LEN];
/*
* Function to trim away spaces at the start and end of a string
*/
static char *
trim_spaces(char *str)
{
if(str != NULL) {
char *p = str + strlen(str);
while(*str != '\0' && *str != '\r' && *str != '\n' && isspace(*str)) {
str++;
}
/* Assume all line end characters are at the end */
while(p > str && isspace(p[-1])) {
p--;
}
*p = '\0';
}
return str;
}
/*
* Define stuff related to "magic" names.
*/
static const char *magic_events[] = {
"Startup",
"Shutdown",
};
#define NMAGICEVENTS (sizeof(magic_events) / sizeof(*magic_events))
static int
sound_magic_event_name2num(const char *name)
{
int i;
for(i = 0 ; i < NMAGICEVENTS ; i++) {
if(strcasecmp(name, magic_events[i]) == 0) {
/* We number these off the far end of the non-magic events */
return event_names_size() + i;
}
}
return -1;
}
/*
* Now we know how many events we need to store up info for
*/
#define NEVENTS (event_names_size() + NMAGICEVENTS)
/*
* Initialize the subsystem and its necessary bits
*/
void
sound_init(void)
{
if(!need_sound_init) {
return;
}
/* Can't happen */
if(sound_fd != 0) {
fprintf(stderr, "BUG: sound_fd not set but sound inited.\n");
exit(1);
}
need_sound_init = 0;
if(hostname[0] == '\0') {
strncpy(hostname, rplay_default_host(), HOSTNAME_LEN - 1);
hostname[HOSTNAME_LEN - 1] = '\0'; /* JIC */
}
if((sound_fd = rplay_open(hostname)) < 0) {
rplay_perror("create");
}
/*
* Init rp if necessary
*/
if(rp == NULL) {
if((rp = calloc(NEVENTS, sizeof(RPLAY *))) == NULL) {
perror("calloc() rplay control");
exit(1);
/*
* Should maybe just bomb out of sound stuff, but there's
* currently no provision for that. If malloc fails, we're
* pretty screwed anyway, so it's not much loss to just die.
*/
}
}
}
/*
* Clear out any set sounds
*/
void
sound_clear_list(void)
{
int i;
/* JIC */
if(rp == NULL) {
return;
}
/*
* Destroy any old sounds
*/
for(i = 0; i < NEVENTS; i++) {
if(rp[i] != NULL) {
rplay_destroy(rp[i]);
}
rp[i] = NULL;
}
}
/*
* [Re]load the sounds
*/
void
sound_load_list(void)
{
FILE *fl;
char *home;
char *soundfile;
char buffer[100];
/* Guard; shouldn't be possible */
if(rp == NULL) {
fprintf(stderr, "Tried to load sounds before subsystem inited.\n");
exit(1);
}
/* Find the .ctwm-sounds file */
if((home = getenv("HOME")) == NULL) {
home = "";
}
if(asprintf(&soundfile, "%s/.ctwm-sounds", home) < 0) {
perror("Failed building path to sound file");
return;
}
fl = fopen(soundfile, "r");
free(soundfile);
/*
* If it was found, but we already have sound set from the config
* file, complain on stderr and then return.
*/
if(fl != NULL && sound_from_config) {
fprintf(stderr, "RplaySounds set in ctwmrc, not reading "
"~/.ctwm-sounds.\n");
fclose(fl);
return;
}
/* Clear out the old list, whether we have new or not */
sound_clear_list();
/* If there wasn't a .ctwm-sounds file, we're done now */
if(fl == NULL) {
return;
}
/* Now go ahead and parse it in */
while(fgets(buffer, 100, fl) != NULL) {
char *ename, *sndfile;
ename = trim_spaces(strtok(buffer, ": \t"));
if(ename == NULL || *ename == '#') {
continue;
}
sndfile = trim_spaces(strtok(NULL, "\r\n"));
if(sndfile == NULL || *sndfile == '#') {
continue;
}
if(set_sound_event_name(ename, sndfile) != 0) {
fprintf(stderr, "Error adding sound for %s; maybe event "
"name is invalid?\n", ename);
}
}
fclose(fl);
}
/*
* Play sound
*/
void
play_sound(int snd)
{
/* Bounds */
if(snd < 0 || snd >= NEVENTS) {
return;
}
/* Playing enabled */
if(sound_state == 0) {
return;
}
/* Better already be initted */
if(need_sound_init) {
fprintf(stderr, "BUG: play_sound() Sound should be initted already.\n");
return;
}
/* Skip if this isn't a sound we have set */
if(rp[snd] == NULL) {
return;
}
/* And if all else fails, play it */
if(rplay(sound_fd, rp[snd]) < 0) {
rplay_perror("rplay");
}
}
void
play_startup_sound(void)
{
play_sound(sound_magic_event_name2num("Startup"));
}
void
play_exit_sound(void)
{
play_sound(sound_magic_event_name2num("Shutdown"));
}
/*
* Flag that we loaded sounds from the ctwmrc
*/
void
sound_set_from_config(void)
{
sound_from_config = 1;
}
/*
* Toggle the sound on/off
*/
void
toggle_sound(void)
{
sound_state ^= 1;
}
/*
* Re-read the sounds mapping file
*/
void
reread_sounds(void)
{
sound_load_list();
}
/*
* Set the SoundHost and force the sound_fd to be re-opened.
*/
void
set_sound_host(char *host)
{
strncpy(hostname, host, HOSTNAME_LEN - 1);
hostname[HOSTNAME_LEN - 1] = '\0'; /* JIC */
if(sound_fd != 0) {
rplay_close(sound_fd);
}
sound_fd = 0;
}
/*
* Set the sound to play for a given event
*/
int
set_sound_event_name(const char *ename, const char *soundfile)
{
int i;
/* Find the index we'll use in rp[] for it */
i = sound_magic_event_name2num(ename);
if(i < 0) {
i = event_num_by_name(ename);
}
if(i < 0) {
return -1;
}
/* Gotcha */
return set_sound_event(i, soundfile);
}
int
set_sound_event(int snd, const char *soundfile)
{
/* This shouldn't get called before things are initialized */
if(rp == NULL) {
fprintf(stderr, "%s(): internal error: called before initialized.\n", __func__);
exit(1);
}
/* Cleanup old if necessary */
if(rp[snd] != NULL) {
rplay_destroy(rp[snd]);
}
/* Setup new */
rp[snd] = rplay_create(RPLAY_PLAY);
if(rp[snd] == NULL) {
rplay_perror("create");
return -1;
}
if(rplay_set(rp[snd], RPLAY_INSERT, 0, RPLAY_SOUND, soundfile, NULL)
< 0) {
rplay_perror("rplay");
}
return 0;
}
|