1 /* Audio hardware handlers (OSS, ALSA, Sun, Windows, Mac OSX, Jack, HPUX, NetBSD, OpenBSD, pulseaudio, portaudio)
2 *
3 * In many cases, only callback driven transfers are supported, so ideally we'd have:
4 * int mus_audio_playback(caller_data, start_func, fill_func, end_func)
5 * returns error indication or MUS_NO_ERROR
6 * calls start_func at startup: void start(caller_data, ...)?
7 * each times it needs a bufferfull, calls fill_func: bool fill(caller_data, void *buf, buf_size_in_samples, buf_data_type)
8 * perhaps returns false to signal normal quit?
9 * at end (either via fill or some interrupt), calls end(caller_data, ...)?
10 */
11
12 /*
13 * layout of this file:
14 * error handlers
15 * OSS
16 * ALSA
17 * Sun
18 * Windows 95/98
19 * OSX
20 * JACK
21 * HPUX
22 * OpenBSD
23 * NetBSD
24 * PulseAudio (in progress?)
25 * PortAudio
26 */
27
28 /*
29 * int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
30 * int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
31 * int mus_audio_write(int line, char *buf, int bytes)
32 * int mus_audio_close(int line)
33 * int mus_audio_read(int line, char *buf, int bytes)
34 * int mus_audio_initialize(void) does whatever is needed to get set up
35 * char *mus_audio_moniker(void) returns some brief description of the overall audio setup (don't free return string).
36 */
37
38 #include "mus-config.h"
39
40 #if USE_SND && __APPLE__ && USE_MOTIF
41 #undef USE_MOTIF
42 #define USE_NO_GUI 1
43 /* Xt's Boolean (/usr/include/X11/Intrinsic.h = char) collides with MacTypes.h Boolean, (actually,
44 * unsigned char in /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFBase.h)
45 * but we want snd.h for other stuff, so, if Motif is in use, don't load its headers at this time
46 * perhaps we could use the -funsigned-char switch in gcc
47 */
48 #endif
49
50 #if USE_SND && __APPLE__ && HAVE_RUBY
51 /* if using Ruby, OpenTransport.h T_* definitions collide with Ruby's -- it isn't needed here, so... */
52 #define REDEFINE_HAVE_RUBY 1
53 #undef HAVE_RUBY
54 #endif
55
56 #if USE_SND
57 #include "snd.h"
58 #else
59 #define PRINT_BUFFER_SIZE 512
60 #define LABEL_BUFFER_SIZE 64
61 #endif
62
63 #if USE_SND && __APPLE__
64 #define USE_MOTIF 1
65 #undef USE_NO_GUI
66 #if REDEFINE_HAVE_RUBY
67 #define HAVE_RUBY 1
68 #endif
69 #endif
70
71 #include <math.h>
72 #include <stdio.h>
73 #include <fcntl.h>
74 #include <errno.h>
75 #include <stdlib.h>
76 #ifndef _MSC_VER
77 #include <unistd.h>
78 #endif
79 #include <string.h>
80
81 #ifdef __APPLE__
82 #include <CoreServices/CoreServices.h>
83 #include <CoreAudio/CoreAudio.h>
84 /* these pull in stdbool.h apparently, so they have to precede sndlib.h */
85 #endif
86
87 /* #define HAVE_JACK_IN_LINUX (MUS_JACK && __linux__) */
88 /* using JACK on GNU/linux, GNU/kFreeBSD and GNU/Hurd is all the same */
89 #if ((defined __linux__) || ((defined __FreeBSD_kernel__) && (defined __GLIBC__)) || (defined __GNU__))
90 #define HAVE_JACK_IN_LINUX MUS_JACK
91 #else
92 #define HAVE_JACK_IN_LINUX 0
93 #endif
94
95 #include "_sndlib.h"
96 #include "sndlib-strings.h"
97
98 #if WITH_AUDIO
99
100 enum {MUS_AUDIO_IGNORED, MUS_AUDIO_DUPLEX_DEFAULT, MUS_AUDIO_LINE_OUT,
101 MUS_AUDIO_LINE_IN, MUS_AUDIO_MICROPHONE, MUS_AUDIO_SPEAKERS, MUS_AUDIO_DIGITAL_OUT,
102 MUS_AUDIO_DAC_OUT, MUS_AUDIO_MIXER, MUS_AUDIO_AUX_OUTPUT
103 };
104
105
106 #define mus_standard_error(Error_Type, Error_Message) \
107 mus_print("%s\n [%s[%d] %s]", Error_Message, __FILE__, __LINE__, __func__)
108
109 #define mus_standard_io_error(Error_Type, IO_Func, IO_Name) \
110 mus_print("%s %s: %s\n [%s[%d] %s]", IO_Func, IO_Name, strerror(errno), __FILE__, __LINE__, __func__)
111
112
113 static char *version_name = NULL;
114 static bool audio_initialized = false;
115
116
117
118
119 /* ------------------------------- OSS ----------------------------------------- */
120
121 /* Thanks to Yair K. for OSS v4 changes. 22-Jan-08 */
122
123 #if (HAVE_OSS || HAVE_ALSA || HAVE_JACK_IN_LINUX)
124 /* actually it's not impossible that someday we'll have ALSA but not OSS... */
125 #define AUDIO_OK 1
126
127 #include <sys/ioctl.h>
128 #include <sys/soundcard.h>
129
130 #if ((SOUND_VERSION > 360) && (defined(OSS_SYSINFO)))
131 #define NEW_OSS 1
132 #endif
133
134 #define MUS_OSS_WRITE_RATE SNDCTL_DSP_SPEED
135 #define MUS_OSS_WRITE_CHANNELS SNDCTL_DSP_CHANNELS
136 #define MUS_OSS_SET_FORMAT SNDCTL_DSP_SETFMT
137 #define MUS_OSS_GET_FORMATS SNDCTL_DSP_GETFMTS
138
139 #define DAC_NAME "/dev/dsp"
140 #define MIXER_NAME "/dev/mixer"
141 /* some programs use /dev/audio */
142
143 /* there can be more than one sound card installed, and a card can be handled through
144 * more than one /dev/dsp device, so we can't use a global dac device here.
145 * The caller has to keep track of the various cards (via AUDIO_SYSTEM) --
146 * I toyed with embedding all that in mus_audio_open_output and mus_audio_write, but
147 * decided it's better to keep them explicit -- the caller may want entirely
148 * different (non-synchronous) streams going to the various cards. This same
149 * code (AUDIO_SYSTEM(n)->devn) should work in Windoze (see below), and
150 * might work on the Mac -- something for a rainy day...
151 */
152
153 #define return_error_exit(Message_Type, Audio_Line, Ur_Message) \
154 do { \
155 char *Message; Message = Ur_Message; \
156 if (Audio_Line != -1) \
157 linux_audio_close(Audio_Line); \
158 if ((Message) && (strlen(Message) > 0)) \
159 { \
160 mus_print("%s\n [%s[%d] %s]", \
161 Message, \
162 __FILE__, __LINE__, __func__); \
163 free(Message); \
164 } \
165 else mus_print("%s\n [%s[%d] %s]", \
166 mus_error_type_to_string(Message_Type), \
167 __FILE__, __LINE__, __func__); \
168 return(MUS_ERROR); \
169 } while (false)
170
171 static int FRAGMENTS = 4;
172 static int FRAGMENT_SIZE = 12;
173 static bool fragments_locked = false;
174
175 /* defaults here are FRAGMENTS 16 and FRAGMENT_SIZE 12; these values however
176 * cause about a .5 second delay, which is not acceptable in "real-time" situations.
177 *
178 * this changed 22-May-01: these are causing more trouble than they're worth
179 */
180
oss_mus_oss_set_buffers(int num,int size)181 static void oss_mus_oss_set_buffers(int num, int size) {FRAGMENTS = num; FRAGMENT_SIZE = size; fragments_locked = true;}
182
183 #define MAX_SOUNDCARDS 8
184 #define MAX_DSPS 8
185 #define MAX_MIXERS 8
186 /* there can be (apparently) any number of mixers and dsps per soundcard, but 8 is enough! */
187
188 static int *audio_fd = NULL;
189 static int *audio_open_ctr = NULL;
190 static int *audio_dsp = NULL;
191 static int *audio_mixer = NULL;
192 static int *audio_mode = NULL;
193
194 static int sound_cards = 0;
195 #ifdef NEW_OSS
196 static int new_oss_running = 0;
197 #endif
198 static char *dev_name = NULL;
199
oss_mus_audio_moniker(void)200 static char *oss_mus_audio_moniker(void)
201 {
202 if (!version_name) version_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
203 if (SOUND_VERSION < 361)
204 {
205 char version[LABEL_BUFFER_SIZE];
206 snprintf(version, LABEL_BUFFER_SIZE, "%d", SOUND_VERSION);
207 snprintf(version_name, LABEL_BUFFER_SIZE, "OSS %c.%c.%c", version[0], version[1], version[2]);
208 }
209 else
210 snprintf(version_name, LABEL_BUFFER_SIZE, "OSS %x.%x.%x",
211 (SOUND_VERSION >> 16) & 0xff,
212 (SOUND_VERSION >> 8) & 0xff,
213 SOUND_VERSION & 0xff);
214 return(version_name);
215 }
216
dac_name(int sys,int offset)217 static char *dac_name(int sys, int offset)
218 {
219 if ((sys < sound_cards) && (audio_mixer[sys] >= -1))
220 {
221 snprintf(dev_name, LABEL_BUFFER_SIZE, "%s%d", DAC_NAME, audio_dsp[sys] + offset);
222 return(dev_name);
223 }
224 return((char *)DAC_NAME);
225 }
226
227 #define MIXER_SIZE SOUND_MIXER_NRDEVICES
228 static int **mixer_state = NULL;
229 static int *init_srate = NULL, *init_chans = NULL, *init_format = NULL;
230
oss_mus_audio_initialize(void)231 static int oss_mus_audio_initialize(void)
232 {
233 /* here we need to set up the map of /dev/dsp and /dev/mixer to a given system */
234 /* since this info is not passed to us by OSS, we have to work at it... */
235 /* for the time being, I'll ignore auxiliary dsp and mixer ports (each is a special case) */
236 int amp, old_mixer_amp, old_dsp_amp, new_mixer_amp;
237 int devmask;
238 #ifdef NEW_OSS
239 int status, ignored;
240 oss_sysinfo sysinfo;
241 static mixer_info mixinfo;
242 int sysinfo_ok = 0;
243 #endif
244 if (!audio_initialized)
245 {
246 int i, num_mixers, num_dsps, nmix, ndsp, err = 0, fd = -1, responsive_field;
247 audio_initialized = true;
248 audio_fd = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
249 audio_open_ctr = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
250 audio_dsp = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
251 audio_mixer = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
252 audio_mode = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
253 dev_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
254 init_srate = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
255 init_chans = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
256 init_format = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
257 mixer_state = (int **)calloc(MAX_SOUNDCARDS, sizeof(int *));
258 for (i = 0; i < MAX_SOUNDCARDS; i++) mixer_state[i] = (int *)calloc(MIXER_SIZE, sizeof(int));
259 for (i = 0; i < MAX_SOUNDCARDS; i++)
260 {
261 audio_fd[i] = -1;
262 audio_open_ctr[i] = 0;
263 audio_dsp[i] = -1;
264 audio_mixer[i] = -1;
265 }
266
267 num_mixers = MAX_MIXERS;
268 num_dsps = MAX_DSPS;
269 #ifdef NEW_OSS
270 fd = open(DAC_NAME, O_WRONLY | O_NONBLOCK, 0);
271 if (fd == -1) fd = open(MIXER_NAME, O_RDONLY | O_NONBLOCK, 0);
272 if (fd != -1)
273 {
274 status = ioctl(fd, OSS_GETVERSION, &ignored);
275 new_oss_running = (status == 0);
276 if (new_oss_running)
277 {
278 status = ioctl(fd, OSS_SYSINFO, &sysinfo);
279 sysinfo_ok = (status == 0);
280 }
281 if ((new_oss_running) && (sysinfo_ok))
282 {
283 num_mixers = sysinfo.nummixers;
284 num_dsps = sysinfo.numaudios;
285 }
286 close(fd);
287 }
288 #endif
289
290 /* need to get which /dev/dsp lines match which /dev/mixer lines,
291 * find out how many separate systems (soundcards) are available,
292 * fill the audio_dsp and audio_mixer arrays with the system-related numbers,
293 * since we have no way to tell from OSS info which mixers/dsps are the
294 * main ones, we'll do some messing aound to try to deduce this info.
295 * for example, SB uses two dsp ports and two mixers per card, whereas
296 * Ensoniq uses 2 dsps and 1 mixer.
297 *
298 * the data we are gathering here:
299 * int audio_dsp[MAX_SOUNDCARDS] -> main_dsp_port[n] (-1 => no such system dsp)
300 * int audio_mixer[MAX_SOUNDCARDS] -> main_mixer_port[n]
301 * int sound_cards = 0 -> usable systems
302 * all auxiliary ports are currently ignored (SB equalizer, etc)
303 */
304 sound_cards = 0;
305 ndsp = 0;
306 nmix = 0;
307 while ((nmix < num_mixers) &&
308 (ndsp < num_dsps))
309 {
310 char dname[LABEL_BUFFER_SIZE];
311 int md;
312 /* for each mixer, find associated main dsp (assumed to be first in /dev/dsp ordering) */
313 /* if mixer's dsp overlaps or we run out of dsps first, ignore it (aux mixer) */
314 /* our by-guess-or-by-gosh method here is to try to open the mixer.
315 * if that fails, quit (if very first, try at least to get the dsp setup)
316 * find volume field, if none, go on, else read current volume
317 * open next unchecked dsp, try to set volume, read current, if different we found a match -- set and go on.
318 * if no change, move to next dsp and try again, if no more dsps, quit (checking for null case as before)
319 */
320 snprintf(dname, LABEL_BUFFER_SIZE, "%s%d", MIXER_NAME, nmix);
321 md = open(dname, O_RDWR, 0);
322 if (md == -1)
323 {
324 if (errno == EBUSY)
325 {
326 mus_print("%s is busy: can't access it [%s[%d] %s]",
327 dname,
328 __FILE__, __LINE__, __func__);
329 nmix++;
330 continue;
331 }
332 else break;
333 }
334 snprintf(dname, LABEL_BUFFER_SIZE, "%s%d", DAC_NAME, ndsp);
335 fd = open(dname, O_RDWR | O_NONBLOCK, 0);
336 if (fd == -1) fd = open(dname, O_RDONLY | O_NONBLOCK, 0);
337 if (fd == -1) fd = open(dname, O_WRONLY | O_NONBLOCK, 0); /* some output devices need this */
338 if (fd == -1)
339 {
340 close(md);
341 if (errno == EBUSY) /* in linux /usr/include/asm-generic/errno-base.h */
342 {
343 fprintf(stderr, "%s is busy: can't access it\n", dname);
344 ndsp++;
345 continue;
346 }
347 else
348 {
349 if ((errno != ENXIO) && (errno != ENODEV) && (errno != ENOENT))
350 fprintf(stderr, "%s: %s! ", dname, strerror(errno));
351 break;
352 }
353 }
354 #ifdef NEW_OSS
355 status = ioctl(md, SOUND_MIXER_INFO, &mixinfo);
356 #endif
357 err = ioctl(md, SOUND_MIXER_READ_DEVMASK, &devmask);
358 responsive_field = SOUND_MIXER_VOLUME;
359 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
360 if ((1 << i) & devmask)
361 {
362 responsive_field = i;
363 break;
364 }
365 if (!err)
366 {
367 err = ioctl(md, MIXER_READ(responsive_field), &old_mixer_amp);
368 if (!err)
369 {
370 err = ioctl(fd, MIXER_READ(responsive_field), &old_dsp_amp);
371 if ((!err) && (old_dsp_amp == old_mixer_amp))
372 {
373 if (old_mixer_amp == 0) amp = 50; else amp = 0; /* 0..100 */
374 err = ioctl(fd, MIXER_WRITE(responsive_field), &);
375 if (!err)
376 {
377 err = ioctl(md, MIXER_READ(responsive_field), &new_mixer_amp);
378 if (!err)
379 {
380 if (new_mixer_amp == amp)
381 {
382 /* found one! */
383 audio_dsp[sound_cards] = ndsp; ndsp++;
384 audio_mixer[sound_cards] = nmix; nmix++;
385 sound_cards++;
386 }
387 else ndsp++;
388 err = ioctl(fd, MIXER_WRITE(responsive_field), &old_dsp_amp);
389 }
390 else nmix++;
391 }
392 else ndsp++;
393 }
394 else ndsp++;
395 }
396 else nmix++;
397 }
398 else nmix++;
399 close(fd);
400 close(md);
401 }
402 if (sound_cards == 0)
403 {
404 fd = open(DAC_NAME, O_WRONLY | O_NONBLOCK, 0);
405 if (fd != -1)
406 {
407 sound_cards = 1;
408 audio_dsp[0] = 0;
409 audio_mixer[0] = -2; /* hmmm -- need a way to see /dev/dsp as lonely outpost */
410 close(fd);
411 fd = open(MIXER_NAME, O_RDONLY | O_NONBLOCK, 0);
412 if (fd == -1)
413 audio_mixer[0] = -3;
414 else close(fd);
415 }
416 }
417 }
418 return(MUS_NO_ERROR);
419 }
420
linux_audio_open(const char * pathname,int flags,mode_t mode,int system)421 static int linux_audio_open(const char *pathname, int flags, mode_t mode, int system)
422 {
423 /* sometimes this is simply searching for a device (so failure is not a mus_error) */
424 if (audio_fd[system] == -1)
425 {
426 audio_fd[system] = open(pathname, flags, mode);
427 audio_open_ctr[system] = 0;
428 }
429 else audio_open_ctr[system]++;
430 return(audio_fd[system]);
431 }
432
linux_audio_open_with_error(const char * pathname,int flags,mode_t mode,int system)433 static int linux_audio_open_with_error(const char *pathname, int flags, mode_t mode, int system)
434 {
435 int fd;
436 static bool already_warned = false;
437 if ((system < 0) ||
438 (system >= MAX_SOUNDCARDS))
439 return(-1);
440
441 fd = linux_audio_open(pathname, flags, mode, system);
442 if ((fd == -1) &&
443 (!already_warned))
444 {
445 already_warned = true;
446 mus_standard_io_error(MUS_AUDIO_CANT_OPEN,
447 ((mode == O_RDONLY) ? "open read" :
448 (mode == O_WRONLY) ? "open write" : "open read/write"),
449 pathname);
450 }
451 return(fd);
452 }
453
find_system(int line)454 static int find_system(int line)
455 {
456 int i;
457 for (i = 0; i < sound_cards; i++)
458 if (line == audio_fd[i])
459 return(i);
460 return(MUS_ERROR);
461 }
462
linux_audio_close(int fd)463 static int linux_audio_close(int fd)
464 {
465 if (fd != -1)
466 {
467 int err = 0, sys;
468 sys = find_system(fd);
469 if (sys != -1)
470 {
471 if (audio_open_ctr[sys] > 0)
472 audio_open_ctr[sys]--;
473 else
474 {
475 err = close(fd);
476 audio_open_ctr[sys] = 0;
477 audio_fd[sys] = -1;
478 }
479 }
480 else err = close(fd);
481 if (err) return_error_exit(MUS_AUDIO_CANT_CLOSE, -1,
482 mus_format("close %d failed: %s",
483 fd, strerror(errno)));
484 }
485 /* is this an error? */
486 return(MUS_NO_ERROR);
487 }
488
to_oss_sample_type(mus_sample_t snd_format)489 static int to_oss_sample_type(mus_sample_t snd_format)
490 {
491 switch (snd_format)
492 {
493 case MUS_BYTE: return(AFMT_S8);
494 case MUS_BSHORT: return(AFMT_S16_BE);
495 case MUS_UBYTE: return(AFMT_U8);
496 case MUS_MULAW: return(AFMT_MU_LAW);
497 case MUS_ALAW: return(AFMT_A_LAW);
498 case MUS_LSHORT: return(AFMT_S16_LE);
499 case MUS_UBSHORT: return(AFMT_U16_BE);
500 case MUS_ULSHORT: return(AFMT_U16_LE);
501 #ifdef NEW_OSS
502 case MUS_LINT: return(AFMT_S32_LE);
503 case MUS_BINT: return(AFMT_S32_BE);
504 #endif
505 default: break;
506 }
507 return(MUS_ERROR);
508 }
509
510 static bool fragment_set_failed = false;
511
oss_mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)512 static int oss_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
513 {
514 int oss_sample_type, buffer_info, audio_out = -1, sys, dev;
515 char *dev_name;
516 #ifndef NEW_OSS
517 int stereo;
518 #endif
519 sys = MUS_AUDIO_SYSTEM(ur_dev);
520 dev = MUS_AUDIO_DEVICE(ur_dev);
521 oss_sample_type = to_oss_sample_type(samp_type);
522 if (oss_sample_type == MUS_ERROR)
523 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
524 mus_format("sample type %d (%s) not available",
525 samp_type,
526 mus_sample_type_name(samp_type)));
527
528 if (dev == MUS_AUDIO_DEFAULT)
529 audio_out = linux_audio_open_with_error(dev_name = dac_name(sys, 0),
530 O_WRONLY, 0, sys);
531 else audio_out = linux_audio_open_with_error(dev_name = dac_name(sys, (dev == MUS_AUDIO_AUX_OUTPUT) ? 1 : 0),
532 O_RDWR, 0, sys);
533 if (audio_out == -1) return(MUS_ERROR);
534
535 /* ioctl(audio_out, SNDCTL_DSP_RESET, 0); */ /* causes clicks */
536 if ((fragments_locked) &&
537 (!(fragment_set_failed)) &&
538 ((dev == MUS_AUDIO_DUPLEX_DEFAULT) ||
539 (size != 0))) /* only set if user has previously called set_oss_buffers */
540 {
541 buffer_info = (FRAGMENTS << 16) | (FRAGMENT_SIZE);
542 if (ioctl(audio_out, SNDCTL_DSP_SETFRAGMENT, &buffer_info) == -1)
543 {
544 /* older Linuces (or OSS's?) refuse to handle the fragment reset if O_RDWR used --
545 * someone at OSS forgot to update the version number when this was fixed, so
546 * I have no way to get around this except to try and retry...
547 */
548 linux_audio_close(audio_out);
549 audio_out = linux_audio_open_with_error(dev_name = dac_name(sys, (dev == MUS_AUDIO_AUX_OUTPUT) ? 1 : 0),
550 O_WRONLY, 0, sys);
551 if (audio_out == -1) return(MUS_ERROR);
552 buffer_info = (FRAGMENTS << 16) | (FRAGMENT_SIZE);
553 if (ioctl(audio_out, SNDCTL_DSP_SETFRAGMENT, &buffer_info) == -1)
554 {
555 char *tmp;
556 tmp = mus_format("can't set %s fragments to: %d x %d",
557 dev_name, FRAGMENTS, FRAGMENT_SIZE); /* not an error if ALSA OSS-emulation */
558 fprintf(stderr, "%s\n", tmp);
559 fragment_set_failed = true;
560 free(tmp);
561 }
562 }
563 }
564 if ((ioctl(audio_out, MUS_OSS_SET_FORMAT, &oss_sample_type) == -1) ||
565 (oss_sample_type != to_oss_sample_type(samp_type)))
566 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_out,
567 mus_format("sample type %d (%s) not available on %s",
568 samp_type,
569 mus_sample_type_name(samp_type),
570 dev_name));
571 #ifdef NEW_OSS
572 if (ioctl(audio_out, MUS_OSS_WRITE_CHANNELS, &chans) == -1)
573 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_out,
574 mus_format("can't get %d channels on %s",
575 chans, dev_name));
576 #else
577 if (chans == 2) stereo = 1; else stereo = 0;
578 if ((ioctl(audio_out, SNDCTL_DSP_STEREO, &stereo) == -1) ||
579 ((chans == 2) && (stereo == 0)))
580 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_out,
581 mus_format("can't get %d channels on %s",
582 chans, dev_name));
583 #endif
584 if (ioctl(audio_out, MUS_OSS_WRITE_RATE, &srate) == -1)
585 return_error_exit(MUS_AUDIO_SRATE_NOT_AVAILABLE, audio_out,
586 mus_format("can't set srate of %s to %d",
587 dev_name, srate));
588 /* http://www.4front-tech.com/pguide/audio.html says this order has to be followed */
589 return(audio_out);
590 }
591
oss_mus_audio_write(int line,char * buf,int bytes)592 static int oss_mus_audio_write(int line, char *buf, int bytes)
593 {
594 int err;
595 if (line < 0) return(-1);
596 errno = 0;
597 err = write(line, buf, bytes);
598 if (err != bytes)
599 {
600 if (errno != 0)
601 return_error_exit(MUS_AUDIO_WRITE_ERROR, -1,
602 mus_format("write error: %s", strerror(errno)));
603 else return_error_exit(MUS_AUDIO_WRITE_ERROR, -1,
604 mus_format("wrote %d bytes of requested %d", err, bytes));
605 }
606 return(MUS_NO_ERROR);
607 }
608
oss_mus_audio_close(int line)609 static int oss_mus_audio_close(int line)
610 {
611 return(linux_audio_close(line));
612 }
613
oss_mus_audio_read(int line,char * buf,int bytes)614 static int oss_mus_audio_read(int line, char *buf, int bytes)
615 {
616 int err;
617 if (line < 0) return(-1);
618 errno = 0;
619 err = read(line, buf, bytes);
620 if (err != bytes)
621 {
622 if (errno != 0)
623 return_error_exit(MUS_AUDIO_READ_ERROR, -1,
624 mus_format("read error: %s", strerror(errno)));
625 else return_error_exit(MUS_AUDIO_READ_ERROR, -1,
626 mus_format("read %d bytes of requested %d", err, bytes));
627 }
628 return(MUS_NO_ERROR);
629 }
630
oss_unsrc(int srcbit)631 static char *oss_unsrc(int srcbit)
632 {
633 if (srcbit == 0)
634 return(mus_strdup("none"));
635 else
636 {
637 bool need_and = false;
638 char *buf;
639 buf = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
640 if (srcbit & SOUND_MASK_MIC) {need_and = true; strcat(buf, "mic");}
641 if (srcbit & SOUND_MASK_LINE) {if (need_and) strcat(buf, " and "); need_and = true; strcat(buf, "line in");}
642 if (srcbit & SOUND_MASK_CD) {if (need_and) strcat(buf, " and "); strcat(buf, "cd");}
643 return(buf);
644 }
645 }
646
647
oss_mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int requested_size)648 static int oss_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size)
649 {
650 /* dev can be MUS_AUDIO_DEFAULT or MUS_AUDIO_DUPLEX_DEFAULT as well as the obvious others */
651 int audio_fd = -1, oss_sample_type, buffer_info, sys, dev, srcbit, cursrc, err;
652 char *dev_name;
653 #ifndef NEW_OSS
654 int stereo;
655 #endif
656 sys = MUS_AUDIO_SYSTEM(ur_dev);
657 dev = MUS_AUDIO_DEVICE(ur_dev);
658 oss_sample_type = to_oss_sample_type(samp_type);
659 if (oss_sample_type == MUS_ERROR)
660 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
661 mus_format("sample type %d (%s) not available",
662 samp_type,
663 mus_sample_type_name(samp_type)));
664
665 if (((dev == MUS_AUDIO_DEFAULT) || (dev == MUS_AUDIO_DUPLEX_DEFAULT)) && (sys == 0))
666 audio_fd = linux_audio_open(dev_name = dac_name(sys, 0),
667 O_RDWR, 0, sys);
668 else audio_fd = linux_audio_open(dev_name = dac_name(sys, 0), O_RDONLY, 0, sys);
669 if (audio_fd == -1)
670 {
671 if (dev == MUS_AUDIO_DUPLEX_DEFAULT)
672 return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
673 mus_format("can't open %s: %s",
674 dev_name, strerror(errno)));
675 if ((audio_fd = linux_audio_open(dev_name = dac_name(sys, 0), O_RDONLY, 0, sys)) == -1)
676 {
677 if ((errno == EACCES) || (errno == ENOENT))
678 return_error_exit(MUS_AUDIO_NO_READ_PERMISSION, -1,
679 mus_format("can't open %s: %s\n to get input in Linux, we need read permission on /dev/dsp",
680 dev_name,
681 strerror(errno)));
682 else return_error_exit(MUS_AUDIO_NO_INPUT_AVAILABLE, -1,
683 mus_format("can't open %s: %s",
684 dev_name,
685 strerror(errno)));
686 }
687 }
688 #ifdef SNDCTL_DSP_SETDUPLEX
689 else
690 ioctl(audio_fd, SNDCTL_DSP_SETDUPLEX, &err); /* not always a no-op! */
691 #endif
692 /* need to make sure the desired recording source is active -- does this actually have any effect? */
693 switch (dev)
694 {
695 case MUS_AUDIO_MICROPHONE: srcbit = SOUND_MASK_MIC; break;
696 case MUS_AUDIO_LINE_IN: srcbit = SOUND_MASK_LINE; break;
697 case MUS_AUDIO_DUPLEX_DEFAULT:
698 case MUS_AUDIO_DEFAULT: srcbit = SOUND_MASK_LINE | SOUND_MASK_MIC; break;
699 default: srcbit = 0; break;
700
701 }
702 ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECSRC), &cursrc);
703 srcbit = (srcbit | cursrc);
704 ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_RECSRC), &srcbit);
705 ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECSRC), &cursrc);
706 if (cursrc != srcbit)
707 {
708 char *str1, *str2;
709 str1 = oss_unsrc(srcbit);
710 str2 = oss_unsrc(cursrc);
711 mus_print("weird: tried to set recorder source to %s, but got %s?", str1, str2);
712 free(str1);
713 free(str2);
714 }
715 if ((fragments_locked) && (requested_size != 0))
716 {
717 buffer_info = (FRAGMENTS << 16) | (FRAGMENT_SIZE);
718 ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &buffer_info);
719 }
720 if ((ioctl(audio_fd, MUS_OSS_SET_FORMAT, &oss_sample_type) == -1) ||
721 (oss_sample_type != to_oss_sample_type(samp_type)))
722 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_fd,
723 mus_format("can't set %s sample type to %d (%s)",
724 dev_name, samp_type,
725 mus_sample_type_name(samp_type)));
726 #ifdef NEW_OSS
727 if (ioctl(audio_fd, MUS_OSS_WRITE_CHANNELS, &chans) == -1)
728 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
729 mus_format("can't get %d channels on %s",
730 chans, dev_name));
731 #else
732 if (chans == 2) stereo = 1; else stereo = 0;
733 if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) ||
734 ((chans == 2) && (stereo == 0)))
735 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
736 mus_format("can't get %d channels on %s",
737 chans, dev_name));
738 #endif
739 if (ioctl(audio_fd, MUS_OSS_WRITE_RATE, &srate) == -1)
740 return_error_exit(MUS_AUDIO_SRATE_NOT_AVAILABLE, audio_fd,
741 mus_format("can't set srate to %d on %s",
742 srate, dev_name));
743 return(audio_fd);
744 }
745
746
747 #if (!HAVE_ALSA) && (!HAVE_JACK_IN_LINUX)
oss_sample_types(int ur_dev,mus_sample_t * val)748 static int oss_sample_types(int ur_dev, mus_sample_t *val)
749 {
750 int fd, samp_types = 0, sys, ind;
751
752 sys = MUS_AUDIO_SYSTEM(ur_dev);
753 /* dev = MUS_AUDIO_DEVICE(ur_dev); */
754
755 fd = open(dac_name(sys, 0), O_WRONLY, 0);
756 if (fd == -1) fd = open(DAC_NAME, O_WRONLY, 0);
757 if (fd == -1)
758 {
759 return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
760 mus_format("can't open %s: %s",
761 DAC_NAME, strerror(errno)));
762 return(MUS_ERROR);
763 }
764
765 ioctl(fd, MUS_OSS_GET_FORMATS, &samp_types);
766 ind = 1;
767 if (samp_types & (to_oss_sample_type(MUS_BSHORT))) val[ind++] = MUS_BSHORT;
768 if (samp_types & (to_oss_sample_type(MUS_LSHORT))) val[ind++] = MUS_LSHORT;
769 if (samp_types & (to_oss_sample_type(MUS_MULAW))) val[ind++] = MUS_MULAW;
770 if (samp_types & (to_oss_sample_type(MUS_ALAW))) val[ind++] = MUS_ALAW;
771 if (samp_types & (to_oss_sample_type(MUS_BYTE))) val[ind++] = MUS_BYTE;
772 if (samp_types & (to_oss_sample_type(MUS_UBYTE))) val[ind++] = MUS_UBYTE;
773 if (samp_types & (to_oss_sample_type(MUS_UBSHORT))) val[ind++] = MUS_UBSHORT;
774 if (samp_types & (to_oss_sample_type(MUS_ULSHORT))) val[ind++] = MUS_ULSHORT;
775 val[0] = (mus_sample_t)(ind - 1);
776 return(MUS_NO_ERROR);
777 }
778 #endif
779
780
781
782
783 /* ------------------------------- ALSA, OSS, Jack-in-Linux ----------------------------------- */
784
785 static int api = MUS_ALSA_API;
mus_audio_api(void)786 int mus_audio_api(void) {return(api);}
787
788 /* hopefully first call to sndlib will be this... */
789 static int probe_api(void);
790 static int (*vect_mus_audio_initialize)(void);
791
792 /* FIXME: add a suitable default for all other vectors
793 so that a call happening before mus_audio_initialize
794 can be detected */
795 /* I don't think this is necessary -- documentation discusses this
796 * (mus_sound_initialize calls mus_audio_initialize)
797 */
798
799 /* vectors for the rest of the sndlib api */
800 static void (*vect_mus_oss_set_buffers)(int num, int size);
801 static char* (*vect_mus_audio_moniker)(void);
802 static int (*vect_mus_audio_open_output)(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size);
803 static int (*vect_mus_audio_open_input)(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size);
804 static int (*vect_mus_audio_write)(int id, char *buf, int bytes);
805 static int (*vect_mus_audio_read)(int id, char *buf, int bytes);
806 static int (*vect_mus_audio_close)(int id);
807
808 /* vectors for the rest of the sndlib api */
mus_audio_initialize(void)809 int mus_audio_initialize(void)
810 {
811 return(probe_api());
812 }
813
mus_oss_set_buffers(int num,int size)814 void mus_oss_set_buffers(int num, int size)
815 {
816 vect_mus_oss_set_buffers(num, size);
817 }
818
819 #if HAVE_ALSA
820 static char* alsa_mus_audio_moniker(void);
821 #endif
822
mus_audio_moniker(void)823 char* mus_audio_moniker(void)
824 {
825 #if (HAVE_OSS && HAVE_ALSA)
826 char *both_names;
827 both_names = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
828 /* need to be careful here since these use the same constant buffer */
829 strcpy(both_names, oss_mus_audio_moniker());
830 strcat(both_names, ", ");
831 strcat(both_names, alsa_mus_audio_moniker());
832 return(both_names); /* tiny memory leak ... */
833 #else
834 return(vect_mus_audio_moniker());
835 #endif
836 }
837
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)838 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
839 {
840 return(vect_mus_audio_open_output(ur_dev, srate, chans, samp_type, size));
841 }
842
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int requested_size)843 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size)
844 {
845 return(vect_mus_audio_open_input(ur_dev, srate, chans, samp_type, requested_size));
846 }
847
mus_audio_write(int id,char * buf,int bytes)848 int mus_audio_write(int id, char *buf, int bytes)
849 {
850 return(vect_mus_audio_write(id, buf, bytes));
851 }
852
mus_audio_read(int id,char * buf,int bytes)853 int mus_audio_read(int id, char *buf, int bytes)
854 {
855 return(vect_mus_audio_read(id, buf, bytes));
856 }
857
mus_audio_close(int id)858 int mus_audio_close(int id)
859 {
860 return(vect_mus_audio_close(id));
861 }
862
863 #if HAVE_JACK_IN_LINUX
864 static int jack_mus_audio_initialize(void);
865 #endif
866
867 #if (!HAVE_ALSA)
probe_api(void)868 static int probe_api(void)
869 {
870 #if HAVE_JACK_IN_LINUX
871 {
872 int jackprobe = jack_mus_audio_initialize();
873 if (jackprobe == MUS_ERROR)
874 {
875 #endif
876 /* go for the oss api */
877 api = MUS_OSS_API;
878 vect_mus_audio_initialize = oss_mus_audio_initialize;
879 vect_mus_oss_set_buffers = oss_mus_oss_set_buffers;
880 vect_mus_audio_moniker = oss_mus_audio_moniker;
881 vect_mus_audio_open_output = oss_mus_audio_open_output;
882 vect_mus_audio_open_input = oss_mus_audio_open_input;
883 vect_mus_audio_write = oss_mus_audio_write;
884 vect_mus_audio_read = oss_mus_audio_read;
885 vect_mus_audio_close = oss_mus_audio_close;
886 return(vect_mus_audio_initialize());
887 #if HAVE_JACK_IN_LINUX
888 }
889 return(jackprobe);
890 }
891 #endif
892 }
893 #endif
894
895 #endif
896
897
898 /* ------------------------------- ALSA ----------------------------------------- */
899 /*
900 * Changed the names of the environment variables to use MUS, not SNDLIB.
901 * reformatted and reorganized to be like the rest of the code
902 * changed default device to "default"
903 * -- Bill 3-Feb-06
904 *
905 * error handling (mus_error) changed by Bill 14-Nov-02
906 * 0.5 support removed by Bill 24-Mar-02
907 *
908 * changed for 0.9.x api by Fernando Lopez-Lezcano <nando@ccrma.stanford.edu>
909 *
910 * sndlib "exports" only one soundcard with two directions (if they are available),
911 * and only deals with the alsa library pcm's. It does not scan for available
912 * cards and devices at the hardware level. Which device it uses can be defined by:
913 *
914 * - setting variables in the environment (searched for in the following order):
915 * MUS_ALSA_PLAYBACK_DEVICE
916 * defines the name of the playback device
917 * MUS_ALSA_CAPTURE_DEVICE
918 * defines the name of the capture device
919 * MUS_ALSA_DEVICE
920 * defines the name of the playback and capture device
921 * use the first two if the playback and capture devices are different or the
922 * third if they are the same.
923 * - if no variables are found in the environment sndlib tries to probe for a
924 * default device named "sndlib" (in alsa 0.9 devices are configured in
925 * /usr/share/alsa/alsa.conf or in ~/.asoundrc)
926 * - if "sndlib" is not a valid device "hw:0,0" was used [but now it looks for "default"] (which by default should
927 * point to the first device of the first card
928 *
929 * Some default settings are controllable through the environment as well:
930 * MUS_ALSA_BUFFER_SIZE = size of each buffer in frames
931 * MUS_ALSA_BUFFERS = number of buffers
932 *
933 * changed 18-Sep-00 by Bill: new error handling: old mus_audio_error folded into
934 * mus_error; mus_error itself should be used only for "real" errors -- things
935 * that can cause a throw (a kind of global jump elsewhere); use mus_print for informational
936 * stuff -- in Snd, mus_print will also save everything printed in the error dialog.
937 * In a few cases, I tried to fix the code to unwind before mus_error, and in others
938 * I've changed mus_error to mus_print, but some of these may be mistaken.
939 * Look for ?? below for areas where I'm not sure I rewrote code correctly.
940 *
941 * changed for 0.6.x api by Paul Barton-Davis, pbd@op.net
942 *
943 * changed for 0.5.x api by Fernando Lopez-Lezcano, nando@ccrma.stanford.edu
944 * 04-10-2000:
945 * based on original 0.4.x code by Paul Barton-Davis (not much left of it :-)
946 * also Bill's code and Jaroslav Kysela (aplay.c and friends)
947 *
948 * Changes:
949 * 04/25/2000: finished major rework, snd-dac now automatically decides which
950 * device or devices it uses for playback. Multiple device use is
951 * for now restricted to only two at most (more changes in Bill's
952 * needed to be able to support more). Four channel playback in
953 * Ensoniq AudioPCI and relatives possible (with proper settings
954 * of the mixer) as well as using two separate cards.
955 * 04/11/2000: added reporting of alsa sound formats
956 */
957
958 #if HAVE_ALSA
959
960 #if (!HAVE_OSS)
961 #define AUDIO_OK 1
962 #endif
963
964 #include <sys/ioctl.h>
965
966 #if HAVE_ALSA
967 #include <alsa/asoundlib.h>
968 #else
969 #include <sys/asoundlib.h>
970 #endif
971
972 #if SND_LIB_VERSION < ((0<<16)|(6<<8)|(0))
973 #error ALSA version is too old -- audio.c needs 0.9 or later
974 #endif
975
976 /* prototypes for the alsa sndlib functions */
977 static int alsa_mus_audio_initialize(void);
978 static void alsa_mus_oss_set_buffers(int num, int size);
979 static int alsa_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size);
980 static int alsa_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size);
981 static int alsa_mus_audio_write(int id, char *buf, int bytes);
982 static int alsa_mus_audio_read(int id, char *buf, int bytes);
983 static int alsa_mus_audio_close(int id);
984
985 /* decide which api to activate */
986
probe_api(void)987 static int probe_api(void)
988 {
989 #if HAVE_JACK_IN_LINUX
990 int jackprobe;
991 jackprobe = jack_mus_audio_initialize();
992 if (jackprobe == MUS_ERROR)
993 {
994 #endif
995 int card = -1;
996 if ((snd_card_next(&card) >= 0) && (card >= 0))
997 {
998 /* the alsa library has detected one or more cards */
999 api = MUS_ALSA_API;
1000 vect_mus_audio_initialize = alsa_mus_audio_initialize;
1001 vect_mus_oss_set_buffers = alsa_mus_oss_set_buffers;
1002 vect_mus_audio_moniker = alsa_mus_audio_moniker;
1003 vect_mus_audio_open_output = alsa_mus_audio_open_output;
1004 vect_mus_audio_open_input = alsa_mus_audio_open_input;
1005 vect_mus_audio_write = alsa_mus_audio_write;
1006 vect_mus_audio_read = alsa_mus_audio_read;
1007 vect_mus_audio_close = alsa_mus_audio_close;
1008 }
1009 else
1010 {
1011 /* go for the oss api */
1012 api = MUS_OSS_API;
1013 vect_mus_audio_initialize = oss_mus_audio_initialize;
1014 vect_mus_oss_set_buffers = oss_mus_oss_set_buffers;
1015 vect_mus_audio_moniker = oss_mus_audio_moniker;
1016 vect_mus_audio_open_output = oss_mus_audio_open_output;
1017 vect_mus_audio_open_input = oss_mus_audio_open_input;
1018 vect_mus_audio_write = oss_mus_audio_write;
1019 vect_mus_audio_read = oss_mus_audio_read;
1020 vect_mus_audio_close = oss_mus_audio_close;
1021 }
1022 /* will the _real_ mus_audio_initialize please stand up? */
1023 return(vect_mus_audio_initialize());
1024 #if HAVE_JACK_IN_LINUX
1025 }
1026 return(jackprobe);
1027 #endif
1028 }
1029
1030 /* convert a sndlib sample type to an alsa sample type */
1031
to_alsa_format(mus_sample_t snd_format)1032 static snd_pcm_format_t to_alsa_format(mus_sample_t snd_format)
1033 {
1034 switch (snd_format)
1035 {
1036 case MUS_BYTE: return(SND_PCM_FORMAT_S8);
1037 case MUS_UBYTE: return(SND_PCM_FORMAT_U8);
1038 case MUS_MULAW: return(SND_PCM_FORMAT_MU_LAW);
1039 case MUS_ALAW: return(SND_PCM_FORMAT_A_LAW);
1040 case MUS_BSHORT: return(SND_PCM_FORMAT_S16_BE);
1041 case MUS_LSHORT: return(SND_PCM_FORMAT_S16_LE);
1042 case MUS_UBSHORT: return(SND_PCM_FORMAT_U16_BE);
1043 case MUS_ULSHORT: return(SND_PCM_FORMAT_U16_LE);
1044 case MUS_B24INT: return(SND_PCM_FORMAT_S24_BE);
1045 case MUS_L24INT: return(SND_PCM_FORMAT_S24_LE);
1046 case MUS_BINT: return(SND_PCM_FORMAT_S32_BE);
1047 case MUS_LINT: return(SND_PCM_FORMAT_S32_LE);
1048 case MUS_BINTN: return(SND_PCM_FORMAT_S32_BE);
1049 case MUS_LINTN: return(SND_PCM_FORMAT_S32_LE);
1050 case MUS_BFLOAT: return(SND_PCM_FORMAT_FLOAT_BE);
1051 case MUS_LFLOAT: return(SND_PCM_FORMAT_FLOAT_LE);
1052 case MUS_BDOUBLE: return(SND_PCM_FORMAT_FLOAT64_BE);
1053 case MUS_LDOUBLE: return(SND_PCM_FORMAT_FLOAT64_LE);
1054 default: break;
1055 }
1056 return((snd_pcm_format_t)MUS_ERROR);
1057 }
1058
1059 /* FIXME: this is not taking yet into account the
1060 * number of bits that a given alsa format is actually
1061 * using...
1062 */
1063
to_mus_sample_type(int alsa_format)1064 static mus_sample_t to_mus_sample_type(int alsa_format)
1065 {
1066 /* alsa format definitions from asoundlib.h (0.9 cvs 6/27/2001) */
1067 switch (alsa_format)
1068 {
1069 case SND_PCM_FORMAT_S8: return(MUS_BYTE);
1070 case SND_PCM_FORMAT_U8: return(MUS_UBYTE);
1071 case SND_PCM_FORMAT_S16_LE: return(MUS_LSHORT);
1072 case SND_PCM_FORMAT_S16_BE: return(MUS_BSHORT);
1073 case SND_PCM_FORMAT_U16_LE: return(MUS_ULSHORT);
1074 case SND_PCM_FORMAT_U16_BE: return(MUS_UBSHORT);
1075 case SND_PCM_FORMAT_S24_LE: return(MUS_L24INT);
1076 case SND_PCM_FORMAT_S24_BE: return(MUS_B24INT);
1077 case SND_PCM_FORMAT_S32_LE: return(MUS_LINTN); /* 32bit normalized plays 24bit and 16bit files with same amplitude bound (for 24 bit cards) */
1078 case SND_PCM_FORMAT_S32_BE: return(MUS_BINTN);
1079 case SND_PCM_FORMAT_FLOAT_LE: return(MUS_LFLOAT);
1080 case SND_PCM_FORMAT_FLOAT_BE: return(MUS_BFLOAT);
1081 case SND_PCM_FORMAT_FLOAT64_LE: return(MUS_LDOUBLE);
1082 case SND_PCM_FORMAT_FLOAT64_BE: return(MUS_BDOUBLE);
1083 case SND_PCM_FORMAT_MU_LAW: return(MUS_MULAW);
1084 case SND_PCM_FORMAT_A_LAW: return(MUS_ALAW);
1085 /* formats with no translation in snd */
1086 case SND_PCM_FORMAT_U24_LE:
1087 case SND_PCM_FORMAT_U24_BE:
1088 case SND_PCM_FORMAT_U32_LE:
1089 case SND_PCM_FORMAT_U32_BE:
1090 case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
1091 case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
1092 case SND_PCM_FORMAT_IMA_ADPCM:
1093 case SND_PCM_FORMAT_MPEG:
1094 case SND_PCM_FORMAT_GSM:
1095 case SND_PCM_FORMAT_SPECIAL:
1096 default:
1097 return(MUS_UNKNOWN_SAMPLE);
1098 }
1099 }
1100
1101 /* convert a sndlib device into an alsa device number and channel
1102 * [has to be coordinated with following function!]
1103 */
1104
1105 /* very simplistic approach, device mapping should also depend
1106 * on which card we're dealing with, digital i/o devices should
1107 * be identified as such and so on
1108 */
1109
1110 /* NOTE: in the Delta1010 digital i/o is just a pair of channels
1111 * in the 10 channel playback frame or 12 channel capture frame,
1112 * how do we specify that???
1113 */
1114
to_alsa_device(int dev,int * adev,snd_pcm_stream_t * achan)1115 static int to_alsa_device(int dev, int *adev, snd_pcm_stream_t *achan)
1116 {
1117 switch (dev)
1118 {
1119 /* default values are a problem because the concept does
1120 * not imply a direction (playback or capture). This works
1121 * fine as long as both directions of a device are symmetric,
1122 * the Midiman 1010, for example, has 10 channel frames for
1123 * playback and 12 channel frames for capture and breaks
1124 * the recorder (probes the default, defaults to output,
1125 * uses the values for input).
1126 */
1127 case MUS_AUDIO_DEFAULT:
1128 case MUS_AUDIO_DUPLEX_DEFAULT:
1129 case MUS_AUDIO_LINE_OUT:
1130 /* analog output */
1131 (*adev) = 0;
1132 (*achan) = SND_PCM_STREAM_PLAYBACK;
1133 break;
1134
1135 case MUS_AUDIO_AUX_OUTPUT:
1136 /* extra analog output */
1137 (*adev) = 1;
1138 (*achan) = SND_PCM_STREAM_PLAYBACK;
1139 break;
1140
1141 case MUS_AUDIO_DAC_OUT:
1142 /* analog outputs */
1143 (*adev) = 2;
1144 (*achan) = SND_PCM_STREAM_PLAYBACK;
1145 break;
1146
1147 case MUS_AUDIO_MICROPHONE:
1148 case MUS_AUDIO_LINE_IN:
1149 /* analog input */
1150 (*adev) = 0;
1151 (*achan) = SND_PCM_STREAM_CAPTURE;
1152 break;
1153
1154 default:
1155 return(MUS_ERROR);
1156 break;
1157 }
1158 return(0);
1159 }
1160
1161 /* convert an alsa device into a sndlib device
1162 * [has to be coordinated with previous function!]
1163 *
1164 * naming here is pretty much arbitrary. We have to have
1165 * a bidirectional mapping between sndlib devices and
1166 * alsa devices and that's just not possible (I think).
1167 * This stopgap mapping ignores digital input and output
1168 * devices - how to differentiate them in alsa?
1169 */
1170
to_sndlib_device(int dev,int channel)1171 static int to_sndlib_device(int dev, int channel)
1172 {
1173 switch (channel)
1174 {
1175 case SND_PCM_STREAM_PLAYBACK:
1176 switch (dev)
1177 {
1178 /* works only for the first three outputs */
1179 case 0: return(MUS_AUDIO_LINE_OUT);
1180 case 1: return(MUS_AUDIO_AUX_OUTPUT);
1181 case 2: return(MUS_AUDIO_DAC_OUT);
1182 default:
1183 return(MUS_ERROR);
1184 }
1185 case SND_PCM_STREAM_CAPTURE:
1186 switch (dev)
1187 {
1188 case 0: return(MUS_AUDIO_LINE_IN);
1189 default:
1190 return(MUS_ERROR);
1191 }
1192 break;
1193 }
1194 return(MUS_ERROR);
1195 }
1196
1197
alsa_mus_error(int type,char * message)1198 static int alsa_mus_error(int type, char *message)
1199 {
1200 if (message)
1201 {
1202 mus_print("%s", message);
1203 free(message);
1204 }
1205 return(MUS_ERROR);
1206 }
1207
1208
1209 /* dump current hardware and software configuration */
1210
alsa_dump_configuration(char * name,snd_pcm_hw_params_t * hw_params,snd_pcm_sw_params_t * sw_params)1211 static void alsa_dump_configuration(char *name, snd_pcm_hw_params_t *hw_params, snd_pcm_sw_params_t *sw_params)
1212 {
1213 int err;
1214 char *str;
1215 snd_output_t *buf;
1216
1217 #if (SND_LIB_MAJOR == 0) || ((SND_LIB_MAJOR == 1) && (SND_LIB_MINOR == 0) && (SND_LIB_SUBMINOR < 8))
1218 return; /* avoid Alsa bug */
1219 #endif
1220
1221 err = snd_output_buffer_open(&buf);
1222 if (err < 0)
1223 mus_print("could not open dump buffer: %s", snd_strerror(err));
1224 else
1225 {
1226 size_t len;
1227 if (hw_params)
1228 {
1229 snd_output_puts(buf, "hw_params status of ");
1230 snd_output_puts(buf, name);
1231 snd_output_puts(buf, "\n");
1232 err = snd_pcm_hw_params_dump(hw_params, buf);
1233 if (err < 0)
1234 mus_print("snd_pcm_hw_params_dump: %s", snd_strerror(err));
1235 }
1236 if (sw_params)
1237 {
1238 snd_output_puts(buf, "sw_params status of ");
1239 snd_output_puts(buf, name);
1240 snd_output_puts(buf, "\n");
1241 err = snd_pcm_sw_params_dump(sw_params, buf);
1242 if (err < 0)
1243 mus_print("snd_pcm_hw_params_dump: %s", snd_strerror(err));
1244 }
1245 snd_output_putc(buf, '\0');
1246 len = snd_output_buffer_string(buf, &str);
1247 if (len > 1)
1248 mus_print("status of %s\n%s", name, str);
1249 snd_output_close(buf);
1250 }
1251 }
1252
1253 /* get hardware params for a pcm */
1254
alsa_get_hardware_params(const char * name,snd_pcm_stream_t stream,int mode)1255 static snd_pcm_hw_params_t *alsa_get_hardware_params(const char *name, snd_pcm_stream_t stream, int mode)
1256 {
1257 int err;
1258 snd_pcm_t *handle;
1259 if ((err = snd_pcm_open(&handle, name, stream, mode | SND_PCM_NONBLOCK)) != 0)
1260 {
1261 alsa_mus_error(MUS_AUDIO_CANT_OPEN,
1262 mus_format("open pcm %s for stream %d: %s",
1263 name, stream, snd_strerror(err)));
1264 return(NULL);
1265 }
1266 else
1267 {
1268 snd_pcm_hw_params_t *params;
1269 params = (snd_pcm_hw_params_t *)calloc(1, snd_pcm_hw_params_sizeof());
1270 if (!params)
1271 {
1272 snd_pcm_close(handle);
1273 alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1274 mus_format("could not allocate memory for hardware params"));
1275 }
1276 else
1277 {
1278 err = snd_pcm_hw_params_any(handle, params);
1279 if (err < 0)
1280 {
1281 snd_pcm_close(handle);
1282 alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1283 mus_format("snd_pcm_hw_params_any: pcm %s, stream %d, error: %s",
1284 name, stream, snd_strerror(err)));
1285 }
1286 else
1287 {
1288 snd_pcm_close(handle);
1289 return(params);
1290 }
1291 }
1292 }
1293 return(NULL);
1294 }
1295
1296 /* allocate software params structure */
1297
alsa_get_software_params(void)1298 static snd_pcm_sw_params_t *alsa_get_software_params(void)
1299 {
1300 snd_pcm_sw_params_t *params = NULL;
1301 params = (snd_pcm_sw_params_t *)calloc(1, snd_pcm_sw_params_sizeof());
1302 if (!params)
1303 {
1304 alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1305 mus_format("could not allocate memory for software params"));
1306 }
1307 return(params);
1308 }
1309
1310 /* probe a device name against the list of available pcm devices */
1311
alsa_probe_device_name(const char * name)1312 static bool alsa_probe_device_name(const char *name)
1313 {
1314 snd_config_t *conf;
1315 snd_config_iterator_t pos, next;
1316 int err;
1317
1318 err = snd_config_update();
1319 if (err < 0)
1320 {
1321 mus_print("snd_config_update: %s", snd_strerror(err));
1322 return(false);
1323 }
1324
1325 err = snd_config_search(snd_config, "pcm", &conf);
1326 if (err < 0)
1327 {
1328 mus_print("snd_config_search: %s", snd_strerror(err));
1329 return(false);
1330 }
1331
1332 snd_config_for_each(pos, next, conf)
1333 {
1334 snd_config_t *c = snd_config_iterator_entry(pos);
1335 const char *id;
1336 int err = snd_config_get_id(c, &id);
1337 if (err == 0) {
1338 int result = strncmp(name, id, strlen(id));
1339 if (result == 0 &&
1340 (name[strlen(id)] == '\0' || name[strlen(id)] == ':'))
1341 {
1342 return(true);
1343 }
1344 }
1345 }
1346 return(false);
1347 }
1348
1349 /* check a device name against the list of available pcm devices */
1350
alsa_check_device_name(const char * name)1351 static int alsa_check_device_name(const char *name)
1352 {
1353 if (!alsa_probe_device_name(name))
1354 {
1355 return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1356 mus_format("alsa could not find device \"%s\" in configuration",
1357 name)));
1358 }
1359 return(MUS_NO_ERROR);
1360 }
1361
1362
1363 /* set scheduling priority to SCHED_FIFO
1364 * this will only work if the program that uses sndlib is run as root or is suid root
1365 */
1366
1367 /* whether we want to trace calls
1368 *
1369 * set to "1" to print function trace information in the
1370 * snd error window
1371 */
1372
1373 static int alsa_trace = 0;
1374
1375 /* this should go away as it is oss specific */
1376
1377 static int fragment_size = 512;
1378 static int fragments = 4;
1379
alsa_mus_oss_set_buffers(int num,int size)1380 static void alsa_mus_oss_set_buffers(int num, int size)
1381 {
1382 fragments = num;
1383 fragment_size = size;
1384 }
1385
1386 /* total number of soundcards in our setup, set by initialize_audio */
1387
1388 /* static int sound_cards = 0; */
1389
1390 /* return the number of cards that are available */
1391
1392 /* return the type of driver we're dealing with */
1393
alsa_mus_audio_moniker(void)1394 static char *alsa_mus_audio_moniker(void)
1395 {
1396 if (!version_name) version_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
1397 snprintf(version_name, LABEL_BUFFER_SIZE, "ALSA %s", SND_LIB_VERSION_STR);
1398 return(version_name);
1399 }
1400
1401 /* handles for both directions of the virtual device */
1402
1403 static snd_pcm_t *handles[2] = {NULL, NULL};
1404
1405 /* hardware and software parameter sctructure pointers */
1406
1407 static snd_pcm_hw_params_t *alsa_hw_params[2] = {NULL, NULL}; /* avoid bogus free */
1408 static snd_pcm_sw_params_t *alsa_sw_params[2] = {NULL, NULL};
1409
1410 /* some defaults */
1411
1412 static int alsa_open_mode = SND_PCM_ASYNC;
1413 static int alsa_buffers = 3;
1414 /* size of buffer in number of samples per channel,
1415 * at 44100 approximately 5.9mSecs
1416 */
1417 static int alsa_samples_per_channel = 1024;
1418 static snd_pcm_access_t alsa_interleave = SND_PCM_ACCESS_RW_INTERLEAVED;
1419 static int alsa_max_capture_channels = 32;
1420
1421 /* first default name for pcm configuration */
1422
1423 static char *alsa_sndlib_device_name = (char *)"sndlib";
1424
1425 /* second default for playback and capture: hardware pcm, first card, first device */
1426 /* pcms used by sndlib, playback and capture */
1427
1428 static char *alsa_playback_device_name = NULL;
1429 static char *alsa_capture_device_name = NULL;
1430
1431
1432
1433 /* -------- tie these names into scheme/ruby -------- */
1434
alsa_get_max_buffers(void)1435 static int alsa_get_max_buffers(void)
1436 {
1437 uint32_t max_periods = 0, max_rec_periods = 0;
1438 int dir = 0;
1439
1440 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1441 snd_pcm_hw_params_get_periods_max(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &max_periods, &dir);
1442
1443 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1444 {
1445 snd_pcm_hw_params_get_periods_max(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &max_rec_periods, &dir);
1446
1447 if (max_periods > max_rec_periods)
1448 max_periods = max_rec_periods;
1449 }
1450 return(max_periods);
1451 }
1452
alsa_get_min_buffers(void)1453 static int alsa_get_min_buffers(void)
1454 {
1455 uint32_t min_periods = 0, min_rec_periods = 0;
1456 int dir = 0;
1457 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1458 snd_pcm_hw_params_get_periods_min(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &min_periods, &dir);
1459
1460 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1461 {
1462 snd_pcm_hw_params_get_periods_min(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &min_rec_periods, &dir);
1463
1464 if (min_periods < min_rec_periods)
1465 min_periods = min_rec_periods;
1466 }
1467 return(min_periods);
1468 }
1469
alsa_clamp_buffers(int bufs)1470 static int alsa_clamp_buffers(int bufs)
1471 {
1472 int minb, maxb;
1473 minb = alsa_get_min_buffers();
1474 maxb = alsa_get_max_buffers();
1475 if (bufs > maxb)
1476 bufs = maxb;
1477 if (bufs < minb)
1478 bufs = minb;
1479 return(bufs);
1480 }
1481
alsa_get_min_buffer_size(void)1482 static snd_pcm_uframes_t alsa_get_min_buffer_size(void)
1483 {
1484 snd_pcm_uframes_t min_buffer_size = 0, min_rec_buffer_size = 0;
1485 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1486 snd_pcm_hw_params_get_buffer_size_min(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &min_buffer_size);
1487
1488 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1489 {
1490 snd_pcm_hw_params_get_buffer_size_min(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &min_rec_buffer_size);
1491 if (min_buffer_size < min_rec_buffer_size)
1492 min_buffer_size = min_rec_buffer_size;
1493 }
1494 return(min_buffer_size);
1495 }
1496
alsa_get_max_buffer_size(void)1497 static snd_pcm_uframes_t alsa_get_max_buffer_size(void)
1498 {
1499 snd_pcm_uframes_t max_buffer_size = 0, max_rec_buffer_size = 0;
1500 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1501 snd_pcm_hw_params_get_buffer_size_max(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &max_buffer_size);
1502
1503 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1504 {
1505 snd_pcm_hw_params_get_buffer_size_max(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &max_rec_buffer_size);
1506 if (max_buffer_size > max_rec_buffer_size)
1507 max_buffer_size = max_rec_buffer_size;
1508 }
1509 return(max_buffer_size);
1510 }
1511
alsa_clamp_buffer_size(snd_pcm_uframes_t buf_size)1512 static snd_pcm_uframes_t alsa_clamp_buffer_size(snd_pcm_uframes_t buf_size)
1513 {
1514 snd_pcm_uframes_t minb, maxb;
1515 minb = alsa_get_min_buffer_size();
1516 maxb = alsa_get_max_buffer_size();
1517 if (buf_size > maxb)
1518 buf_size = maxb;
1519 if (buf_size < minb)
1520 buf_size = minb;
1521 return(buf_size);
1522 }
1523
alsa_set_playback_parameters(void)1524 static bool alsa_set_playback_parameters(void)
1525 {
1526 /* playback stream parameters */
1527 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK]) free(alsa_hw_params[SND_PCM_STREAM_PLAYBACK]);
1528 alsa_hw_params[SND_PCM_STREAM_PLAYBACK] = alsa_get_hardware_params(alsa_playback_device_name, SND_PCM_STREAM_PLAYBACK, alsa_open_mode);
1529 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1530 {
1531 snd_pcm_uframes_t size;
1532 int old_buffers;
1533 old_buffers = alsa_buffers;
1534 if (alsa_sw_params[SND_PCM_STREAM_PLAYBACK]) free(alsa_sw_params[SND_PCM_STREAM_PLAYBACK]);
1535 alsa_sw_params[SND_PCM_STREAM_PLAYBACK] = alsa_get_software_params();
1536 sound_cards = 1;
1537 alsa_buffers = alsa_clamp_buffers(alsa_buffers);
1538 if (alsa_buffers <= 0)
1539 {
1540 alsa_buffers = old_buffers;
1541 return(false);
1542 }
1543 size = alsa_clamp_buffer_size((snd_pcm_uframes_t)(alsa_samples_per_channel * alsa_buffers));
1544 if (size <= 0) return(false);
1545 alsa_samples_per_channel = size / alsa_buffers;
1546 }
1547 return(alsa_hw_params[SND_PCM_STREAM_PLAYBACK] && alsa_sw_params[SND_PCM_STREAM_PLAYBACK]);
1548 }
1549
alsa_set_capture_parameters(void)1550 static bool alsa_set_capture_parameters(void)
1551 {
1552 /* capture stream parameters */
1553 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE]) free(alsa_hw_params[SND_PCM_STREAM_CAPTURE]);
1554 alsa_hw_params[SND_PCM_STREAM_CAPTURE] = alsa_get_hardware_params(alsa_capture_device_name, SND_PCM_STREAM_CAPTURE, alsa_open_mode);
1555 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1556 {
1557 snd_pcm_uframes_t size;
1558 int old_buffers;
1559 old_buffers = alsa_buffers;
1560 if (alsa_sw_params[SND_PCM_STREAM_CAPTURE]) free(alsa_sw_params[SND_PCM_STREAM_CAPTURE]);
1561 alsa_sw_params[SND_PCM_STREAM_CAPTURE] = alsa_get_software_params();
1562 sound_cards = 1;
1563 alsa_buffers = alsa_clamp_buffers(alsa_buffers);
1564 if (alsa_buffers <= 0)
1565 {
1566 alsa_buffers = old_buffers;
1567 return(false);
1568 }
1569 size = alsa_clamp_buffer_size((snd_pcm_uframes_t)(alsa_samples_per_channel * alsa_buffers));
1570 if (size <= 0) return(false);
1571 alsa_samples_per_channel = size / alsa_buffers;
1572 }
1573 return(alsa_hw_params[SND_PCM_STREAM_CAPTURE] && alsa_sw_params[SND_PCM_STREAM_CAPTURE]);
1574 }
1575
1576
mus_alsa_playback_device(void)1577 char *mus_alsa_playback_device(void) {return(alsa_playback_device_name);}
mus_alsa_set_playback_device(const char * name)1578 char *mus_alsa_set_playback_device(const char *name)
1579 {
1580 if (alsa_check_device_name(name) == MUS_NO_ERROR)
1581 {
1582 char *old_name = alsa_playback_device_name;
1583 alsa_playback_device_name = mus_strdup(name);
1584 if (!alsa_set_playback_parameters())
1585 {
1586 alsa_playback_device_name = old_name; /* try to back out of the mistake */
1587 alsa_set_playback_parameters();
1588 }
1589 }
1590 return(alsa_playback_device_name);
1591 }
1592
mus_alsa_capture_device(void)1593 char *mus_alsa_capture_device(void) {return(alsa_capture_device_name);}
mus_alsa_set_capture_device(const char * name)1594 char *mus_alsa_set_capture_device(const char *name)
1595 {
1596 if (alsa_check_device_name(name) == MUS_NO_ERROR)
1597 {
1598 char *old_name = alsa_capture_device_name;
1599 alsa_capture_device_name = mus_strdup(name);
1600 if (!alsa_set_capture_parameters())
1601 {
1602 alsa_capture_device_name = old_name;
1603 alsa_set_capture_parameters();
1604 }
1605 }
1606 return(alsa_capture_device_name);
1607 }
1608
mus_alsa_device(void)1609 char *mus_alsa_device(void) {return(alsa_sndlib_device_name);}
mus_alsa_set_device(const char * name)1610 char *mus_alsa_set_device(const char *name)
1611 {
1612 if (alsa_check_device_name(name) == MUS_NO_ERROR)
1613 {
1614 alsa_sndlib_device_name = mus_strdup(name);
1615 mus_alsa_set_playback_device(name);
1616 mus_alsa_set_capture_device(name);
1617 }
1618 return(alsa_sndlib_device_name);
1619 }
1620
mus_alsa_buffer_size(void)1621 int mus_alsa_buffer_size(void) {return(alsa_samples_per_channel);}
mus_alsa_set_buffer_size(int size)1622 int mus_alsa_set_buffer_size(int size)
1623 {
1624 snd_pcm_uframes_t bsize;
1625 if (alsa_buffers == 0) alsa_buffers = 1;
1626 if (size > 0)
1627 {
1628 bsize = alsa_clamp_buffer_size((snd_pcm_uframes_t)(size * alsa_buffers));
1629 alsa_samples_per_channel = bsize / alsa_buffers;
1630 }
1631 return(alsa_samples_per_channel);
1632 }
1633
mus_alsa_buffers(void)1634 int mus_alsa_buffers(void) {return(alsa_buffers);}
mus_alsa_set_buffers(int num)1635 int mus_alsa_set_buffers(int num)
1636 {
1637 snd_pcm_uframes_t size;
1638 if (num > 0)
1639 {
1640 alsa_buffers = alsa_clamp_buffers(num);
1641 if (alsa_buffers > 0)
1642 {
1643 size = alsa_clamp_buffer_size((snd_pcm_uframes_t)(alsa_samples_per_channel * alsa_buffers));
1644 alsa_samples_per_channel = size / alsa_buffers;
1645 }
1646 }
1647 return(alsa_buffers);
1648 }
1649
1650 static bool alsa_squelch_warning = false;
mus_alsa_squelch_warning(void)1651 bool mus_alsa_squelch_warning(void) {return(alsa_squelch_warning);}
mus_alsa_set_squelch_warning(bool val)1652 bool mus_alsa_set_squelch_warning(bool val)
1653 {
1654 alsa_squelch_warning = val;
1655 return(val);
1656 }
1657
1658
1659
1660
1661 /* get a device name from the environment */
1662
alsa_get_device_from_env(const char * name)1663 static char *alsa_get_device_from_env(const char *name)
1664 {
1665 char *string = getenv(name);
1666 if (string)
1667 if (alsa_check_device_name(string) == MUS_NO_ERROR)
1668 return(string);
1669 return(NULL);
1670 }
1671
1672 /* get an integer from the environment */
1673
alsa_get_int_from_env(const char * name,int * value,int min,int max)1674 static int alsa_get_int_from_env(const char *name, int *value, int min, int max)
1675 {
1676 char *string = getenv(name);
1677 if (string)
1678 {
1679 char *end;
1680 long int result = strtol(string, &end, 10);
1681 if (((min != -1) && (max != -1)) &&
1682 (result < min || result > max))
1683 {
1684 return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1685 mus_format("%s ignored: out of range, value=%d, min=%d, max=%d",
1686 name, (int)result, min, max)));
1687 }
1688 else
1689 {
1690 if (errno == ERANGE)
1691 {
1692 return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1693 mus_format("%s ignored: strlol conversion out of range",
1694 name)));
1695 }
1696 else
1697 {
1698 if ((*string != '\0') && (*end == '\0'))
1699 {
1700 *value = (int)result;
1701 return(MUS_NO_ERROR);
1702 }
1703 else
1704 {
1705 return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1706 mus_format("%s ignored: value is \"%s\", not an integer",
1707 name, string)));
1708 }
1709 }
1710 }
1711 }
1712 return(MUS_ERROR);
1713 }
1714
1715 /* initialize the audio subsystem */
1716
1717 /* define environment variable names */
1718 #define MUS_ALSA_PLAYBACK_DEVICE_ENV_NAME "MUS_ALSA_PLAYBACK_DEVICE"
1719 #define MUS_ALSA_CAPTURE_DEVICE_ENV_NAME "MUS_ALSA_CAPTURE_DEVICE"
1720 #define MUS_ALSA_DEVICE_ENV_NAME "MUS_ALSA_DEVICE"
1721 #define MUS_ALSA_BUFFERS_ENV_NAME "MUS_ALSA_BUFFERS"
1722 #define MUS_ALSA_BUFFER_SIZE_ENV_NAME "MUS_ALSA_BUFFER_SIZE"
1723 #define MUS_ALSA_TRACE_ENV_NAME "MUS_ALSA_TRACE"
1724
alsa_mus_audio_initialize(void)1725 static int alsa_mus_audio_initialize(void)
1726 {
1727 char *name = NULL;
1728 char *pname;
1729 char *cname;
1730 int value = 0, alsa_buffer_size = 0;
1731
1732 if (audio_initialized)
1733 return(0);
1734
1735 sound_cards = 0;
1736
1737 /* get trace flag from environment */
1738 if (alsa_get_int_from_env(MUS_ALSA_TRACE_ENV_NAME, &value, 0, 1) == MUS_NO_ERROR)
1739 alsa_trace = value;
1740
1741 /* try to get device names from environment */
1742 pname = alsa_get_device_from_env(MUS_ALSA_PLAYBACK_DEVICE_ENV_NAME);
1743 if ((pname) && (alsa_probe_device_name(pname)))
1744 alsa_playback_device_name = pname;
1745
1746 cname = alsa_get_device_from_env(MUS_ALSA_CAPTURE_DEVICE_ENV_NAME);
1747 if ((cname) && (alsa_probe_device_name(cname)))
1748 alsa_capture_device_name = cname;
1749
1750 name = alsa_get_device_from_env(MUS_ALSA_DEVICE_ENV_NAME);
1751 if ((name) && (alsa_probe_device_name(name)))
1752 {
1753 if (!alsa_playback_device_name)
1754 alsa_playback_device_name = name;
1755
1756 if (!alsa_capture_device_name)
1757 alsa_capture_device_name = name;
1758
1759 alsa_sndlib_device_name = name;
1760 }
1761
1762 /* now check that we have a plausible name */
1763 if (!alsa_probe_device_name(alsa_sndlib_device_name))
1764 {
1765 alsa_sndlib_device_name = (char *)"default";
1766 if (!alsa_probe_device_name(alsa_sndlib_device_name))
1767 {
1768 alsa_sndlib_device_name = (char *)"plughw:0";
1769 if (!alsa_probe_device_name(alsa_sndlib_device_name))
1770 alsa_sndlib_device_name = (char *)"hw:0";
1771 }
1772 }
1773
1774 /* if no device name set yet, try for special sndlib name first */
1775 if (!alsa_playback_device_name)
1776 {
1777 if (alsa_probe_device_name(alsa_sndlib_device_name))
1778 alsa_playback_device_name = alsa_sndlib_device_name;
1779 else alsa_playback_device_name = (char *)"hw:0";
1780 }
1781
1782 if (!alsa_capture_device_name)
1783 {
1784 if (alsa_probe_device_name(alsa_sndlib_device_name))
1785 alsa_capture_device_name = alsa_sndlib_device_name;
1786 else alsa_capture_device_name = (char *)"hw:0";
1787 }
1788
1789 alsa_get_int_from_env(MUS_ALSA_BUFFERS_ENV_NAME, &alsa_buffers, -1, -1);
1790 alsa_get_int_from_env(MUS_ALSA_BUFFER_SIZE_ENV_NAME, &alsa_buffer_size, -1, -1);
1791
1792 if ((alsa_buffer_size > 0) && (alsa_buffers > 0))
1793 alsa_samples_per_channel = alsa_buffer_size / alsa_buffers;
1794
1795 if (!alsa_set_playback_parameters())
1796 {
1797 /* somehow we got a device that passed muster with alsa_probe_device_name, but doesn't return hw params! */
1798 alsa_playback_device_name = (char *)"plughw:0";
1799 if (!alsa_set_playback_parameters())
1800 {
1801 alsa_playback_device_name = (char *)"hw:0";
1802 if (!alsa_set_playback_parameters())
1803 return(MUS_ERROR);
1804 }
1805 }
1806
1807 if (!alsa_set_capture_parameters())
1808 {
1809 alsa_capture_device_name = (char *)"plughw:0";
1810 if (!alsa_set_capture_parameters())
1811 {
1812 alsa_capture_device_name = (char *)"hw:0";
1813 if (!alsa_set_capture_parameters())
1814 return(MUS_ERROR);
1815 }
1816 }
1817
1818 if ((!alsa_hw_params[SND_PCM_STREAM_CAPTURE]) ||
1819 (!alsa_hw_params[SND_PCM_STREAM_PLAYBACK]))
1820 return(MUS_ERROR);
1821
1822 audio_initialized = true;
1823 return(0);
1824 }
1825
1826 /* open an input or output stream */
1827
alsa_audio_open(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)1828 static int alsa_audio_open(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
1829 {
1830 int device, alsa_device;
1831 snd_pcm_format_t alsa_format;
1832 snd_pcm_stream_t alsa_stream;
1833 char *alsa_name;
1834 int frames, periods;
1835 int err;
1836 snd_pcm_t *handle;
1837 snd_pcm_hw_params_t *hw_params = NULL;
1838 snd_pcm_sw_params_t *sw_params = NULL;
1839
1840 if ((!audio_initialized) &&
1841 (mus_audio_initialize() != MUS_NO_ERROR))
1842 return(MUS_ERROR);
1843 if (chans <= 0) return(MUS_ERROR);
1844
1845 if (alsa_trace)
1846 mus_print("%s: %x rate=%d, chans=%d, format=%d:%s, size=%d",
1847 __func__, ur_dev, srate, chans, samp_type,
1848 mus_sample_type_to_string(samp_type), size);
1849
1850 /* card = MUS_AUDIO_SYSTEM(ur_dev); */
1851 device = MUS_AUDIO_DEVICE(ur_dev);
1852
1853 if ((err = to_alsa_device(device, &alsa_device, &alsa_stream)) < 0)
1854 {
1855 return(alsa_mus_error(MUS_AUDIO_DEVICE_NOT_AVAILABLE,
1856 mus_format("%s: cannot translate device %d to alsa",
1857 snd_strerror(err), device)));
1858 }
1859 if ((alsa_format = to_alsa_format(samp_type)) == (snd_pcm_format_t)MUS_ERROR)
1860 {
1861 return(alsa_mus_error(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE,
1862 mus_format("could not change %s<%d> to alsa format",
1863 mus_sample_type_to_string(samp_type), samp_type)));
1864 }
1865
1866 alsa_name = (alsa_stream == SND_PCM_STREAM_PLAYBACK) ? alsa_playback_device_name : alsa_capture_device_name;
1867 if ((err = snd_pcm_open(&handle, alsa_name, alsa_stream, alsa_open_mode)) != 0)
1868 {
1869 /* snd_pcm_close(handle); */
1870 /* this segfaults in some versions of ALSA */
1871 return(alsa_mus_error(MUS_AUDIO_CANT_OPEN,
1872 mus_format("open pcm %s stream %s: %s",
1873 alsa_name, snd_pcm_stream_name(alsa_stream),
1874 snd_strerror(err))));
1875 }
1876 handles[alsa_stream] = handle;
1877 hw_params = alsa_hw_params[alsa_stream];
1878 sw_params = alsa_sw_params[alsa_stream];
1879 if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0)
1880 {
1881 snd_pcm_close(handle);
1882 handles[alsa_stream] = NULL;
1883 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1884 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1885 mus_format("%s: no parameter configurations available for %s",
1886 snd_strerror(err), alsa_name)));
1887 }
1888
1889 err = snd_pcm_hw_params_set_access(handle, hw_params, alsa_interleave);
1890 if (err < 0)
1891 {
1892 snd_pcm_close(handle);
1893 handles[alsa_stream] = NULL;
1894 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1895 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1896 mus_format("%s: %s: access type %s not available",
1897 snd_strerror(err), alsa_name, snd_pcm_access_name(alsa_interleave))));
1898 }
1899
1900 periods = alsa_buffers;
1901 err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
1902 if (err < 0)
1903 {
1904 uint32_t minp, maxp;
1905 int dir;
1906 snd_pcm_hw_params_get_periods_min(hw_params, &minp, &dir);
1907 snd_pcm_hw_params_get_periods_max(hw_params, &maxp, &dir);
1908 snd_pcm_close(handle);
1909 handles[alsa_stream] = NULL;
1910 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1911 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1912 mus_format("%s: %s: cannot set number of periods to %d, min is %d, max is %d",
1913 snd_strerror(err), alsa_name, periods, (int)minp, (int)maxp)));
1914 }
1915
1916 frames = size / chans / mus_bytes_per_sample(samp_type);
1917
1918 err = snd_pcm_hw_params_set_buffer_size(handle, hw_params, frames * periods);
1919 if (err < 0)
1920 {
1921 snd_pcm_uframes_t minp, maxp;
1922 snd_pcm_hw_params_get_buffer_size_min(hw_params, &minp);
1923 snd_pcm_hw_params_get_buffer_size_max(hw_params, &maxp);
1924 snd_pcm_close(handle);
1925 handles[alsa_stream] = NULL;
1926 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1927 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1928 mus_format("%s: %s: cannot set buffer size to %d periods of %d frames; \
1929 total requested buffer size is %d frames, minimum allowed is %d, maximum is %d",
1930 snd_strerror(err), alsa_name, periods, frames, periods * frames, (int)minp, (int)maxp)));
1931 }
1932
1933 err = snd_pcm_hw_params_set_format(handle, hw_params, alsa_format);
1934 if (err < 0)
1935 {
1936 snd_pcm_close(handle);
1937 handles[alsa_stream] = NULL;
1938 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1939 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1940 mus_format("%s: %s: cannot set format to %s",
1941 snd_strerror(err), alsa_name, snd_pcm_format_name(alsa_format))));
1942 }
1943
1944 err = snd_pcm_hw_params_set_channels(handle, hw_params, chans);
1945 if (err < 0)
1946 {
1947 snd_pcm_close(handle);
1948 handles[alsa_stream] = NULL;
1949 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1950 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1951 mus_format("%s: %s: cannot set channels to %d",
1952 snd_strerror(err), alsa_name, chans)));
1953 }
1954
1955 {
1956 uint32_t new_rate;
1957 new_rate = srate;
1958 /* r is uint32_t so it can't be negative */
1959 err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &new_rate, 0);
1960 if ((new_rate != (uint32_t)srate) && (!alsa_squelch_warning))
1961 {
1962 mus_print("%s: could not set rate to exactly %d, set to %d instead",
1963 alsa_name, srate, new_rate);
1964 }
1965 }
1966
1967 err = snd_pcm_hw_params(handle, hw_params);
1968 if (err < 0)
1969 {
1970 snd_pcm_close(handle);
1971 handles[alsa_stream] = NULL;
1972 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1973 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1974 mus_format("%s: cannot set hardware parameters for %s",
1975 snd_strerror(err), alsa_name)));
1976 }
1977
1978 snd_pcm_sw_params_current(handle, sw_params);
1979 err = snd_pcm_sw_params(handle, sw_params);
1980 if (err < 0)
1981 {
1982 snd_pcm_close(handle);
1983 handles[alsa_stream] = NULL;
1984 alsa_dump_configuration(alsa_name, hw_params, sw_params);
1985 return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1986 mus_format("%s: cannot set software parameters for %s",
1987 snd_strerror(err), alsa_name)));
1988 }
1989
1990 /* for now the id for the stream is the direction identifier, that is
1991 not a problem because we only advertise one card with two devices */
1992 return(alsa_stream);
1993 }
1994
1995 /* sndlib support for opening output devices */
1996
alsa_mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)1997 static int alsa_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
1998 {
1999 return(alsa_audio_open(ur_dev, srate, chans, samp_type, size));
2000 }
2001
2002 /* sndlib support for opening input devices */
2003
alsa_mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2004 static int alsa_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2005 {
2006 return(alsa_audio_open(ur_dev, srate, chans, samp_type, size));
2007 }
2008
2009 /* sndlib support for closing a device */
2010
2011 /* to force it to stop, snd_pcm_drop */
2012
2013 static bool xrun_warned = false;
2014
alsa_mus_audio_close(int id)2015 static int alsa_mus_audio_close(int id)
2016 {
2017 xrun_warned = false;
2018 if (id == MUS_ERROR) return(MUS_ERROR);
2019 if (alsa_trace) mus_print( "%s: %d", __func__, id);
2020 if (handles[id])
2021 {
2022 int err;
2023 err = snd_pcm_drain(handles[id]);
2024 if (err != 0)
2025 mus_print("snd_pcm_drain: %s", snd_strerror(err));
2026
2027 err = snd_pcm_close(handles[id]);
2028 if (err != 0)
2029 return(alsa_mus_error(MUS_AUDIO_CANT_CLOSE,
2030 mus_format("snd_pcm_close: %s",
2031 snd_strerror(err))));
2032 handles[id] = NULL;
2033 }
2034 return(MUS_NO_ERROR);
2035 }
2036
2037 /* recover from underruns or overruns */
2038
recover_from_xrun(int id)2039 static int recover_from_xrun(int id)
2040 {
2041 int err;
2042 snd_pcm_status_t *status;
2043 snd_pcm_state_t state;
2044 snd_pcm_status_alloca(&status);
2045 err = snd_pcm_status(handles[id], status);
2046 if (err < 0)
2047 {
2048 mus_print("%s: snd_pcm_status: %s", __func__, snd_strerror(err));
2049 return(MUS_ERROR);
2050 }
2051 state = snd_pcm_status_get_state(status);
2052 if (state == SND_PCM_STATE_XRUN)
2053 {
2054 if (!xrun_warned)
2055 {
2056 xrun_warned = true;
2057 mus_print("[under|over]run detected");
2058 }
2059 err = snd_pcm_prepare(handles[id]);
2060 if (err < 0)
2061 mus_print("snd_pcm_prepare: %s", snd_strerror(err));
2062 else return(MUS_NO_ERROR);
2063 }
2064 else mus_print("%s: error, current state is %s", __func__, snd_pcm_state_name(state));
2065 return(MUS_ERROR);
2066 }
2067
2068 /* sndlib support for writing a buffer to an output device */
2069
alsa_mus_audio_write(int id,char * buf,int bytes)2070 static int alsa_mus_audio_write(int id, char *buf, int bytes)
2071 {
2072 snd_pcm_sframes_t status;
2073 ssize_t frames;
2074 if (id == MUS_ERROR) return(MUS_ERROR);
2075 frames = snd_pcm_bytes_to_frames(handles[id], bytes);
2076 status = snd_pcm_writei(handles[id], buf, frames);
2077 if ((status == -EAGAIN) ||
2078 ((status >= 0) && (status < frames)))
2079 snd_pcm_wait(handles[id], 1000);
2080 else
2081 {
2082 if (status == -EPIPE)
2083 return(recover_from_xrun(id));
2084 else
2085 {
2086 if (status < 0)
2087 {
2088 mus_print("snd_pcm_writei: %s", snd_strerror(status));
2089 return(MUS_ERROR);
2090 }
2091 }
2092 }
2093 return(MUS_NO_ERROR);
2094 }
2095
2096 /* sndlib support for reading a buffer from an input device */
2097
alsa_mus_audio_read(int id,char * buf,int bytes)2098 static int alsa_mus_audio_read(int id, char *buf, int bytes)
2099 {
2100 snd_pcm_sframes_t status;
2101 ssize_t frames;
2102 if (id == MUS_ERROR) return(MUS_ERROR);
2103 frames = snd_pcm_bytes_to_frames(handles[id], bytes);
2104 status = snd_pcm_readi(handles[id], buf, frames);
2105 if ((status == -EAGAIN) ||
2106 ((status >= 0) && (status < frames)))
2107 snd_pcm_wait(handles[id], 1000);
2108 else
2109 {
2110 if (status == -EPIPE)
2111 return(recover_from_xrun(id));
2112 else
2113 {
2114 if (status < 0)
2115 {
2116 mus_print("snd_pcm_readi: %s", snd_strerror(status));
2117 return(MUS_ERROR);
2118 }
2119 }
2120 }
2121 return(MUS_NO_ERROR);
2122 }
2123
2124 /* read state of the audio hardware */
2125
alsa_chans(int ur_dev,int * info)2126 static int alsa_chans(int ur_dev, int *info)
2127 {
2128 int card;
2129 int device;
2130 int alsa_device = 0;
2131 snd_pcm_stream_t alsa_stream = SND_PCM_STREAM_PLAYBACK;
2132
2133 if ((!audio_initialized) &&
2134 (mus_audio_initialize() != MUS_NO_ERROR))
2135 return(MUS_ERROR);
2136
2137 card = MUS_AUDIO_SYSTEM(ur_dev);
2138 device = MUS_AUDIO_DEVICE(ur_dev);
2139 to_alsa_device(device, &alsa_device, &alsa_stream);
2140
2141 if (card > 0 || alsa_device > 0)
2142 return(alsa_mus_error(MUS_AUDIO_CANT_READ, NULL));
2143
2144 if ((alsa_stream == SND_PCM_STREAM_CAPTURE) &&
2145 (alsa_capture_device_name) &&
2146 (strcmp(alsa_capture_device_name, "default") == 0))
2147 {
2148 if (info)
2149 info[0] = 2;
2150 else return(2);
2151 }
2152
2153 {
2154 uint32_t max_channels = 0;
2155 snd_pcm_hw_params_get_channels_max(alsa_hw_params[alsa_stream], &max_channels);
2156
2157 if ((alsa_stream == SND_PCM_STREAM_CAPTURE) &&
2158 (max_channels > (uint32_t)alsa_max_capture_channels))
2159 {
2160 /* limit number of capture channels to a reasonable maximum, if the user
2161 specifies a plug pcm as the capture pcm then the returned number of channels
2162 would be MAXINT (or whatever the name is for a really big number). At this
2163 point there is no support in the alsa api to distinguish between default
2164 parameters or those that have been set by a user on purpose, of for querying
2165 the hardware pcm device that is hidden by the plug device to see what is the
2166 real number of channels for the device we are dealing with. We could also try
2167 to flag this as an error to the user and exit the program */
2168 max_channels = alsa_max_capture_channels;
2169 }
2170
2171 if (info)
2172 {
2173 uint32_t tmp = 0;
2174 info[0] = max_channels;
2175 snd_pcm_hw_params_get_channels_min(alsa_hw_params[alsa_stream], &tmp);
2176 info[1] = tmp;
2177 info[2] = max_channels;
2178 }
2179
2180 return(max_channels);
2181 }
2182 }
2183
2184
alsa_sample_types(int ur_dev,int chan,mus_sample_t * val)2185 static int alsa_sample_types(int ur_dev, int chan, mus_sample_t *val)
2186 {
2187 int card;
2188 int device;
2189 int alsa_device = 0;
2190 snd_pcm_stream_t alsa_stream = SND_PCM_STREAM_PLAYBACK;
2191
2192 if ((!audio_initialized) &&
2193 (mus_audio_initialize() != MUS_NO_ERROR))
2194 return(MUS_ERROR);
2195
2196 card = MUS_AUDIO_SYSTEM(ur_dev);
2197 device = MUS_AUDIO_DEVICE(ur_dev);
2198 to_alsa_device(device, &alsa_device, &alsa_stream);
2199
2200 if (card > 0 || alsa_device > 0)
2201 return(alsa_mus_error(MUS_AUDIO_CANT_READ, NULL));
2202
2203 {
2204 int f, format;
2205 snd_pcm_format_mask_t *mask;
2206
2207 snd_pcm_format_mask_alloca(&mask);
2208 snd_pcm_hw_params_get_format_mask(alsa_hw_params[alsa_stream], mask);
2209
2210 for (format = 0, f = 1; format < SND_PCM_FORMAT_LAST; format++)
2211 {
2212 int err;
2213 err = snd_pcm_format_mask_test(mask, (snd_pcm_format_t)format);
2214 if (err > 0)
2215 {
2216 if ((f < chan) &&
2217 (to_mus_sample_type(format) != MUS_UNKNOWN_SAMPLE))
2218 val[f++] = to_mus_sample_type(format);
2219 }
2220 }
2221 val[0] = (mus_sample_t)(f - 1);
2222 }
2223
2224 return(MUS_NO_ERROR);
2225 }
2226
2227 #endif /* HAVE_ALSA */
2228
2229
2230
2231 /* -------------------------------- SUN -------------------------------- */
2232 /*
2233 * Thanks to Seppo Ingalsuo for several bugfixes.
2234 * record case improved after perusal of Snack 1.6/src/jkAudio_sun.c
2235 */
2236
2237 /* apparently input other than 8000 is 16-bit, 8000 is (?) mulaw */
2238
2239 #if (defined(__sun) || defined(__SVR4)) && (!(defined(AUDIO_OK)))
2240 #define AUDIO_OK 1
2241
2242 #include <sys/types.h>
2243 #ifdef SUNOS
2244 #include <stropts.h>
2245 #endif
2246 #include <sys/filio.h>
2247
2248 #ifdef SUNOS
2249 #include <sun/audioio.h>
2250 #else
2251 #include <sys/audioio.h>
2252 #endif
2253
2254 #include <sys/mixer.h>
2255
mus_audio_initialize(void)2256 int mus_audio_initialize(void) {return(MUS_NO_ERROR);}
2257
2258 #define DAC_NAME "/dev/audio"
2259 #define AUDIODEV_ENV "AUDIODEV"
2260
2261 #define return_error_exit(Error_Type, Audio_Line, Ur_Error_Message) \
2262 do { char *Error_Message; Error_Message = Ur_Error_Message; \
2263 if (Audio_Line != -1) close(Audio_Line); \
2264 if (Error_Message) \
2265 {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
2266 else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
2267 return(MUS_ERROR); \
2268 } while (false)
2269
mus_audio_moniker(void)2270 char *mus_audio_moniker(void)
2271 {
2272 #ifndef AUDIO_DEV_AMD
2273 struct audio_device ad;
2274 #else
2275 int ad;
2276 #endif
2277 int audio_fd, err;
2278 char *dev_name;
2279 if (getenv(AUDIODEV_ENV))
2280 dev_name = getenv(AUDIODEV_ENV);
2281 else dev_name = (char *)DAC_NAME;
2282 audio_fd = open(dev_name, O_RDONLY | O_NONBLOCK, 0);
2283 if (audio_fd == -1)
2284 {
2285 audio_fd = open("/dev/audioctl", O_RDONLY | O_NONBLOCK, 0);
2286 if (audio_fd == -1) return("sun probably");
2287 }
2288 err = ioctl(audio_fd, AUDIO_GETDEV, &ad);
2289 if (err == -1)
2290 {
2291 close(audio_fd);
2292 return("sun?");
2293 }
2294 mus_audio_close(audio_fd);
2295
2296 if (!version_name) version_name = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
2297 #ifndef AUDIO_DEV_AMD
2298 snprintf(version_name, LABEL_BUFFER_SIZE, "audio: %s (%s)", ad.name, ad.version);
2299 #else
2300 switch (ad)
2301 {
2302 case AUDIO_DEV_AMD: snprintf(version_name, LABEL_BUFFER_SIZE, "audio: amd"); break;
2303 #ifdef AUDIO_DEV_CS4231
2304 case AUDIO_DEV_CS4231: snprintf(version_name, LABEL_BUFFER_SIZE, "audio: cs4231"); break;
2305 #endif
2306 case AUDIO_DEV_SPEAKERBOX: snprintf(version_name, LABEL_BUFFER_SIZE, "audio: speakerbox"); break;
2307 case AUDIO_DEV_CODEC: snprintf(version_name, LABEL_BUFFER_SIZE, "audio: codec"); break;
2308 default: snprintf(version_name, LABEL_BUFFER_SIZE, "audio: unknown"); break;
2309 }
2310 #endif
2311 return(version_name);
2312 }
2313
to_sun_sample_type(mus_sample_t samp_type)2314 static int to_sun_sample_type(mus_sample_t samp_type)
2315 {
2316 switch (samp_type)
2317 {
2318 #if MUS_LITTLE_ENDIAN
2319 case MUS_LSHORT: /* Solaris on Intel? */
2320 #else
2321 case MUS_BSHORT:
2322 #endif
2323 return(AUDIO_ENCODING_LINEAR);
2324 break;
2325 case MUS_BYTE:
2326 #if defined(AUDIO_ENCODING_LINEAR8)
2327 return(AUDIO_ENCODING_LINEAR8); break;
2328 #else
2329 return(AUDIO_ENCODING_LINEAR);
2330 break;
2331 #endif
2332 case MUS_MULAW: return(AUDIO_ENCODING_ULAW); break;
2333 case MUS_ALAW: return(AUDIO_ENCODING_ALAW); break;
2334 /* there's also AUDIO_ENCODING_DVI */
2335
2336 default: break;
2337 }
2338 return(MUS_ERROR);
2339 }
2340
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2341 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2342 {
2343 struct audio_info info;
2344 char *dev_name;
2345 int encode, bits, dev;
2346 int audio_fd, err;
2347 dev = MUS_AUDIO_DEVICE(ur_dev);
2348 encode = to_sun_sample_type(samp_type);
2349 if (encode == MUS_ERROR)
2350 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
2351 mus_format("sample type %d (%s) not available",
2352 samp_type,
2353 mus_sample_type_name(samp_type)));
2354 if (getenv(AUDIODEV_ENV))
2355 dev_name = getenv(AUDIODEV_ENV);
2356 else dev_name = (char *)DAC_NAME;
2357 if (dev != MUS_AUDIO_DUPLEX_DEFAULT)
2358 audio_fd = open(dev_name, O_WRONLY, 0);
2359 else audio_fd = open(dev_name, O_RDWR, 0);
2360 if (audio_fd == -1)
2361 return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
2362 mus_format("can't open output %s: %s",
2363 dev_name, strerror(errno)));
2364 AUDIO_INITINFO(&info);
2365 if (dev == MUS_AUDIO_LINE_OUT)
2366 info.play.port = AUDIO_LINE_OUT;
2367 else
2368 {
2369 if (dev == MUS_AUDIO_SPEAKERS)
2370 /* OR may not be available */
2371 info.play.port = AUDIO_SPEAKER | AUDIO_HEADPHONE;
2372 else
2373 info.play.port = AUDIO_SPEAKER;
2374 }
2375 info.play.sample_rate = srate;
2376 info.play.channels = chans;
2377 bits = 8 * mus_bytes_per_sample(samp_type);
2378 info.play.precision = bits;
2379 info.play.encoding = encode;
2380 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2381 if (err == -1)
2382 {
2383 ioctl(audio_fd, AUDIO_GETINFO, &info);
2384
2385 if ((int)info.play.channels != chans)
2386 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
2387 mus_format("can't set output %s channels to %d",
2388 dev_name, chans));
2389
2390 if (((int)info.play.precision != bits) ||
2391 ((int)info.play.encoding != encode))
2392 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_fd,
2393 mus_format("can't set output %s sample type to %d bits, %d encode (%s)",
2394 dev_name,
2395 bits, encode,
2396 mus_sample_type_name(samp_type)));
2397
2398 if ((int)info.play.sample_rate != srate)
2399 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
2400 mus_format("can't set output %s srate to %d",
2401 dev_name, srate));
2402 }
2403 /* man audio sez the play.buffer_size field is not currently supported */
2404 /* but since the default buffer size is 8180! we need ioctl(audio_fd, I_SETSIG, ...) */
2405 #ifdef SUNOS
2406 ioctl(audio_fd, I_FLUSH, FLUSHR);
2407 #endif
2408 return(audio_fd);
2409 }
2410
mus_audio_write(int line,char * buf,int bytes)2411 int mus_audio_write(int line, char *buf, int bytes)
2412 {
2413 if (write(line, buf, bytes) != bytes)
2414 return_error_exit(MUS_AUDIO_WRITE_ERROR, -1,
2415 mus_format("write error: %s", strerror(errno)));
2416 return(MUS_NO_ERROR);
2417 }
2418
mus_audio_close(int line)2419 int mus_audio_close(int line)
2420 {
2421 write(line, (char *)NULL, 0);
2422 close(line);
2423 return(MUS_NO_ERROR);
2424 }
2425
mus_audio_read(int line,char * buf,int bytes)2426 int mus_audio_read(int line, char *buf, int bytes)
2427 {
2428 int total = 0;
2429 char *curbuf;
2430 /* ioctl(line, AUDIO_DRAIN, NULL) */
2431 /* this seems to return 8-12 bytes fewer than requested -- perverse! */
2432 /* should I buffer data internally? */
2433
2434 /* apparently we need to loop here ... */
2435 curbuf = buf;
2436 while (total < bytes)
2437 {
2438 int bytes_available;
2439 ioctl(line, FIONREAD, &bytes_available);
2440 if (bytes_available > 0)
2441 {
2442 int bytes_read;
2443 if ((total + bytes_available) > bytes) bytes_available = bytes - total;
2444 bytes_read = read(line, curbuf, bytes_available);
2445 if (bytes_read > 0)
2446 {
2447 total += bytes_read;
2448 curbuf = (char *)(buf + total);
2449 }
2450 /* else return anyway?? */
2451 }
2452 }
2453 return(MUS_NO_ERROR);
2454 }
2455
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2456 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2457 {
2458 struct audio_info info;
2459 int indev, encode, bits, dev, audio_fd, err;
2460 char *dev_name;
2461 dev = MUS_AUDIO_DEVICE(ur_dev);
2462 encode = to_sun_sample_type(samp_type);
2463 bits = 8 * mus_bytes_per_sample(samp_type);
2464 if (encode == -1)
2465 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
2466 mus_format("sample type %d bits, %d encode (%s) not available",
2467 bits, encode,
2468 mus_sample_type_name(samp_type)));
2469 if (getenv(AUDIODEV_ENV))
2470 dev_name = getenv(AUDIODEV_ENV);
2471 else dev_name = (char *)DAC_NAME;
2472 if (dev != MUS_AUDIO_DUPLEX_DEFAULT)
2473 audio_fd = open(dev_name, O_RDONLY, 0);
2474 else audio_fd = open(dev_name, O_RDWR, 0);
2475 if (audio_fd == -1)
2476 return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
2477 mus_format("can't open input %s: %s",
2478 dev_name, strerror(errno)));
2479 AUDIO_INITINFO(&info);
2480 /* ioctl(audio_fd, AUDIO_GETINFO, &info); */
2481 info.record.sample_rate = srate;
2482 info.record.channels = chans;
2483 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2484 if (err == -1)
2485 return_error_exit(MUS_AUDIO_CANT_OPEN, audio_fd,
2486 mus_format("can't set srate %d and chans %d for input %s",
2487 srate, chans,
2488 dev_name));
2489 ioctl(audio_fd, AUDIO_GETINFO, &info);
2490 if (info.record.sample_rate != (uint32_t)srate)
2491 mus_print("%s[%d]: sampling rate: %d != %d\n",
2492 __FILE__, __LINE__,
2493 info.record.sample_rate, srate);
2494 if (info.record.channels != (uint32_t)chans)
2495 mus_print("%s[%d]: channels: %d != %d\n",
2496 __FILE__, __LINE__,
2497 info.record.channels, chans);
2498
2499 info.record.precision = bits; /* was play, changed 10-Jul-03 thanks to Jurgen Keil */
2500 info.record.encoding = encode;
2501 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2502 if (err == -1)
2503 return_error_exit(MUS_AUDIO_CANT_OPEN, audio_fd,
2504 mus_format("can't set bits %d, encode %d (sample type %s) for input %s",
2505 bits, encode, mus_sample_type_name(samp_type),
2506 dev_name));
2507 ioctl(audio_fd, AUDIO_GETINFO, &info);
2508
2509 /* these cannot be OR'd */
2510 if (dev == MUS_AUDIO_LINE_IN)
2511 indev = AUDIO_LINE_IN;
2512 else indev = AUDIO_MICROPHONE;
2513 info.record.port = indev;
2514 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2515 if (err == -1)
2516 return_error_exit(MUS_AUDIO_CANT_WRITE, audio_fd,
2517 mus_format("can't set record.port to %d for %s",
2518 indev, dev_name));
2519 err = ioctl(audio_fd, AUDIO_GETINFO, &info);
2520 if (err == -1)
2521 return_error_exit(MUS_AUDIO_CANT_READ, audio_fd,
2522 mus_format("can't getinfo on input %s (line: %d)",
2523 dev_name,
2524 audio_fd));
2525 else
2526 {
2527 if ((int)info.record.port != indev)
2528 return_error_exit(MUS_AUDIO_DEVICE_NOT_AVAILABLE, audio_fd,
2529 mus_format("confusion in record.port: %d != %d (%s)",
2530 (int)info.record.port, indev,
2531 dev_name));
2532 if ((int)info.record.channels != chans)
2533 return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
2534 mus_format("confusion in record.channels: %d != %d (%s)",
2535 (int)info.record.channels, chans,
2536 dev_name));
2537 if (((int)info.record.precision != bits) ||
2538 ((int)info.record.encoding != encode))
2539 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_fd,
2540 mus_format("confusion in record.precision|encoding: %d != %d or %d != %d (%s)",
2541 (int)info.record.precision, bits,
2542 (int)info.record.encoding, encode,
2543 dev_name));
2544 }
2545 /* this may be a bad idea */
2546 info.record.buffer_size = size;
2547 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2548 if (err == -1)
2549 return_error_exit(MUS_AUDIO_CANT_WRITE, audio_fd,
2550 mus_format("can't set buffer size to %d on input %s",
2551 size,
2552 dev_name));
2553 return(audio_fd);
2554 }
2555
2556 #if 0
2557 /* pause can be implemented with play.pause and record.pause */
2558
2559 static const char *sun_sample_type_name(mus_sample_t samp_type)
2560 {
2561 switch (samp_type)
2562 {
2563 #ifdef AUDIO_ENCODING_ALAW
2564 case AUDIO_ENCODING_ALAW: return("alaw"); break;
2565 #endif
2566 #ifdef AUDIO_ENCODING_ULAW
2567 case AUDIO_ENCODING_ULAW: return("ulaw"); break;
2568 #endif
2569 #ifdef AUDIO_ENCODING_DVI
2570 case AUDIO_ENCODING_DVI: return("dvi adpcm"); break;
2571 #endif
2572 #ifdef AUDIO_ENCODING_LINEAR8
2573 case AUDIO_ENCODING_LINEAR8: return("linear"); break;
2574 #else
2575 #ifdef AUDIO_ENCODING_PCM8
2576 case AUDIO_ENCODING_PCM8: return("linear"); break;
2577 #endif
2578 #endif
2579 #ifdef AUDIO_ENCODING_LINEAR
2580 case AUDIO_ENCODING_LINEAR: return("linear"); break;
2581 #else
2582 #ifdef AUDIO_ENCODING_PCM16
2583 case AUDIO_ENCODING_PCM16: return("linear"); break;
2584 #endif
2585 #endif
2586 #ifdef AUDIO_ENCODING_NONE
2587 case AUDIO_ENCODING_NONE: return("not audio"); break; /* dbri interface configured for something else */
2588 #endif
2589 }
2590 return("unknown");
2591 }
2592
2593 static const char *sun_in_device_name(int dev)
2594 {
2595 if (dev == AUDIO_MICROPHONE) return("microphone");
2596 if (dev == AUDIO_LINE_IN) return("line in");
2597 if (dev == AUDIO_INTERNAL_CD_IN) return("cd");
2598 if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN)) return("microphone + line in");
2599 if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("microphone + line in + cd");
2600 if (dev == (AUDIO_MICROPHONE | AUDIO_INTERNAL_CD_IN)) return("microphone + cd");
2601 if (dev == (AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("line in + cd");
2602 return("unknown");
2603 }
2604
2605 static const char *sun_out_device_name(int dev)
2606 {
2607 if (dev == AUDIO_SPEAKER) return("speakers");
2608 if (dev == AUDIO_LINE_OUT) return("line out");
2609 if (dev == AUDIO_HEADPHONE) return("headphones");
2610 if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT)) return("speakers + line out");
2611 if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("speakers + line out + headphones");
2612 if (dev == (AUDIO_SPEAKER | AUDIO_HEADPHONE)) return("speakers + headphones");
2613 if (dev == (AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("line out + headphones");
2614 return("unknown");
2615 }
2616
2617
2618 static char *sun_vol_name = NULL;
2619 static char *sun_volume_name(float vol, int balance, int chans)
2620 {
2621 if (!sun_vol_name) sun_vol_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
2622 if (chans != 2)
2623 snprintf(sun_vol_name, LABEL_BUFFER_SIZE, "%.3f", vol);
2624 else
2625 {
2626 snprintf(sun_vol_name, LABEL_BUFFER_SIZE, "%.3f %.3f",
2627 vol * (float)(AUDIO_RIGHT_BALANCE - balance) / (float)AUDIO_RIGHT_BALANCE,
2628 vol * (float)balance / (float)AUDIO_RIGHT_BALANCE);
2629 }
2630 return(sun_vol_name);
2631 }
2632
2633 #endif
2634 #endif
2635
2636
2637
2638 /* ------------------------------- WINDOZE ----------------------------------------- */
2639
2640 #if defined(_MSC_VER) && (!(defined(__CYGWIN__)))
2641 #define AUDIO_OK 1
2642
2643 #include <windows.h>
2644 #include <mmsystem.h>
2645
2646 #define BUFFER_FILLED 1
2647 #define BUFFER_EMPTY 2
2648
2649 #define OUTPUT_LINE 1
2650 #define INPUT_LINE 2
2651
2652 #define SOUND_UNREADY 0
2653 #define SOUND_INITIALIZED 1
2654 #define SOUND_RUNNING 2
2655
2656 static int buffer_size = 1024;
2657 static int db_state[2];
2658 static int sound_state = 0;
2659 static int current_chans = 1;
2660 static int current_datum_size = 2;
2661 static int current_buf = 0;
2662 WAVEHDR wh[2];
2663 HWAVEOUT fd;
2664 HWAVEIN record_fd;
2665 WAVEHDR rec_wh;
2666 static int rec_state = SOUND_UNREADY;
2667
2668 static MMRESULT win_in_err = 0, win_out_err = 0;
2669 static char errstr[128], getstr[128];
2670
2671 static char *win_err_buf = NULL;
2672 static mus_print_handler_t *old_handler;
2673
win_mus_print(char * msg)2674 static void win_mus_print(char *msg)
2675 {
2676 if ((win_in_err == 0) && (win_out_err == 0))
2677 (*old_handler)(msg);
2678 else
2679 {
2680 if (win_in_err)
2681 waveInGetErrorText(win_in_err, getstr, PRINT_BUFFER_SIZE);
2682 else waveOutGetErrorText(win_out_err, getstr, PRINT_BUFFER_SIZE);
2683 snprintf(errstr, PRINT_BUFFER_SIZE, "%s [%s]", msg, getstr);
2684 (*old_handler)(errstr);
2685 }
2686 }
2687
start_win_print(void)2688 static void start_win_print(void)
2689 {
2690 if (old_handler != win_mus_print)
2691 old_handler = mus_print_set_handler(win_mus_print);
2692 }
2693
end_win_print(void)2694 static void end_win_print(void)
2695 {
2696 if (old_handler == win_mus_print)
2697 mus_print_set_handler(NULL);
2698 else mus_print_set_handler(old_handler);
2699 }
2700
2701 #define return_error_exit(Error_Type, Ur_Error_Message) \
2702 do { char *Error_Message; Error_Message = Ur_Error_Message; \
2703 if (Error_Message) \
2704 {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
2705 else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
2706 end_win_print(); \
2707 return(MUS_ERROR); \
2708 } while (false)
2709
2710
2711
next_buffer(HWAVEOUT w,UINT msg,DWORD user_data,DWORD p1,DWORD p2)2712 DWORD CALLBACK next_buffer(HWAVEOUT w, UINT msg, DWORD user_data, DWORD p1, DWORD p2)
2713 {
2714 if (msg == WOM_DONE)
2715 {
2716 db_state[current_buf] = BUFFER_EMPTY;
2717 }
2718 return(0);
2719 }
2720
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2721 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2722 {
2723 WAVEFORMATEX wf;
2724 int dev;
2725 start_win_print();
2726 dev = MUS_AUDIO_DEVICE(ur_dev);
2727 wf.nChannels = chans;
2728 current_chans = chans;
2729 wf.wFormatTag = WAVE_FORMAT_PCM;
2730 wf.cbSize = 0;
2731 if (samp_type == MUS_UBYTE)
2732 {
2733 wf.wBitsPerSample = 8;
2734 current_datum_size = 1;
2735 }
2736 else
2737 {
2738 wf.wBitsPerSample = 16;
2739 current_datum_size = 2;
2740 }
2741 wf.nSamplesPerSec = srate;
2742 wf.nBlockAlign = chans * current_datum_size;
2743 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
2744 #if _MSC_VER
2745 win_out_err = waveOutOpen(&fd, WAVE_MAPPER, &wf, (DWORD (*)(HWAVEOUT,UINT,DWORD,DWORD,DWORD))next_buffer, 0, CALLBACK_FUNCTION);
2746 #else
2747 win_out_err = waveOutOpen(&fd, WAVE_MAPPER, &wf, (DWORD)next_buffer, 0, CALLBACK_FUNCTION);
2748 #endif
2749 /* 0 here = user_data above, other case = WAVE_FORMAT_QUERY */
2750 if (win_out_err)
2751 return_error_exit(MUS_AUDIO_DEVICE_NOT_AVAILABLE,
2752 mus_format("can't open %d", dev));
2753 waveOutPause(fd);
2754 if (size <= 0)
2755 buffer_size = 1024;
2756 else buffer_size = size;
2757 wh[0].dwBufferLength = buffer_size * current_datum_size;
2758 wh[0].dwFlags = 0;
2759 wh[0].dwLoops = 0;
2760 wh[0].lpData = (char *)calloc(wh[0].dwBufferLength, sizeof(char));
2761 if ((wh[0].lpData) == 0)
2762 {
2763 waveOutClose(fd);
2764 return_error_exit(MUS_AUDIO_SIZE_NOT_AVAILABLE,
2765 mus_format("can't allocate buffer size %d for output %d", buffer_size, dev));
2766 }
2767 win_out_err = waveOutPrepareHeader(fd, &(wh[0]), sizeof(WAVEHDR));
2768 if (win_out_err)
2769 {
2770 free(wh[0].lpData);
2771 waveOutClose(fd);
2772 return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
2773 mus_format("can't setup output 'header' for %d", dev));
2774 }
2775 db_state[0] = BUFFER_EMPTY;
2776 wh[1].dwBufferLength = buffer_size * current_datum_size;
2777 wh[1].dwFlags = 0;
2778 wh[1].dwLoops = 0;
2779 wh[1].lpData = (char *)calloc(wh[0].dwBufferLength, sizeof(char));
2780 if ((wh[1].lpData) == 0)
2781 {
2782 free(wh[0].lpData);
2783 waveOutClose(fd);
2784 return_error_exit(MUS_AUDIO_SIZE_NOT_AVAILABLE,
2785 mus_format("can't allocate buffer size %d for output %d", buffer_size, dev));
2786 }
2787 win_out_err = waveOutPrepareHeader(fd, &(wh[1]), sizeof(WAVEHDR));
2788 if (win_out_err)
2789 {
2790 waveOutUnprepareHeader(fd, &(wh[0]), sizeof(WAVEHDR));
2791 free(wh[0].lpData);
2792 free(wh[1].lpData);
2793 waveOutClose(fd);
2794 return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
2795 mus_format("can't setup output 'header' for %d", dev));
2796 }
2797 db_state[1] = BUFFER_EMPTY;
2798 sound_state = SOUND_INITIALIZED;
2799 current_buf = 0;
2800 end_win_print();
2801 return(OUTPUT_LINE);
2802 }
2803
fill_buffer(int dbi,char * inbuf,int instart,int bytes)2804 static MMRESULT fill_buffer(int dbi, char *inbuf, int instart, int bytes)
2805 {
2806 int i, j;
2807 win_out_err = 0;
2808 if (sound_state == SOUND_UNREADY) return(0);
2809 for (i = instart, j = 0; j < bytes; j++, i++)
2810 wh[dbi].lpData[j] = inbuf[i];
2811 wh[dbi].dwBufferLength = bytes;
2812 db_state[dbi] = BUFFER_FILLED;
2813 if ((sound_state == SOUND_INITIALIZED) &&
2814 (dbi == 1))
2815 {
2816 sound_state = SOUND_RUNNING;
2817 win_out_err = waveOutRestart(fd);
2818 }
2819 return(win_out_err);
2820 }
2821
wait_for_empty_buffer(int buf)2822 static void wait_for_empty_buffer(int buf)
2823 {
2824 while (db_state[buf] != BUFFER_EMPTY)
2825 {
2826 Sleep(1); /* in millisecs, so even this may be too much if buf = 256 bytes */
2827 }
2828 }
2829
mus_audio_write(int line,char * buf,int bytes)2830 int mus_audio_write(int line, char *buf, int bytes)
2831 {
2832 int leftover, start;
2833 start_win_print();
2834 if (line != OUTPUT_LINE)
2835 return_error_exit(MUS_AUDIO_CANT_WRITE,
2836 mus_format("write error: line %d != %d?",
2837 line, OUTPUT_LINE));
2838 win_out_err = 0;
2839 leftover = bytes;
2840 start = 0;
2841 if (sound_state == SOUND_UNREADY)
2842 {
2843 end_win_print();
2844 return(MUS_NO_ERROR);
2845 }
2846 while (leftover > 0)
2847 {
2848 int lim;
2849 lim = leftover;
2850 if (lim > buffer_size) lim = buffer_size;
2851 leftover -= lim;
2852 wait_for_empty_buffer(current_buf);
2853 win_out_err = fill_buffer(current_buf, buf, start, lim);
2854 if (win_out_err)
2855 return_error_exit(MUS_AUDIO_CANT_WRITE,
2856 mus_format("write error on %d",
2857 line));
2858 win_out_err = waveOutWrite(fd, &wh[current_buf], sizeof(WAVEHDR));
2859 if (win_out_err)
2860 return_error_exit(MUS_AUDIO_CANT_WRITE,
2861 mus_format("write error on %d",
2862 line));
2863 start += lim;
2864 current_buf++;
2865 if (current_buf > 1) current_buf = 0;
2866 }
2867 return(MUS_NO_ERROR);
2868 }
2869
unlog(unsigned short val)2870 static float unlog(unsigned short val)
2871 {
2872 /* 1.0 linear is 0xffff, rest is said to be "logarithmic", whatever that really means here */
2873 if (val == 0) return(0.0);
2874 return((float)val / 65536.0);
2875 /* return(pow(2.0, amp) - 1.0); */ /* doc seems to be bogus */
2876 }
2877
mixer_status_name(int status)2878 static char *mixer_status_name(int status)
2879 {
2880 switch (status)
2881 {
2882 case MIXERLINE_LINEF_ACTIVE: return(", (active)"); break;
2883 case MIXERLINE_LINEF_DISCONNECTED: return(", (disconnected)"); break;
2884 case MIXERLINE_LINEF_SOURCE: return(", (source)"); break;
2885 default: return(""); break;
2886 }
2887 }
2888
mixer_target_name(int type)2889 static char *mixer_target_name(int type)
2890 {
2891 switch (type)
2892 {
2893 case MIXERLINE_TARGETTYPE_UNDEFINED: return("undefined"); break;
2894 case MIXERLINE_TARGETTYPE_WAVEOUT: return("output"); break;
2895 case MIXERLINE_TARGETTYPE_WAVEIN: return("input"); break;
2896 case MIXERLINE_TARGETTYPE_MIDIOUT: return("midi output"); break;
2897 case MIXERLINE_TARGETTYPE_MIDIIN: return("midi input"); break;
2898 case MIXERLINE_TARGETTYPE_AUX: return("aux"); break;
2899 default: return(""); break;
2900 }
2901 }
2902
mixer_component_name(int type)2903 static char *mixer_component_name(int type)
2904 {
2905 switch (type)
2906 {
2907 case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: return("undefined"); break;
2908 case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: return("digital"); break;
2909 case MIXERLINE_COMPONENTTYPE_DST_LINE: return("line"); break;
2910 case MIXERLINE_COMPONENTTYPE_DST_MONITOR: return("monitor"); break;
2911 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: return("speakers"); break;
2912 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: return("headphones"); break;
2913 case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: return("telephone"); break;
2914 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: return("wave in"); break;
2915 case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: return("voice in"); break;
2916 case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: return("undefined"); break;
2917 case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: return("digital"); break;
2918 case MIXERLINE_COMPONENTTYPE_SRC_LINE: return("line"); break;
2919 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: return("mic"); break;
2920 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: return("synth"); break;
2921 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: return("CD"); break;
2922 case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: return("telephone"); break;
2923 case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: return("speaker"); break;
2924 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: return("wave out"); break;
2925 case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: return("aux"); break;
2926 case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: return("analog"); break;
2927 default: return(""); break;
2928 }
2929 }
2930
mus_audio_moniker(void)2931 char *mus_audio_moniker(void) {return("MS audio");} /* version number of some sort? */
2932
mus_audio_initialize(void)2933 int mus_audio_initialize(void)
2934 {
2935 return(MUS_NO_ERROR);
2936 }
2937
mus_audio_close(int line)2938 int mus_audio_close(int line)
2939 {
2940 win_out_err = 0;
2941 win_in_err = 0;
2942 if (line == OUTPUT_LINE)
2943 {
2944 /* fill with a few zeros, wait for empty flag */
2945 if (sound_state != SOUND_UNREADY)
2946 {
2947 int i;
2948 wait_for_empty_buffer(current_buf);
2949 for (i = 0; i < 128; i++) wh[current_buf].lpData[i] = 0;
2950 wait_for_empty_buffer(current_buf);
2951 win_out_err = waveOutClose(fd);
2952 i = 0;
2953 while (win_out_err == WAVERR_STILLPLAYING)
2954 {
2955 Sleep(1);
2956 win_out_err = waveOutClose(fd);
2957 i++;
2958 if (i > 1024) break;
2959 }
2960 db_state[0] = BUFFER_EMPTY;
2961 db_state[1] = BUFFER_EMPTY;
2962 sound_state = SOUND_UNREADY;
2963 waveOutUnprepareHeader(fd, &(wh[0]), sizeof(WAVEHDR));
2964 waveOutUnprepareHeader(fd, &(wh[1]), sizeof(WAVEHDR));
2965 free(wh[0].lpData);
2966 free(wh[1].lpData);
2967 if (win_out_err)
2968 return_error_exit(MUS_AUDIO_CANT_CLOSE,
2969 mus_format("close failed on %d",
2970 line));
2971 }
2972 }
2973 else
2974 {
2975 if (line == INPUT_LINE)
2976 {
2977 if (rec_state != SOUND_UNREADY)
2978 {
2979 waveInReset(record_fd);
2980 waveInClose(record_fd);
2981 waveInUnprepareHeader(record_fd, &rec_wh, sizeof(WAVEHDR));
2982 if (rec_wh.lpData)
2983 {
2984 free(rec_wh.lpData);
2985 rec_wh.lpData = NULL;
2986 }
2987 rec_state = SOUND_UNREADY;
2988 }
2989 }
2990 else
2991 return_error_exit(MUS_AUDIO_CANT_CLOSE,
2992 mus_format("can't close unrecognized line %d",
2993 line));
2994 }
2995 return(MUS_NO_ERROR);
2996 }
2997
2998 /*
2999 * waveInAddBuffer sends buffer to get data
3000 * MM_WIM_DATA lParam->WAVEHDR dwBytesRecorded =>how much data actually in buffer
3001 */
3002
3003 static int current_record_chans = 0, current_record_datum_size = 0;
3004
next_input_buffer(HWAVEIN w,UINT msg,DWORD user_data,DWORD p1,DWORD p2)3005 DWORD CALLBACK next_input_buffer(HWAVEIN w, UINT msg, DWORD user_data, DWORD p1, DWORD p2)
3006 {
3007 if (msg == WIM_DATA)
3008 {
3009 /* grab data */
3010 /* p1->dwBytesRecorded */
3011 }
3012 return(0);
3013 }
3014
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)3015 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
3016 {
3017 WAVEFORMATEX wf;
3018 int dev;
3019 win_in_err = 0;
3020 dev = MUS_AUDIO_DEVICE(ur_dev);
3021 wf.nChannels = chans;
3022 current_record_chans = chans;
3023
3024 wf.wFormatTag = WAVE_FORMAT_PCM;
3025 wf.cbSize = 0;
3026 if (samp_type == MUS_UBYTE)
3027 {
3028 wf.wBitsPerSample = 8;
3029 current_record_datum_size = 1;
3030 }
3031 else
3032 {
3033 wf.wBitsPerSample = 16;
3034 current_record_datum_size = 2;
3035 }
3036 wf.nSamplesPerSec = srate;
3037 wf.nBlockAlign = chans * current_datum_size;
3038 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
3039
3040 rec_wh.dwBufferLength = size * current_record_datum_size;
3041 rec_wh.dwFlags = 0;
3042 rec_wh.dwLoops = 0;
3043 rec_wh.lpData = (char *)calloc(rec_wh.dwBufferLength, sizeof(char));
3044 if ((rec_wh.lpData) == 0)
3045 return_error_exit(MUS_AUDIO_SIZE_NOT_AVAILABLE,
3046 mus_format("can't allocated %d bytes for input buffer of %d", size, dev));
3047 #if _MSC_VER
3048 win_in_err = waveInOpen(&record_fd, WAVE_MAPPER, &wf, (DWORD (*)(HWAVEIN,UINT,DWORD,DWORD,DWORD))next_input_buffer, 0, CALLBACK_FUNCTION);
3049 /* why isn't the simple cast (DWORD) correct here as below? -- the docs say the 4th arg's type is DWORD */
3050 #else
3051 win_in_err = waveInOpen(&record_fd, WAVE_MAPPER, &wf, (DWORD)next_input_buffer, 0, CALLBACK_FUNCTION);
3052 #endif
3053 if (win_in_err)
3054 {
3055 free(rec_wh.lpData);
3056 return_error_exit(MUS_AUDIO_DEVICE_NOT_AVAILABLE,
3057 mus_format("can't open input device %d", dev));
3058 }
3059 win_in_err = waveInPrepareHeader(record_fd, &(rec_wh), sizeof(WAVEHDR));
3060 if (win_in_err)
3061 {
3062 free(rec_wh.lpData);
3063 waveInClose(record_fd);
3064 return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
3065 mus_format("can't prepare input 'header' for %d", dev));
3066 }
3067 return(MUS_NO_ERROR);
3068 }
3069
mus_audio_read(int line,char * buf,int bytes)3070 int mus_audio_read(int line, char *buf, int bytes)
3071 {
3072 win_in_err = 0;
3073 return(MUS_ERROR);
3074 }
3075
3076 #endif
3077
3078
3079
3080 /* ------------------------------- Mac OSX ----------------------------------------- */
3081
3082 /* this code based primarily on the CoreAudio headers and portaudio pa_mac_core.c,
3083 * and to a much lesser extent, coreaudio.pdf and the HAL/Daisy examples.
3084 */
3085
3086 #ifdef __APPLE__
3087 #define AUDIO_OK 1
3088
3089 #include <AvailabilityMacros.h>
3090
3091 /*
3092 #include <CoreServices/CoreServices.h>
3093 #include <CoreAudio/CoreAudio.h>
3094 */
3095 /* ./System/Library/Frameworks/CoreAudio.framework/Headers/CoreAudio.h */
3096
osx_error(OSStatus err)3097 static const char* osx_error(OSStatus err)
3098 {
3099 if (err == noErr) return("no error");
3100 switch (err)
3101 {
3102 case kAudioHardwareNoError: return("no error");
3103 case kAudioHardwareUnspecifiedError: return("unspecified audio hardware error");
3104 case kAudioHardwareNotRunningError: return("audio hardware not running");
3105 case kAudioHardwareUnknownPropertyError: return("unknown property");
3106 case kAudioHardwareBadPropertySizeError: return("bad property");
3107 case kAudioHardwareBadDeviceError: return("bad device");
3108 case kAudioHardwareBadStreamError: return("bad stream");
3109 case kAudioHardwareIllegalOperationError: return("illegal operation");
3110 case kAudioDeviceUnsupportedFormatError: return("unsupported sample type");
3111 case kAudioDevicePermissionsError: return("device permissions error");
3112 }
3113 return("unknown error");
3114 }
3115
3116 #define MAX_BUFS 4
3117 static char **bufs = NULL;
3118 static uint32_t in_buf = 0, out_buf = 0;
3119
writer(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * InputData,const AudioTimeStamp * InputTime,AudioBufferList * OutputData,const AudioTimeStamp * OutputTime,void * appGlobals)3120 static OSStatus writer(AudioDeviceID inDevice,
3121 const AudioTimeStamp *inNow,
3122 const AudioBufferList *InputData, const AudioTimeStamp *InputTime,
3123 AudioBufferList *OutputData, const AudioTimeStamp *OutputTime,
3124 void *appGlobals)
3125 {
3126 AudioBuffer abuf;
3127 char *aplbuf, *sndbuf;
3128 abuf = OutputData->mBuffers[0];
3129 aplbuf = (char *)(abuf.mData);
3130 sndbuf = bufs[out_buf];
3131 memmove((void *)aplbuf, (void *)sndbuf, abuf.mDataByteSize);
3132 out_buf++;
3133 if (out_buf >= MAX_BUFS) out_buf = 0;
3134 return(noErr);
3135 }
3136
reader(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * InputData,const AudioTimeStamp * InputTime,AudioBufferList * OutputData,const AudioTimeStamp * OutputTime,void * appGlobals)3137 static OSStatus reader(AudioDeviceID inDevice,
3138 const AudioTimeStamp *inNow,
3139 const AudioBufferList *InputData, const AudioTimeStamp *InputTime,
3140 AudioBufferList *OutputData, const AudioTimeStamp *OutputTime,
3141 void *appGlobals)
3142 {
3143 AudioBuffer abuf;
3144 char *aplbuf, *sndbuf;
3145 abuf = InputData->mBuffers[0];
3146 aplbuf = (char *)(abuf.mData);
3147 sndbuf = bufs[out_buf];
3148 memmove((void *)sndbuf, (void *)aplbuf, abuf.mDataByteSize);
3149 out_buf++;
3150 if (out_buf >= MAX_BUFS) out_buf = 0;
3151 return(noErr);
3152 }
3153
3154
3155 static AudioDeviceID device = kAudioDeviceUnknown;
3156 static bool writing = false, open_for_input = false;
3157
3158 #ifdef MAC_OS_X_VERSION_10_5
3159 #define HAVE_OSX_10_5 1
3160 #else
3161 #define HAVE_OSX_10_5 0
3162 #endif
3163
3164 #if HAVE_OSX_10_5
3165 static AudioDeviceIOProcID read_procId, write_procId;
3166 #endif
3167
mus_audio_close(int line)3168 int mus_audio_close(int line)
3169 {
3170 OSStatus err = noErr;
3171 UInt32 sizeof_running;
3172 UInt32 running;
3173 if (open_for_input)
3174 {
3175 in_buf = 0;
3176 err = AudioDeviceStop(device, (AudioDeviceIOProc)reader);
3177 if (err == noErr)
3178 #if HAVE_OSX_10_5
3179 err = AudioDeviceDestroyIOProcID(device, read_procId);
3180 #else
3181 err = AudioDeviceRemoveIOProc(device, (AudioDeviceIOProc)reader);
3182 #endif
3183 }
3184 else
3185 {
3186 if ((in_buf > 0) && (!writing))
3187 {
3188 /* short enough sound that we never got started? */
3189 #if HAVE_OSX_10_5
3190 err = AudioDeviceCreateIOProcID(device, (AudioDeviceIOProc)writer, NULL, &write_procId);
3191 #else
3192 err = AudioDeviceAddIOProc(device, (AudioDeviceIOProc)writer, NULL);
3193 #endif
3194 if (err == noErr)
3195 err = AudioDeviceStart(device, (AudioDeviceIOProc)writer); /* writer will be called right away */
3196 if (err == noErr)
3197 writing = true;
3198 }
3199 if (writing)
3200 {
3201 /* send out waiting buffers */
3202 sizeof_running = sizeof(UInt32);
3203 while (in_buf == out_buf)
3204 {
3205 /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3206 {
3207 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3208 kAudioDevicePropertyScopeOutput,
3209 kAudioObjectPropertyElementMaster };
3210 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3211 }
3212 }
3213 while (in_buf != out_buf)
3214 {
3215 /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3216 {
3217 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3218 kAudioDevicePropertyScopeOutput,
3219 kAudioObjectPropertyElementMaster };
3220 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3221 }
3222 }
3223 in_buf = 0;
3224 err = AudioDeviceStop(device, (AudioDeviceIOProc)writer);
3225 if (err == noErr)
3226 #if HAVE_OSX_10_5
3227 err = AudioDeviceDestroyIOProcID(device, write_procId);
3228 #else
3229 err = AudioDeviceRemoveIOProc(device, (AudioDeviceIOProc)writer);
3230 #endif
3231 writing = false;
3232 }
3233 }
3234 device = kAudioDeviceUnknown;
3235 if (err == noErr)
3236 return(MUS_NO_ERROR);
3237 return(MUS_ERROR);
3238 }
3239
3240 typedef enum {CONVERT_NOT, CONVERT_COPY, CONVERT_SKIP, CONVERT_COPY_AND_SKIP, CONVERT_SKIP_N, CONVERT_COPY_AND_SKIP_N} audio_convert_t;
3241 static audio_convert_t conversion_choice = CONVERT_NOT;
3242 static float conversion_multiplier = 1.0;
3243 static int dac_out_chans, dac_out_srate;
3244 static int incoming_out_chans = 1, incoming_out_srate = 44100;
3245 static uint32_t fill_point = 0;
3246 static uint32_t bufsize = 0, current_bufsize = 0;
3247 static bool match_dac_to_sound = true;
3248
3249
mus_audio_output_properties_mutable(bool mut)3250 bool mus_audio_output_properties_mutable(bool mut)
3251 {
3252 match_dac_to_sound = mut;
3253 return(mut);
3254 }
3255
3256
3257 /* I'm getting bogus buffer sizes from the audio conversion stuff from Apple,
3258 * and I think AudioConvert doesn't handle cases like 4->6 chans correctly
3259 * so, I'll just do the conversions myself -- there is little need here
3260 * for non-integer srate conversion anyway, and the rest is trivial.
3261 */
3262
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)3263 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
3264 {
3265 OSStatus err = noErr;
3266 UInt32 sizeof_device, sizeof_format, sizeof_bufsize;
3267 AudioStreamBasicDescription device_desc;
3268
3269 device = 0;
3270 sizeof_device = sizeof(AudioDeviceID);
3271 sizeof_bufsize = sizeof(uint32_t);
3272
3273 /* err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &sizeof_device, (void *)(&device)); */
3274 {
3275 AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultOutputDevice,
3276 kAudioObjectPropertyScopeGlobal,
3277 kAudioObjectPropertyElementMaster };
3278 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &sizeof_device, &device);
3279 }
3280
3281 bufsize = 4096;
3282 if (err == noErr)
3283 {
3284 /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyBufferSize, &sizeof_bufsize, &bufsize); */
3285 {
3286 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyBufferSize,
3287 kAudioDevicePropertyScopeOutput,
3288 kAudioObjectPropertyElementMaster };
3289 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_bufsize, &bufsize);
3290 }
3291 }
3292 if (err != noErr)
3293 {
3294 fprintf(stderr, "open audio output err: %d %s\n", (int)err, osx_error(err));
3295 return(MUS_ERROR);
3296 }
3297
3298 sizeof_format = sizeof(AudioStreamBasicDescription);
3299 /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &sizeof_format, &device_desc); */
3300 {
3301 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3302 kAudioDevicePropertyScopeOutput,
3303 kAudioObjectPropertyElementMaster };
3304 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3305 }
3306
3307 if (err != noErr)
3308 {
3309 fprintf(stderr, "open audio output (get device format) err: %d %s\n", (int)err, osx_error(err));
3310 return(MUS_ERROR);
3311 }
3312
3313 if (match_dac_to_sound)
3314 {
3315 /* now check for srate/chan mismatches and so on */
3316
3317 /* current DAC state: device_desc.mChannelsPerFrame, (int)(device_desc.mSampleRate) */
3318 /* apparently get stream format can return noErr but chans == 0?? */
3319
3320 if (((int)device_desc.mChannelsPerFrame != chans) ||
3321 ((int)(device_desc.mSampleRate) != srate))
3322 {
3323 /* try to match DAC settings to current sound */
3324 device_desc.mChannelsPerFrame = chans;
3325 device_desc.mSampleRate = srate;
3326 device_desc.mBytesPerPacket = chans * 4; /* assume 1 frame/packet and float32 data */
3327 device_desc.mBytesPerFrame = chans * 4;
3328 sizeof_format = sizeof(AudioStreamBasicDescription);
3329 /* err = AudioDeviceSetProperty(device, 0, 0, false, kAudioDevicePropertyStreamFormat, sizeof_format, &device_desc); */
3330 {
3331 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3332 kAudioDevicePropertyScopeOutput,
3333 kAudioObjectPropertyElementMaster };
3334 err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof_format, &device_desc);
3335 }
3336
3337 /* this error is bogus in some cases -- other audio systems just ignore it,
3338 * but in my case (a standard MacIntel with no special audio hardware), if I leave
3339 * this block out, the sound is played back at the wrong rate, and the volume
3340 * of outa is set to 0.0??
3341 */
3342
3343 if (err != noErr)
3344 {
3345 /* it must have failed for some reason -- look for closest match available */
3346 /* if srate = 22050 try 44100, if chans = 1 try 2 */
3347 /* the "get closest match" business appears to be completely bogus... */
3348
3349 device_desc.mChannelsPerFrame = (chans == 1) ? 2 : chans;
3350 device_desc.mSampleRate = (srate == 22050) ? 44100 : srate;
3351 device_desc.mBytesPerPacket = device_desc.mChannelsPerFrame * 4; /* assume 1 frame/packet and float32 data */
3352 device_desc.mBytesPerFrame = device_desc.mChannelsPerFrame * 4;
3353 sizeof_format = sizeof(AudioStreamBasicDescription);
3354 /* err = AudioDeviceSetProperty(device, 0, 0, false, kAudioDevicePropertyStreamFormat, sizeof_format, &device_desc); */
3355 {
3356 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3357 kAudioDevicePropertyScopeOutput,
3358 kAudioObjectPropertyElementMaster };
3359 err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof_format, &device_desc);
3360 }
3361 if (err != noErr)
3362 {
3363 sizeof_format = sizeof(AudioStreamBasicDescription);
3364 /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormatMatch, &sizeof_format, &device_desc); */
3365 {
3366 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormatMatch,
3367 kAudioDevicePropertyScopeOutput,
3368 kAudioObjectPropertyElementMaster };
3369 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3370 }
3371
3372 if (err == noErr)
3373 {
3374 /* match suggests: device_desc.mChannelsPerFrame, (int)(device_desc.mSampleRate) */
3375 /* try to set DAC to reflect that match */
3376 /* a bug here in emagic 2|6 -- we can get 6 channel match, but then can't set it?? */
3377
3378 sizeof_format = sizeof(AudioStreamBasicDescription);
3379 /* err = AudioDeviceSetProperty(device, 0, 0, false, kAudioDevicePropertyStreamFormat, sizeof_format, &device_desc); */
3380 {
3381 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3382 kAudioDevicePropertyScopeOutput,
3383 kAudioObjectPropertyElementMaster };
3384 err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof_format, &device_desc);
3385 }
3386 if (err != noErr)
3387 {
3388 /* no luck -- get current DAC settings at least */
3389 sizeof_format = sizeof(AudioStreamBasicDescription);
3390 /* AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &sizeof_format, &device_desc); */
3391 {
3392 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3393 kAudioDevicePropertyScopeOutput,
3394 kAudioObjectPropertyElementMaster };
3395 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3396 }
3397 }
3398 }
3399 }
3400 else
3401 {
3402 /* nothing matches? -- get current DAC settings */
3403 sizeof_format = sizeof(AudioStreamBasicDescription);
3404 /* AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &sizeof_format, &device_desc); */
3405 {
3406 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3407 kAudioDevicePropertyScopeOutput,
3408 kAudioObjectPropertyElementMaster };
3409 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3410 }
3411 }
3412 }
3413 }
3414 } /* end mismatch check */
3415
3416 /* now DAC claims it is ready for device_desc.mChannelsPerFrame, (int)(device_desc.mSampleRate) */
3417 dac_out_chans = device_desc.mChannelsPerFrame; /* use better variable names */
3418 dac_out_srate = (int)(device_desc.mSampleRate);
3419
3420 open_for_input = false;
3421 if ((!bufs) || (bufsize > current_bufsize))
3422 {
3423 int i;
3424 if (bufs)
3425 {
3426 for (i = 0; i < MAX_BUFS; i++) free(bufs[i]);
3427 free(bufs);
3428 }
3429 bufs = (char **)calloc(MAX_BUFS, sizeof(char *));
3430 for (i = 0; i < MAX_BUFS; i++)
3431 bufs[i] = (char *)calloc(bufsize, sizeof(char));
3432 current_bufsize = bufsize;
3433 }
3434
3435 in_buf = 0;
3436 out_buf = 0;
3437 fill_point = 0;
3438
3439 if (!match_dac_to_sound)
3440 {
3441 incoming_out_srate = dac_out_srate;
3442 incoming_out_chans = dac_out_chans;
3443 conversion_choice = CONVERT_NOT;
3444 conversion_multiplier = 1.0;
3445 return(MUS_NO_ERROR);
3446 }
3447
3448 incoming_out_srate = srate;
3449 incoming_out_chans = chans;
3450
3451 if (incoming_out_chans == dac_out_chans)
3452 {
3453 if (incoming_out_srate == dac_out_srate)
3454 {
3455 conversion_choice = CONVERT_NOT;
3456 conversion_multiplier = 1.0;
3457 }
3458 else
3459 {
3460 /* here we don't get very fancy -- assume dac/2=in */
3461 conversion_choice = CONVERT_COPY;
3462 conversion_multiplier = 2.0;
3463 }
3464 }
3465 else
3466 {
3467 if (incoming_out_srate == dac_out_srate)
3468 {
3469 if ((dac_out_chans == 2) && (incoming_out_chans == 1)) /* the usual case */
3470 {
3471 conversion_choice = CONVERT_SKIP;
3472 conversion_multiplier = 2.0;
3473 }
3474 else
3475 {
3476 conversion_choice = CONVERT_SKIP_N;
3477 conversion_multiplier = ((float)dac_out_chans / (float)incoming_out_chans);
3478 }
3479 }
3480 else
3481 {
3482 if ((dac_out_chans == 2) && (incoming_out_chans == 1)) /* the usual case */
3483 {
3484 conversion_choice = CONVERT_COPY_AND_SKIP;
3485 conversion_multiplier = 4.0;
3486 }
3487 else
3488 {
3489 conversion_choice = CONVERT_COPY_AND_SKIP_N;
3490 conversion_multiplier = ((float)dac_out_chans / (float)incoming_out_chans) * 2;
3491 }
3492 }
3493 }
3494 return(MUS_NO_ERROR);
3495 }
3496
3497
convert_incoming(char * to_buf,int fill_point,int lim,char * buf)3498 static void convert_incoming(char *to_buf, int fill_point, int lim, char *buf)
3499 {
3500 int i, j, k, jc, kc, ic;
3501 switch (conversion_choice)
3502 {
3503 case CONVERT_NOT:
3504 /* no conversion needed */
3505 for (i = 0; i < lim; i++)
3506 to_buf[i + fill_point] = buf[i];
3507 break;
3508
3509 case CONVERT_COPY:
3510 /* copy sample to mimic lower srate */
3511 for (i = 0, j = fill_point; i < lim; i += 8, j += 16)
3512 for (k = 0; k < 8; k++)
3513 {
3514 to_buf[j + k] = buf[i + k];
3515 to_buf[j + k + 8] = buf[i + k];
3516 }
3517 break;
3518
3519 case CONVERT_SKIP:
3520 /* skip sample for empty chan */
3521 for (i = 0, j = fill_point; i < lim; i += 4, j += 8)
3522 for (k = 0; k < 4; k++)
3523 {
3524 to_buf[j + k] = buf[i + k];
3525 to_buf[j + k + 4] = 0;
3526 }
3527 break;
3528
3529 case CONVERT_SKIP_N:
3530 /* copy incoming_out_chans then skip up to dac_out_chans */
3531 jc = dac_out_chans * 4;
3532 ic = incoming_out_chans * 4;
3533 for (i = 0, j = fill_point; i < lim; i += ic, j += jc)
3534 {
3535 for (k = 0; k < ic; k++) to_buf[j + k] = buf[i + k];
3536 for (k = ic; k < jc; k++) to_buf[j + k] = 0;
3537 }
3538 break;
3539
3540 case CONVERT_COPY_AND_SKIP:
3541 for (i = 0, j = fill_point; i < lim; i += 4, j += 16)
3542 for (k = 0; k < 4; k++)
3543 {
3544 to_buf[j + k] = buf[i + k];
3545 to_buf[j + k + 4] = 0;
3546 to_buf[j + k + 8] = buf[i + k];
3547 to_buf[j + k + 12] = 0;
3548 }
3549 break;
3550
3551 case CONVERT_COPY_AND_SKIP_N:
3552 /* copy for each active chan, skip rest */
3553 jc = dac_out_chans * 8;
3554 ic = incoming_out_chans * 4;
3555 kc = dac_out_chans * 4;
3556 for (i = 0, j = fill_point; i < lim; i += ic, j += jc)
3557 {
3558 for (k = 0; k < ic; k++)
3559 {
3560 to_buf[j + k] = buf[i + k];
3561 to_buf[j + k + kc] = buf[i + k];
3562 }
3563 for (k = ic; k < kc; k++)
3564 {
3565 to_buf[j + k] = 0;
3566 to_buf[j + k + kc] = 0;
3567 }
3568 }
3569 break;
3570 }
3571 }
3572
3573
mus_audio_write(int line,char * buf,int bytes)3574 int mus_audio_write(int line, char *buf, int bytes)
3575 {
3576 OSStatus err = noErr;
3577 uint32_t lim, out_bytes;
3578 UInt32 sizeof_running;
3579 UInt32 running;
3580 char *to_buf;
3581
3582 to_buf = bufs[in_buf];
3583 out_bytes = (uint32_t)(bytes * conversion_multiplier);
3584 if ((fill_point + out_bytes) > bufsize)
3585 out_bytes = bufsize - fill_point;
3586 lim = (uint32_t)(out_bytes / conversion_multiplier);
3587
3588 if (!writing)
3589 {
3590 convert_incoming(to_buf, fill_point, lim, buf);
3591 fill_point += out_bytes;
3592 if (fill_point >= bufsize)
3593 {
3594 in_buf++;
3595 fill_point = 0;
3596 if (in_buf == MAX_BUFS)
3597 {
3598 in_buf = 0;
3599 #if HAVE_OSX_10_5
3600 err = AudioDeviceCreateIOProcID(device, (AudioDeviceIOProc)writer, NULL, &write_procId);
3601 #else
3602 err = AudioDeviceAddIOProc(device, (AudioDeviceIOProc)writer, NULL);
3603 #endif
3604 if (err == noErr)
3605 err = AudioDeviceStart(device, (AudioDeviceIOProc)writer); /* writer will be called right away */
3606 if (err == noErr)
3607 {
3608 writing = true;
3609 return(MUS_NO_ERROR);
3610 }
3611 else return(MUS_ERROR);
3612 }
3613 }
3614 return(MUS_NO_ERROR);
3615 }
3616 if ((fill_point == 0) && (in_buf == out_buf))
3617 {
3618 uint32_t bp;
3619 bp = out_buf;
3620 sizeof_running = sizeof(UInt32);
3621 while (bp == out_buf)
3622 {
3623 /* i.e. just kill time without hanging */
3624 /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3625 {
3626 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3627 kAudioDevicePropertyScopeOutput,
3628 kAudioObjectPropertyElementMaster };
3629 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3630 }
3631 /* usleep(10); */
3632 }
3633 }
3634 to_buf = bufs[in_buf];
3635 if (fill_point == 0) memset((void *)to_buf, 0, bufsize);
3636 convert_incoming(to_buf, fill_point, lim, buf);
3637 fill_point += out_bytes;
3638 if (fill_point >= bufsize)
3639 {
3640 in_buf++;
3641 fill_point = 0;
3642 if (in_buf >= MAX_BUFS) in_buf = 0;
3643 }
3644 return(MUS_NO_ERROR);
3645 }
3646
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)3647 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
3648 {
3649 OSStatus err = noErr;
3650 UInt32 sizeof_device;
3651 UInt32 sizeof_bufsize;
3652
3653 sizeof_device = sizeof(AudioDeviceID);
3654 sizeof_bufsize = sizeof(uint32_t);
3655
3656 device = 0;
3657 /* err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &sizeof_device, (void *)(&device)); */
3658 {
3659 AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultInputDevice,
3660 kAudioObjectPropertyScopeGlobal,
3661 kAudioObjectPropertyElementMaster };
3662 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &sizeof_device, &device);
3663 }
3664
3665 bufsize = 4096;
3666 if (err == noErr)
3667 {
3668 /* err = AudioDeviceGetProperty(device, 0, true, kAudioDevicePropertyBufferSize, &sizeof_bufsize, &bufsize); */
3669 {
3670 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyBufferSize,
3671 kAudioDevicePropertyScopeInput,
3672 kAudioObjectPropertyElementMaster };
3673 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_bufsize, &bufsize);
3674 }
3675 }
3676 if (err != noErr)
3677 {
3678 fprintf(stderr, "open audio input err: %d %s\n", (int)err, osx_error(err));
3679 return(MUS_ERROR);
3680 }
3681 open_for_input = true;
3682 /* assume for now that recorder (higher level) will enforce match */
3683 if ((!bufs) || (bufsize > current_bufsize))
3684 {
3685 int i;
3686 if (bufs)
3687 {
3688 for (i = 0; i < MAX_BUFS; i++) free(bufs[i]);
3689 free(bufs);
3690 }
3691 bufs = (char **)calloc(MAX_BUFS, sizeof(char *));
3692 for (i = 0; i < MAX_BUFS; i++)
3693 bufs[i] = (char *)calloc(bufsize, sizeof(char));
3694 current_bufsize = bufsize;
3695 }
3696 in_buf = 0;
3697 out_buf = 0;
3698 fill_point = 0;
3699 incoming_out_srate = srate;
3700 incoming_out_chans = chans;
3701
3702 #if HAVE_OSX_10_5
3703 err = AudioDeviceCreateIOProcID(device, (AudioDeviceIOProc)reader, NULL, &read_procId);
3704 #else
3705 err = AudioDeviceAddIOProc(device, (AudioDeviceIOProc)reader, NULL);
3706 #endif
3707
3708 if (err == noErr)
3709 err = AudioDeviceStart(device, (AudioDeviceIOProc)reader);
3710 if (err != noErr)
3711 {
3712 fprintf(stderr, "add open audio input err: %d %s\n", (int)err, osx_error(err));
3713 return(MUS_ERROR);
3714 }
3715 return(MUS_NO_ERROR);
3716 }
3717
mus_audio_read(int line,char * buf,int bytes)3718 int mus_audio_read(int line, char *buf, int bytes)
3719 {
3720 OSStatus err = noErr;
3721 UInt32 sizeof_running;
3722 UInt32 running;
3723 char *to_buf;
3724
3725 if (in_buf == out_buf)
3726 {
3727 uint32_t bp;
3728 bp = out_buf;
3729 sizeof_running = sizeof(UInt32);
3730 while (bp == out_buf)
3731 {
3732 /* err = AudioDeviceGetProperty(device, 0, true, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3733 {
3734 AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3735 kAudioDevicePropertyScopeInput,
3736 kAudioObjectPropertyElementMaster };
3737 err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3738 }
3739 if (err != noErr)
3740 fprintf(stderr, "wait err: %s ", osx_error(err));
3741 }
3742 }
3743 to_buf = bufs[in_buf];
3744 if (bytes <= (int)bufsize)
3745 memmove((void *)buf, (void *)to_buf, bytes);
3746 else memmove((void *)buf, (void *)to_buf, bufsize);
3747 in_buf++;
3748 if (in_buf >= MAX_BUFS) in_buf = 0;
3749 return(MUS_ERROR);
3750 }
3751
mus_audio_initialize(void)3752 int mus_audio_initialize(void) {return(MUS_NO_ERROR);}
3753
mus_audio_moniker(void)3754 char *mus_audio_moniker(void) {return((char *)"Mac OSX audio");}
3755 #endif
3756
3757
3758
3759
3760 /* ------------------------------- JACK ----------------------------------------- */
3761
3762 /* Kjetil S. Matheussen. k.s.matheussen@notam02.no */
3763 /* Based on code from ceres. */
3764
3765 #if MUS_JACK
3766 #define AUDIO_OK 1
3767 #include <pthread.h>
3768 #include <jack/jack.h>
3769 #include <samplerate.h>
3770 #include <sys/mman.h>
3771 #include <signal.h>
3772
3773 #if MUS_LITTLE_ENDIAN
3774 # define MUS_COMP_SHORT MUS_LSHORT
3775 # define MUS_COMP_FLOAT MUS_LFLOAT
3776 #else
3777 # define MUS_COMP_SHORT MUS_BSHORT
3778 # define MUS_COMP_FLOAT MUS_BFLOAT
3779 #endif
3780
3781 #define SRC_QUALITY SRC_SINC_BEST_QUALITY
3782
atomic_add(int * mem,int how_much)3783 static inline void atomic_add(int *mem, int how_much){
3784 __atomic_fetch_add(mem, how_much, __ATOMIC_SEQ_CST);
3785 }
3786
3787
3788 /*************/
3789 /* Jack Part */
3790 /*************/
3791
3792 #define SNDJACK_BUFFERSIZE 32768
3793
3794 typedef jack_default_audio_sample_t sample_t;
3795 typedef jack_nframes_t nframes_t;
3796
3797 struct SndjackChannel{
3798 jack_port_t *port;
3799 sample_t *buffer;
3800 };
3801
3802 static jack_client_t *sndjack_client = NULL;
3803
3804
3805 /*************************/
3806 /* Variables for reading */
3807 /*************************/
3808 static int sndjack_num_read_channels_allocated=0;
3809 static int sndjack_num_read_channels_inuse=0;
3810 static struct SndjackChannel *sndjack_read_channels=NULL;
3811 static pthread_cond_t sndjack_read_cond= PTHREAD_COND_INITIALIZER;
3812 static pthread_mutex_t sndjack_read_mutex= PTHREAD_MUTEX_INITIALIZER;
3813 static int sj_r_buffersize=0;
3814 static int sj_r_writeplace=0;
3815 static int sj_r_readplace=0;
3816 static int sj_r_unread=0;
3817 static int sj_r_xrun=0;
3818 static int sj_r_totalxrun=0;
3819
3820 /*************************/
3821 /* Variables for writing */
3822 /*************************/
3823 static pthread_cond_t sndjack_cond= PTHREAD_COND_INITIALIZER;
3824 static pthread_mutex_t sndjack_mutex= PTHREAD_MUTEX_INITIALIZER;
3825
3826 enum{SJ_STOPPED,SJ_RUNNING,SJ_ABOUTTOSTOP};
3827
3828 // Variables for the ringbuffer:
3829 static int sj_writeplace=0;
3830 static int sj_readplace=0;
3831 static int sj_unread=0;
3832 static int sj_buffersize;
3833 static int sj_jackbuffersize; // number of frames sent to sndjack_process.
3834 static int sj_totalxrun=0;
3835 static int sj_xrun=0;
3836 static int sj_status=SJ_STOPPED;
3837
3838 static int sndjack_num_channels_allocated=0;
3839 static int sndjack_num_channels_inuse=0;
3840 static struct SndjackChannel *sndjack_channels=NULL;
3841 static int sndjack_read_format;
3842
3843 static SRC_STATE **sndjack_srcstates;
3844 static double sndjack_srcratio=1.0;
3845
3846 static int jack_mus_watchdog_counter=0;
3847
3848
3849 #define SJ_MAX(a,b) (((a)>(b))?(a):(b))
3850
sndjack_read_process(jack_nframes_t nframes)3851 static void sndjack_read_process(jack_nframes_t nframes){
3852 int i,ch;
3853 sample_t *out[sndjack_num_channels_allocated];
3854
3855 if (sndjack_num_read_channels_inuse==0) return;
3856
3857 for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
3858 out[ch]=(sample_t*)jack_port_get_buffer(sndjack_read_channels[ch].port,nframes);
3859 }
3860
3861 for (i=0;i<(int)nframes;i++){
3862 if (sj_r_unread==sj_buffersize){
3863 sj_r_xrun+=nframes-i;
3864 goto exit;
3865 }
3866 for (ch=0;ch<sndjack_num_read_channels_inuse;ch++)
3867 sndjack_read_channels[ch].buffer[sj_r_writeplace]=out[ch][i];
3868 atomic_add(&sj_r_unread,1);
3869 sj_r_writeplace++;
3870 if (sj_r_writeplace==sj_r_buffersize)
3871 sj_r_writeplace=0;
3872 }
3873 exit:
3874 pthread_cond_broadcast(&sndjack_read_cond);
3875 }
3876
3877
sndjack_write_process(jack_nframes_t nframes)3878 static void sndjack_write_process(jack_nframes_t nframes){
3879 int ch,i;
3880 sample_t *out[sndjack_num_channels_allocated];
3881
3882 for (ch=0;ch<sndjack_num_channels_allocated;ch++){
3883 out[ch]=(sample_t*)jack_port_get_buffer(sndjack_channels[ch].port,nframes);
3884 }
3885
3886 if (sj_status==SJ_STOPPED){
3887 for (ch=0;ch<sndjack_num_channels_allocated;ch++){
3888 memset(out[ch],0,nframes*sizeof(sample_t));
3889 }
3890 }else{
3891
3892 // First null out unused channels, if any.
3893 if (sndjack_num_channels_inuse==1 && sndjack_num_channels_allocated>=2){
3894 for (ch=2;ch<sndjack_num_channels_allocated;ch++){
3895 memset(out[ch],0,nframes*sizeof(sample_t));
3896 }
3897 }else{
3898 for (ch=sndjack_num_channels_inuse;ch<sndjack_num_channels_allocated;ch++){
3899 memset(out[ch],0,nframes*sizeof(sample_t));
3900 }
3901 }
3902
3903 for (i=0;i<(int)nframes;i++){
3904 if (sj_unread==0){
3905 if (sj_status==SJ_RUNNING)
3906 sj_xrun+=nframes-i;
3907 for (;i<(int)nframes;i++){
3908 for (ch=0;ch<sndjack_num_channels_inuse;ch++){
3909 out[ch][i]=0.0f;
3910 }
3911 }
3912 break;
3913 }
3914
3915 if (sndjack_num_channels_inuse==1 && sndjack_num_channels_allocated>=2){
3916 for (ch=0;ch<2;ch++){
3917 out[ch][i]=sndjack_channels[0].buffer[sj_readplace];
3918 }
3919 }else{
3920 for (ch=0;ch<sndjack_num_channels_inuse;ch++){
3921 out[ch][i]=sndjack_channels[ch].buffer[sj_readplace];
3922 }
3923 }
3924 atomic_add(&sj_unread,-1);
3925 sj_readplace++;
3926 if (sj_readplace==sj_buffersize)
3927 sj_readplace=0;
3928 }
3929
3930 pthread_cond_broadcast(&sndjack_cond);
3931
3932 if (sj_status==SJ_ABOUTTOSTOP && sj_unread==0)
3933 sj_status=SJ_STOPPED;
3934 }
3935
3936 }
3937
3938
3939
sndjack_process(jack_nframes_t nframes,void * arg)3940 static int sndjack_process(jack_nframes_t nframes, void *arg){
3941 sndjack_read_process(nframes);
3942 sndjack_write_process(nframes);
3943 return 0;
3944 }
3945
3946
sndjack_read(void * buf,int bytes,int chs)3947 static int sndjack_read(void *buf,int bytes,int chs){
3948 int i,ch;
3949 int nframes=bytes /
3950 sndjack_read_format==MUS_COMP_FLOAT ? sizeof(float) :
3951 sndjack_read_format==MUS_COMP_SHORT ? sizeof(short) :
3952 1;
3953 float *buf_f=(float *)buf;
3954 short *buf_s=(short *)buf;
3955 char *buf_c=(char *)buf;
3956
3957 for (i=0;i<nframes;i++){
3958 while(sj_r_unread==0){
3959 pthread_cond_wait(&sndjack_read_cond,&sndjack_read_mutex);
3960 jack_mus_watchdog_counter++;
3961 }
3962
3963 if (sj_r_xrun>0){
3964 sj_r_totalxrun+=sj_r_xrun;
3965 sj_r_xrun=0;
3966 return -1;
3967 }
3968 for (ch=0;ch<chs;ch++){
3969 switch (sndjack_read_format){
3970 case MUS_BYTE:
3971 buf_c[i*chs+ch]=sndjack_read_channels[ch].buffer[sj_r_readplace] * 127.9f;
3972 break;
3973 case MUS_COMP_SHORT:
3974 buf_s[i*chs+ch]=sndjack_read_channels[ch].buffer[sj_r_readplace] * 32767.9f;
3975 break;
3976 case MUS_COMP_FLOAT:
3977 buf_f[i*chs+ch]=sndjack_read_channels[ch].buffer[sj_r_readplace];
3978 break;
3979 }}
3980 atomic_add(&sj_r_unread,-1);
3981 sj_r_readplace++;
3982 if (sj_r_readplace==sj_r_buffersize)
3983 sj_r_readplace=0;
3984 }
3985 return 0;
3986 }
3987
sndjack_write(sample_t ** buf,int nframes,int latencyframes,int chs)3988 static void sndjack_write(sample_t **buf,int nframes,int latencyframes,int chs){
3989 int ch;
3990 int i;
3991
3992 if (sj_xrun>0){
3993 if (sj_status==SJ_RUNNING){
3994 printf("Warning. %d frames delayed.\n",sj_xrun);
3995 sj_totalxrun+=sj_xrun;
3996 }
3997 sj_xrun=0;
3998 }
3999
4000 for (i=0;i<nframes;i++){
4001 while(
4002 sj_status==SJ_RUNNING
4003 && (sj_unread==sj_buffersize
4004 || sj_unread >= SJ_MAX(sj_jackbuffersize*2, latencyframes))
4005 )
4006 {
4007 jack_mus_watchdog_counter++;
4008 pthread_cond_wait(&sndjack_cond,&sndjack_mutex);
4009 }
4010
4011 for (ch=0;ch<chs;ch++)
4012 sndjack_channels[ch].buffer[sj_writeplace]=buf[ch][i];
4013
4014 atomic_add(&sj_unread,1);
4015 sj_writeplace++;
4016 if (sj_writeplace==sj_buffersize)
4017 sj_writeplace=0;
4018 }
4019
4020 if (sj_status==SJ_STOPPED)
4021 if (sj_unread>=sj_jackbuffersize)
4022 sj_status=SJ_RUNNING;
4023 }
4024
sndjack_buffersizecallback(jack_nframes_t nframes,void * arg)4025 static int sndjack_buffersizecallback(jack_nframes_t nframes, void *arg){
4026 sj_jackbuffersize=nframes;
4027 return 0;
4028 }
4029
sndjack_getnumoutchannels(void)4030 static int sndjack_getnumoutchannels(void){
4031 char *a=getenv("SNDLIB_NUM_JACK_CHANNELS");
4032 if (a!=NULL){
4033 int num_ch=atoi(a);
4034 return
4035 (num_ch<=0 || num_ch > 100000)
4036 ? 2
4037 : num_ch;
4038 }else{
4039 int lokke=0;
4040 const char **ports=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsInput);
4041 while(ports!=NULL && ports[lokke]!=NULL){
4042 lokke++;
4043 }
4044
4045 if (lokke<2) return 2;
4046 return lokke;
4047 }
4048 }
4049
sndjack_getnuminchannels(void)4050 static int sndjack_getnuminchannels(void){
4051 char *a=getenv("SNDLIB_NUM_JACK_CHANNELS");
4052 if (a!=NULL){
4053 int num_ch=atoi(a);
4054 return
4055 (num_ch<=0 || num_ch > 100000)
4056 ? 2
4057 : num_ch;
4058 }else{
4059 int lokke=0;
4060 const char **ports=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsOutput);
4061 while(ports!=NULL && ports[lokke]!=NULL){
4062 lokke++;
4063 }
4064 if (lokke<2) return 2;
4065 return lokke;
4066 }
4067 }
4068
4069
sndjack_init(void)4070 static int sndjack_init(void){
4071 int ch;
4072 int numch;
4073
4074 {
4075 jack_status_t status;
4076 sndjack_client=jack_client_open("sndlib",JackNoStartServer,&status,NULL);
4077 if (!sndjack_client) {
4078 #if 0
4079 fprintf (stderr, "jack_client_open() failed, "
4080 "status = 0x%2.0x\n", status);
4081 if (status & JackServerFailed) {
4082 fprintf (stderr, "Unable to connect to JACK server\n");
4083 }
4084 #endif
4085 return -1;
4086 }
4087 }
4088
4089 pthread_mutex_init(&sndjack_mutex,NULL);
4090 pthread_cond_init(&sndjack_cond,NULL);
4091 pthread_mutex_init(&sndjack_read_mutex,NULL);
4092 pthread_cond_init(&sndjack_read_cond,NULL);
4093
4094 jack_set_process_callback(sndjack_client,sndjack_process,NULL);
4095
4096 sndjack_num_channels_allocated = numch = sndjack_getnumoutchannels();
4097 sndjack_num_read_channels_allocated = sndjack_getnuminchannels();
4098
4099 sndjack_channels=(struct SndjackChannel *)calloc(sizeof(struct SndjackChannel),numch);
4100 sndjack_read_channels=(struct SndjackChannel *)calloc(sizeof(struct SndjackChannel),sndjack_num_read_channels_allocated);
4101
4102 for (ch=0;ch<numch;ch++){
4103 sndjack_channels[ch].buffer=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4104 }
4105 for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
4106 sndjack_read_channels[ch].buffer=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4107 }
4108 sj_buffersize=SNDJACK_BUFFERSIZE;
4109
4110 for (ch=0;ch<numch;ch++){
4111 char temp[500];
4112 snprintf(temp, 500, "out_%d",ch+1);
4113 if ((sndjack_channels[ch].port=jack_port_register(
4114 sndjack_client,
4115 mus_strdup(temp),
4116 JACK_DEFAULT_AUDIO_TYPE,
4117 JackPortIsOutput,
4118 0
4119 ))==NULL)
4120 {
4121 fprintf(stderr, "Error. Could not register jack port.\n");
4122 goto failed_register;
4123 }
4124 }
4125
4126 for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
4127 char temp[500];
4128 snprintf(temp, 500, "in_%d",ch+1);
4129 if ((sndjack_read_channels[ch].port=jack_port_register(
4130 sndjack_client,
4131 mus_strdup(temp),
4132 JACK_DEFAULT_AUDIO_TYPE,
4133 JackPortIsInput,
4134 0
4135 ))==NULL)
4136 {
4137 fprintf(stderr, "Error. Could not register jack port.\n");
4138 goto failed_register;
4139 }
4140 }
4141
4142
4143
4144
4145 sj_jackbuffersize=jack_get_buffer_size(sndjack_client);
4146 jack_set_buffer_size_callback(sndjack_client,sndjack_buffersizecallback,NULL);
4147
4148 if (jack_activate (sndjack_client)) {
4149 fprintf (stderr, "Error. Cannot activate jack client.\n");
4150 goto failed_activate;
4151 }
4152
4153 if (getenv("SNDLIB_JACK_DONT_AUTOCONNECT")==NULL){
4154
4155 const char **outportnames=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsInput);
4156 for (ch=0;outportnames && outportnames[ch]!=NULL && ch<numch;ch++){
4157 if (
4158 jack_connect(
4159 sndjack_client,
4160 jack_port_name(sndjack_channels[ch].port),
4161 outportnames[ch]
4162 )
4163 )
4164 {
4165 printf ("Warning. Cannot connect jack output port %d: \"%s\".\n",ch,outportnames[ch]);
4166 }
4167 }
4168
4169 const char **inportnames=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsOutput);
4170 for (ch=0;inportnames && inportnames[ch]!=NULL && ch<numch;ch++){
4171 if (
4172 jack_connect(
4173 sndjack_client,
4174 inportnames[ch],
4175 jack_port_name(sndjack_read_channels[ch].port)
4176 )
4177 )
4178 {
4179 printf ("Warning. Cannot connect jack input port %d: \"%s\".\n",ch,inportnames[ch]);
4180 }
4181 }
4182 }
4183
4184 return 0;
4185
4186 // failed_connect:
4187 failed_activate:
4188 jack_deactivate(sndjack_client);
4189
4190 failed_register:
4191 jack_client_close(sndjack_client);
4192 sndjack_client=NULL;
4193
4194 return -1;
4195 }
sndjack_cleanup(void)4196 static void sndjack_cleanup(void){
4197 int ch;
4198 for (ch=0;ch<sndjack_num_channels_allocated;ch++){
4199 src_delete(sndjack_srcstates[ch]);
4200 }
4201 jack_deactivate(sndjack_client);
4202 jack_client_close(sndjack_client);
4203
4204 }
4205
4206
4207 /***************/
4208 /* Sndlib Part */
4209 /***************/
4210
4211 static int sndjack_format;
4212 static sample_t **sndjack_buffer;
4213 static sample_t *sndjack_srcbuffer;
4214
4215 static int sndjack_dev;
4216 static int sndjack_read_dev;
4217
4218 /* prototypes for the jack sndlib functions */
4219 static int jack_mus_audio_initialize(void);
4220 static void jack_mus_oss_set_buffers(int num, int size);
4221 static char* jack_mus_audio_moniker(void);
4222 static int jack_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size);
4223 static int jack_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size);
4224 static int jack_mus_audio_write(int id, char *buf, int bytes);
4225 static int jack_mus_audio_read(int id, char *buf, int bytes);
4226 static int jack_mus_audio_close(int id);
4227
4228 #if (!HAVE_JACK_IN_LINUX) // Ie. Not using Linux.
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4229 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4230 {
4231 return(jack_mus_audio_open_output(ur_dev, srate, chans, samp_type, size));
4232 }
4233
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int requested_size)4234 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size)
4235 {
4236 return(jack_mus_audio_open_input(ur_dev, srate, chans, samp_type, requested_size));
4237 }
4238
mus_audio_write(int id,char * buf,int bytes)4239 int mus_audio_write(int id, char *buf, int bytes)
4240 {
4241 return(jack_mus_audio_write(id, buf, bytes));
4242 }
4243
mus_audio_read(int id,char * buf,int bytes)4244 int mus_audio_read(int id, char *buf, int bytes)
4245 {
4246 return(jack_mus_audio_read(id, buf, bytes));
4247 }
4248
mus_audio_close(int id)4249 int mus_audio_close(int id)
4250 {
4251 return(jack_mus_audio_close(id));
4252 }
4253
mus_audio_initialize(void)4254 int mus_audio_initialize(void){
4255 return jack_mus_audio_initialize();
4256 }
4257
mus_audio_moniker(void)4258 char* mus_audio_moniker(void)
4259 {
4260 return(jack_mus_audio_moniker());
4261 }
4262 #endif
4263
4264
jack_mus_audio_initialize(void)4265 static int jack_mus_audio_initialize(void) {
4266 int ch;
4267
4268 if (audio_initialized){
4269 return MUS_NO_ERROR;
4270 }
4271
4272 if (sndjack_init()!=0)
4273 return MUS_ERROR;
4274
4275 sndjack_buffer=(sample_t **)calloc(sizeof(sample_t*),sndjack_num_channels_allocated);
4276 for (ch=0;ch<sndjack_num_channels_allocated;ch++)
4277 sndjack_buffer[ch]=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4278 sndjack_srcbuffer=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4279
4280 sndjack_srcstates=(SRC_STATE **)calloc(sizeof(SRC_STATE*),sndjack_num_channels_allocated);
4281 for (ch=0;ch<sndjack_num_channels_allocated;ch++){
4282 sndjack_srcstates[ch]=src_new(SRC_QUALITY,1,NULL);
4283 }
4284
4285 atexit(sndjack_cleanup);
4286
4287 api = MUS_JACK_API;
4288 vect_mus_audio_initialize = jack_mus_audio_initialize;
4289 vect_mus_oss_set_buffers = jack_mus_oss_set_buffers;
4290 vect_mus_audio_moniker = jack_mus_audio_moniker;
4291 vect_mus_audio_open_output = jack_mus_audio_open_output;
4292 vect_mus_audio_open_input = jack_mus_audio_open_input;
4293 vect_mus_audio_write = jack_mus_audio_write;
4294 vect_mus_audio_read = jack_mus_audio_read;
4295 vect_mus_audio_close = jack_mus_audio_close;
4296
4297 audio_initialized = true;
4298
4299 #if 0
4300
4301 /* Locking all future memory shouldn't be that necessary, and might even freeze the machine in certain situations. */
4302 /* So remove MCL_FUTURE from the mlockall call. (No. We can't do that. It can screw up code using the realtime extension. -Kjetil.*/
4303 munlockall();
4304 //mlockall(MCL_CURRENT);
4305
4306 // Instead we just do this: (which is not enough, but maybe better than nothing)
4307 {
4308 mlock(sndjack_channels,sizeof(struct SndjackChannel)*sndjack_num_channels_allocated);
4309 mlock(sndjack_read_channels,sizeof(struct SndjackChannel)*sndjack_num_read_channels_allocated);
4310
4311 for (ch=0;ch<numch;ch++){
4312 mlock(sndjack_channels[ch].buffer,sizeof(sample_t)*SNDJACK_BUFFERSIZE);
4313 }
4314 for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
4315 mlock(sndjack_read_channels[ch].buffer,sizeof(sample_t)*SNDJACK_BUFFERSIZE);
4316 }
4317 }
4318 #endif
4319
4320 return MUS_NO_ERROR;
4321 }
4322
4323 // ??
jack_mus_oss_set_buffers(int num,int size)4324 static void jack_mus_oss_set_buffers(int num, int size){
4325 }
4326
4327 static int jack_mus_isrunning=0;
4328 static pid_t jack_mus_player_pid;
4329 static pthread_t jack_mus_watchdog_thread;
4330
jack_mus_audio_watchdog(void * arg)4331 static void *jack_mus_audio_watchdog(void *arg){
4332 #if MUS_JACK
4333 struct sched_param par;
4334
4335 par.sched_priority = sched_get_priority_max(SCHED_RR);
4336 if (sched_setscheduler(0,SCHED_RR,&par)==-1){
4337 fprintf(stderr, "SNDLIB: Unable to set SCHED_RR realtime priority for the watchdog thread. No watchdog.\n");
4338 goto exit;
4339 }
4340
4341 for (;;){
4342 int last=jack_mus_watchdog_counter;
4343 sleep(1);
4344
4345 if (jack_mus_isrunning && jack_mus_watchdog_counter<last+10){
4346 struct sched_param par;
4347 fprintf(stderr, "SNDLIB: Setting player to non-realtime for 2 seconds.\n");
4348
4349 par.sched_priority = 0;
4350 if (sched_setscheduler(jack_mus_player_pid,SCHED_OTHER,&par)==-1){
4351 fprintf(stderr, "SNDLIB: Unable to set non-realtime priority. Must kill player thread. Sorry!\n");
4352 while(1){
4353 kill(jack_mus_player_pid,SIGKILL);
4354 sleep(2);
4355 }
4356 }
4357
4358 sleep(2);
4359
4360 if (jack_mus_isrunning){
4361 par.sched_priority = sched_get_priority_min(SCHED_RR)+1;
4362 if (sched_setscheduler(jack_mus_player_pid,SCHED_RR,&par)==-1){
4363 fprintf(stderr, "SNDLIB: Could not set back to realtime priority...\n");
4364 }else
4365 fprintf(stderr, "SNDLIB: Play thread set back to realtime priority.\n");
4366 }
4367
4368 }
4369 }
4370 exit:
4371 fprintf(stderr, "SNDLIB: Watchdog exiting\n");
4372 #endif
4373 return NULL;
4374 }
4375
4376
jack_mus_audio_set_realtime(void)4377 static void jack_mus_audio_set_realtime(void){
4378 #if HAVE_JACK_IN_LINUX
4379 struct sched_param par;
4380 static int watchdog_started=0;
4381
4382 jack_mus_player_pid=getpid();
4383
4384 if (watchdog_started==0){
4385 if (pthread_create(&jack_mus_watchdog_thread,NULL,jack_mus_audio_watchdog,NULL)!=0){
4386 fprintf(stderr, "Could not create watchdog. Not running realtime\n");
4387 return;
4388 }
4389 watchdog_started=1;
4390 }
4391
4392 jack_mus_isrunning=1;
4393
4394 par.sched_priority = sched_get_priority_min(SCHED_RR)+1;
4395 if (sched_setscheduler(0,SCHED_RR,&par)==-1){
4396 fprintf(stderr, "SNDLIB: Unable to set SCHED_RR realtime priority for the player thread.\n");
4397 }{
4398 //fprintf(stderr, "Set realtime priority\n");
4399 }
4400 #endif
4401 }
4402
jack_mus_audio_set_non_realtime(void)4403 static void jack_mus_audio_set_non_realtime(void){
4404 #if HAVE_JACK_IN_LINUX
4405 struct sched_param par;
4406 par.sched_priority = 0;
4407 sched_setscheduler(0,SCHED_OTHER,&par);
4408 //fprintf(stderr, "Set non-realtime priority\n");
4409 jack_mus_isrunning=0;
4410 #endif
4411 }
4412
4413 #ifndef JACK_AUTO_SRC
4414 #define JACK_AUTO_SRC 1
4415 #endif
4416
jack_mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)4417 int jack_mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size){
4418 if (sndjack_client==NULL){
4419 if (jack_mus_audio_initialize()==MUS_ERROR)
4420 return MUS_ERROR;
4421 }
4422
4423 if (sndjack_num_channels_allocated<chans){
4424 printf("Error. Can not play back %d channels. (Only %d)\n",chans,sndjack_num_channels_allocated);
4425 return MUS_ERROR;
4426 }
4427
4428 if (samp_type!=MUS_BYTE && samp_type!=MUS_COMP_SHORT && samp_type!=MUS_COMP_FLOAT){
4429 printf("Error, unable to handle sample type %s.\n",mus_sample_type_to_string(samp_type));
4430 return MUS_ERROR;
4431 }
4432
4433 while(sj_status!=SJ_STOPPED) usleep(5);
4434
4435 sj_unread=0;
4436 sj_writeplace=0;
4437 sj_readplace=0;
4438
4439 #if JACK_AUTO_SRC
4440 if (srate!=(int)jack_get_sample_rate(sndjack_client)){
4441 int lokke;
4442 //printf("Warning, sample-rate differs between snd and jack. Sound will not be played correctly! %d/%d\n",srate,jack_get_sample_rate(sndjack_client));
4443 sndjack_srcratio=(double)jack_get_sample_rate(sndjack_client)/(double)srate;
4444 for (lokke=0;lokke<chans;lokke++){
4445 src_reset(sndjack_srcstates[lokke]);
4446 }
4447 }else{
4448 sndjack_srcratio=1.0;
4449 }
4450 #else
4451 sndjack_srcratio=1.0;
4452 #endif
4453
4454 sndjack_format=samp_type;
4455 sndjack_num_channels_inuse=chans;
4456 sndjack_dev=dev;
4457
4458 jack_mus_audio_set_realtime();
4459
4460 return(MUS_NO_ERROR);
4461 }
4462
4463
4464 #define MUS_BYTE_TO_SAMPLE(n) (((mus_float_t)(n) / (mus_float_t)(1 << 7)))
4465
sndjack_from_byte(int ch,int chs,char * buf,float * out,int bytes)4466 static int sndjack_from_byte(int ch,int chs,char *buf,float *out,int bytes){
4467 int i;
4468 int len=bytes/chs;
4469 if (len>SNDJACK_BUFFERSIZE) return -1;
4470
4471 for (i=0;i<len;i++){
4472 out[i]=MUS_BYTE_TO_SAMPLE(buf[i*chs+ch]);
4473 }
4474 return len;
4475 }
4476
sndjack_from_short(int ch,int chs,short * buf,float * out,int bytes)4477 static int sndjack_from_short(int ch,int chs,short *buf,float *out,int bytes){
4478 int i;
4479 int len=bytes/(sizeof(short)*chs);
4480 if (len>SNDJACK_BUFFERSIZE) return -1;
4481
4482 for (i=0;i<len;i++){
4483 out[i]=(float)buf[i*chs+ch]/32768.1f;
4484 }
4485 return len;
4486 }
4487
sndjack_from_float(int ch,int chs,float * buf,float * out,int bytes)4488 static int sndjack_from_float(int ch,int chs,float *buf,float *out,int bytes){
4489 int i;
4490 int len=bytes/(sizeof(float)*chs);
4491 if (len>SNDJACK_BUFFERSIZE) return -1;
4492
4493 for (i=0;i<len;i++){
4494 out[i]=buf[i*chs+ch];
4495 }
4496 return len;
4497 }
4498
4499
jack_mus_audio_write(int line,char * buf,int bytes)4500 int jack_mus_audio_write(int line, char *buf, int bytes){
4501 int ch;
4502 int outlen=0;
4503
4504 for (ch=0;ch<sndjack_num_channels_inuse;ch++){
4505 int len = 0;
4506 float *buf2=sndjack_srcratio==1.0?sndjack_buffer[ch]:sndjack_srcbuffer;
4507
4508 switch (sndjack_format){
4509 case MUS_BYTE:
4510 len=sndjack_from_byte(ch,sndjack_num_channels_inuse,buf,buf2,bytes);
4511 break;
4512 case MUS_COMP_SHORT:
4513 len=sndjack_from_short(ch,sndjack_num_channels_inuse,(short *)buf,buf2,bytes);
4514 break;
4515 case MUS_COMP_FLOAT:
4516 len=sndjack_from_float(ch,sndjack_num_channels_inuse,(float *)buf,buf2,bytes);
4517 break;
4518 }
4519 if (len<0){
4520 printf("Errur. Input buffer to large for mus_audio_write.\n");
4521 return MUS_ERROR;
4522 }
4523
4524 if (sndjack_srcratio!=1.0){
4525 SRC_DATA src_data={
4526 buf2,sndjack_buffer[ch],
4527 len,SNDJACK_BUFFERSIZE,
4528 0,0,
4529 0,
4530 sndjack_srcratio
4531 };
4532 int res=src_process(sndjack_srcstates[ch],&src_data);
4533 if (res!=0){
4534 printf("Error while resampling. (%s)\n",src_strerror(res));
4535 return MUS_ERROR;
4536 }
4537 if (src_data.input_frames!=len){
4538 printf("Unsuccessful resampling: Should have used %d bytes, used %ld.",len,(long int)(src_data.input_frames));
4539 return MUS_ERROR;
4540 }
4541 if (ch>0 && src_data.output_frames_gen!=outlen){
4542 printf("Error, src_process did not output the same number of frames as previous resampled channel (%ld/%d).\n"
4543 "Please report this problem to k.s.matheussen@notam02.no. Thanks!\n",(long int)(src_data.output_frames_gen),outlen);
4544 return MUS_ERROR;
4545 }
4546 outlen=src_data.output_frames_gen;
4547 }else{
4548 outlen=len;
4549 }
4550 }
4551
4552
4553 sndjack_write(sndjack_buffer,outlen,outlen*2,sndjack_num_channels_inuse);
4554
4555 return MUS_NO_ERROR;
4556 }
4557
jack_mus_audio_close(int line)4558 int jack_mus_audio_close(int line)
4559 {
4560 jack_mus_audio_set_non_realtime();
4561 if (line==sndjack_dev){
4562 sj_status=SJ_ABOUTTOSTOP;
4563 sndjack_num_channels_inuse=0;
4564 }
4565 return MUS_NO_ERROR;
4566 }
4567
jack_mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)4568 int jack_mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size){
4569 if (sndjack_client==NULL){
4570 if (jack_mus_audio_initialize()==MUS_ERROR)
4571 return MUS_ERROR;
4572 }
4573
4574 if (sndjack_num_read_channels_allocated<chans){
4575 printf("Error. Can not record %d channels. (Only %d)\n",chans,sndjack_num_read_channels_allocated);
4576 return MUS_ERROR;
4577 }
4578
4579 printf("dev: %d\n" ,dev);
4580 if (samp_type!=MUS_BYTE && samp_type!=MUS_COMP_SHORT && samp_type!=MUS_COMP_FLOAT){
4581 printf("Error, unable to handle format %s.\n",mus_sample_type_to_string(samp_type));
4582 return MUS_ERROR;
4583 }
4584
4585 if (srate!=(int)jack_get_sample_rate(sndjack_client)){
4586 printf("Warning, jacks samplerate is %d (and not %d), and the recording will use this samplerate too.\n",jack_get_sample_rate(sndjack_client),srate);
4587 }
4588
4589 sndjack_read_format=samp_type;
4590 sndjack_num_read_channels_inuse=chans;
4591 sndjack_read_dev=dev;
4592
4593 return(MUS_NO_ERROR);
4594 }
4595
4596
jack_mus_audio_read(int line,char * buf,int bytes)4597 int jack_mus_audio_read(int line, char *buf, int bytes){
4598 if (sndjack_read(buf,bytes,sndjack_num_read_channels_inuse)==-1)
4599 return(MUS_ERROR);
4600 return MUS_NO_ERROR;
4601 }
4602
4603
jack_mus_audio_moniker(void)4604 char *jack_mus_audio_moniker(void)
4605 {
4606 return((char *)"Jack");
4607 }
4608 #endif
4609
4610
4611
4612 /* ------------------------------- HPUX ----------------------------------------- */
4613
4614 /* if this is basically the same as the Sun case with different macro names,
4615 * then it could perhaps be updated to match the new Sun version above --
4616 * Sun version changed 28-Jan-99
4617 */
4618
4619 #if defined(__hpux) && (!(defined(AUDIO_OK)))
4620 #define AUDIO_OK 1
4621 #include <sys/audio.h>
4622
4623
4624 #define return_error_exit(Error_Type, Audio_Line, Ur_Error_Message) \
4625 do { char *Error_Message; Error_Message = Ur_Error_Message; \
4626 if (Audio_Line != -1) close(Audio_Line); \
4627 if (Error_Message) \
4628 {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
4629 else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
4630 return(MUS_ERROR); \
4631 } while (false)
4632
4633
mus_audio_moniker(void)4634 char *mus_audio_moniker(void)
4635 {
4636 return("HPUX audio");
4637 }
4638
4639
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4640 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4641 {
4642 int fd, i, dev;
4643 struct audio_describe desc;
4644
4645 dev = MUS_AUDIO_DEVICE(ur_dev);
4646 fd = open("/dev/audio", O_RDWR);
4647 if (fd == -1)
4648 return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
4649 mus_format("can't open /dev/audio for output: %s",
4650 strerror(errno)));
4651
4652 ioctl(fd, AUDIO_SET_CHANNELS, chans);
4653 if (dev == MUS_AUDIO_SPEAKERS)
4654 ioctl(fd, AUDIO_SET_OUTPUT, AUDIO_OUT_SPEAKER);
4655 else
4656 if (dev == MUS_AUDIO_LINE_OUT)
4657 ioctl(fd, AUDIO_SET_OUTPUT, AUDIO_OUT_LINE);
4658 else ioctl(fd, AUDIO_SET_OUTPUT, AUDIO_OUT_HEADPHONE);
4659
4660 if (samp_type == MUS_BSHORT)
4661 ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_LINEAR16BIT);
4662 else
4663 {
4664 if (samp_type == MUS_MULAW)
4665 ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ULAW);
4666 else
4667 {
4668 if (samp_type == MUS_ALAW)
4669 ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ALAW);
4670 else
4671 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, fd,
4672 mus_format("can't set output sample type to %d (%s) for %d",
4673 samp_type, mus_sample_type_to_string(samp_type),
4674 dev));
4675 }
4676 }
4677
4678 ioctl(fd, AUDIO_DESCRIBE, &desc);
4679 for (i = 0; i < desc.nrates; i++)
4680 if (srate == desc.sample_rate[i])
4681 break;
4682
4683 if (i == desc.nrates)
4684 return_error_exit(SRATE_NOT_AVAILABLE, fd,
4685 mus_format("can't set srate to %d on %d",
4686 srate, dev));
4687
4688 ioctl(fd, AUDIO_SET_SAMPLE_RATE, srate);
4689 return(fd);
4690 }
4691
4692
mus_audio_write(int line,char * buf,int bytes)4693 int mus_audio_write(int line, char *buf, int bytes)
4694 {
4695 write(line, buf, bytes);
4696 return(MUS_NO_ERROR);
4697 }
4698
4699
mus_audio_close(int line)4700 int mus_audio_close(int line)
4701 {
4702 close(line);
4703 return(MUS_NO_ERROR);
4704 }
4705
4706
mus_audio_initialize(void)4707 int mus_audio_initialize(void)
4708 {
4709 return(MUS_NO_ERROR);
4710 }
4711
4712
4713 /* struct audio_status status_b;
4714 * ioctl(devAudio, AUDIO_GET_STATUS, &status_b)
4715 * not_busy = (status_b.transmit_status == AUDIO_DONE);
4716 */
4717
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4718 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4719 {
4720 int fd, i, dev;
4721 struct audio_describe desc;
4722
4723 dev = MUS_AUDIO_DEVICE(ur_dev);
4724 fd = open("/dev/audio", O_RDWR);
4725 if (fd == -1)
4726 return_error_exit(MUS_AUDIO_CANT_OPEN, NULL,
4727 mus_format("can't open /dev/audio for input: %s",
4728 strerror(errno)));
4729
4730 ioctl(fd, AUDIO_SET_CHANNELS, chans);
4731 if (dev == MUS_AUDIO_MICROPHONE)
4732 ioctl(fd, AUDIO_SET_INPUT, AUDIO_IN_MIKE);
4733 else ioctl(fd, AUDIO_SET_INPUT, AUDIO_IN_LINE);
4734
4735 if (samp_type == MUS_BSHORT)
4736 ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_LINEAR16BIT);
4737 else
4738 {
4739 if (samp_type == MUS_MULAW)
4740 ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ULAW);
4741 else
4742 {
4743 if (samp_type == MUS_ALAW)
4744 ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ALAW);
4745 else
4746 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, fd,
4747 mus_format("can't set input sample type to %d (%s) on %d",
4748 samp_type, mus_sample_type_to_string(samp_type),
4749 dev));
4750 }
4751 }
4752
4753 ioctl(fd, AUDIO_DESCRIBE, &desc);
4754 for (i = 0; i < desc.nrates; i++)
4755 if (srate == desc.sample_rate[i])
4756 break;
4757
4758 if (i == desc.nrates)
4759 return_error_exit(MUS_AUDIO_SRATE_NOT_AVAILABLE, fd,
4760 mus_format("can't set srate to %d on %d",
4761 srate, dev));
4762
4763 ioctl(fd, AUDIO_SET_SAMPLE_RATE, srate);
4764 return(fd);
4765 }
4766
4767
mus_audio_read(int line,char * buf,int bytes)4768 int mus_audio_read(int line, char *buf, int bytes)
4769 {
4770 read(line, buf, bytes);
4771 return(MUS_NO_ERROR);
4772 }
4773
4774 #endif
4775
4776 /* ------------------------------- OpenBSD ----------------------------------------- */
4777 #if (__OpenBSD__) && (!(defined(AUDIO_OK)))
4778 #define AUDIO_OK 1
4779 #include <sndio.h>
4780 /* this code thanks to Koen De Turck May-18 */
4781
4782 static struct sio_hdl *in_hdl = NULL;
4783 static struct sio_hdl *out_hdl = NULL;
4784
4785 #define SNDIO_OUT 0
4786 #define SNDIO_IN 1
4787
mus_audio_initialize(void)4788 int mus_audio_initialize(void)
4789 {
4790 return(MUS_NO_ERROR);
4791 }
4792
mus_audio_moniker(void)4793 char *mus_audio_moniker(void)
4794 {
4795 return((char *)"OpenBSD audio (sndio)");
4796 }
4797
mus_sndio_open(int mode,int srate,int chans,mus_sample_t samp_type,int size)4798 static int mus_sndio_open(int mode, int srate, int chans, mus_sample_t samp_type, int size)
4799 {
4800 struct sio_hdl *hdl;
4801 struct sio_par par, par2;
4802 hdl = sio_open(SIO_DEVANY, mode, 0 /*non-blocking io=0 -> we choose blocking*/);
4803 sio_initpar(&par);
4804 switch (samp_type)
4805 {
4806 case MUS_BYTE: par.bits=8;par.bps=1;par.sig=1;break;
4807 case MUS_UBYTE: par.bits=8;par.bps=1;par.sig=0;break;
4808 case MUS_LSHORT: par.bits=16;par.bps=2;par.sig=1;par.le=1;break;
4809 case MUS_BSHORT: par.bits=16;par.bps=2;par.sig=1;par.le=0;break;
4810 case MUS_ULSHORT: par.bits=16;par.bps=2;par.sig=0;par.le=1;break;
4811 case MUS_UBSHORT: par.bits=16;par.bps=2;par.sig=0;par.le=0;break;
4812 /* actually, all linear integer formats are accepted by sndio */
4813 default:
4814 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4815 }
4816 if(mode==SIO_PLAY)
4817 par.pchan=chans;
4818 else
4819 par.rchan=chans;
4820 par.rate=srate;
4821 par.appbufsz=size;
4822 /* set params */
4823 if (!sio_setpar(hdl, &par))
4824 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4825 /* then see what sndio thinks of it */
4826 if (!sio_getpar(hdl, &par2))
4827 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4828
4829 if (par2.bits!=par.bits || par2.bps!=par.bps ||
4830 par2.sig!=par.sig || par2.le!=par.le ||
4831 par2.rate!=par.rate ||par2.bufsz<size)
4832 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4833 if (mode==SIO_PLAY && par2.pchan != par.pchan)
4834 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4835 if (mode==SIO_REC && par2.rchan != par.rchan)
4836 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4837
4838 sio_start(hdl);
4839
4840 if (mode==SIO_PLAY) out_hdl=hdl;
4841 if (mode==SIO_REC) in_hdl=hdl;
4842 return(MUS_NO_ERROR);
4843 }
4844
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)4845 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
4846 {
4847 if (out_hdl!=NULL) return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4848 mus_sndio_open(SIO_PLAY, srate, chans, samp_type, size);
4849 return(SNDIO_OUT);
4850 }
4851
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4852 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4853 {
4854 if (in_hdl!=NULL) return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4855 mus_sndio_open(SIO_REC, srate, chans, samp_type, size);
4856 return(SNDIO_IN);
4857 }
4858
mus_audio_read(int line,char * buf,int bytes)4859 int mus_audio_read(int line, char *buf, int bytes)
4860 {
4861 if(bytes==sio_read(in_hdl, buf, bytes))
4862 return(MUS_NO_ERROR);
4863 else return MUS_ERROR;
4864 }
4865
4866
mus_audio_write(int line,char * buf,int bytes)4867 int mus_audio_write(int line, char *buf, int bytes)
4868 {
4869 if(bytes==sio_write(out_hdl, buf, bytes))
4870 return(MUS_NO_ERROR);
4871 else return MUS_ERROR;
4872 }
4873
mus_audio_close(int line)4874 int mus_audio_close(int line)
4875 {
4876 if (line==SNDIO_IN && in_hdl!=NULL) {
4877 sio_stop(in_hdl);
4878 sio_close(in_hdl);
4879 in_hdl=NULL;
4880 }
4881 if (line==SNDIO_OUT && out_hdl!=NULL) {
4882 sio_stop(out_hdl);
4883 sio_close(out_hdl);
4884 out_hdl=NULL;
4885 }
4886 return(MUS_NO_ERROR);
4887 }
4888
4889 #endif
4890
4891 /* ------------------------------- NETBSD ----------------------------------------- */
4892
4893 #if (__NetBSD__) && (!(defined(AUDIO_OK)))
4894 #define AUDIO_OK 1
4895
4896 /* started from Xanim a long time ago..., bugfixes from Thomas Klausner 30-Jul-05, worked into better shape Aug-05 */
4897 #include <fcntl.h>
4898 #include <sys/audioio.h>
4899 #include <sys/ioctl.h>
4900 #include <sys/param.h>
4901
4902 #define return_error_exit(Error_Type, Audio_Line, Ur_Error_Message) \
4903 do { char *Error_Message; Error_Message = Ur_Error_Message; \
4904 if (Audio_Line != -1) close(Audio_Line); \
4905 if (Error_Message) \
4906 {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
4907 else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
4908 return(MUS_ERROR); \
4909 } while (false)
4910
4911
bsd_format_to_sndlib(int encoding)4912 static mus_sample_t bsd_format_to_sndlib(int encoding)
4913 {
4914 switch (encoding)
4915 {
4916 case AUDIO_ENCODING_ULAW: return(MUS_MULAW);
4917 case AUDIO_ENCODING_ALAW: return(MUS_ALAW);
4918 case AUDIO_ENCODING_LINEAR: return(MUS_BSHORT); /* "sun compatible" so probably big-endian? */
4919 case AUDIO_ENCODING_SLINEAR:
4920 case AUDIO_ENCODING_LINEAR8: return(MUS_BYTE);
4921 case AUDIO_ENCODING_SLINEAR_LE: return(MUS_LSHORT);
4922 case AUDIO_ENCODING_SLINEAR_BE: return(MUS_BSHORT);
4923 case AUDIO_ENCODING_ULINEAR_LE: return(MUS_ULSHORT);
4924 case AUDIO_ENCODING_ULINEAR_BE: return(MUS_UBSHORT);
4925 case AUDIO_ENCODING_ULINEAR: return(MUS_UBYTE);
4926 case AUDIO_ENCODING_NONE:
4927 case AUDIO_ENCODING_ADPCM:
4928 default: return(MUS_UNKNOWN_SAMPLE);
4929 }
4930 return(MUS_UNKNOWN_SAMPLE);
4931 }
4932
4933
sndlib_format_to_bsd(mus_sample_t encoding)4934 static int sndlib_format_to_bsd(mus_sample_t encoding)
4935 {
4936 switch (encoding)
4937 {
4938 case MUS_MULAW: return(AUDIO_ENCODING_ULAW);
4939 case MUS_ALAW: return(AUDIO_ENCODING_ALAW);
4940 case MUS_BYTE: return(AUDIO_ENCODING_SLINEAR);
4941 case MUS_LSHORT: return(AUDIO_ENCODING_SLINEAR_LE);
4942 case MUS_BSHORT: return(AUDIO_ENCODING_SLINEAR_BE);
4943 case MUS_ULSHORT: return(AUDIO_ENCODING_ULINEAR_LE);
4944 case MUS_UBSHORT: return(AUDIO_ENCODING_ULINEAR_BE);
4945 case MUS_UBYTE: return(AUDIO_ENCODING_ULINEAR);
4946 default: break;
4947 }
4948 return(AUDIO_ENCODING_NONE);
4949 }
4950
4951
mus_audio_initialize(void)4952 int mus_audio_initialize(void)
4953 {
4954 return(MUS_NO_ERROR);
4955 }
4956
4957
mus_audio_moniker(void)4958 char *mus_audio_moniker(void)
4959 {
4960 #if __NetBSD__
4961 return((char *)"NetBSD audio");
4962 #else
4963 return((char *)"OpenBSD audio");
4964 #endif
4965 }
4966
4967
4968 static int cur_chans = 1, cur_srate = 22050;
4969
mus_audio_write(int line,char * buf,int bytes)4970 int mus_audio_write(int line, char *buf, int bytes)
4971 {
4972 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 700000000)
4973 if (write(line, buf, bytes) != bytes)
4974 return_error_exit(MUS_AUDIO_WRITE_ERROR, line,
4975 mus_format("write error: %s", strerror(errno)));
4976 #else
4977 /* trouble... AUDIO_WSEEK always returns 0, no way to tell that I'm about to
4978 * hit "hiwat", but when I do, it hangs. Can't use AUDIO_DRAIN --
4979 * it introduces interruptions. Not sure what to do...
4980 */
4981 int b = 0;
4982
4983 b = write(line, buf, bytes);
4984 usleep(10000);
4985
4986 if ((b != bytes) && (b > 0)) /* b <= 0 presumably some sort of error, and we want to avoid infinite recursion below */
4987 {
4988 /* hangs at close if we don't handle this somehow */
4989 if ((cur_chans == 1) || (cur_srate == 22050))
4990 sleep(1);
4991 else usleep(10000);
4992 mus_audio_write(line, (char *)(buf + b), bytes - b);
4993 }
4994 #endif
4995 return(MUS_NO_ERROR);
4996 }
4997
4998 /* from Mike Scholz, 11-Feb-16 (edited):
4999 * On Netbsd sound output with Snd and Sndplay stops before the sound is really at the end.
5000 * [In audioplay] after the read-write loop they call ioctl(fd, AUDIO_DRAIN, NULL).
5001 * Before closing sound output they call ioctl(fd, AUDIO_FLUSH, NULL) (like in audio.c),
5002 * and in addition ioctl(fd, AUDIO_SETINFO, &info). The latter requires that
5003 * audio_info_t a_info be a global variable. The AUDIO_DRAIN call has been in their
5004 * sources since version 1.1 of /usr/src/usr.bin/audio/play/play.c from March 1999.
5005 */
5006
5007 static audio_info_t a_info;
5008
mus_audio_close(int line)5009 int mus_audio_close(int line)
5010 {
5011 ioctl(line, AUDIO_DRAIN, NULL);
5012 ioctl(line, AUDIO_FLUSH, NULL);
5013 ioctl(line, AUDIO_SETINFO, &a_info);
5014 close(line);
5015 return(MUS_NO_ERROR);
5016 }
5017
5018 #if defined(__NetBSD__) && (__NetBSD_Version__ < 900000000)
5019 static int netbsd_default_outputs = (AUDIO_HEADPHONE | AUDIO_LINE_OUT | AUDIO_SPEAKER);
5020 #else
5021 static int netbsd_default_outputs = 0;
5022 #endif
5023
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5024 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5025 {
5026 int line, encode;
5027
5028 line = open("/dev/sound", O_WRONLY); /* /dev/audio assumes mono 8-bit mulaw */
5029 if (line == -1)
5030 {
5031 if (errno == EBUSY)
5032 return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
5033 else return(mus_error(MUS_AUDIO_DEVICE_NOT_AVAILABLE, NULL));
5034 }
5035 AUDIO_INITINFO(&a_info);
5036
5037 /* a_info.blocksize = size; */
5038 encode = sndlib_format_to_bsd(samp_type);
5039 if (encode == AUDIO_ENCODING_NONE)
5040 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
5041 mus_format("sample type %d (%s) not available",
5042 samp_type,
5043 mus_sample_type_name(samp_type)));
5044
5045 a_info.play.encoding = encode;
5046 a_info.mode = AUMODE_PLAY | AUMODE_PLAY_ALL;
5047 a_info.play.precision = mus_bytes_per_sample(samp_type) * 8;
5048 a_info.play.sample_rate = srate;
5049
5050 if (dev == MUS_AUDIO_LINE_OUT)
5051 a_info.play.port = AUDIO_LINE_OUT;
5052 else
5053 {
5054 if (dev == MUS_AUDIO_SPEAKERS)
5055 a_info.play.port = AUDIO_SPEAKER | (netbsd_default_outputs & AUDIO_HEADPHONE);
5056 else a_info.play.port = netbsd_default_outputs;
5057 }
5058
5059 a_info.play.channels = chans;
5060 ioctl(line, AUDIO_SETINFO, &a_info);
5061 /* actually doesn't set the "ports" field -- always 0 */
5062
5063 ioctl(line, AUDIO_GETINFO, &a_info);
5064
5065 if ((int)(a_info.play.sample_rate) != srate)
5066 mus_print("srate: %d -> %d\n", srate, a_info.play.sample_rate);
5067 if ((int)(a_info.play.encoding) != sndlib_format_to_bsd(samp_type))
5068 mus_print("encoding: %d -> %d\n", sndlib_format_to_bsd(samp_type), a_info.play.encoding);
5069 if ((int)(a_info.play.channels) != chans)
5070 mus_print("chans: %d -> %d\n", chans, a_info.play.channels);
5071
5072 cur_chans = chans;
5073 cur_srate = srate;
5074
5075 return(line);
5076 }
5077
5078
mus_audio_read(int line,char * buf,int bytes)5079 int mus_audio_read(int line, char *buf, int bytes)
5080 {
5081 read(line, buf, bytes);
5082 return(MUS_NO_ERROR);
5083 }
5084
5085
netbsd_sample_types(int ur_dev,mus_sample_t * val)5086 static int netbsd_sample_types(int ur_dev, mus_sample_t *val)
5087 {
5088 int i, audio_fd, err, dev;
5089 audio_info_t info;
5090 audio_encoding_t e_info;
5091
5092 dev = MUS_AUDIO_DEVICE(ur_dev);
5093 AUDIO_INITINFO(&info);
5094
5095 audio_fd = open("/dev/sound", O_RDONLY | O_NONBLOCK, 0);
5096 if (audio_fd == -1)
5097 return_error_exit(MUS_AUDIO_CANT_READ, -1, mus_format("can't open /dev/sound: %s", strerror(errno)));
5098 err = ioctl(audio_fd, AUDIO_GETINFO, &info);
5099 if (err == -1)
5100 {
5101 close(audio_fd);
5102 return_error_exit(MUS_AUDIO_CANT_READ, audio_fd, mus_format("can't get dac info"));
5103 }
5104
5105 for (i = 0; ; i++)
5106 {
5107 e_info.index = i;
5108 err = ioctl(audio_fd, AUDIO_GETENC, &e_info);
5109 if (err != 0) break;
5110 val[i + 1] = bsd_format_to_sndlib(e_info.encoding);
5111 }
5112 val[0] = (mus_sample_t)i;
5113 close(audio_fd);
5114 return(MUS_NO_ERROR);
5115 }
5116
5117
5118
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)5119 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
5120 {
5121 audio_info_t info;
5122 int encode, bits, dev, audio_fd, err;
5123
5124 dev = MUS_AUDIO_DEVICE(ur_dev);
5125 encode = sndlib_format_to_bsd(samp_type);
5126 bits = 8 * mus_bytes_per_sample(samp_type);
5127 if (encode == AUDIO_ENCODING_NONE)
5128 return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
5129 mus_format("sample type %s not available for recording",
5130 mus_sample_type_name(samp_type)));
5131
5132 if (dev != MUS_AUDIO_DUPLEX_DEFAULT)
5133 audio_fd = open("/dev/sound", O_RDONLY, 0);
5134 else audio_fd = open("/dev/sound", O_RDWR, 0);
5135 if (audio_fd == -1)
5136 return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
5137 mus_format("can't open /dev/sound: %s",
5138 strerror(errno)));
5139
5140 AUDIO_INITINFO(&info);
5141 info.record.sample_rate = srate;
5142 info.record.channels = chans;
5143 info.record.precision = bits;
5144 info.record.encoding = encode;
5145 info.record.port = AUDIO_MICROPHONE;
5146 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
5147 if (err == -1)
5148 return_error_exit(MUS_AUDIO_CANT_WRITE, audio_fd,
5149 mus_format("can't set up for recording"));
5150 return(audio_fd);
5151 }
5152
5153 #endif
5154
5155
5156
5157 /* -------------------------------- PULSEAUDIO -------------------------------- */
5158
5159 #if defined(MUS_PULSEAUDIO) && (!(defined(AUDIO_OK)))
5160 #define AUDIO_OK 1
5161
5162
5163 /* this code compiles/loads, but I don't know if it works -- paplay itself
5164 * doesn't work on my machine due to either a libtool/dlopen mismatch
5165 * or some problem with "pulse-rt".
5166 */
5167
5168
5169 #include <pulse/simple.h>
5170 #include <pulse/error.h>
5171 #include <pulse/gccmacro.h>
5172
5173
sndlib_to_pa_format(mus_sample_t samp_type)5174 static int sndlib_to_pa_format(mus_sample_t samp_type)
5175 {
5176 switch (samp_type)
5177 {
5178 case MUS_BYTE: return(PA_SAMPLE_U8);
5179 case MUS_LSHORT: return(PA_SAMPLE_S16LE);
5180 case MUS_BSHORT: return(PA_SAMPLE_S16BE);
5181 case MUS_LINT: return(PA_SAMPLE_S32LE);
5182 case MUS_BINT: return(PA_SAMPLE_S32BE);
5183 case MUS_LFLOAT: return(PA_SAMPLE_FLOAT32LE);
5184 case MUS_BFLOAT: return(PA_SAMPLE_FLOAT32BE);
5185 case MUS_ALAW: return(PA_SAMPLE_ALAW);
5186 case MUS_MULAW: return(PA_SAMPLE_ULAW);
5187
5188 default:
5189 fprintf(stderr, "unsupported sample type: %d\n", samp_type);
5190 return(0);
5191 break;
5192 }
5193 }
5194
5195
5196 static pa_simple *pa_out = NULL, *pa_in = NULL;
5197
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5198 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5199 {
5200 pa_sample_spec spec = {0};
5201 int error;
5202
5203 spec.format = sndlib_to_pa_format(samp_type);
5204 spec.rate = srate;
5205 spec.channels = chans;
5206
5207 pa_out = pa_simple_new(NULL, "snd", PA_STREAM_PLAYBACK, NULL, "playback", &spec, NULL, NULL, &error);
5208 if (!pa_out)
5209 {
5210 fprintf(stderr, "can't play: %s\n", pa_strerror(error));
5211 return(MUS_ERROR);
5212 }
5213 return(0);
5214 }
5215
5216
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5217 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5218 {
5219 return(MUS_ERROR);
5220 }
5221
5222
mus_audio_write(int line,char * buf,int bytes)5223 int mus_audio_write(int line, char *buf, int bytes)
5224 {
5225 int error;
5226 pa_simple_write(pa_out, (unsigned char *)buf, (size_t)bytes, &error);
5227 return(error);
5228 }
5229
5230
mus_audio_close(int line)5231 int mus_audio_close(int line)
5232 {
5233 int error;
5234 pa_simple_drain(pa_out, &error);
5235 pa_simple_free(pa_out);
5236 pa_out = NULL;
5237 return(error);
5238 }
5239
5240
mus_audio_read(int line,char * buf,int bytes)5241 int mus_audio_read(int line, char *buf, int bytes)
5242 {
5243 return(MUS_ERROR);
5244 }
5245
5246
mus_audio_initialize(void)5247 int mus_audio_initialize(void)
5248 {
5249 return(MUS_ERROR);
5250 }
5251
5252
mus_audio_moniker(void)5253 char *mus_audio_moniker(void)
5254 {
5255 return(mus_format("pulseaudio %s", pa_get_library_version()));
5256 }
5257
5258
5259 #endif
5260
5261
5262
5263 /* -------------------------------- PORTAUDIO -------------------------------- */
5264
5265 #if defined(MUS_PORTAUDIO) && (!(defined(AUDIO_OK)))
5266 #define AUDIO_OK 1
5267
5268 #include <portaudio.h>
5269
5270 #define PA_OUT_STREAM 0
5271 #define PA_IN_STREAM 1
5272
sndlib_to_portaudio_format(mus_sample_t samp_type)5273 static unsigned long sndlib_to_portaudio_format(mus_sample_t samp_type)
5274 {
5275 switch (samp_type)
5276 {
5277 case MUS_BYTE: return(paInt8);
5278 case MUS_LSHORT: return(paInt16);
5279 case MUS_BSHORT: return(paInt16);
5280 case MUS_LINT: return(paInt32);
5281 case MUS_BINT: return(paInt32);
5282 case MUS_LFLOAT: return(paFloat32);
5283 case MUS_BFLOAT: return(paFloat32);
5284 default: break;
5285 }
5286 return(paInt16);
5287 }
5288
5289 static PaStream *out_stream = NULL;
5290
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5291 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5292 {
5293 PaStreamParameters output_pars;
5294 PaError err;
5295
5296 output_pars.device = Pa_GetDefaultOutputDevice();
5297 output_pars.channelCount = chans;
5298 output_pars.sampleFormat = sndlib_to_portaudio_format(samp_type);
5299 output_pars.suggestedLatency = Pa_GetDeviceInfo(output_pars.device)->defaultHighOutputLatency;
5300 output_pars.hostApiSpecificStreamInfo = NULL;
5301
5302 err = Pa_OpenStream(&out_stream, NULL, &output_pars, srate, 1024, paClipOff, NULL, NULL); /* 1024 = frames [dac_size] but can we use "size"? */
5303 if (err == paNoError)
5304 err = Pa_StartStream(out_stream);
5305
5306 if (err != paNoError)
5307 {
5308 fprintf(stderr, "portaudio open output: %s\n", Pa_GetErrorText(err));
5309 return(MUS_ERROR);
5310 }
5311 return(PA_OUT_STREAM);
5312 }
5313
5314
5315 static PaStream *in_stream = NULL;
5316
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5317 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5318 {
5319 PaStreamParameters input_pars;
5320 PaError err;
5321
5322 input_pars.device = Pa_GetDefaultInputDevice();
5323 input_pars.channelCount = chans;
5324 input_pars.sampleFormat = sndlib_to_portaudio_format(samp_type);
5325 input_pars.suggestedLatency = Pa_GetDeviceInfo(input_pars.device)->defaultHighInputLatency;
5326 input_pars.hostApiSpecificStreamInfo = NULL;
5327
5328 err = Pa_OpenStream(&in_stream, &input_pars, NULL, srate, 1024, paClipOff, NULL, NULL);
5329 if (err == paNoError)
5330 err = Pa_StartStream(in_stream);
5331
5332 if (err != paNoError)
5333 {
5334 fprintf(stderr, "portaudio open input: %s\n", Pa_GetErrorText(err));
5335 return(MUS_ERROR);
5336 }
5337 return(MUS_NO_ERROR);
5338
5339 }
5340
5341
mus_audio_write(int line,char * buf,int bytes)5342 int mus_audio_write(int line, char *buf, int bytes)
5343 {
5344 PaError err;
5345 err = Pa_WriteStream(out_stream, buf, 1024);
5346
5347 if (err != paNoError)
5348 {
5349 fprintf(stderr, "portaudio write: %s\n", Pa_GetErrorText(err));
5350 return(MUS_ERROR);
5351 }
5352 return(MUS_NO_ERROR);
5353 }
5354
5355
mus_audio_close(int line)5356 int mus_audio_close(int line)
5357 {
5358 PaError err;
5359 if (line == PA_IN_STREAM)
5360 err = Pa_CloseStream(in_stream);
5361 else err = Pa_CloseStream(out_stream);
5362
5363 if (err != paNoError)
5364 {
5365 fprintf(stderr, "portaudio close: %s\n", Pa_GetErrorText(err));
5366 return(MUS_ERROR);
5367 }
5368 return(MUS_NO_ERROR);
5369 }
5370
5371
mus_audio_read(int line,char * buf,int bytes)5372 int mus_audio_read(int line, char *buf, int bytes)
5373 {
5374 PaError err;
5375 err = Pa_ReadStream(in_stream, buf, 1024);
5376
5377 if (err != paNoError)
5378 {
5379 fprintf(stderr, "portaudio read: %s\n", Pa_GetErrorText(err));
5380 return(MUS_ERROR);
5381 }
5382 return(MUS_NO_ERROR);
5383 }
5384
5385
5386 static bool portaudio_initialized = false;
5387
mus_audio_initialize(void)5388 int mus_audio_initialize(void)
5389 {
5390 PaError err;
5391
5392 if (portaudio_initialized) return(MUS_NO_ERROR);
5393 portaudio_initialized = true;
5394
5395 err = Pa_Initialize();
5396 if (err == paNoError)
5397 return(MUS_NO_ERROR);
5398
5399 fprintf(stderr, "portaudio initialize: %s\n", Pa_GetErrorText(err));
5400 return(MUS_ERROR);
5401 }
5402
5403
mus_audio_moniker(void)5404 char *mus_audio_moniker(void)
5405 {
5406 return((char *)Pa_GetVersionText());
5407 }
5408 #endif
5409
5410
5411
5412
5413 /* ------------------------------- STUBS ----------------------------------------- */
5414
5415 #ifndef AUDIO_OK
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5416 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(MUS_ERROR);}
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5417 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(MUS_ERROR);}
mus_audio_write(int line,char * buf,int bytes)5418 int mus_audio_write(int line, char *buf, int bytes) {return(MUS_ERROR);}
mus_audio_close(int line)5419 int mus_audio_close(int line) {return(MUS_ERROR);}
mus_audio_read(int line,char * buf,int bytes)5420 int mus_audio_read(int line, char *buf, int bytes) {return(MUS_ERROR);}
mus_audio_initialize(void)5421 int mus_audio_initialize(void) {return(MUS_ERROR);}
mus_audio_moniker(void)5422 char *mus_audio_moniker(void) {return((char *)"no audio support");}
5423 #endif
5424
5425
5426
5427 /* for CLM */
mus_reset_audio_c(void)5428 void mus_reset_audio_c(void)
5429 {
5430 audio_initialized = false;
5431 version_name = NULL;
5432 }
5433
5434
5435 #if HAVE_ALSA || HAVE_OSS
5436
5437 void mus_audio_alsa_channel_info(int dev, int *info);
mus_audio_alsa_channel_info(int dev,int * info)5438 void mus_audio_alsa_channel_info(int dev, int *info)
5439 {
5440 #if MUS_JACK
5441 if (api == MUS_JACK_API)
5442 {
5443 info[0] = sndjack_num_channels_allocated;
5444 return;
5445 }
5446 #endif
5447
5448 #if HAVE_ALSA
5449 if (api == MUS_ALSA_API)
5450 {
5451 alsa_chans(dev, info);
5452 return;
5453 }
5454 #endif
5455
5456 #if HAVE_OSS
5457 info[0] = 2;
5458 #endif
5459
5460 }
5461
5462
5463 int mus_audio_alsa_samples_per_channel(int dev);
mus_audio_alsa_samples_per_channel(int dev)5464 int mus_audio_alsa_samples_per_channel(int dev)
5465 {
5466 #if HAVE_ALSA
5467 return(alsa_samples_per_channel);
5468 #else
5469 return(1024);
5470 #endif
5471 }
5472
5473
5474 void mus_audio_alsa_device_list(int ur_dev, int chan, int *val);
mus_audio_alsa_device_list(int ur_dev,int chan,int * val)5475 void mus_audio_alsa_device_list(int ur_dev, int chan, int *val)
5476 {
5477 #if HAVE_ALSA
5478 int i = 1;
5479
5480 if (!audio_initialized) mus_audio_initialize();
5481
5482 if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
5483 val[i++] = to_sndlib_device(0, SND_PCM_STREAM_PLAYBACK);
5484
5485 if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
5486 val[i++] = to_sndlib_device(0, SND_PCM_STREAM_CAPTURE);
5487
5488 val[0] = (i - 1);
5489 #endif
5490 }
5491
5492 #define MUS_AUDIO_DIRECTION_PLAYBACK 0
5493 #define MUS_AUDIO_DIRECTION_RECORD 1
5494
5495 int mus_audio_alsa_device_direction(int dev);
mus_audio_alsa_device_direction(int dev)5496 int mus_audio_alsa_device_direction(int dev)
5497 {
5498 #if HAVE_OSS
5499 switch (MUS_AUDIO_DEVICE(dev))
5500 {
5501 case MUS_AUDIO_DIGITAL_OUT: case MUS_AUDIO_LINE_OUT: case MUS_AUDIO_DEFAULT:
5502 case MUS_AUDIO_SPEAKERS: case MUS_AUDIO_MIXER:
5503 case MUS_AUDIO_AUX_OUTPUT: case MUS_AUDIO_DAC_OUT:
5504 return(MUS_AUDIO_DIRECTION_PLAYBACK);
5505
5506 default:
5507 return(MUS_AUDIO_DIRECTION_RECORD);
5508 }
5509 #else
5510 {
5511 int card, device, alsa_device = 0;
5512 snd_pcm_stream_t alsa_stream = SND_PCM_STREAM_PLAYBACK;
5513
5514 if ((!audio_initialized) &&
5515 (mus_audio_initialize() != MUS_NO_ERROR))
5516 return(MUS_ERROR);
5517
5518 card = MUS_AUDIO_SYSTEM(dev);
5519 device = MUS_AUDIO_DEVICE(dev);
5520 to_alsa_device(device, &alsa_device, &alsa_stream);
5521
5522 if (card > 0 || alsa_device > 0)
5523 return(alsa_mus_error(MUS_AUDIO_CANT_READ, NULL));
5524 return(alsa_stream);
5525 }
5526 #endif
5527 }
5528 #endif
5529
5530
mus_audio_device_channels(int dev)5531 int mus_audio_device_channels(int dev)
5532 {
5533 #if MUS_JACK
5534 if (api == MUS_JACK_API)
5535 {
5536 return(sndjack_num_channels_allocated);
5537 }
5538 #endif
5539
5540 #if HAVE_ALSA
5541 if (api == MUS_ALSA_API)
5542 {
5543 return(alsa_chans(dev, NULL));
5544 }
5545 #endif
5546
5547 return(2); /* netbsd hpux sun mac and oss with quibbles */
5548 }
5549
5550
mus_audio_compatible_sample_type(int dev)5551 mus_sample_t mus_audio_compatible_sample_type(int dev) /* snd-dac and sndplay */
5552 {
5553 #if HAVE_ALSA
5554 if (api == MUS_ALSA_API)
5555 {
5556 int err;
5557 mus_sample_t ival[32];
5558 err = alsa_sample_types(dev, 32, ival);
5559 if (err != MUS_ERROR)
5560 {
5561 int i;
5562 for (i = 1; i <= (int)(ival[0]); i++)
5563 if (ival[i] == MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE)
5564 return(MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5565
5566 for (i = 1; i <= (int)(ival[0]); i++)
5567 if ((ival[i] == MUS_BINT) || (ival[i] == MUS_LINT) ||
5568 (ival[i] == MUS_BFLOAT) || (ival[i] == MUS_LFLOAT) ||
5569 (ival[i] == MUS_BSHORT) || (ival[i] == MUS_LSHORT))
5570 return(ival[i]);
5571
5572 for (i = 1; i <= (int)(ival[0]); i++)
5573 if ((ival[i] == MUS_MULAW) || (ival[i] == MUS_ALAW) ||
5574 (ival[i] == MUS_UBYTE) || (ival[i] == MUS_BYTE))
5575 return(ival[i]);
5576
5577 return(ival[1]);
5578 }
5579 }
5580 #endif
5581
5582 #if MUS_JACK
5583 if (api == MUS_JACK_API)
5584 return(MUS_COMP_FLOAT);
5585 #endif
5586 return(MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5587 }
5588
5589
look_for_sample_type(mus_sample_t * mixer_vals,mus_sample_t samp_type)5590 static mus_sample_t look_for_sample_type (mus_sample_t *mixer_vals, mus_sample_t samp_type)
5591 {
5592 int i, lim;
5593 lim = mixer_vals[0];
5594 for (i = 1; i <= lim; i++)
5595 if (mixer_vals[i] == samp_type)
5596 return(samp_type);
5597 return(MUS_UNKNOWN_SAMPLE);
5598 }
5599
5600
mus_audio_device_sample_type(int dev)5601 mus_sample_t mus_audio_device_sample_type(int dev) /* snd-dac */
5602 {
5603 mus_sample_t mixer_vals[16];
5604 mus_sample_t samp_type;
5605 int i;
5606 /* we return the new sample type, so mixer_vals is just a local collector of possible sample types */
5607 for (i = 0; i < 16; i++) mixer_vals[i] = MUS_UNKNOWN_SAMPLE;
5608
5609 #if (!WITH_AUDIO)
5610 return(MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5611 #endif
5612
5613 #if HAVE_OSS
5614 if (api == MUS_OSS_API)
5615 oss_sample_types(dev, mixer_vals);
5616 #endif
5617
5618 #if HAVE_ALSA
5619 if (api == MUS_ALSA_API)
5620 alsa_sample_types(dev, 16, mixer_vals);
5621 #endif
5622
5623 #if MUS_JACK
5624 if (api == MUS_JACK_API)
5625 {
5626 mixer_vals[0] = (mus_sample_t)1;
5627 mixer_vals[1] = MUS_COMP_FLOAT;
5628 }
5629 #endif
5630
5631 #if HAVE_SUN
5632 mixer_vals[0] = (mus_sample_t)2;
5633 mixer_vals[1] = MUS_LSHORT;
5634 mixer_vals[2] = MUS_MULAW;
5635 #endif
5636
5637 #if __APPLE__
5638 mixer_vals[0] = (mus_sample_t)1;
5639 #if MUS_LITTLE_ENDIAN
5640 mixer_vals[1] = MUS_LFLOAT;
5641 #else
5642 mixer_vals[1] = MUS_BFLOAT;
5643 #endif
5644 #endif
5645
5646 #if __NetBSD__
5647 netbsd_sample_types(dev, mixer_vals);
5648 #endif
5649
5650 #if __OpenBSD__
5651 mixer_vals[0] = (mus_sample_t)1;
5652 #if MUS_LITTLE_ENDIAN
5653 mixer_vals[1] = MUS_LSHORT;
5654 #else
5655 mixer_vals[1] = MUS_BSHORT;
5656 #endif
5657 #endif
5658
5659 samp_type = look_for_sample_type(mixer_vals, MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5660 if (samp_type != MUS_UNKNOWN_SAMPLE)
5661 return(samp_type);
5662
5663 #if MUS_LITTLE_ENDIAN
5664 samp_type = look_for_sample_type(mixer_vals, MUS_LFLOAT);
5665 if (samp_type == MUS_UNKNOWN_SAMPLE)
5666 {
5667 samp_type = look_for_sample_type(mixer_vals, MUS_LSHORT);
5668 if (samp_type == MUS_UNKNOWN_SAMPLE)
5669 samp_type = mixer_vals[1];
5670 }
5671 #else
5672 samp_type = look_for_sample_type(mixer_vals, MUS_BFLOAT);
5673 if (samp_type == MUS_UNKNOWN_SAMPLE)
5674 {
5675 samp_type = look_for_sample_type(mixer_vals, MUS_BSHORT);
5676 if (samp_type == MUS_UNKNOWN_SAMPLE)
5677 samp_type = mixer_vals[1];
5678 }
5679 #endif
5680 return(samp_type);
5681 }
5682
5683
5684 #else
5685 /* not WITH_AUDIO */
5686
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5687 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(-1);}
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5688 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(-1);}
mus_audio_write(int line,char * buf,int bytes)5689 int mus_audio_write(int line, char *buf, int bytes) {return(-1);}
mus_audio_close(int line)5690 int mus_audio_close(int line) {return(-1);}
mus_audio_read(int line,char * buf,int bytes)5691 int mus_audio_read(int line, char *buf, int bytes) {return(-1);}
mus_audio_initialize(void)5692 int mus_audio_initialize(void) {return(-1);}
mus_audio_moniker(void)5693 char *mus_audio_moniker(void) {return((char *)"no audio support");}
5694
mus_reset_audio_c(void)5695 void mus_reset_audio_c(void) {}
5696
mus_audio_device_channels(int dev)5697 int mus_audio_device_channels(int dev) {return(0);}
mus_audio_compatible_sample_type(int dev)5698 mus_sample_t mus_audio_compatible_sample_type(int dev) {return(MUS_UNKNOWN_SAMPLE);}
mus_audio_device_sample_type(int dev)5699 mus_sample_t mus_audio_device_sample_type(int dev) {return(MUS_UNKNOWN_SAMPLE);}
5700
5701 #if __APPLE__
mus_audio_output_properties_mutable(bool mut)5702 bool mus_audio_output_properties_mutable(bool mut) {return(false);}
5703 #endif
5704 #endif
5705