shithub: mp3dec

ref: 87180cbdb314a2e3f583b88c43eb8f458a861ef8
dir: /mp3dec.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#define MINIMP3_IMPLEMENTATION
#include "minimp3_ex.h"

static int noseek;
static Biobuf in;
static uchar inb[MINIMP3_BUF_SIZE];

static size_t
readcb(void *buf, size_t size, void *)
{
	int n;
	n = Bread(&in, buf, size);
	return n > 0 ? n : 0;
}

static int
seekcb(uint64_t position, void *)
{
	if(!noseek)
		Bseek(&in, position, 0);
	return 0;
}

static void
usage(void)
{
	fprint(2, "usage: %s [ -s SECONDS ]\n", argv0);
	exits("usage");
}

static mp3dec_ex_t dec;
static mp3dec_io_t io = {
	.read = readcb,
	.seek = seekcb,
};
static mp3d_sample_t buf[2*4410];

void
main(int argc, char **argv)
{
	size_t n;
	double seekto;
	int out, pfd[2], pid;
	char fmt[32];

	seekto = 0.0;
	ARGBEGIN{
	case 's':
		seekto = atof(EARGF(usage()));
		break;
	default:
		usage();
	}ARGEND

	if(Binits(&in, 0, OREAD, inb, sizeof(inb)) != 0)
		sysfatal("Binits");
	noseek = Bseek(&in, 0, 2) < 0;
	if(!noseek)
		Bseek(&in, 0, 0);
	if(mp3dec_ex_open_cb(&dec, &io, MP3D_SEEK_TO_SAMPLE|MP3D_DO_NOT_SCAN) != 0)
		sysfatal("mp3dec_ex_open_cb");
	if(seekto != 0.0)
		fprint(2, "time: %g\n", (noseek || mp3dec_ex_seek(&dec, seekto*dec.info.channels*dec.info.hz) != 0) ? 0.0 : seekto);

	out = 1;
	if(dec.info.channels != 2 || dec.info.hz != 44100){
		pid = -1;
		if(pipe(pfd) < 0 || (pid = fork()) < 0)
			sysfatal("%r");
		if(pid == 0){
			dup(pfd[1], 0);
			close(pfd[1]);
			close(pfd[0]);
			snprint(fmt, sizeof(fmt), "s16c%dr%d", dec.info.channels, dec.info.hz);
			execl("/bin/audio/pcmconv", "pcmconv", "-i", fmt, nil);
			sysfatal("%r");
		}
		close(1);
		close(pfd[1]);
		out = pfd[0];
	}

	while((n = mp3dec_ex_read(&dec, buf, nelem(buf))) > 0)
		write(out, buf, n*sizeof(buf[0]));
	Bterm(&in);
	close(out);
	mp3dec_ex_close(&dec);

	exits(nil);
}