version 1.19, 2008/11/16 17:08:32 |
version 1.20, 2008/12/07 17:10:41 |
|
|
#include "safile.h" |
#include "safile.h" |
|
|
unsigned dev_bufsz, dev_round, dev_rate; |
unsigned dev_bufsz, dev_round, dev_rate; |
unsigned dev_rate_div, dev_round_div; |
|
struct aparams dev_ipar, dev_opar; |
struct aparams dev_ipar, dev_opar; |
struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play; |
struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play; |
struct file *dev_file; |
struct file *dev_file; |
|
|
/* |
unsigned |
* supported rates |
dev_roundof(unsigned newrate) |
*/ |
|
#define NRATES (sizeof(dev_rates) / sizeof(dev_rates[0])) |
|
unsigned dev_rates[] = { |
|
6400, 7200, 8000, 9600, 11025, 12000, |
|
12800, 14400, 16000, 19200, 22050, 24000, |
|
25600, 28800, 32000, 38400, 44100, 48000, |
|
51200, 57600, 64000, 76800, 88200, 96000, |
|
102400, 115200, 128000, 153600, 176400, 192000 |
|
}; |
|
|
|
/* |
|
* factors of supported rates |
|
*/ |
|
#define NPRIMES (sizeof(dev_primes) / sizeof(dev_primes[0])) |
|
unsigned dev_primes[] = {2, 3, 5, 7}; |
|
|
|
int |
|
dev_setrate(unsigned rate) |
|
{ |
{ |
unsigned i, r, p; |
return (dev_round * newrate + dev_rate / 2) / dev_rate; |
|
|
r = 1000 * rate; |
|
for (i = 0; i < NRATES; i++) { |
|
if (i == NRATES) { |
|
fprintf(stderr, "dev_setrate: %u, unsupported\n", rate); |
|
return 0; |
|
} |
|
if (r > 996 * dev_rates[i] && |
|
r < 1004 * dev_rates[i]) { |
|
dev_rate = dev_rates[i]; |
|
break; |
|
} |
|
} |
|
|
|
dev_rate_div = dev_rate; |
|
dev_round_div = dev_round; |
|
for (i = 0; i < NPRIMES; i++) { |
|
p = dev_primes[i]; |
|
while (dev_rate_div % p == 0 && dev_round_div % p == 0) { |
|
dev_rate_div /= p; |
|
dev_round_div /= p; |
|
} |
|
} |
|
return 1; |
|
} |
} |
|
|
void |
|
dev_roundrate(unsigned *newrate, unsigned *newround) |
|
{ |
|
*newrate += dev_rate_div - 1; |
|
*newrate -= *newrate % dev_rate_div; |
|
*newround = *newrate * dev_round_div / dev_rate_div; |
|
} |
|
|
|
/* |
/* |
* open the device with the given hardware parameters and create a mixer |
* open the device with the given hardware parameters and create a mixer |
* and a multiplexer connected to it with all necessary conversions |
* and a multiplexer connected to it with all necessary conversions |
|
|
*/ |
*/ |
void |
void |
dev_init(char *devpath, |
dev_init(char *devpath, |
struct aparams *dipar, struct aparams *dopar, |
struct aparams *dipar, struct aparams *dopar, unsigned bufsz) |
unsigned bufsz, int blkio) |
|
{ |
{ |
struct aparams ipar, opar; |
struct aparams ipar, opar; |
struct aproc *conv; |
struct aproc *conv; |
struct abuf *buf; |
struct abuf *buf; |
unsigned nfr, ibufsz, obufsz; |
unsigned nfr, ibufsz, obufsz; |
|
|
/* |
/* |
* ask for 1/4 of the buffer for the kernel ring and |
* ask for 1/4 of the buffer for the kernel ring and |
* limit the block size to 1/4 of the requested buffer |
* limit the block size to 1/4 of the requested buffer |
|
|
dev_bufsz = (bufsz + 3) / 4; |
dev_bufsz = (bufsz + 3) / 4; |
dev_round = (bufsz + 3) / 4; |
dev_round = (bufsz + 3) / 4; |
dev_file = (struct file *)safile_new(&safile_ops, devpath, |
dev_file = (struct file *)safile_new(&safile_ops, devpath, |
dipar, dopar, &dev_bufsz, &dev_round, blkio); |
dipar, dopar, &dev_bufsz, &dev_round); |
if (!dev_file) |
if (!dev_file) |
exit(1); |
exit(1); |
if (!dev_setrate(dipar ? dipar->rate : dopar->rate)) |
|
exit(1); |
|
if (dipar) { |
if (dipar) { |
dipar->rate = dev_rate; |
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level > 0) { |
if (debug_level > 0) { |
fprintf(stderr, "dev_init: hw recording "); |
fprintf(stderr, "dev_init: hw recording "); |
|
|
fprintf(stderr, "\n"); |
fprintf(stderr, "\n"); |
} |
} |
#endif |
#endif |
|
dev_rate = dipar->rate; |
} |
} |
if (dopar) { |
if (dopar) { |
dopar->rate = dev_rate; |
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level > 0) { |
if (debug_level > 0) { |
fprintf(stderr, "dev_init: hw playing "); |
fprintf(stderr, "dev_init: hw playing "); |
|
|
fprintf(stderr, "\n"); |
fprintf(stderr, "\n"); |
} |
} |
#endif |
#endif |
|
dev_rate = dopar->rate; |
} |
} |
ibufsz = obufsz = dev_bufsz; |
ibufsz = obufsz = dev_bufsz; |
bufsz = (bufsz > dev_bufsz) ? bufsz - dev_bufsz : 0; |
bufsz = (bufsz > dev_bufsz) ? bufsz - dev_bufsz : 0; |
|
|
struct abuf *pbuf = NULL, *rbuf = NULL; |
struct abuf *pbuf = NULL, *rbuf = NULL; |
struct aparams ipar, opar; |
struct aparams ipar, opar; |
struct aproc *conv; |
struct aproc *conv; |
unsigned nfr; |
unsigned round, nblk; |
|
|
if (ibuf) { |
if (ibuf) { |
ipar = *sipar; |
ipar = *sipar; |
pbuf = LIST_FIRST(&dev_mix->obuflist); |
pbuf = LIST_FIRST(&dev_mix->obuflist); |
|
nblk = (dev_bufsz / dev_round + 3) / 4; |
|
round = dev_roundof(ipar.rate); |
if (!aparams_eqenc(&ipar, &dev_opar)) { |
if (!aparams_eqenc(&ipar, &dev_opar)) { |
nfr = (dev_bufsz + 3) / 4 + dev_round - 1; |
|
nfr -= nfr % dev_round; |
|
conv = dec_new(name, &ipar); |
conv = dec_new(name, &ipar); |
ipar.bps = dev_opar.bps; |
ipar.bps = dev_opar.bps; |
ipar.bits = dev_opar.bits; |
ipar.bits = dev_opar.bits; |
|
|
ipar.le = dev_opar.le; |
ipar.le = dev_opar.le; |
ipar.msb = dev_opar.msb; |
ipar.msb = dev_opar.msb; |
aproc_setin(conv, ibuf); |
aproc_setin(conv, ibuf); |
ibuf = abuf_new(nfr, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
} |
} |
if (!aparams_subset(&ipar, &dev_opar)) { |
if (!aparams_subset(&ipar, &dev_opar)) { |
nfr = (dev_bufsz + 3) / 4 + dev_round - 1; |
|
nfr -= nfr % dev_round; |
|
conv = cmap_new(name, &ipar, &dev_opar); |
conv = cmap_new(name, &ipar, &dev_opar); |
ipar.cmin = dev_opar.cmin; |
ipar.cmin = dev_opar.cmin; |
ipar.cmax = dev_opar.cmax; |
ipar.cmax = dev_opar.cmax; |
aproc_setin(conv, ibuf); |
aproc_setin(conv, ibuf); |
ibuf = abuf_new(nfr, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
} |
} |
if (!aparams_eqrate(&ipar, &dev_opar)) { |
if (!aparams_eqrate(&ipar, &dev_opar)) { |
nfr = (dev_bufsz + 3) / 4 + dev_round - 1; |
conv = resamp_new(name, round, dev_round); |
nfr -= nfr % dev_round; |
|
conv = resamp_new(name, &ipar, &dev_opar); |
|
ipar.rate = dev_opar.rate; |
ipar.rate = dev_opar.rate; |
|
round = dev_round; |
aproc_setin(conv, ibuf); |
aproc_setin(conv, ibuf); |
ibuf = abuf_new(nfr, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
} |
} |
aproc_setin(dev_mix, ibuf); |
aproc_setin(dev_mix, ibuf); |
|
|
if (obuf) { |
if (obuf) { |
opar = *sopar; |
opar = *sopar; |
rbuf = LIST_FIRST(&dev_sub->ibuflist); |
rbuf = LIST_FIRST(&dev_sub->ibuflist); |
|
round = dev_roundof(opar.rate); |
|
nblk = (dev_bufsz / dev_round + 3) / 4; |
if (!aparams_eqenc(&opar, &dev_ipar)) { |
if (!aparams_eqenc(&opar, &dev_ipar)) { |
nfr = (dev_bufsz + 3) / 4 + dev_round - 1; |
|
nfr -= nfr % dev_round; |
|
conv = enc_new(name, &opar); |
conv = enc_new(name, &opar); |
opar.bps = dev_ipar.bps; |
opar.bps = dev_ipar.bps; |
opar.bits = dev_ipar.bits; |
opar.bits = dev_ipar.bits; |
|
|
opar.le = dev_ipar.le; |
opar.le = dev_ipar.le; |
opar.msb = dev_ipar.msb; |
opar.msb = dev_ipar.msb; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nfr, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
if (!aparams_subset(&opar, &dev_ipar)) { |
if (!aparams_subset(&opar, &dev_ipar)) { |
nfr = (dev_bufsz + 3) / 4 + dev_round - 1; |
|
nfr -= nfr % dev_round; |
|
conv = cmap_new(name, &dev_ipar, &opar); |
conv = cmap_new(name, &dev_ipar, &opar); |
opar.cmin = dev_ipar.cmin; |
opar.cmin = dev_ipar.cmin; |
opar.cmax = dev_ipar.cmax; |
opar.cmax = dev_ipar.cmax; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nfr, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
if (!aparams_eqrate(&opar, &dev_ipar)) { |
if (!aparams_eqrate(&opar, &dev_ipar)) { |
nfr = (dev_bufsz + 3) / 4 + dev_round - 1; |
conv = resamp_new(name, dev_round, round); |
nfr -= nfr % dev_round; |
|
conv = resamp_new(name, &dev_ipar, &opar); |
|
opar.rate = dev_ipar.rate; |
opar.rate = dev_ipar.rate; |
|
round = dev_round; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nfr, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
aproc_setout(dev_sub, obuf); |
aproc_setout(dev_sub, obuf); |