⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abfile.c

📁 lpc 2400 bps语音编解码程序
💻 C
字号:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <math.h>
#include <multimedia/libaudio.h>
#include "abplay.h"

#define	MAX(a, b)	((a) < (b) ? (b) : (a))
#define	MIN(a, b)	((a) < (b) ? (a) : (b))
#define INFO_SIZE	80	/* Max length of file description string */
#define NSMAX		1000	/* Maximum number of segments */
#define STEPMAX 	2400	/* Max samples/energy point = 50 ms.*48 KHz */
#define SIG_SIZE 	4096	/* Audio output buffer size (>= STEPMAX!) */

static struct abfile abf[MAXFILES]; /* One of these for each file */
static struct segstate sg;	/* Energy/segmentation state */
static struct seg seg[NSMAX];	/* start, end (secs) of each segment */
static int nfiles = 0;		/* Number of currently open files */

/*
 * Open a signal file and initialize its abfile header.
 */
abp_open_file(char *file)
{
	int fd, nsamp, nstep, hlen, i, j, n, trans;
	caddr_t base;
	struct stat st;
	struct abfile *f;
	char info[INFO_SIZE+1];
	float win[STEPMAX];
	float erms1, erms2, epeak, *w1, *w2, *rb, *pb, t;
	char *ip;
	short *bp;
	char etbuf[SIG_SIZE];
	Audio_hdr default_hdr;	/* Defaults for headerless (spd) files */

   /* Open file, get its size, and mmap it */

	fd = open(file, O_RDONLY);
	if (fd < 0 || fstat(fd, &st) < 0) return Perr(fd, "open", file);
	if (!S_ISREG(st.st_mode))
	    return Pmsg(fd, "open: not a regular file", file);
	base = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
	if (base < (caddr_t)0) return Perr(fd, "mmap", file);

   /* Find first empty file slot */

	if (nfiles >= MAXFILES) return Pmsg(fd, "open: too many files", file);
	abf[nfiles].id = -1;
	for (j=0; j<=nfiles; j++) if (abf[j].id < 0) break;
	if (j == nfiles) nfiles += 1;
	f = &abf[j];

   /* Fill in the misc details */

	f->id = j;
	f->fd = fd;
	f->data = base;
	f->dsize = st.st_size;
	f->p.scale = 1.0;

   /* Get the audio header */

  /* Set defaults for files without audio headers - spd files */

	default_hdr.sample_rate = 8000;		/* 8 KHz */
	default_hdr.samples_per_unit = 1;	/* no blocking */
	default_hdr.bytes_per_unit = 2;		/* 16-bit samples */
	default_hdr.channels = 1;		/* monophonic */
	default_hdr.encoding = AUDIO_ENCODING_LINEAR;	/* linear */
	default_hdr.data_size = AUDIO_UNKNOWN_SIZE;	/* fill in later */

	if (audio_read_filehdr(fd, &f->h, info, INFO_SIZE) != AUDIO_SUCCESS) {
	    lseek(fd, 0L, SEEK_SET);	/* rewind file */
	    f->h = default_hdr;		/* not a Sun audio file - fake it */
	    info[0] = 0;
	}
	if (f->h.bytes_per_unit == 0) {
	    printf("bogus header - using default 16 bit linear encoding\n");
	    f->h = default_hdr;
	}
	f->hsize = lseek(fd, 0L, SEEK_CUR);
	if (f->h.data_size == AUDIO_UNKNOWN_SIZE)
	    f->h.data_size = f->dsize - f->hsize;

   /* Allocate energy buffers, set up translation to 16 bit linear */

	sg.step = .020;				/* Energy step size (20 ms.) */
	nsamp = f->h.samples_per_unit * (f->h.data_size/f->h.bytes_per_unit);
	nstep = nint(f->h.sample_rate * sg.step);	/* samples per step */
	f->esize = (nsamp-1) / nstep + 1;	/* # of energy points */
	f->rbuf = (float *)calloc(f->esize, sizeof(*f->rbuf));
	f->pbuf = (float *)calloc(f->esize, sizeof(*f->pbuf));
	if (f->rbuf==0 || f->pbuf==0) Perr(0, "abtool", "buffer alloc failed");
	trans = audio_setup_translate(f->h, default_hdr, 1);
	if (trans < 0) return -1;

/*	printf("hsize = %d, s/u = %d, b/u = %d, srate = %d\n", f->hsize,
	    f->h.samples_per_unit, f->h.bytes_per_unit, f->h.sample_rate);
	printf("nsamp = %d, nstep = %d, esize = %d\n", nsamp, nstep, f->esize);
*/

   /* Calculate the energy tracks */

	for (j=0, w2=win; j <= nstep; j++) *w2++ = 1.0 / nstep;
	ip = f->data + f->hsize;
	n = nstep * f->h.bytes_per_unit;
	rb = f->rbuf;
	pb = f->pbuf;
	erms1 = 0.0;
	for (i = 0; i < f->esize-1; i++) {
	    erms2 = erms1;
	    erms1 = epeak = 0.0;
	    w1 = win + nstep;
	    w2 = win;
	    if (trans == 0)
	        bp = (short *)ip;
	    else {
	        bp = (short *)etbuf;
	        j = audio_translate(trans, ip, etbuf, n);
	    }
	    ip += n;
	    for (j = 0; j < nstep; j++) {
	        t = *bp++;
	        epeak = MAX(epeak, abs(t));
	        t = t*t;
	        erms1 += t**w1--;
	        erms2 += t**w2++;
	    }
	    *rb++ = 10.*log10((double)MAX(erms2, 1.0));
	    *pb++ = 20.*log10((double)MAX(epeak, 1.0));
	}
	*rb++ = 10.*log10((double)MAX(erms1, 1.0));
	*pb++ = 0.0;

/*	printf("'%s' opened (%d,%d), len = %d, elen = %d\n",
	    file, f->id, nfiles, nsamp, f->esize);
	if (info[0] != 0) printf("'%s'\n", info);
*/
	abp_align(f->id, 0.0, sg.p.taumax);
	return f->id;
}

