diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_audio.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/s_audio.c | 1746 |
1 files changed, 1746 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_audio.c b/apps/plugins/pdbox/PDa/src/s_audio.c new file mode 100644 index 0000000000..4cb93307b0 --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/s_audio.c | |||
@@ -0,0 +1,1746 @@ | |||
1 | /* Copyright (c) 2003, Miller Puckette and others. | ||
2 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
3 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
4 | |||
5 | /* machine-independent (well, mostly!) audio layer. Stores and recalls | ||
6 | audio settings from argparse routine and from dialog window. | ||
7 | */ | ||
8 | |||
9 | #include "m_pd.h" | ||
10 | #include "s_stuff.h" | ||
11 | #include <stdio.h> | ||
12 | #ifdef UNIX | ||
13 | #include <unistd.h> | ||
14 | #include <sys/time.h> | ||
15 | #include <sys/resource.h> | ||
16 | #endif | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <errno.h> | ||
20 | |||
21 | #define SYS_DEFAULTCH 2 | ||
22 | #define SYS_MAXCH 100 | ||
23 | #define SYS_DEFAULTSRATE 44100 | ||
24 | typedef long t_pa_sample; | ||
25 | #define SYS_SAMPLEWIDTH sizeof(t_pa_sample) | ||
26 | #define SYS_BYTESPERCHAN (DEFDACBLKSIZE * SYS_SAMPLEWIDTH) | ||
27 | #define SYS_XFERSAMPS (SYS_DEFAULTCH*DEFDACBLKSIZE) | ||
28 | #define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS) | ||
29 | |||
30 | /* these are set in this file when opening audio, but then may be reduced, | ||
31 | even to zero, in the system dependent open_audio routines. */ | ||
32 | int sys_inchannels; | ||
33 | int sys_outchannels; | ||
34 | int sys_advance_samples; /* scheduler advance in samples */ | ||
35 | int sys_blocksize = 0; /* audio I/O block size in sample frames */ | ||
36 | int sys_audioapi = API_DEFAULT; | ||
37 | |||
38 | static int sys_meters; /* true if we're metering */ | ||
39 | static float sys_inmax; /* max input amplitude */ | ||
40 | static float sys_outmax; /* max output amplitude */ | ||
41 | |||
42 | /* exported variables */ | ||
43 | int sys_schedadvance; /* scheduler advance in microseconds */ | ||
44 | float sys_dacsr; | ||
45 | |||
46 | #ifdef MACOSX | ||
47 | int sys_hipriority = 1; | ||
48 | #else | ||
49 | int sys_hipriority = 0; | ||
50 | #endif | ||
51 | |||
52 | t_sample *sys_soundout; | ||
53 | t_sample *sys_soundin; | ||
54 | |||
55 | /* the "state" is normally one if we're open and zero otherwise; | ||
56 | but if the state is one, we still haven't necessarily opened the | ||
57 | audio hardware; see audio_isopen() below. */ | ||
58 | static int audio_state; | ||
59 | |||
60 | /* last requested parameters */ | ||
61 | static int audio_naudioindev; | ||
62 | static int audio_audioindev[MAXAUDIOINDEV]; | ||
63 | static int audio_audiochindev[MAXAUDIOINDEV]; | ||
64 | static int audio_naudiooutdev; | ||
65 | static int audio_audiooutdev[MAXAUDIOOUTDEV]; | ||
66 | static int audio_audiochoutdev[MAXAUDIOOUTDEV]; | ||
67 | static int audio_rate; | ||
68 | static int audio_advance; | ||
69 | |||
70 | static int audio_isopen(void) | ||
71 | { | ||
72 | return (audio_state && | ||
73 | ((audio_naudioindev > 0 && audio_audiochindev[0] > 0) | ||
74 | || (audio_naudiooutdev > 0 && audio_audiochoutdev[0] > 0))); | ||
75 | } | ||
76 | |||
77 | static void sys_get_audio_params( | ||
78 | int *pnaudioindev, int *paudioindev, int *chindev, | ||
79 | int *pnaudiooutdev, int *paudiooutdev, int *choutdev, | ||
80 | int *prate, int *padvance) | ||
81 | { | ||
82 | int i; | ||
83 | *pnaudioindev = audio_naudioindev; | ||
84 | for (i = 0; i < MAXAUDIOINDEV; i++) | ||
85 | paudioindev[i] = audio_audioindev[i], | ||
86 | chindev[i] = audio_audiochindev[i]; | ||
87 | *pnaudiooutdev = audio_naudiooutdev; | ||
88 | for (i = 0; i < MAXAUDIOOUTDEV; i++) | ||
89 | paudiooutdev[i] = audio_audiooutdev[i], | ||
90 | choutdev[i] = audio_audiochoutdev[i]; | ||
91 | *prate = audio_rate; | ||
92 | *padvance = audio_advance; | ||
93 | } | ||
94 | |||
95 | static void sys_save_audio_params( | ||
96 | int naudioindev, int *audioindev, int *chindev, | ||
97 | int naudiooutdev, int *audiooutdev, int *choutdev, | ||
98 | int rate, int advance) | ||
99 | { | ||
100 | int i; | ||
101 | audio_naudioindev = naudioindev; | ||
102 | for (i = 0; i < MAXAUDIOINDEV; i++) | ||
103 | audio_audioindev[i] = audioindev[i], | ||
104 | audio_audiochindev[i] = chindev[i]; | ||
105 | audio_naudiooutdev = naudiooutdev; | ||
106 | for (i = 0; i < MAXAUDIOOUTDEV; i++) | ||
107 | audio_audiooutdev[i] = audiooutdev[i], | ||
108 | audio_audiochoutdev[i] = choutdev[i]; | ||
109 | audio_rate = rate; | ||
110 | audio_advance = advance; | ||
111 | } | ||
112 | |||
113 | /* init routines for any API which needs to set stuff up before | ||
114 | any other API gets used. This is only true of OSS so far. */ | ||
115 | #ifdef USEAPI_OSS | ||
116 | void oss_init(void); | ||
117 | #endif | ||
118 | |||
119 | static void audio_init( void) | ||
120 | { | ||
121 | static int initted = 0; | ||
122 | if (initted) | ||
123 | return; | ||
124 | initted = 1; | ||
125 | #ifdef USEAPI_OSS | ||
126 | oss_init(); | ||
127 | #endif | ||
128 | } | ||
129 | |||
130 | /* set channels and sample rate. */ | ||
131 | |||
132 | static void sys_setchsr(int chin, int chout, int sr) | ||
133 | { | ||
134 | int nblk; | ||
135 | int inbytes = (chin ? chin : 2) * (DEFDACBLKSIZE*sizeof(float)); | ||
136 | int outbytes = (chout ? chout : 2) * (DEFDACBLKSIZE*sizeof(float)); | ||
137 | |||
138 | sys_inchannels = chin; | ||
139 | sys_outchannels = chout; | ||
140 | sys_dacsr = sr; | ||
141 | sys_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.); | ||
142 | if (sys_advance_samples < 3 * DEFDACBLKSIZE) | ||
143 | sys_advance_samples = 3 * DEFDACBLKSIZE; | ||
144 | |||
145 | if (sys_soundin) | ||
146 | free(sys_soundin); | ||
147 | sys_soundin = (t_float *)malloc(inbytes); | ||
148 | memset(sys_soundin, 0, inbytes); | ||
149 | |||
150 | if (sys_soundout) | ||
151 | free(sys_soundout); | ||
152 | sys_soundout = (t_float *)malloc(outbytes); | ||
153 | memset(sys_soundout, 0, outbytes); | ||
154 | |||
155 | if (sys_verbose) | ||
156 | post("input channels = %d, output channels = %d", | ||
157 | sys_inchannels, sys_outchannels); | ||
158 | canvas_resume_dsp(canvas_suspend_dsp()); | ||
159 | } | ||
160 | |||
161 | /* ----------------------- public routines ----------------------- */ | ||
162 | |||
163 | /* open audio devices (after cleaning up the specified device and channel | ||
164 | vectors). The audio devices are "zero based" (i.e. "0" means the first | ||
165 | one.) We also save the cleaned-up device specification so that we | ||
166 | can later re-open audio and/or show the settings on a dialog window. */ | ||
167 | |||
168 | void sys_open_audio(int naudioindev, int *audioindev, int nchindev, | ||
169 | int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, | ||
170 | int *choutdev, int rate, int advance, int enable) | ||
171 | { | ||
172 | int i, *ip; | ||
173 | int defaultchannels = SYS_DEFAULTCH; | ||
174 | int inchans, outchans; | ||
175 | if (rate < 1) | ||
176 | rate = SYS_DEFAULTSRATE; | ||
177 | audio_init(); | ||
178 | /* Since the channel vector might be longer than the | ||
179 | audio device vector, or vice versa, we fill the shorter one | ||
180 | in to match the longer one. Also, if both are empty, we fill in | ||
181 | one device (the default) and two channels. */ | ||
182 | if (naudioindev == -1) | ||
183 | { /* no input audio devices specified */ | ||
184 | if (nchindev == -1) | ||
185 | { | ||
186 | nchindev=1; | ||
187 | chindev[0] = defaultchannels; | ||
188 | naudioindev = 1; | ||
189 | audioindev[0] = DEFAULTAUDIODEV; | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | for (i = 0; i < MAXAUDIOINDEV; i++) | ||
194 | audioindev[i] = i; | ||
195 | naudioindev = nchindev; | ||
196 | } | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | if (nchindev == -1) | ||
201 | { | ||
202 | nchindev = naudioindev; | ||
203 | for (i = 0; i < naudioindev; i++) | ||
204 | chindev[i] = defaultchannels; | ||
205 | } | ||
206 | else if (nchindev > naudioindev) | ||
207 | { | ||
208 | for (i = naudioindev; i < nchindev; i++) | ||
209 | { | ||
210 | if (i == 0) | ||
211 | audioindev[0] = DEFAULTAUDIODEV; | ||
212 | else audioindev[i] = audioindev[i-1] + 1; | ||
213 | } | ||
214 | naudioindev = nchindev; | ||
215 | } | ||
216 | else if (nchindev < naudioindev) | ||
217 | { | ||
218 | for (i = nchindev; i < naudioindev; i++) | ||
219 | { | ||
220 | if (i == 0) | ||
221 | chindev[0] = defaultchannels; | ||
222 | else chindev[i] = chindev[i-1]; | ||
223 | } | ||
224 | naudioindev = nchindev; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | if (naudiooutdev == -1) | ||
229 | { /* not set */ | ||
230 | if (nchoutdev == -1) | ||
231 | { | ||
232 | nchoutdev=1; | ||
233 | choutdev[0]=defaultchannels; | ||
234 | naudiooutdev=1; | ||
235 | audiooutdev[0] = DEFAULTAUDIODEV; | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | for (i = 0; i < MAXAUDIOOUTDEV; i++) | ||
240 | audiooutdev[i] = i; | ||
241 | naudiooutdev = nchoutdev; | ||
242 | } | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | if (nchoutdev == -1) | ||
247 | { | ||
248 | nchoutdev = naudiooutdev; | ||
249 | for (i = 0; i < naudiooutdev; i++) | ||
250 | choutdev[i] = defaultchannels; | ||
251 | } | ||
252 | else if (nchoutdev > naudiooutdev) | ||
253 | { | ||
254 | for (i = naudiooutdev; i < nchoutdev; i++) | ||
255 | { | ||
256 | if (i == 0) | ||
257 | audiooutdev[0] = DEFAULTAUDIODEV; | ||
258 | else audiooutdev[i] = audiooutdev[i-1] + 1; | ||
259 | } | ||
260 | naudiooutdev = nchoutdev; | ||
261 | } | ||
262 | else if (nchoutdev < naudiooutdev) | ||
263 | { | ||
264 | for (i = nchoutdev; i < naudiooutdev; i++) | ||
265 | { | ||
266 | if (i == 0) | ||
267 | choutdev[0] = defaultchannels; | ||
268 | else choutdev[i] = choutdev[i-1]; | ||
269 | } | ||
270 | naudiooutdev = nchoutdev; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* count total number of input and output channels */ | ||
275 | for (i = inchans = 0; i < naudioindev; i++) | ||
276 | inchans += chindev[i]; | ||
277 | for (i = outchans = 0; i < naudiooutdev; i++) | ||
278 | outchans += choutdev[i]; | ||
279 | /* if no input or output devices seem to have been specified, | ||
280 | this really means just disable audio, which we now do. Meanwhile, | ||
281 | we can set audio input and output devices to their defaults. */ | ||
282 | if (!inchans && !outchans) | ||
283 | { | ||
284 | enable = 0; | ||
285 | naudioindev = nchindev = naudiooutdev = nchoutdev = 1; | ||
286 | audioindev[0] = audiooutdev[0] = DEFAULTAUDIODEV; | ||
287 | chindev[0] = choutdev[0] = 0; | ||
288 | } | ||
289 | sys_schedadvance = advance * 1000; | ||
290 | sys_setchsr(inchans, outchans, rate); | ||
291 | sys_log_error(ERR_NOTHING); | ||
292 | |||
293 | if (enable && (inchans > 0 || outchans > 0)) | ||
294 | { | ||
295 | #ifdef USEAPI_PORTAUDIO | ||
296 | if (sys_audioapi == API_PORTAUDIO) | ||
297 | { | ||
298 | int blksize = (sys_blocksize ? sys_blocksize : 64); | ||
299 | pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, | ||
300 | blksize, sys_advance_samples/blksize, | ||
301 | (naudiooutdev > 0 ? audioindev[0] : 0), | ||
302 | (naudiooutdev > 0 ? audiooutdev[0] : 0)); | ||
303 | } | ||
304 | else | ||
305 | #endif | ||
306 | #ifdef USEAPI_JACK | ||
307 | if (sys_audioapi == API_JACK) | ||
308 | jack_open_audio((naudioindev > 0 ? chindev[0] : 0), | ||
309 | (naudiooutdev > 0 ? choutdev[0] : 0), rate); | ||
310 | |||
311 | else | ||
312 | #endif | ||
313 | #ifdef USEAPI_OSS | ||
314 | if (sys_audioapi == API_OSS) | ||
315 | oss_open_audio(naudioindev, audioindev, nchindev, chindev, | ||
316 | naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); | ||
317 | else | ||
318 | #endif | ||
319 | #ifdef USEAPI_ALSA | ||
320 | /* for alsa, only one device is supported; it may | ||
321 | be open for both input and output. */ | ||
322 | if (sys_audioapi == API_ALSA) | ||
323 | alsa_open_audio(naudioindev, audioindev, nchindev, chindev, | ||
324 | naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); | ||
325 | else | ||
326 | #endif | ||
327 | #ifdef USEAPI_MMIO | ||
328 | if (sys_audioapi == API_MMIO) | ||
329 | mmio_open_audio(naudioindev, audioindev, nchindev, chindev, | ||
330 | naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); | ||
331 | else | ||
332 | #endif | ||
333 | post("unknown audio API specified"); | ||
334 | } | ||
335 | sys_save_audio_params(naudioindev, audioindev, chindev, | ||
336 | naudiooutdev, audiooutdev, choutdev, rate, advance); | ||
337 | if (sys_inchannels == 0 && sys_outchannels == 0) | ||
338 | enable = 0; | ||
339 | audio_state = enable; | ||
340 | sys_vgui("set pd_whichapi %d\n", (audio_isopen() ? sys_audioapi : 0)); | ||
341 | sched_set_using_dacs(enable); | ||
342 | } | ||
343 | |||
344 | void sys_close_audio(void) | ||
345 | { | ||
346 | if (!audio_isopen()) | ||
347 | return; | ||
348 | #ifdef USEAPI_PORTAUDIO | ||
349 | if (sys_audioapi == API_PORTAUDIO) | ||
350 | pa_close_audio(); | ||
351 | else | ||
352 | #endif | ||
353 | #ifdef USEAPI_JACK | ||
354 | if (sys_audioapi == API_JACK) | ||
355 | jack_close_audio(); | ||
356 | else | ||
357 | #endif | ||
358 | #ifdef USEAPI_OSS | ||
359 | if (sys_audioapi == API_OSS) | ||
360 | oss_close_audio(); | ||
361 | else | ||
362 | #endif | ||
363 | #ifdef USEAPI_ALSA | ||
364 | if (sys_audioapi == API_ALSA) | ||
365 | alsa_close_audio(); | ||
366 | else | ||
367 | #endif | ||
368 | #ifdef USEAPI_MMIO | ||
369 | if (sys_audioapi == API_MMIO) | ||
370 | mmio_close_audio(); | ||
371 | else | ||
372 | #endif | ||
373 | post("sys_close_audio: unknown API %d", sys_audioapi); | ||
374 | sys_inchannels = sys_outchannels = 0; | ||
375 | } | ||
376 | |||
377 | /* open audio using whatever parameters were last used */ | ||
378 | void sys_reopen_audio( void) | ||
379 | { | ||
380 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
381 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
382 | int rate, advance; | ||
383 | sys_get_audio_params(&naudioindev, audioindev, chindev, | ||
384 | &naudiooutdev, audiooutdev, choutdev, &rate, &advance); | ||
385 | sys_open_audio(naudioindev, audioindev, naudioindev, chindev, | ||
386 | naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, 1); | ||
387 | } | ||
388 | |||
389 | int sys_send_dacs(void) | ||
390 | { | ||
391 | if (sys_meters) | ||
392 | { | ||
393 | int i, n; | ||
394 | float maxsamp; | ||
395 | for (i = 0, n = sys_inchannels * DEFDACBLKSIZE, maxsamp = sys_inmax; | ||
396 | i < n; i++) | ||
397 | { | ||
398 | float f = sys_soundin[i]; | ||
399 | if (f > maxsamp) maxsamp = f; | ||
400 | else if (-f > maxsamp) maxsamp = -f; | ||
401 | } | ||
402 | sys_inmax = maxsamp; | ||
403 | for (i = 0, n = sys_outchannels * DEFDACBLKSIZE, maxsamp = sys_outmax; | ||
404 | i < n; i++) | ||
405 | { | ||
406 | float f = sys_soundout[i]; | ||
407 | if (f > maxsamp) maxsamp = f; | ||
408 | else if (-f > maxsamp) maxsamp = -f; | ||
409 | } | ||
410 | sys_outmax = maxsamp; | ||
411 | } | ||
412 | |||
413 | #ifdef USEAPI_PORTAUDIO | ||
414 | if (sys_audioapi == API_PORTAUDIO) | ||
415 | return (pa_send_dacs()); | ||
416 | else | ||
417 | #endif | ||
418 | #ifdef USEAPI_JACK | ||
419 | if (sys_audioapi == API_JACK) | ||
420 | return (jack_send_dacs()); | ||
421 | else | ||
422 | #endif | ||
423 | #ifdef USEAPI_OSS | ||
424 | if (sys_audioapi == API_OSS) | ||
425 | return (oss_send_dacs()); | ||
426 | else | ||
427 | #endif | ||
428 | #ifdef USEAPI_ALSA | ||
429 | if (sys_audioapi == API_ALSA) | ||
430 | return (alsa_send_dacs()); | ||
431 | else | ||
432 | #endif | ||
433 | #ifdef USEAPI_MMIO | ||
434 | if (sys_audioapi == API_MMIO) | ||
435 | return (mmio_send_dacs()); | ||
436 | else | ||
437 | #endif | ||
438 | post("unknown API"); | ||
439 | return (0); | ||
440 | } | ||
441 | |||
442 | float sys_getsr(void) | ||
443 | { | ||
444 | return (sys_dacsr); | ||
445 | } | ||
446 | |||
447 | int sys_get_outchannels(void) | ||
448 | { | ||
449 | return (sys_outchannels); | ||
450 | } | ||
451 | |||
452 | int sys_get_inchannels(void) | ||
453 | { | ||
454 | return (sys_inchannels); | ||
455 | } | ||
456 | |||
457 | void sys_audiobuf(int n) | ||
458 | { | ||
459 | /* set the size, in milliseconds, of the audio FIFO */ | ||
460 | if (n < 5) n = 5; | ||
461 | else if (n > 5000) n = 5000; | ||
462 | sys_schedadvance = n * 1000; | ||
463 | } | ||
464 | |||
465 | void sys_getmeters(float *inmax, float *outmax) | ||
466 | { | ||
467 | if (inmax) | ||
468 | { | ||
469 | sys_meters = 1; | ||
470 | *inmax = sys_inmax; | ||
471 | *outmax = sys_outmax; | ||
472 | } | ||
473 | else | ||
474 | sys_meters = 0; | ||
475 | sys_inmax = sys_outmax = 0; | ||
476 | } | ||
477 | |||
478 | void sys_reportidle(void) | ||
479 | { | ||
480 | } | ||
481 | |||
482 | #define MAXNDEV 20 | ||
483 | #define DEVDESCSIZE 80 | ||
484 | |||
485 | static void audio_getdevs(char *indevlist, int *nindevs, | ||
486 | char *outdevlist, int *noutdevs, int *canmulti, | ||
487 | int maxndev, int devdescsize) | ||
488 | { | ||
489 | audio_init(); | ||
490 | #ifdef USEAPI_OSS | ||
491 | if (sys_audioapi == API_OSS) | ||
492 | { | ||
493 | oss_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
494 | maxndev, devdescsize); | ||
495 | } | ||
496 | else | ||
497 | #endif | ||
498 | #ifdef USEAPI_ALSA | ||
499 | if (sys_audioapi == API_ALSA) | ||
500 | { | ||
501 | alsa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
502 | maxndev, devdescsize); | ||
503 | } | ||
504 | else | ||
505 | #endif | ||
506 | #ifdef USEAPI_PORTAUDIO | ||
507 | if (sys_audioapi == API_PORTAUDIO) | ||
508 | { | ||
509 | pa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
510 | maxndev, devdescsize); | ||
511 | } | ||
512 | else | ||
513 | #endif | ||
514 | #ifdef USEAPI_MMIO | ||
515 | if (sys_audioapi == API_MMIO) | ||
516 | { | ||
517 | mmio_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
518 | maxndev, devdescsize); | ||
519 | } | ||
520 | else | ||
521 | #endif | ||
522 | { | ||
523 | /* this shouldn't happen once all the above get filled in. */ | ||
524 | int i; | ||
525 | *nindevs = *noutdevs = 3; | ||
526 | for (i = 0; i < 3; i++) | ||
527 | { | ||
528 | sprintf(indevlist + i * devdescsize, "input device #%d", i+1); | ||
529 | sprintf(outdevlist + i * devdescsize, "output device #%d", i+1); | ||
530 | } | ||
531 | *canmulti = 0; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | #ifdef MSW | ||
536 | #define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */ | ||
537 | #else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */ | ||
538 | #define DEVONSET 1 /* To agree with command line flags, normally start at 1 */ | ||
539 | #endif | ||
540 | |||
541 | static void sys_listaudiodevs(void ) | ||
542 | { | ||
543 | char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; | ||
544 | int nindevs = 0, noutdevs = 0, i, canmulti = 0; | ||
545 | |||
546 | audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, | ||
547 | MAXNDEV, DEVDESCSIZE); | ||
548 | |||
549 | if (!nindevs) | ||
550 | post("no audio input devices found"); | ||
551 | else | ||
552 | { | ||
553 | post("input devices:"); | ||
554 | for (i = 0; i < nindevs; i++) | ||
555 | post("%d. %s", i+1, indevlist + i * DEVDESCSIZE); | ||
556 | } | ||
557 | if (!noutdevs) | ||
558 | post("no audio output devices found"); | ||
559 | else | ||
560 | { | ||
561 | post("output devices:"); | ||
562 | for (i = 0; i < noutdevs; i++) | ||
563 | post("%d. %s", i + DEVONSET, outdevlist + i * DEVDESCSIZE); | ||
564 | } | ||
565 | post("API number %d\n", sys_audioapi); | ||
566 | } | ||
567 | |||
568 | /* start an audio settings dialog window */ | ||
569 | void glob_audio_properties(t_pd *dummy, t_floatarg flongform) | ||
570 | { | ||
571 | char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)]; | ||
572 | /* these are the devices you're using: */ | ||
573 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
574 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
575 | int audioindev1, audioindev2, audioindev3, audioindev4, | ||
576 | audioinchan1, audioinchan2, audioinchan3, audioinchan4, | ||
577 | audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, | ||
578 | audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4; | ||
579 | int rate, advance; | ||
580 | /* these are all the devices on your system: */ | ||
581 | char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; | ||
582 | int nindevs = 0, noutdevs = 0, canmulti = 0, i; | ||
583 | |||
584 | char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80], | ||
585 | outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80]; | ||
586 | |||
587 | audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, | ||
588 | MAXNDEV, DEVDESCSIZE); | ||
589 | |||
590 | strcpy(indevliststring, "{"); | ||
591 | for (i = 0; i < nindevs; i++) | ||
592 | { | ||
593 | strcat(indevliststring, "\""); | ||
594 | strcat(indevliststring, indevlist + i * DEVDESCSIZE); | ||
595 | strcat(indevliststring, "\" "); | ||
596 | } | ||
597 | strcat(indevliststring, "}"); | ||
598 | |||
599 | strcpy(outdevliststring, "{"); | ||
600 | for (i = 0; i < noutdevs; i++) | ||
601 | { | ||
602 | strcat(outdevliststring, "\""); | ||
603 | strcat(outdevliststring, outdevlist + i * DEVDESCSIZE); | ||
604 | strcat(outdevliststring, "\" "); | ||
605 | } | ||
606 | strcat(outdevliststring, "}"); | ||
607 | |||
608 | sys_get_audio_params(&naudioindev, audioindev, chindev, | ||
609 | &naudiooutdev, audiooutdev, choutdev, &rate, &advance); | ||
610 | |||
611 | /* post("naudioindev %d naudiooutdev %d longform %f", | ||
612 | naudioindev, naudiooutdev, flongform); */ | ||
613 | if (naudioindev > 1 || naudiooutdev > 1) | ||
614 | flongform = 1; | ||
615 | |||
616 | |||
617 | audioindev1 = (naudioindev > 0 && audioindev[0]>= 0 ? audioindev[0] : 0); | ||
618 | audioindev2 = (naudioindev > 1 && audioindev[1]>= 0 ? audioindev[1] : 0); | ||
619 | audioindev3 = (naudioindev > 2 && audioindev[2]>= 0 ? audioindev[2] : 0); | ||
620 | audioindev4 = (naudioindev > 3 && audioindev[3]>= 0 ? audioindev[3] : 0); | ||
621 | audioinchan1 = (naudioindev > 0 ? chindev[0] : 0); | ||
622 | audioinchan2 = (naudioindev > 1 ? chindev[1] : 0); | ||
623 | audioinchan3 = (naudioindev > 2 ? chindev[2] : 0); | ||
624 | audioinchan4 = (naudioindev > 3 ? chindev[3] : 0); | ||
625 | audiooutdev1 = (naudiooutdev > 0 && audiooutdev[0]>=0 ? audiooutdev[0] : 0); | ||
626 | audiooutdev2 = (naudiooutdev > 1 && audiooutdev[1]>=0 ? audiooutdev[1] : 0); | ||
627 | audiooutdev3 = (naudiooutdev > 2 && audiooutdev[2]>=0 ? audiooutdev[2] : 0); | ||
628 | audiooutdev4 = (naudiooutdev > 3 && audiooutdev[3]>=0 ? audiooutdev[3] : 0); | ||
629 | audiooutchan1 = (naudiooutdev > 0 ? choutdev[0] : 0); | ||
630 | audiooutchan2 = (naudiooutdev > 1 ? choutdev[1] : 0); | ||
631 | audiooutchan3 = (naudiooutdev > 2 ? choutdev[2] : 0); | ||
632 | audiooutchan4 = (naudiooutdev > 3 ? choutdev[3] : 0); | ||
633 | sprintf(buf, | ||
634 | "pdtk_audio_dialog %%s \ | ||
635 | %s %d %d %d %d %d %d %d %d \ | ||
636 | %s %d %d %d %d %d %d %d %d \ | ||
637 | %d %d %d %d\n", | ||
638 | indevliststring, | ||
639 | audioindev1, audioindev2, audioindev3, audioindev4, | ||
640 | audioinchan1, audioinchan2, audioinchan3, audioinchan4, | ||
641 | outdevliststring, | ||
642 | audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, | ||
643 | audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4, | ||
644 | rate, advance, canmulti, (flongform != 0)); | ||
645 | gfxstub_deleteforkey(0); | ||
646 | gfxstub_new(&glob_pdobject, glob_audio_properties, buf); | ||
647 | } | ||
648 | |||
649 | /* new values from dialog window */ | ||
650 | void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) | ||
651 | { | ||
652 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
653 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
654 | int rate, advance, audioon, i, nindev, noutdev; | ||
655 | int audioindev1, audioinchan1, audiooutdev1, audiooutchan1; | ||
656 | int newaudioindev[4], newaudioinchan[4], | ||
657 | newaudiooutdev[4], newaudiooutchan[4]; | ||
658 | /* the new values the dialog came back with: */ | ||
659 | int newrate = atom_getintarg(16, argc, argv); | ||
660 | int newadvance = atom_getintarg(17, argc, argv); | ||
661 | int statewas; | ||
662 | |||
663 | for (i = 0; i < 4; i++) | ||
664 | { | ||
665 | newaudioindev[i] = atom_getintarg(i, argc, argv); | ||
666 | newaudioinchan[i] = atom_getintarg(i+4, argc, argv); | ||
667 | newaudiooutdev[i] = atom_getintarg(i+8, argc, argv); | ||
668 | newaudiooutchan[i] = atom_getintarg(i+12, argc, argv); | ||
669 | } | ||
670 | |||
671 | for (i = 0, nindev = 0; i < 4; i++) | ||
672 | { | ||
673 | if (newaudioinchan[i] > 0) | ||
674 | { | ||
675 | newaudioindev[nindev] = newaudioindev[i]; | ||
676 | newaudioinchan[nindev] = newaudioinchan[i]; | ||
677 | /* post("in %d %d %d", nindev, | ||
678 | newaudioindev[nindev] , newaudioinchan[nindev]); */ | ||
679 | nindev++; | ||
680 | } | ||
681 | } | ||
682 | for (i = 0, noutdev = 0; i < 4; i++) | ||
683 | { | ||
684 | if (newaudiooutchan[i] > 0) | ||
685 | { | ||
686 | newaudiooutdev[noutdev] = newaudiooutdev[i]; | ||
687 | newaudiooutchan[noutdev] = newaudiooutchan[i]; | ||
688 | /* post("out %d %d %d", noutdev, | ||
689 | newaudiooutdev[noutdev] , newaudioinchan[noutdev]); */ | ||
690 | noutdev++; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | sys_close_audio(); | ||
695 | sys_open_audio(nindev, newaudioindev, nindev, newaudioinchan, | ||
696 | noutdev, newaudiooutdev, noutdev, newaudiooutchan, | ||
697 | newrate, newadvance, 1); | ||
698 | } | ||
699 | |||
700 | void sys_listdevs(void ) | ||
701 | { | ||
702 | #ifdef USEAPI_PORTAUDIO | ||
703 | if (sys_audioapi == API_PORTAUDIO) | ||
704 | sys_listaudiodevs(); | ||
705 | else | ||
706 | #endif | ||
707 | #ifdef USEAPI_JACK | ||
708 | if (sys_audioapi == API_JACK) | ||
709 | jack_listdevs(); | ||
710 | else | ||
711 | #endif | ||
712 | #ifdef USEAPI_OSS | ||
713 | if (sys_audioapi == API_OSS) | ||
714 | sys_listaudiodevs(); | ||
715 | else | ||
716 | #endif | ||
717 | #ifdef USEAPI_MMIO | ||
718 | if (sys_audioapi == API_MMIO) | ||
719 | sys_listaudiodevs(); | ||
720 | else | ||
721 | #endif | ||
722 | #ifdef USEAPI_ALSA | ||
723 | if (sys_audioapi == API_ALSA) | ||
724 | sys_listaudiodevs(); | ||
725 | else | ||
726 | #endif | ||
727 | post("unknown API"); | ||
728 | |||
729 | sys_listmididevs(); | ||
730 | } | ||
731 | |||
732 | void sys_setblocksize(int n) | ||
733 | { | ||
734 | if (n < 1) | ||
735 | n = 1; | ||
736 | if (n != (1 << ilog2(n))) | ||
737 | post("warning: adjusting blocksize to power of 2: %d", | ||
738 | (n = (1 << ilog2(n)))); | ||
739 | sys_blocksize = n; | ||
740 | } | ||
741 | |||
742 | void sys_set_audio_api(int which) | ||
743 | { | ||
744 | sys_audioapi = which; | ||
745 | if (sys_verbose) | ||
746 | post("sys_audioapi %d", sys_audioapi); | ||
747 | } | ||
748 | |||
749 | void glob_audio_setapi(void *dummy, t_floatarg f) | ||
750 | { | ||
751 | int newapi = f; | ||
752 | if (newapi) | ||
753 | { | ||
754 | if (newapi == sys_audioapi) | ||
755 | { | ||
756 | if (!audio_isopen()) | ||
757 | sys_reopen_audio(); | ||
758 | } | ||
759 | else | ||
760 | { | ||
761 | sys_close_audio(); | ||
762 | sys_audioapi = newapi; | ||
763 | /* bash device params back to default */ | ||
764 | audio_naudioindev = audio_naudiooutdev = 1; | ||
765 | audio_audioindev[0] = audio_audiooutdev[0] = DEFAULTAUDIODEV; | ||
766 | audio_audiochindev[0] = audio_audiochoutdev[0] = SYS_DEFAULTCH; | ||
767 | sys_reopen_audio(); | ||
768 | } | ||
769 | glob_audio_properties(0, 0); | ||
770 | } | ||
771 | else if (audio_isopen()) | ||
772 | { | ||
773 | sys_close_audio(); | ||
774 | audio_state = 0; | ||
775 | sched_set_using_dacs(0); | ||
776 | } | ||
777 | } | ||
778 | |||
779 | /* start or stop the audio hardware */ | ||
780 | void sys_set_audio_state(int onoff) | ||
781 | { | ||
782 | if (onoff) /* start */ | ||
783 | { | ||
784 | if (!audio_isopen()) | ||
785 | sys_reopen_audio(); | ||
786 | } | ||
787 | else | ||
788 | { | ||
789 | if (audio_isopen()) | ||
790 | { | ||
791 | sys_close_audio(); | ||
792 | sched_set_using_dacs(0); | ||
793 | } | ||
794 | } | ||
795 | audio_state = onoff; | ||
796 | } | ||
797 | |||
798 | void sys_get_audio_apis(char *buf) | ||
799 | { | ||
800 | int n = 0; | ||
801 | strcpy(buf, "{ "); | ||
802 | #ifdef USEAPI_OSS | ||
803 | sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++; | ||
804 | #endif | ||
805 | #ifdef USEAPI_MMIO | ||
806 | sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++; | ||
807 | #endif | ||
808 | #ifdef USEAPI_ALSA | ||
809 | sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++; | ||
810 | #endif | ||
811 | #ifdef USEAPI_PORTAUDIO | ||
812 | #ifdef MSW | ||
813 | sprintf(buf + strlen(buf), | ||
814 | "{\"ASIO (via portaudio)\" %d} ", API_PORTAUDIO); | ||
815 | #else | ||
816 | #ifdef OSX | ||
817 | sprintf(buf + strlen(buf), | ||
818 | "{\"standard (portaudio)\" %d} ", API_PORTAUDIO); | ||
819 | #else | ||
820 | sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO); | ||
821 | #endif | ||
822 | #endif | ||
823 | n++; | ||
824 | #endif | ||
825 | #ifdef USEAPI_JACK | ||
826 | sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++; | ||
827 | #endif | ||
828 | strcat(buf, "}"); | ||
829 | /* then again, if only one API (or none) we don't offer any choice. */ | ||
830 | if (n < 2) | ||
831 | strcpy(buf, "{}"); | ||
832 | |||
833 | } | ||
834 | |||
835 | #ifdef USEAPI_ALSA | ||
836 | void alsa_putzeros(int n); | ||
837 | void alsa_getzeros(int n); | ||
838 | void alsa_printstate( void); | ||
839 | #endif | ||
840 | |||
841 | /* debugging */ | ||
842 | void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) | ||
843 | { | ||
844 | t_symbol *arg = atom_getsymbolarg(0, argc, argv); | ||
845 | if (arg == gensym("restart")) | ||
846 | { | ||
847 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
848 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
849 | int rate, advance; | ||
850 | sys_get_audio_params(&naudioindev, audioindev, chindev, | ||
851 | &naudiooutdev, audiooutdev, choutdev, &rate, &advance); | ||
852 | sys_close_audio(); | ||
853 | sys_open_audio(naudioindev, audioindev, naudioindev, chindev, | ||
854 | naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, | ||
855 | 1); | ||
856 | } | ||
857 | #ifdef USEAPI_ALSA | ||
858 | else if (arg == gensym("alsawrite")) | ||
859 | { | ||
860 | int n = atom_getintarg(1, argc, argv); | ||
861 | alsa_putzeros(n); | ||
862 | } | ||
863 | else if (arg == gensym("alsaread")) | ||
864 | { | ||
865 | int n = atom_getintarg(1, argc, argv); | ||
866 | alsa_getzeros(n); | ||
867 | } | ||
868 | else if (arg == gensym("print")) | ||
869 | { | ||
870 | alsa_printstate(); | ||
871 | } | ||
872 | #endif | ||
873 | } | ||
874 | /* Copyright (c) 2003, Miller Puckette and others. | ||
875 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
876 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
877 | |||
878 | /* machine-independent (well, mostly!) audio layer. Stores and recalls | ||
879 | audio settings from argparse routine and from dialog window. | ||
880 | */ | ||
881 | |||
882 | #include "m_pd.h" | ||
883 | #include "s_stuff.h" | ||
884 | #include <stdio.h> | ||
885 | #ifdef UNIX | ||
886 | #include <unistd.h> | ||
887 | #include <sys/time.h> | ||
888 | #include <sys/resource.h> | ||
889 | #endif | ||
890 | #include <stdlib.h> | ||
891 | #include <string.h> | ||
892 | #include <errno.h> | ||
893 | |||
894 | #define SYS_DEFAULTCH 2 | ||
895 | #define SYS_MAXCH 100 | ||
896 | #define SYS_DEFAULTSRATE 44100 | ||
897 | typedef long t_pa_sample; | ||
898 | #define SYS_SAMPLEWIDTH sizeof(t_pa_sample) | ||
899 | #define SYS_BYTESPERCHAN (DEFDACBLKSIZE * SYS_SAMPLEWIDTH) | ||
900 | #define SYS_XFERSAMPS (SYS_DEFAULTCH*DEFDACBLKSIZE) | ||
901 | #define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS) | ||
902 | |||
903 | /* these are set in this file when opening audio, but then may be reduced, | ||
904 | even to zero, in the system dependent open_audio routines. */ | ||
905 | int sys_inchannels; | ||
906 | int sys_outchannels; | ||
907 | int sys_advance_samples; /* scheduler advance in samples */ | ||
908 | int sys_blocksize = 0; /* audio I/O block size in sample frames */ | ||
909 | int sys_audioapi = API_DEFAULT; | ||
910 | |||
911 | static int sys_meters; /* true if we're metering */ | ||
912 | static float sys_inmax; /* max input amplitude */ | ||
913 | static float sys_outmax; /* max output amplitude */ | ||
914 | |||
915 | /* exported variables */ | ||
916 | int sys_schedadvance; /* scheduler advance in microseconds */ | ||
917 | float sys_dacsr; | ||
918 | |||
919 | #ifdef MACOSX | ||
920 | int sys_hipriority = 1; | ||
921 | #else | ||
922 | int sys_hipriority = 0; | ||
923 | #endif | ||
924 | |||
925 | t_sample *sys_soundout; | ||
926 | t_sample *sys_soundin; | ||
927 | |||
928 | /* the "state" is normally one if we're open and zero otherwise; | ||
929 | but if the state is one, we still haven't necessarily opened the | ||
930 | audio hardware; see audio_isopen() below. */ | ||
931 | static int audio_state; | ||
932 | |||
933 | /* last requested parameters */ | ||
934 | static int audio_naudioindev; | ||
935 | static int audio_audioindev[MAXAUDIOINDEV]; | ||
936 | static int audio_audiochindev[MAXAUDIOINDEV]; | ||
937 | static int audio_naudiooutdev; | ||
938 | static int audio_audiooutdev[MAXAUDIOOUTDEV]; | ||
939 | static int audio_audiochoutdev[MAXAUDIOOUTDEV]; | ||
940 | static int audio_rate; | ||
941 | static int audio_advance; | ||
942 | |||
943 | static int audio_isopen(void) | ||
944 | { | ||
945 | return (audio_state && | ||
946 | ((audio_naudioindev > 0 && audio_audiochindev[0] > 0) | ||
947 | || (audio_naudiooutdev > 0 && audio_audiochoutdev[0] > 0))); | ||
948 | } | ||
949 | |||
950 | static void sys_get_audio_params( | ||
951 | int *pnaudioindev, int *paudioindev, int *chindev, | ||
952 | int *pnaudiooutdev, int *paudiooutdev, int *choutdev, | ||
953 | int *prate, int *padvance) | ||
954 | { | ||
955 | int i; | ||
956 | *pnaudioindev = audio_naudioindev; | ||
957 | for (i = 0; i < MAXAUDIOINDEV; i++) | ||
958 | paudioindev[i] = audio_audioindev[i], | ||
959 | chindev[i] = audio_audiochindev[i]; | ||
960 | *pnaudiooutdev = audio_naudiooutdev; | ||
961 | for (i = 0; i < MAXAUDIOOUTDEV; i++) | ||
962 | paudiooutdev[i] = audio_audiooutdev[i], | ||
963 | choutdev[i] = audio_audiochoutdev[i]; | ||
964 | *prate = audio_rate; | ||
965 | *padvance = audio_advance; | ||
966 | } | ||
967 | |||
968 | static void sys_save_audio_params( | ||
969 | int naudioindev, int *audioindev, int *chindev, | ||
970 | int naudiooutdev, int *audiooutdev, int *choutdev, | ||
971 | int rate, int advance) | ||
972 | { | ||
973 | int i; | ||
974 | audio_naudioindev = naudioindev; | ||
975 | for (i = 0; i < MAXAUDIOINDEV; i++) | ||
976 | audio_audioindev[i] = audioindev[i], | ||
977 | audio_audiochindev[i] = chindev[i]; | ||
978 | audio_naudiooutdev = naudiooutdev; | ||
979 | for (i = 0; i < MAXAUDIOOUTDEV; i++) | ||
980 | audio_audiooutdev[i] = audiooutdev[i], | ||
981 | audio_audiochoutdev[i] = choutdev[i]; | ||
982 | audio_rate = rate; | ||
983 | audio_advance = advance; | ||
984 | } | ||
985 | |||
986 | /* init routines for any API which needs to set stuff up before | ||
987 | any other API gets used. This is only true of OSS so far. */ | ||
988 | #ifdef USEAPI_OSS | ||
989 | void oss_init(void); | ||
990 | #endif | ||
991 | |||
992 | static void audio_init( void) | ||
993 | { | ||
994 | static int initted = 0; | ||
995 | if (initted) | ||
996 | return; | ||
997 | initted = 1; | ||
998 | #ifdef USEAPI_OSS | ||
999 | oss_init(); | ||
1000 | #endif | ||
1001 | } | ||
1002 | |||
1003 | /* set channels and sample rate. */ | ||
1004 | |||
1005 | static void sys_setchsr(int chin, int chout, int sr) | ||
1006 | { | ||
1007 | int nblk; | ||
1008 | int inbytes = (chin ? chin : 2) * (DEFDACBLKSIZE*sizeof(float)); | ||
1009 | int outbytes = (chout ? chout : 2) * (DEFDACBLKSIZE*sizeof(float)); | ||
1010 | |||
1011 | sys_inchannels = chin; | ||
1012 | sys_outchannels = chout; | ||
1013 | sys_dacsr = sr; | ||
1014 | sys_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.); | ||
1015 | if (sys_advance_samples < 3 * DEFDACBLKSIZE) | ||
1016 | sys_advance_samples = 3 * DEFDACBLKSIZE; | ||
1017 | |||
1018 | if (sys_soundin) | ||
1019 | free(sys_soundin); | ||
1020 | sys_soundin = (t_float *)malloc(inbytes); | ||
1021 | memset(sys_soundin, 0, inbytes); | ||
1022 | |||
1023 | if (sys_soundout) | ||
1024 | free(sys_soundout); | ||
1025 | sys_soundout = (t_float *)malloc(outbytes); | ||
1026 | memset(sys_soundout, 0, outbytes); | ||
1027 | |||
1028 | if (sys_verbose) | ||
1029 | post("input channels = %d, output channels = %d", | ||
1030 | sys_inchannels, sys_outchannels); | ||
1031 | canvas_resume_dsp(canvas_suspend_dsp()); | ||
1032 | } | ||
1033 | |||
1034 | /* ----------------------- public routines ----------------------- */ | ||
1035 | |||
1036 | /* open audio devices (after cleaning up the specified device and channel | ||
1037 | vectors). The audio devices are "zero based" (i.e. "0" means the first | ||
1038 | one.) We also save the cleaned-up device specification so that we | ||
1039 | can later re-open audio and/or show the settings on a dialog window. */ | ||
1040 | |||
1041 | void sys_open_audio(int naudioindev, int *audioindev, int nchindev, | ||
1042 | int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, | ||
1043 | int *choutdev, int rate, int advance, int enable) | ||
1044 | { | ||
1045 | int i, *ip; | ||
1046 | int defaultchannels = SYS_DEFAULTCH; | ||
1047 | int inchans, outchans; | ||
1048 | if (rate < 1) | ||
1049 | rate = SYS_DEFAULTSRATE; | ||
1050 | audio_init(); | ||
1051 | /* Since the channel vector might be longer than the | ||
1052 | audio device vector, or vice versa, we fill the shorter one | ||
1053 | in to match the longer one. Also, if both are empty, we fill in | ||
1054 | one device (the default) and two channels. */ | ||
1055 | if (naudioindev == -1) | ||
1056 | { /* no input audio devices specified */ | ||
1057 | if (nchindev == -1) | ||
1058 | { | ||
1059 | nchindev=1; | ||
1060 | chindev[0] = defaultchannels; | ||
1061 | naudioindev = 1; | ||
1062 | audioindev[0] = DEFAULTAUDIODEV; | ||
1063 | } | ||
1064 | else | ||
1065 | { | ||
1066 | for (i = 0; i < MAXAUDIOINDEV; i++) | ||
1067 | audioindev[i] = i; | ||
1068 | naudioindev = nchindev; | ||
1069 | } | ||
1070 | } | ||
1071 | else | ||
1072 | { | ||
1073 | if (nchindev == -1) | ||
1074 | { | ||
1075 | nchindev = naudioindev; | ||
1076 | for (i = 0; i < naudioindev; i++) | ||
1077 | chindev[i] = defaultchannels; | ||
1078 | } | ||
1079 | else if (nchindev > naudioindev) | ||
1080 | { | ||
1081 | for (i = naudioindev; i < nchindev; i++) | ||
1082 | { | ||
1083 | if (i == 0) | ||
1084 | audioindev[0] = DEFAULTAUDIODEV; | ||
1085 | else audioindev[i] = audioindev[i-1] + 1; | ||
1086 | } | ||
1087 | naudioindev = nchindev; | ||
1088 | } | ||
1089 | else if (nchindev < naudioindev) | ||
1090 | { | ||
1091 | for (i = nchindev; i < naudioindev; i++) | ||
1092 | { | ||
1093 | if (i == 0) | ||
1094 | chindev[0] = defaultchannels; | ||
1095 | else chindev[i] = chindev[i-1]; | ||
1096 | } | ||
1097 | naudioindev = nchindev; | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | if (naudiooutdev == -1) | ||
1102 | { /* not set */ | ||
1103 | if (nchoutdev == -1) | ||
1104 | { | ||
1105 | nchoutdev=1; | ||
1106 | choutdev[0]=defaultchannels; | ||
1107 | naudiooutdev=1; | ||
1108 | audiooutdev[0] = DEFAULTAUDIODEV; | ||
1109 | } | ||
1110 | else | ||
1111 | { | ||
1112 | for (i = 0; i < MAXAUDIOOUTDEV; i++) | ||
1113 | audiooutdev[i] = i; | ||
1114 | naudiooutdev = nchoutdev; | ||
1115 | } | ||
1116 | } | ||
1117 | else | ||
1118 | { | ||
1119 | if (nchoutdev == -1) | ||
1120 | { | ||
1121 | nchoutdev = naudiooutdev; | ||
1122 | for (i = 0; i < naudiooutdev; i++) | ||
1123 | choutdev[i] = defaultchannels; | ||
1124 | } | ||
1125 | else if (nchoutdev > naudiooutdev) | ||
1126 | { | ||
1127 | for (i = naudiooutdev; i < nchoutdev; i++) | ||
1128 | { | ||
1129 | if (i == 0) | ||
1130 | audiooutdev[0] = DEFAULTAUDIODEV; | ||
1131 | else audiooutdev[i] = audiooutdev[i-1] + 1; | ||
1132 | } | ||
1133 | naudiooutdev = nchoutdev; | ||
1134 | } | ||
1135 | else if (nchoutdev < naudiooutdev) | ||
1136 | { | ||
1137 | for (i = nchoutdev; i < naudiooutdev; i++) | ||
1138 | { | ||
1139 | if (i == 0) | ||
1140 | choutdev[0] = defaultchannels; | ||
1141 | else choutdev[i] = choutdev[i-1]; | ||
1142 | } | ||
1143 | naudiooutdev = nchoutdev; | ||
1144 | } | ||
1145 | } | ||
1146 | |||
1147 | /* count total number of input and output channels */ | ||
1148 | for (i = inchans = 0; i < naudioindev; i++) | ||
1149 | inchans += chindev[i]; | ||
1150 | for (i = outchans = 0; i < naudiooutdev; i++) | ||
1151 | outchans += choutdev[i]; | ||
1152 | /* if no input or output devices seem to have been specified, | ||
1153 | this really means just disable audio, which we now do. Meanwhile, | ||
1154 | we can set audio input and output devices to their defaults. */ | ||
1155 | if (!inchans && !outchans) | ||
1156 | { | ||
1157 | enable = 0; | ||
1158 | naudioindev = nchindev = naudiooutdev = nchoutdev = 1; | ||
1159 | audioindev[0] = audiooutdev[0] = DEFAULTAUDIODEV; | ||
1160 | chindev[0] = choutdev[0] = 0; | ||
1161 | } | ||
1162 | sys_schedadvance = advance * 1000; | ||
1163 | sys_setchsr(inchans, outchans, rate); | ||
1164 | sys_log_error(ERR_NOTHING); | ||
1165 | |||
1166 | if (enable && (inchans > 0 || outchans > 0)) | ||
1167 | { | ||
1168 | #ifdef USEAPI_PORTAUDIO | ||
1169 | if (sys_audioapi == API_PORTAUDIO) | ||
1170 | { | ||
1171 | int blksize = (sys_blocksize ? sys_blocksize : 64); | ||
1172 | pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, | ||
1173 | blksize, sys_advance_samples/blksize, | ||
1174 | (naudiooutdev > 0 ? audioindev[0] : 0), | ||
1175 | (naudiooutdev > 0 ? audiooutdev[0] : 0)); | ||
1176 | } | ||
1177 | else | ||
1178 | #endif | ||
1179 | #ifdef USEAPI_JACK | ||
1180 | if (sys_audioapi == API_JACK) | ||
1181 | jack_open_audio((naudioindev > 0 ? chindev[0] : 0), | ||
1182 | (naudiooutdev > 0 ? choutdev[0] : 0), rate); | ||
1183 | |||
1184 | else | ||
1185 | #endif | ||
1186 | #ifdef USEAPI_OSS | ||
1187 | if (sys_audioapi == API_OSS) | ||
1188 | oss_open_audio(naudioindev, audioindev, nchindev, chindev, | ||
1189 | naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); | ||
1190 | else | ||
1191 | #endif | ||
1192 | #ifdef USEAPI_ALSA | ||
1193 | /* for alsa, only one device is supported; it may | ||
1194 | be open for both input and output. */ | ||
1195 | if (sys_audioapi == API_ALSA) | ||
1196 | alsa_open_audio(naudioindev, audioindev, nchindev, chindev, | ||
1197 | naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); | ||
1198 | else | ||
1199 | #endif | ||
1200 | #ifdef USEAPI_MMIO | ||
1201 | if (sys_audioapi == API_MMIO) | ||
1202 | mmio_open_audio(naudioindev, audioindev, nchindev, chindev, | ||
1203 | naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); | ||
1204 | else | ||
1205 | #endif | ||
1206 | post("unknown audio API specified"); | ||
1207 | } | ||
1208 | sys_save_audio_params(naudioindev, audioindev, chindev, | ||
1209 | naudiooutdev, audiooutdev, choutdev, rate, advance); | ||
1210 | if (sys_inchannels == 0 && sys_outchannels == 0) | ||
1211 | enable = 0; | ||
1212 | audio_state = enable; | ||
1213 | sys_vgui("set pd_whichapi %d\n", (audio_isopen() ? sys_audioapi : 0)); | ||
1214 | sched_set_using_dacs(enable); | ||
1215 | } | ||
1216 | |||
1217 | void sys_close_audio(void) | ||
1218 | { | ||
1219 | if (!audio_isopen()) | ||
1220 | return; | ||
1221 | #ifdef USEAPI_PORTAUDIO | ||
1222 | if (sys_audioapi == API_PORTAUDIO) | ||
1223 | pa_close_audio(); | ||
1224 | else | ||
1225 | #endif | ||
1226 | #ifdef USEAPI_JACK | ||
1227 | if (sys_audioapi == API_JACK) | ||
1228 | jack_close_audio(); | ||
1229 | else | ||
1230 | #endif | ||
1231 | #ifdef USEAPI_OSS | ||
1232 | if (sys_audioapi == API_OSS) | ||
1233 | oss_close_audio(); | ||
1234 | else | ||
1235 | #endif | ||
1236 | #ifdef USEAPI_ALSA | ||
1237 | if (sys_audioapi == API_ALSA) | ||
1238 | alsa_close_audio(); | ||
1239 | else | ||
1240 | #endif | ||
1241 | #ifdef USEAPI_MMIO | ||
1242 | if (sys_audioapi == API_MMIO) | ||
1243 | mmio_close_audio(); | ||
1244 | else | ||
1245 | #endif | ||
1246 | post("sys_close_audio: unknown API %d", sys_audioapi); | ||
1247 | sys_inchannels = sys_outchannels = 0; | ||
1248 | } | ||
1249 | |||
1250 | /* open audio using whatever parameters were last used */ | ||
1251 | void sys_reopen_audio( void) | ||
1252 | { | ||
1253 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
1254 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
1255 | int rate, advance; | ||
1256 | sys_get_audio_params(&naudioindev, audioindev, chindev, | ||
1257 | &naudiooutdev, audiooutdev, choutdev, &rate, &advance); | ||
1258 | sys_open_audio(naudioindev, audioindev, naudioindev, chindev, | ||
1259 | naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, 1); | ||
1260 | } | ||
1261 | |||
1262 | int sys_send_dacs(void) | ||
1263 | { | ||
1264 | if (sys_meters) | ||
1265 | { | ||
1266 | int i, n; | ||
1267 | float maxsamp; | ||
1268 | for (i = 0, n = sys_inchannels * DEFDACBLKSIZE, maxsamp = sys_inmax; | ||
1269 | i < n; i++) | ||
1270 | { | ||
1271 | float f = sys_soundin[i]; | ||
1272 | if (f > maxsamp) maxsamp = f; | ||
1273 | else if (-f > maxsamp) maxsamp = -f; | ||
1274 | } | ||
1275 | sys_inmax = maxsamp; | ||
1276 | for (i = 0, n = sys_outchannels * DEFDACBLKSIZE, maxsamp = sys_outmax; | ||
1277 | i < n; i++) | ||
1278 | { | ||
1279 | float f = sys_soundout[i]; | ||
1280 | if (f > maxsamp) maxsamp = f; | ||
1281 | else if (-f > maxsamp) maxsamp = -f; | ||
1282 | } | ||
1283 | sys_outmax = maxsamp; | ||
1284 | } | ||
1285 | |||
1286 | #ifdef USEAPI_PORTAUDIO | ||
1287 | if (sys_audioapi == API_PORTAUDIO) | ||
1288 | return (pa_send_dacs()); | ||
1289 | else | ||
1290 | #endif | ||
1291 | #ifdef USEAPI_JACK | ||
1292 | if (sys_audioapi == API_JACK) | ||
1293 | return (jack_send_dacs()); | ||
1294 | else | ||
1295 | #endif | ||
1296 | #ifdef USEAPI_OSS | ||
1297 | if (sys_audioapi == API_OSS) | ||
1298 | return (oss_send_dacs()); | ||
1299 | else | ||
1300 | #endif | ||
1301 | #ifdef USEAPI_ALSA | ||
1302 | if (sys_audioapi == API_ALSA) | ||
1303 | return (alsa_send_dacs()); | ||
1304 | else | ||
1305 | #endif | ||
1306 | #ifdef USEAPI_MMIO | ||
1307 | if (sys_audioapi == API_MMIO) | ||
1308 | return (mmio_send_dacs()); | ||
1309 | else | ||
1310 | #endif | ||
1311 | post("unknown API"); | ||
1312 | return (0); | ||
1313 | } | ||
1314 | |||
1315 | float sys_getsr(void) | ||
1316 | { | ||
1317 | return (sys_dacsr); | ||
1318 | } | ||
1319 | |||
1320 | int sys_get_outchannels(void) | ||
1321 | { | ||
1322 | return (sys_outchannels); | ||
1323 | } | ||
1324 | |||
1325 | int sys_get_inchannels(void) | ||
1326 | { | ||
1327 | return (sys_inchannels); | ||
1328 | } | ||
1329 | |||
1330 | void sys_audiobuf(int n) | ||
1331 | { | ||
1332 | /* set the size, in milliseconds, of the audio FIFO */ | ||
1333 | if (n < 5) n = 5; | ||
1334 | else if (n > 5000) n = 5000; | ||
1335 | sys_schedadvance = n * 1000; | ||
1336 | } | ||
1337 | |||
1338 | void sys_getmeters(float *inmax, float *outmax) | ||
1339 | { | ||
1340 | if (inmax) | ||
1341 | { | ||
1342 | sys_meters = 1; | ||
1343 | *inmax = sys_inmax; | ||
1344 | *outmax = sys_outmax; | ||
1345 | } | ||
1346 | else | ||
1347 | sys_meters = 0; | ||
1348 | sys_inmax = sys_outmax = 0; | ||
1349 | } | ||
1350 | |||
1351 | void sys_reportidle(void) | ||
1352 | { | ||
1353 | } | ||
1354 | |||
1355 | #define MAXNDEV 20 | ||
1356 | #define DEVDESCSIZE 80 | ||
1357 | |||
1358 | static void audio_getdevs(char *indevlist, int *nindevs, | ||
1359 | char *outdevlist, int *noutdevs, int *canmulti, | ||
1360 | int maxndev, int devdescsize) | ||
1361 | { | ||
1362 | audio_init(); | ||
1363 | #ifdef USEAPI_OSS | ||
1364 | if (sys_audioapi == API_OSS) | ||
1365 | { | ||
1366 | oss_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
1367 | maxndev, devdescsize); | ||
1368 | } | ||
1369 | else | ||
1370 | #endif | ||
1371 | #ifdef USEAPI_ALSA | ||
1372 | if (sys_audioapi == API_ALSA) | ||
1373 | { | ||
1374 | alsa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
1375 | maxndev, devdescsize); | ||
1376 | } | ||
1377 | else | ||
1378 | #endif | ||
1379 | #ifdef USEAPI_PORTAUDIO | ||
1380 | if (sys_audioapi == API_PORTAUDIO) | ||
1381 | { | ||
1382 | pa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
1383 | maxndev, devdescsize); | ||
1384 | } | ||
1385 | else | ||
1386 | #endif | ||
1387 | #ifdef USEAPI_MMIO | ||
1388 | if (sys_audioapi == API_MMIO) | ||
1389 | { | ||
1390 | mmio_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, | ||
1391 | maxndev, devdescsize); | ||
1392 | } | ||
1393 | else | ||
1394 | #endif | ||
1395 | { | ||
1396 | /* this shouldn't happen once all the above get filled in. */ | ||
1397 | int i; | ||
1398 | *nindevs = *noutdevs = 3; | ||
1399 | for (i = 0; i < 3; i++) | ||
1400 | { | ||
1401 | sprintf(indevlist + i * devdescsize, "input device #%d", i+1); | ||
1402 | sprintf(outdevlist + i * devdescsize, "output device #%d", i+1); | ||
1403 | } | ||
1404 | *canmulti = 0; | ||
1405 | } | ||
1406 | } | ||
1407 | |||
1408 | #ifdef MSW | ||
1409 | #define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */ | ||
1410 | #else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */ | ||
1411 | #define DEVONSET 1 /* To agree with command line flags, normally start at 1 */ | ||
1412 | #endif | ||
1413 | |||
1414 | static void sys_listaudiodevs(void ) | ||
1415 | { | ||
1416 | char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; | ||
1417 | int nindevs = 0, noutdevs = 0, i, canmulti = 0; | ||
1418 | |||
1419 | audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, | ||
1420 | MAXNDEV, DEVDESCSIZE); | ||
1421 | |||
1422 | if (!nindevs) | ||
1423 | post("no audio input devices found"); | ||
1424 | else | ||
1425 | { | ||
1426 | post("input devices:"); | ||
1427 | for (i = 0; i < nindevs; i++) | ||
1428 | post("%d. %s", i+1, indevlist + i * DEVDESCSIZE); | ||
1429 | } | ||
1430 | if (!noutdevs) | ||
1431 | post("no audio output devices found"); | ||
1432 | else | ||
1433 | { | ||
1434 | post("output devices:"); | ||
1435 | for (i = 0; i < noutdevs; i++) | ||
1436 | post("%d. %s", i + DEVONSET, outdevlist + i * DEVDESCSIZE); | ||
1437 | } | ||
1438 | post("API number %d\n", sys_audioapi); | ||
1439 | } | ||
1440 | |||
1441 | /* start an audio settings dialog window */ | ||
1442 | void glob_audio_properties(t_pd *dummy, t_floatarg flongform) | ||
1443 | { | ||
1444 | char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)]; | ||
1445 | /* these are the devices you're using: */ | ||
1446 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
1447 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
1448 | int audioindev1, audioindev2, audioindev3, audioindev4, | ||
1449 | audioinchan1, audioinchan2, audioinchan3, audioinchan4, | ||
1450 | audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, | ||
1451 | audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4; | ||
1452 | int rate, advance; | ||
1453 | /* these are all the devices on your system: */ | ||
1454 | char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; | ||
1455 | int nindevs = 0, noutdevs = 0, canmulti = 0, i; | ||
1456 | |||
1457 | char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80], | ||
1458 | outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80]; | ||
1459 | |||
1460 | audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, | ||
1461 | MAXNDEV, DEVDESCSIZE); | ||
1462 | |||
1463 | strcpy(indevliststring, "{"); | ||
1464 | for (i = 0; i < nindevs; i++) | ||
1465 | { | ||
1466 | strcat(indevliststring, "\""); | ||
1467 | strcat(indevliststring, indevlist + i * DEVDESCSIZE); | ||
1468 | strcat(indevliststring, "\" "); | ||
1469 | } | ||
1470 | strcat(indevliststring, "}"); | ||
1471 | |||
1472 | strcpy(outdevliststring, "{"); | ||
1473 | for (i = 0; i < noutdevs; i++) | ||
1474 | { | ||
1475 | strcat(outdevliststring, "\""); | ||
1476 | strcat(outdevliststring, outdevlist + i * DEVDESCSIZE); | ||
1477 | strcat(outdevliststring, "\" "); | ||
1478 | } | ||
1479 | strcat(outdevliststring, "}"); | ||
1480 | |||
1481 | sys_get_audio_params(&naudioindev, audioindev, chindev, | ||
1482 | &naudiooutdev, audiooutdev, choutdev, &rate, &advance); | ||
1483 | |||
1484 | /* post("naudioindev %d naudiooutdev %d longform %f", | ||
1485 | naudioindev, naudiooutdev, flongform); */ | ||
1486 | if (naudioindev > 1 || naudiooutdev > 1) | ||
1487 | flongform = 1; | ||
1488 | |||
1489 | |||
1490 | audioindev1 = (naudioindev > 0 && audioindev[0]>= 0 ? audioindev[0] : 0); | ||
1491 | audioindev2 = (naudioindev > 1 && audioindev[1]>= 0 ? audioindev[1] : 0); | ||
1492 | audioindev3 = (naudioindev > 2 && audioindev[2]>= 0 ? audioindev[2] : 0); | ||
1493 | audioindev4 = (naudioindev > 3 && audioindev[3]>= 0 ? audioindev[3] : 0); | ||
1494 | audioinchan1 = (naudioindev > 0 ? chindev[0] : 0); | ||
1495 | audioinchan2 = (naudioindev > 1 ? chindev[1] : 0); | ||
1496 | audioinchan3 = (naudioindev > 2 ? chindev[2] : 0); | ||
1497 | audioinchan4 = (naudioindev > 3 ? chindev[3] : 0); | ||
1498 | audiooutdev1 = (naudiooutdev > 0 && audiooutdev[0]>=0 ? audiooutdev[0] : 0); | ||
1499 | audiooutdev2 = (naudiooutdev > 1 && audiooutdev[1]>=0 ? audiooutdev[1] : 0); | ||
1500 | audiooutdev3 = (naudiooutdev > 2 && audiooutdev[2]>=0 ? audiooutdev[2] : 0); | ||
1501 | audiooutdev4 = (naudiooutdev > 3 && audiooutdev[3]>=0 ? audiooutdev[3] : 0); | ||
1502 | audiooutchan1 = (naudiooutdev > 0 ? choutdev[0] : 0); | ||
1503 | audiooutchan2 = (naudiooutdev > 1 ? choutdev[1] : 0); | ||
1504 | audiooutchan3 = (naudiooutdev > 2 ? choutdev[2] : 0); | ||
1505 | audiooutchan4 = (naudiooutdev > 3 ? choutdev[3] : 0); | ||
1506 | sprintf(buf, | ||
1507 | "pdtk_audio_dialog %%s \ | ||
1508 | %s %d %d %d %d %d %d %d %d \ | ||
1509 | %s %d %d %d %d %d %d %d %d \ | ||
1510 | %d %d %d %d\n", | ||
1511 | indevliststring, | ||
1512 | audioindev1, audioindev2, audioindev3, audioindev4, | ||
1513 | audioinchan1, audioinchan2, audioinchan3, audioinchan4, | ||
1514 | outdevliststring, | ||
1515 | audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, | ||
1516 | audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4, | ||
1517 | rate, advance, canmulti, (flongform != 0)); | ||
1518 | gfxstub_deleteforkey(0); | ||
1519 | gfxstub_new(&glob_pdobject, glob_audio_properties, buf); | ||
1520 | } | ||
1521 | |||
1522 | /* new values from dialog window */ | ||
1523 | void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) | ||
1524 | { | ||
1525 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
1526 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
1527 | int rate, advance, audioon, i, nindev, noutdev; | ||
1528 | int audioindev1, audioinchan1, audiooutdev1, audiooutchan1; | ||
1529 | int newaudioindev[4], newaudioinchan[4], | ||
1530 | newaudiooutdev[4], newaudiooutchan[4]; | ||
1531 | /* the new values the dialog came back with: */ | ||
1532 | int newrate = atom_getintarg(16, argc, argv); | ||
1533 | int newadvance = atom_getintarg(17, argc, argv); | ||
1534 | int statewas; | ||
1535 | |||
1536 | for (i = 0; i < 4; i++) | ||
1537 | { | ||
1538 | newaudioindev[i] = atom_getintarg(i, argc, argv); | ||
1539 | newaudioinchan[i] = atom_getintarg(i+4, argc, argv); | ||
1540 | newaudiooutdev[i] = atom_getintarg(i+8, argc, argv); | ||
1541 | newaudiooutchan[i] = atom_getintarg(i+12, argc, argv); | ||
1542 | } | ||
1543 | |||
1544 | for (i = 0, nindev = 0; i < 4; i++) | ||
1545 | { | ||
1546 | if (newaudioinchan[i] > 0) | ||
1547 | { | ||
1548 | newaudioindev[nindev] = newaudioindev[i]; | ||
1549 | newaudioinchan[nindev] = newaudioinchan[i]; | ||
1550 | /* post("in %d %d %d", nindev, | ||
1551 | newaudioindev[nindev] , newaudioinchan[nindev]); */ | ||
1552 | nindev++; | ||
1553 | } | ||
1554 | } | ||
1555 | for (i = 0, noutdev = 0; i < 4; i++) | ||
1556 | { | ||
1557 | if (newaudiooutchan[i] > 0) | ||
1558 | { | ||
1559 | newaudiooutdev[noutdev] = newaudiooutdev[i]; | ||
1560 | newaudiooutchan[noutdev] = newaudiooutchan[i]; | ||
1561 | /* post("out %d %d %d", noutdev, | ||
1562 | newaudiooutdev[noutdev] , newaudioinchan[noutdev]); */ | ||
1563 | noutdev++; | ||
1564 | } | ||
1565 | } | ||
1566 | |||
1567 | sys_close_audio(); | ||
1568 | sys_open_audio(nindev, newaudioindev, nindev, newaudioinchan, | ||
1569 | noutdev, newaudiooutdev, noutdev, newaudiooutchan, | ||
1570 | newrate, newadvance, 1); | ||
1571 | } | ||
1572 | |||
1573 | void sys_listdevs(void ) | ||
1574 | { | ||
1575 | #ifdef USEAPI_PORTAUDIO | ||
1576 | if (sys_audioapi == API_PORTAUDIO) | ||
1577 | sys_listaudiodevs(); | ||
1578 | else | ||
1579 | #endif | ||
1580 | #ifdef USEAPI_JACK | ||
1581 | if (sys_audioapi == API_JACK) | ||
1582 | jack_listdevs(); | ||
1583 | else | ||
1584 | #endif | ||
1585 | #ifdef USEAPI_OSS | ||
1586 | if (sys_audioapi == API_OSS) | ||
1587 | sys_listaudiodevs(); | ||
1588 | else | ||
1589 | #endif | ||
1590 | #ifdef USEAPI_MMIO | ||
1591 | if (sys_audioapi == API_MMIO) | ||
1592 | sys_listaudiodevs(); | ||
1593 | else | ||
1594 | #endif | ||
1595 | #ifdef USEAPI_ALSA | ||
1596 | if (sys_audioapi == API_ALSA) | ||
1597 | sys_listaudiodevs(); | ||
1598 | else | ||
1599 | #endif | ||
1600 | post("unknown API"); | ||
1601 | |||
1602 | sys_listmididevs(); | ||
1603 | } | ||
1604 | |||
1605 | void sys_setblocksize(int n) | ||
1606 | { | ||
1607 | if (n < 1) | ||
1608 | n = 1; | ||
1609 | if (n != (1 << ilog2(n))) | ||
1610 | post("warning: adjusting blocksize to power of 2: %d", | ||
1611 | (n = (1 << ilog2(n)))); | ||
1612 | sys_blocksize = n; | ||
1613 | } | ||
1614 | |||
1615 | void sys_set_audio_api(int which) | ||
1616 | { | ||
1617 | sys_audioapi = which; | ||
1618 | if (sys_verbose) | ||
1619 | post("sys_audioapi %d", sys_audioapi); | ||
1620 | } | ||
1621 | |||
1622 | void glob_audio_setapi(void *dummy, t_floatarg f) | ||
1623 | { | ||
1624 | int newapi = f; | ||
1625 | if (newapi) | ||
1626 | { | ||
1627 | if (newapi == sys_audioapi) | ||
1628 | { | ||
1629 | if (!audio_isopen()) | ||
1630 | sys_reopen_audio(); | ||
1631 | } | ||
1632 | else | ||
1633 | { | ||
1634 | sys_close_audio(); | ||
1635 | sys_audioapi = newapi; | ||
1636 | /* bash device params back to default */ | ||
1637 | audio_naudioindev = audio_naudiooutdev = 1; | ||
1638 | audio_audioindev[0] = audio_audiooutdev[0] = DEFAULTAUDIODEV; | ||
1639 | audio_audiochindev[0] = audio_audiochoutdev[0] = SYS_DEFAULTCH; | ||
1640 | sys_reopen_audio(); | ||
1641 | } | ||
1642 | glob_audio_properties(0, 0); | ||
1643 | } | ||
1644 | else if (audio_isopen()) | ||
1645 | { | ||
1646 | sys_close_audio(); | ||
1647 | audio_state = 0; | ||
1648 | sched_set_using_dacs(0); | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | /* start or stop the audio hardware */ | ||
1653 | void sys_set_audio_state(int onoff) | ||
1654 | { | ||
1655 | if (onoff) /* start */ | ||
1656 | { | ||
1657 | if (!audio_isopen()) | ||
1658 | sys_reopen_audio(); | ||
1659 | } | ||
1660 | else | ||
1661 | { | ||
1662 | if (audio_isopen()) | ||
1663 | { | ||
1664 | sys_close_audio(); | ||
1665 | sched_set_using_dacs(0); | ||
1666 | } | ||
1667 | } | ||
1668 | audio_state = onoff; | ||
1669 | } | ||
1670 | |||
1671 | void sys_get_audio_apis(char *buf) | ||
1672 | { | ||
1673 | int n = 0; | ||
1674 | strcpy(buf, "{ "); | ||
1675 | #ifdef USEAPI_OSS | ||
1676 | sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++; | ||
1677 | #endif | ||
1678 | #ifdef USEAPI_MMIO | ||
1679 | sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++; | ||
1680 | #endif | ||
1681 | #ifdef USEAPI_ALSA | ||
1682 | sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++; | ||
1683 | #endif | ||
1684 | #ifdef USEAPI_PORTAUDIO | ||
1685 | #ifdef MSW | ||
1686 | sprintf(buf + strlen(buf), | ||
1687 | "{\"ASIO (via portaudio)\" %d} ", API_PORTAUDIO); | ||
1688 | #else | ||
1689 | #ifdef OSX | ||
1690 | sprintf(buf + strlen(buf), | ||
1691 | "{\"standard (portaudio)\" %d} ", API_PORTAUDIO); | ||
1692 | #else | ||
1693 | sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO); | ||
1694 | #endif | ||
1695 | #endif | ||
1696 | n++; | ||
1697 | #endif | ||
1698 | #ifdef USEAPI_JACK | ||
1699 | sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++; | ||
1700 | #endif | ||
1701 | strcat(buf, "}"); | ||
1702 | /* then again, if only one API (or none) we don't offer any choice. */ | ||
1703 | if (n < 2) | ||
1704 | strcpy(buf, "{}"); | ||
1705 | |||
1706 | } | ||
1707 | |||
1708 | #ifdef USEAPI_ALSA | ||
1709 | void alsa_putzeros(int n); | ||
1710 | void alsa_getzeros(int n); | ||
1711 | void alsa_printstate( void); | ||
1712 | #endif | ||
1713 | |||
1714 | /* debugging */ | ||
1715 | void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) | ||
1716 | { | ||
1717 | t_symbol *arg = atom_getsymbolarg(0, argc, argv); | ||
1718 | if (arg == gensym("restart")) | ||
1719 | { | ||
1720 | int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | ||
1721 | int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | ||
1722 | int rate, advance; | ||
1723 | sys_get_audio_params(&naudioindev, audioindev, chindev, | ||
1724 | &naudiooutdev, audiooutdev, choutdev, &rate, &advance); | ||
1725 | sys_close_audio(); | ||
1726 | sys_open_audio(naudioindev, audioindev, naudioindev, chindev, | ||
1727 | naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, | ||
1728 | 1); | ||
1729 | } | ||
1730 | #ifdef USEAPI_ALSA | ||
1731 | else if (arg == gensym("alsawrite")) | ||
1732 | { | ||
1733 | int n = atom_getintarg(1, argc, argv); | ||
1734 | alsa_putzeros(n); | ||
1735 | } | ||
1736 | else if (arg == gensym("alsaread")) | ||
1737 | { | ||
1738 | int n = atom_getintarg(1, argc, argv); | ||
1739 | alsa_getzeros(n); | ||
1740 | } | ||
1741 | else if (arg == gensym("print")) | ||
1742 | { | ||
1743 | alsa_printstate(); | ||
1744 | } | ||
1745 | #endif | ||
1746 | } | ||