shithub: riscv

ref: 8a53b8192db4848626722a00bf4478a2836102d8
dir: /sys/src/cmd/audio/flacdec/flacdec.c/

View raw version
#include <stdio.h>
#include <stdlib.h>
#include "FLAC/stream_decoder.h"

int rate = 44100;

typedef unsigned long ulong;
typedef unsigned char uchar;
typedef long long vlong;

typedef struct Chan Chan;
struct Chan
{
	ulong		phase;
	FLAC__int32	last;
	FLAC__int32	rand;
};

enum
{
	OutBits = 16,
	Max = 32767,
	Min = -32768,
};

#define PRNG(x) (((x)*0x19660dL + 0x3c6ef35fL) & 0xffffffffL)

static uchar*
resample(Chan *c, FLAC__int32 *src, uchar *dst, int mono, ulong delta, ulong count, ulong bps)
{
	FLAC__int32 last, val, out, rand;
	ulong phase, pos, scale, lowmask, lowmask2;
	vlong v;

	scale = 0;
	if(bps > OutBits){
		scale = bps - OutBits;
		lowmask = (1<<scale)-1;
		lowmask2 = lowmask/2;
	}

	rand = c->rand;
	last = c->last;
	phase = c->phase;
	pos = phase >> 16;
	while(pos < count){
		val = src[pos];
		if(pos)
			last = src[pos-1];

		/* interpolate */
		v = val;
		v -= last;
		v *= (phase & 0xFFFF);
		out = last + (v >> 16);

		/* scale / dithering */
		if(scale){
			out += (rand & lowmask) - lowmask2;
			rand = PRNG(rand);
			out >>= scale;
		}

		/* cliping */
		if(out > Max)
			out = Max;
		else if(out < Min)
			out = Min;

		*dst++ = out;
		*dst++ = out >> 8;
		if(mono){
			*dst++ = out;
			*dst++ = out >> 8;
		} else
			dst += 2;
		phase += delta;
		pos = phase >> 16;
	}
	c->rand = rand;
	c->last = val;
	if(delta < 0x10000)
		c->phase = phase & 0xFFFF;
	else
		c->phase = phase - (count << 16);

	return dst;
}

static FLAC__StreamDecoderReadStatus
decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *client_data)
{
	int n = *bytes;

	n = fread(buffer,1,n,stdin);
	if(n <= 0){
		*bytes = 0;
		return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
	} else {
		*bytes = n;
		return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
	}
}

static FLAC__StreamDecoderWriteStatus
decoutput(FLAC__StreamDecoder *dec, FLAC__Frame *frame, FLAC__int32 *buffer[], void *client_data)
{
	static uchar *buf;
	static int nbuf;
	static Chan c1, c0;
	ulong length, n, delta, bps;
	uchar *p;

	bps = frame->header.bits_per_sample;
	length = frame->header.blocksize;
	delta = (frame->header.sample_rate << 16) / rate;
	n = 4 * (frame->header.sample_rate + length * rate) / frame->header.sample_rate;
	if(n > nbuf){
		nbuf = n;
		buf = realloc(buf, nbuf);
	}
	if(frame->header.channels == 2)
		resample(&c1, buffer[1], buf+2, 0, delta, length, bps);
	p = resample(&c0, buffer[0], buf, frame->header.channels == 1, delta, length, bps);
	fwrite(buf, p-buf, 1, stdout);
	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}

static void
decerror(FLAC__StreamDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
}

static void
decmeta(FLAC__StreamDecoder *dec, FLAC__StreamMetadata *metadata, void *client_data)
{
}

int main(int argc, char *argv[])
{
	FLAC__bool ok = true;
	FLAC__StreamDecoder *dec = 0;

	dec = FLAC__stream_decoder_new();
	FLAC__stream_decoder_set_read_callback(dec, decinput);
	FLAC__stream_decoder_set_write_callback(dec, decoutput);
	FLAC__stream_decoder_set_error_callback(dec, decerror);
	FLAC__stream_decoder_set_metadata_callback(dec, decmeta);
	FLAC__stream_decoder_init(dec);
	FLAC__stream_decoder_process_until_end_of_stream(dec);
	FLAC__stream_decoder_finish(dec);
	return 0;
}