/* Copyright (c) 1995,1996,1997 Nick Ing-Simmons. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. */ #include #include #include #include #include #include #include #include "../../Data/Audio.m" AudioVtab *AudioVptr; #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #ifdef HAVE_SYS_AUDIOIO_H #include #endif #ifdef HAVE_SUN_AUDIOIO_H #include #endif #define SAMP_RATE 8000 typedef struct { audio_info_t info; int fd; int kind; } play_audio_t; static char *dev_file = "/dev/audio"; audio_open(play_audio_t *dev, int Wait) { /* Try it quickly, first */ Zero(dev, 1, play_audio_t); dev->fd = open(dev_file, O_WRONLY | O_NDELAY); if ((dev->fd < 0) && (errno == EBUSY)) { if (!Wait) { croak("%s is busy\n", dev_file); } /* Now hang until it's open */ dev->fd = open(dev_file, O_WRONLY); } else if (dev->fd >= 0) { int flags = fcntl(dev->fd, F_GETFL, NULL); if (flags >= 0) fcntl(dev->fd, F_SETFL, flags & ~O_NDELAY); else perror("fcntl - F_GETFL"); } if (dev->fd < 0) { return 0; } else { #ifdef AUDIO_DEV_AMD /* Get the device output encoding configuration */ if (ioctl(dev->fd, AUDIO_GETDEV, &dev->kind)) { /* Old releases of SunOs don't support the ioctl, but can only be run on old machines which have AMD device... */ dev->kind = AUDIO_DEV_AMD; } #endif if (ioctl(dev->fd, AUDIO_GETINFO, &dev->info) != 0) { return 0; } } return 1; } static int audio_setinfo(play_audio_t *dev) { return (ioctl(dev->fd, AUDIO_SETINFO, &dev->info) != 0); } IV audio_rate(play_audio_t *dev,IV rate) { IV prev_rate = dev->info.play.sample_rate; if (rate) { dev->info.play.sample_rate = rate; #ifdef AUDIO_ENCODING_LINEAR if (rate > 8000) { dev->info.play.encoding = AUDIO_ENCODING_LINEAR; dev->info.play.precision = 16; } else { dev->info.play.encoding = AUDIO_ENCODING_ULAW; dev->info.play.precision = 8; } #endif audio_setinfo(dev); } return prev_rate; } float audio_gain(play_audio_t *dev,float gain) { float prev_gain = ((float) dev->info.play.gain)/AUDIO_MAX_GAIN; if (gain >= 0.0) { dev->info.play.gain = (unsigned) (AUDIO_MAX_GAIN * gain); audio_setinfo(dev); } return prev_gain; } IV audio_speaker(play_audio_t *dev,int flag) { IV old = (dev->info.play.port & AUDIO_SPEAKER) != 0; if (flag) { if (flag > 0) dev->info.play.port |= AUDIO_SPEAKER; else dev->info.play.port &= ~AUDIO_SPEAKER; audio_setinfo(dev); } return old; } IV audio_headphone(play_audio_t *dev,int flag) { IV old = (dev->info.play.port & AUDIO_HEADPHONE) != 0; if (flag) { if (flag > 0) dev->info.play.port |= AUDIO_HEADPHONE; else dev->info.play.port &= ~AUDIO_HEADPHONE; audio_setinfo(dev); } return old; } void audio_flush(play_audio_t *dev) { ioctl(dev->fd, AUDIO_DRAIN, 0); } void audio_DESTROY(play_audio_t *dev) { /* Close audio system */ if (dev->fd >= 0) { audio_flush(dev); close(dev->fd); dev->fd = -1; } } void audio_play16(play_audio_t *dev, int n, short *data) { if (n > 0 && dev->fd >= 0) { #ifdef AUDIO_ENCODING_LINEAR if (dev->info.play.encoding == AUDIO_ENCODING_LINEAR) { unsigned size = n * sizeof(short); if (write(dev->fd, data, n * sizeof(short)) != size) perror("write"); } else #endif if (dev->info.play.encoding == AUDIO_ENCODING_ULAW) { unsigned char *plabuf = (unsigned char *) malloc(n); if (plabuf) { int w; unsigned char *p = plabuf; unsigned char *e = p + n; while (p < e) { *p++ = short2ulaw(*data++); } p = plabuf; while ((w = write(dev->fd, p, n)) != n) { if (w == -1) { fprintf(stderr, "%d,%s:%d\n", errno, __FILE__, __LINE__); perror("audio"); abort(); } else { fprintf(stderr, "Writing %u, only wrote %u\n", n, w); p += w; n -= w; } } free(plabuf); } else { croak("No memory for ulaw data"); } } } } void audio_play(play_audio_t *dev, Audio *au, float volume) { STRLEN samp = Audio_samples(au); SV *tmp = Audio_shorts(au); if (volume >= 0) audio_gain(dev, volume); if (au->rate != audio_rate(dev,0)) audio_rate(dev, au->rate); audio_play16(dev, samp, (short *) SvPVX(tmp)); SvREFCNT_dec(tmp); } MODULE = Audio::Play::#OSNAME# PACKAGE=Audio::Play::#OSNAME# PREFIX = audio_ PROTOTYPES: DISABLE play_audio_t * audio_new(class,wait = 1) char * class IV wait CODE: {static play_audio_t buf; if (!audio_open(RETVAL = &buf,wait)) { XSRETURN_NO; } } OUTPUT: RETVAL void audio_DESTROY(dev) play_audio_t * dev void audio_flush(dev) play_audio_t * dev IV audio_speaker(dev,flag = 0) play_audio_t * dev IV flag IV audio_headphone(dev,flag = 0) play_audio_t * dev IV flag float audio_gain(dev,val = -1.0) play_audio_t * dev float val IV audio_rate(dev,rate = 0) play_audio_t * dev IV rate void audio_play(dev, au, vol = -1.0) play_audio_t * dev Audio * au; float vol BOOT: { AudioVptr = (AudioVtab *) SvIV(perl_get_sv("Audio::Data::AudioVtab",5)); }