Audio-DSP
view release on metacpan or search on metacpan
else if (strEQ(val, "AFMT_U16_LE"))
return(AFMT_U16_LE);
else if (strEQ(val, "AFMT_U16_BE"))
return(AFMT_U16_BE);
else if (strEQ(val, "AFMT_MPEG"))
return(AFMT_MPEG);
else {
return(-1);
}
} else {
return(-1);
}
}
int _modeflag (SV* flag) {
int mode;
char* val;
/* mode specified as integer */
if (SvIOK(flag))
mode = SvIV(flag);
/* Fcntl.pm-exported constants are recognized as
* floating-point numbers
*/
else if (SvNOK(flag))
return (int)SvNV(flag);
/* mode specified as string - DEPRECATED */
else if (SvPOK(flag)) {
val = SvPVX(flag);
if (strEQ(val, "O_RDONLY"))
mode = O_RDONLY;
else if (strEQ(val, "O_WRONLY"))
mode = O_WRONLY;
else if (strEQ(val, "O_RDWR"))
mode = O_RDWR;
else
mode = -1;
} else {
mode = -1;
}
return(mode);
}
MODULE = Audio::DSP PACKAGE = Audio::DSP
PROTOTYPES: ENABLED
double
constant(name,arg)
char * name
int arg
#############################################
################ Constructor ################
void
new (...)
PPCODE:
{
HV* construct = newHV();
HV* thistash = newHV();
SV* buff = newSViv(4096); /* read/write buffer size */
SV* chan = newSViv(1); /* mono(1) or stereo(2) */
SV* data = newSVpv("",0); /* stored audio data */
SV* device = newSVpv("/dev/dsp",8);
SV* errstr = newSVpvf("",0);
SV* file_indicator = newSViv(0); /* file descriptor */
SV* format = newSViv(AFMT_U8); /* 8 bit unsigned is default */
SV* mark = newSViv(0); /* play position */
SV* rate = newSViv(8192); /* sampling rate */
SV* self;
char audio_buff[AUDIO_FILE_BUFFER_SIZE];
char* audio_file; /* if "file" param exists */
char* key; /* param name */
int audio_fd;
int status;
int stidx; /* stack index */
/******** get parameters ********/
for (stidx = items % 2; stidx < items; stidx += 2) {
key = SvPVX(ST(stidx));
if (strEQ(key, "device"))
sv_setpv(device, SvPVX(ST(stidx + 1)));
else if (strEQ(key, "buffer"))
sv_setiv(buff, SvIV(ST(stidx + 1)));
else if (strEQ(key, "rate"))
sv_setiv(rate, SvIV(ST(stidx + 1)));
else if (strEQ(key, "format")) {
sv_setiv(format, _audioformat(ST(stidx + 1)));
if (SvIV(format) < 0)
croak("error determining audio format");
}
else if (strEQ(key, "channels"))
sv_setiv(chan, SvIV(ST(stidx + 1)));
/**** store data from existing audio file ****/
else if (strEQ(key, "file")) {
audio_file = SvPVX(ST(stidx + 1));
audio_fd = open(audio_file, O_RDONLY);
if (audio_fd < 0)
croak("failed to open %s", audio_file);
for (;;) {
status = read(audio_fd, audio_buff, AUDIO_FILE_BUFFER_SIZE); if (status == 0)
break;
else
sv_catpvn(data, audio_buff, status);
}
if (close(audio_fd) < 0)
croak("problem closing audio file %s", audio_file);
}
}
/******** assign settings to new object ********/
hv_store(construct, "buffer", 6, buff, 0);
hv_store(construct, "channels", 8, chan, 0);
hv_store(construct, "data", 4, data, 0);
hv_store(construct, "device", 6, device, 0);
hv_store(construct, "errstr", 6, errstr, 0);
hv_store(construct, "file_indicator", 14, file_indicator, 0);
hv_store(construct, "format", 6, format, 0);
hv_store(construct, "mark", 4, mark, 0);
hv_store(construct, "rate", 4, rate, 0);
self = newRV_inc((SV*)construct); /* make a reference */
thistash = gv_stashpv("Audio::DSP", 0);
sv_bless(self, thistash); /* bless it */
XPUSHs(self); /* push it */
}
#################################################################
############## Methods for opening / closing device #############
void
init (...)
PPCODE:
{
SV* format;
HV* caller = (HV*)SvRV(ST(0));
char* dev;
char* key;
char* val;
int arg;
int fd;
int mode = O_RDWR; /* device open mode */
int status;
int stidx;
if ((items % 2) == 0)
croak("Odd number of elements in hash list");
for (stidx = 1; stidx < items; stidx += 2) {
key = SvPVX(ST(stidx));
if (strEQ(key, "device")) {
hv_store(caller, "device", 6, newSVsv(ST(stidx + 1)), 0);
} else if (strEQ(key, "buffer")) {
hv_store(caller, "buffer", 6, newSVsv(ST(stidx + 1)), 0);
} else if (strEQ(key, "channels")) {
hv_store(caller, "channels", 8, newSVsv(ST(stidx + 1)), 0);
} else if (strEQ(key, "rate")) {
hv_store(caller, "rate", 4, newSVsv(ST(stidx + 1)), 0);
} else if (strEQ(key, "format")) {
hv_store(caller, "format", 6,
newSViv(_audioformat(ST(stidx + 1))), 0);
if (SvIV(*hv_fetch(caller, "format", 6, 0)) < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("error determining audio format"), 0);
XSRETURN_NO;
}
}
/******** get file mode ********/
else if (strEQ(key, "mode")) {
mode = _modeflag(ST(stidx + 1));
if (mode < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to recognize open flag"), 0);
XSRETURN_NO;
}
}
}
/**** device name ****/
dev = SvPVX(*hv_fetch(caller, "device", 6, 0));
/**** open device ****/
fd = open(dev, mode);
if (fd < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to open device '%s'", dev), 0);
XSRETURN_NO;
}
/**** set sampling format ****/
arg = SvIV(*hv_fetch(caller, "format", 6, 0));
if (ioctl(fd, SNDCTL_DSP_SETFMT, &arg) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_SETFMT ioctl failed"), 0);
XSRETURN_NO;
}
if (arg != SvIV(*hv_fetch(caller, "format", 6, 0))) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to set sample format"), 0);
XSRETURN_NO;
}
/**** set channels ****/
arg = SvIV(*hv_fetch(caller, "channels", 8, 0));
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &arg) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_CHANNELS ioctl failed"), 0);
XSRETURN_NO;
}
if (arg != SvIV(*hv_fetch(caller, "channels", 8, 0))) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to set number of channels"), 0);
XSRETURN_NO;
}
/**** set sampling rate ****/
arg = SvIV(*hv_fetch(caller, "rate", 4, 0));
if (ioctl(fd, SNDCTL_DSP_SPEED, &arg) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_SPEED ioctl failed"), 0);
XSRETURN_NO;
}
if (arg != SvIV(*hv_fetch(caller, "rate", 4, 0))) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to set sampling rate"), 0);
XSRETURN_NO;
}
/**** store file descriptor in Audio::DSP object ****/
hv_store(caller, "file_indicator", 14, newSViv(fd), 0);
XSRETURN_YES;
}
void
open (...)
PPCODE:
{
/* open without sending any ioctl messages */
HV* caller = (HV*)SvRV(ST(0));
SV* flag;
int fd;
int mode = O_RDWR;
char* dev = SvPVX(*hv_fetch(caller, "device", 6, 0));
if (items > 1) {
flag = ST(1);
mode = _modeflag(flag);
if (mode < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("unrecognized open flag"), 0);
XSRETURN_NO;
}
}
fd = open(dev, mode);
if (fd < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to open audio device file"), 0);
XSRETURN_NO;
}
hv_store(caller, "file_indicator", 14, newSViv(fd), 0);
XSRETURN_YES;
}
void
close (...)
PPCODE:
{
/* fetch file descriptor and close... nothing fancy */
int fd = SvIV(*hv_fetch((HV*)SvRV(ST(0)), "file_indicator", 14, 0));
if (close(fd) < 0)
XSRETURN_NO;
else
XSRETURN_YES;
}
#################################################################
####################### I/O control methods #####################
void
channels (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int chan, arg;
chan = arg = SvIV(ST(1));
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &arg) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_CHANNELS ioctl failed"), 0);
XSRETURN_NO;
}
XPUSHs(newSViv(arg));
}
void
getfmts (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int mask;
if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_GETFMTS ioctl failed"), 0);
XSRETURN_NO;
}
XPUSHs(newSViv(mask));
}
void
post (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
if (ioctl(fd, SNDCTL_DSP_POST, 0) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_POST ioctl failed"), 0);
XSRETURN_NO;
}
XSRETURN_YES;
}
void
reset (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
if (ioctl(fd, SNDCTL_DSP_RESET, 0) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_RESET ioctl failed"), 0);
XSRETURN_NO;
}
XSRETURN_YES;
}
void
setduplex (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
if (ioctl(fd, SNDCTL_DSP_SETDUPLEX) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_SETDUPLEX ioctl failed"), 0);
XSRETURN_NO;
}
XSRETURN_YES;
}
void
setfmt (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
/* SV* format = ST(1); */
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int fmt, arg;
/* fmt = arg = _audioformat(format); */
fmt = arg = SvIV(ST(1));
if (ioctl(fd, SNDCTL_DSP_SETFMT, &arg) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_SETFMT ioctl failed"), 0);
XSRETURN_NO;
}
XPUSHs(newSViv(arg));
}
void
speed (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int rate, arg;
rate = arg = SvIV(ST(1));
if (ioctl(fd, SNDCTL_DSP_SPEED, &arg) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_SPEED ioctl failed"), 0);
XSRETURN_NO;
}
XPUSHs(newSViv(arg));
}
void
sync (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
if (ioctl(fd, SNDCTL_DSP_SYNC, 0) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_SYNC ioctl failed"), 0);
XSRETURN_NO;
}
XSRETURN_YES;
}
#################################################################
##################### Direct device I/O #########################
void
dread (...)
PPCODE:
{
/* read data and return it */
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int count;
int status;
char *buf;
if (items > 1)
count = SvIV(ST(1));
else
count = SvIV(*hv_fetch(caller, "buffer", 6, 0));
buf = malloc(count);
status = read(fd, buf, count);
if (status != count) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to read correct number of bytes"), 0);
XSRETURN_NO;
}
XPUSHs(newSVpvn(buf, status));
free(buf);
}
void
dwrite (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int status;
int count = SvCUR(ST(1));
char* diy_data = SvPVX(ST(1));
status = write(fd, diy_data, count);
if (status != count) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to write correct number of bytes"), 0);
XSRETURN_NO;
}
XSRETURN_YES;
}
#################################################################
##################### "data-in-memory" methods ##################
void
audiofile (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
char audio_buff[AUDIO_FILE_BUFFER_SIZE];
char* audio_file;
int audio_fd;
int status;
audio_file = SvPVX(ST(1));
audio_fd = open(audio_file, O_RDONLY);
if (audio_fd < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to open audio file '%s'", audio_file), 0);
XSRETURN_NO;
}
for (;;) {
status = read(audio_fd, audio_buff, AUDIO_FILE_BUFFER_SIZE);
if (status == 0)
break;
else
sv_catpvn(*hv_fetch(caller, "data", 4, 0), audio_buff, status);
}
if (close(audio_fd) < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("problem closing audio file '%s'", audio_file), 0);
XSRETURN_NO;
}
XSRETURN_YES;
}
void
clear (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
hv_store(caller, "data", 4, newSVpv("",0), 0);
hv_store(caller, "mark", 4, newSViv(0), 0);
}
void
data (...)
PPCODE:
{
XPUSHs(*hv_fetch((HV*)SvRV(ST(0)), "data", 4, 0));
}
void
datacat (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int len = SvCUR(ST(1));
sv_catpvn(*hv_fetch(caller, "data", 4, 0), SvPVX(ST(1)), len);
XPUSHs(sv_2mortal(newSViv(SvCUR(*hv_fetch(caller, "data", 4, 0)))));
}
void
datalen (...)
PPCODE:
{
XPUSHs(sv_2mortal(newSViv(SvCUR(*hv_fetch((HV*)SvRV(ST(0)), "data", 4, 0)))));
}
void
read (...)
PPCODE:
{
/* read one buffer length of data */
HV* caller = (HV*)SvRV(ST(0));
int count = SvIV(*hv_fetch(caller, "buffer", 6, 0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int status;
char buf[count];
status = read(fd, buf, count); /* record some sound */
if (status != count) {
hv_store(caller, "errstr", 6,
newSVpvf("failed to read correct number of bytes"), 0);
XSRETURN_NO;
}
sv_catpvn(*hv_fetch(caller, "data", 4, 0), buf, status);
XSRETURN_YES;
}
void
setmark (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
if (items >= 2) {
SvREFCNT_inc(ST(1));
hv_store(caller, "mark", 4, ST(1), 0);
}
XPUSHs(*hv_fetch(caller, "mark", 4, 0));
}
void
write (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int count = SvIV(*hv_fetch(caller, "buffer", 6, 0));
int dlength = SvCUR(*hv_fetch(caller, "data", 4, 0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int mark = SvIV(*hv_fetch(caller, "mark", 4, 0));
int status;
char* data;
if (mark >= dlength) /* end of data */
XSRETURN_NO;
data = SvPVX(*hv_fetch(caller, "data", 4, 0));
status = write(fd, &data[mark], count);
/*** This just causes unnecessary problems...
* if (status != count) {
* hv_store(caller, "errstr", 6,
* newSVpvf("failed to write correct number of bytes"), 0);
* XSRETURN_NO;
* }
*/
hv_store(caller, "mark", 4, newSViv(mark + count), 0);
XSRETURN_YES;
}
####################################################################
######################### misc. methods ############################
void
errstr (...)
PPCODE:
{
XPUSHs(*hv_fetch((HV*)SvRV(ST(0)), "errstr", 6, 0));
}
####################################################################
################## Deprecated methods from v.0.01 ##################
void
getformat (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
SV* format = ST(1);
int arg = _audioformat(format);
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int mask;
if (arg < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("error determining audio format"), 0);
XSRETURN_NO;
}
if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
hv_store(caller, "errstr", 6,
newSVpvf("SNDCTL_DSP_GETFMTS ioctl failed"), 0);
XSRETURN_NO;
} else if (mask & arg) /* the format is supported */
XSRETURN_YES;
else
hv_store(caller, "errstr", 6,
newSVpvf("format not supported"), 0);
XSRETURN_NO;
}
void
queryformat (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
int fd = SvIV(*hv_fetch(caller, "file_indicator", 14, 0));
int status = ioctl(fd, SNDCTL_DSP_SETFMT, AFMT_QUERY);
XPUSHs(newSViv(status));
}
void
setbuffer (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
if (items >= 2) {
SvREFCNT_inc(ST(1));
hv_store(caller, "buffer", 6, ST(1), 0);
}
XPUSHs(*hv_fetch(caller, "buffer", 6, 0));
}
void
setchannels (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
if (items >= 2) {
SvREFCNT_inc(ST(1));
hv_store(caller, "channels", 8, ST(1), 0);
}
XPUSHs(*hv_fetch(caller, "channels", 8, 0));
}
void
setdevice (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
if (items >= 2) {
SvREFCNT_inc(ST(1));
hv_store(caller, "device", 6, ST(1), 0);
}
XPUSHs(*hv_fetch(caller, "device", 6, 0));
}
void
setformat (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
if (items >= 2) {
SvREFCNT_inc(ST(1));
hv_store(caller, "format", 6, newSViv(_audioformat(ST(1))), 0);
if (SvIV(*hv_fetch(caller, "format", 6, 0)) < 0) {
hv_store(caller, "errstr", 6,
newSVpvf("error determining audio format"), 0);
XSRETURN_NO;
}
}
XPUSHs(*hv_fetch(caller, "format", 6, 0));
}
void
setrate (...)
PPCODE:
{
HV* caller = (HV*)SvRV(ST(0));
if (items >= 2) {
SvREFCNT_inc(ST(1));
hv_store(caller, "rate", 4, ST(1), 0);
}
XPUSHs(*hv_fetch(caller, "rate", 4, 0));
}
( run in 2.342 seconds using v1.01-cache-2.11-cpan-71847e10f99 )