abp_close_file(int id)
{
	struct abfile *f;
	struct audio_status status;

	if (id<0 || id>=nfiles || id!=abf[id].id) {
	    fprintf(stderr, "close: invalid file (%d)\n", id);
	    return -1;
	}
	abp_get_audio_status(&status);
	if (id == status.id && status.state != IDLE) abp_abort_play();
	if (id == sg.id) sg.id = -1;
	f = &abf[id];
	f->id = -1;
	munmap(f->data, f->dsize);
	free(f->rbuf);
	free(f->pbuf);
	close(f->fd);
	return 0;
}

struct abfile *
abp_get_abfile(int id)
{
	if (id<0 || id>=nfiles || id!=abf[id].id) return (struct abfile *)0;
	return &abf[id];
}

struct segstate
abp_get_segstate()
{
	return sg;
}

abp_segment(int id, struct segparms parm)
{
	int i, nstart, nend, newseg, npad, ngap;
	int nsmax = NSMAX;

	sg.id = -1;
	sg.nsegs = 0;
	if (id<0 || id>=nfiles || id!=abf[id].id)
	    return sg.nsegs;

	sg.id = id;
	sg.p = parm;
	sg.elength = abf[id].esize;
	sg.segs = seg;
	sg.energy = abf[id].rbuf;

	nstart = sg.elength;
	nend = 0;
	newseg = 0;
	ngap = nint(.001*sg.p.gap / sg.step);
	npad = nint(.001*sg.p.pad / sg.step);

	for (i = 0; i < sg.elength; i++) {
	    if (sg.energy[i] > (float)sg.p.thresh && i < sg.elength-1) {
	        nstart = MIN(nstart, i);
	        nend = MAX(nend, i);
	        newseg = 1;
	    } else if (newseg > 0) {
	        if (i >= sg.elength-1 || i > nend+ngap) {
	            seg[sg.nsegs].start = sg.step * MAX(nstart-npad, 0);
	            seg[sg.nsegs].end = sg.step * MIN(nend+npad, sg.elength);
	            sg.nsegs += 1;
	            newseg = 0;
	            if (sg.nsegs >= nsmax) break;
	            nstart = sg.elength;
	            nend = 0;
	        }
	    }
	}
/*	fprintf(stderr, "segment id=%d, thr=%d, gap=%d, pad=%d, nsegs=%d\n",
	    id, sg.p.thresh, ngap, npad, sg.nsegs); */

	for (i = 0; i < nfiles; i++)
	    abp_align(i, 0.0, sg.p.taumax);

	return sg.nsegs;
}

abp_align(int id2, double tau, double taumax)
{
	int id1, n1, n2, i, m, maxm;
	float t, c, *e1, *e2;
	double corr();

	if (id2<0 || id2>=nfiles || abf[id2].id != id2) return -1;
	abf[id2].p.corr = abf[id2].p.delay = 0.0;
	id1 = sg.id;
	if (id1<0 || id1>=nfiles || abf[id1].id != id1) return -1;

	n1 = abf[id1].esize;
	n2 = abf[id2].esize;
	e1 = abf[id1].rbuf;
	e2 = abf[id2].rbuf;

	m = nint(tau / sg.step);
	if (m != 0) {
	    c = corr(n1, n2-m, e1, e2+m);
	} else {
	    c = corr(n1, n2, e1, e2);
	    maxm = nint(taumax / sg.step);
	    for (i = 1; i < maxm; i++) {
	        if ((t = corr(n1, n2-i, e1, e2+i)) > c) {
	            c = t;
	            m = i;
	        }
	        if ((t = corr(n1-i, n2, e1+i, e2)) > c) {
	            c = t;
	            m = -i;
	        }
	    }
	}
	abf[id2].p.delay = m * sg.step;
	abf[id2].p.corr = c / sqrt(corr(n1,n1,e1,e1) * corr(n2,n2,e2,e2));

/*	fprintf(stderr, "corr(%d, %d) = %6.3f at %6.3f sec\n",
	    id1, id2, abf[id2].p.corr, abf[id2].p.delay);   */

	return 1;
}

double
corr(int n1, int n2, float *e1, float *e2)
{
	int i, n;
	double t;

	n = MIN(n1, n2);
	t = 0.0;
	for (i = 0; i < n; i++) t += (*e1++) * (*e2++);
	return t;
}

Perr(int fd, char *s1, char *s2)
{
	if (fd > 0) close(fd);
	fprintf(stderr, "%s: ", s1);
	perror(s2);
	return -1;
}

Pmsg(int fd, char *s1, char *s2)
{
	if (fd > 0) close(fd);
	fprintf(stderr, "%s: %s\n", s1, s2);
	return(-1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -