/* $Id$ */

// [gophi@dupa ~]$ rec -t raw -r 44100 -c 2 -s w -f s - 2>/dev/null | tee sound.raw | ./soundanl

#include <inttypes.h>
#include <assert.h>
#include <stdio.h>

#define countof(x) (sizeof(x) / sizeof(*(x)))

static const uint16_t SMP_MIN = 0;
static const uint16_t SMP_MAX = 0xFFFF;
static const uint16_t SMP_CLIP = 4;

static const size_t FREQ = 44100;
static const size_t BUFSZ = 11025;

struct sample_t
{
	uint16_t chan[2];
};

static inline uint16_t read_channel(void)
{
	int16_t smp;
	assert(fread(&smp, sizeof(smp), 1, stdin) == 1);
	return 0x8000 + smp;
}

void read_buffer(struct sample_t *samples, size_t count)
{
	size_t i;

	for (i = 0; i < count; ++i) {
		samples[i].chan[0] = read_channel();
		samples[i].chan[1] = read_channel();
	}
}

int main(void)
{
	static const char heartbeats[] = "|/-\\";
	static size_t heartbeat_index = 0;
	static size_t iter_count;

	fprintf(stderr, "Sound analyzer (C) 2008 Adam Wysocki\n");
	fprintf(stderr, "Buffer size set to %u samples (%.fms)\n", BUFSZ, BUFSZ * 1000. / FREQ);
	fprintf(stderr, "Clip threshold set to %u samples\n", SMP_CLIP);
	fprintf(stderr, "Expecting stereo 16-bit signed data\n");
	fprintf(stderr, "|  Length |      Peak power |     Clip factor | Average DC bias | \n");

	for (iter_count = 0; 1; ++iter_count) {
		struct sample_t samples[BUFSZ];
		size_t i;
		size_t nclip[2] = {0, 0};
		uint16_t smin[2] = {SMP_MAX, SMP_MAX}, smax[2] = {SMP_MIN, SMP_MIN};
		uint16_t distance[2];
		char heartbeat;
		size_t time_min, time_sec;
		uint32_t sum[2] = {SMP_MIN, SMP_MIN};

		read_buffer(samples, countof(samples));

		for (i = 0; i < countof(samples); ++i) {
			size_t chan;

			for (chan = 0; chan < 2; ++chan) {
				uint16_t sample = samples[i].chan[chan];

				if (sample < smin[chan])
					smin[chan] = sample;

				if (sample > smax[chan])
					smax[chan] = sample;

				if (sample <= (SMP_MIN + SMP_CLIP) || sample >= (SMP_MAX - SMP_CLIP))
					++nclip[chan];

				sum[chan] += sample;
			}
		}

		distance[0] = smax[0] - smin[0];
		distance[1] = smax[1] - smin[1];

		heartbeat = heartbeats[heartbeat_index++];
		heartbeat_index &= 3;

		time_sec = iter_count * BUFSZ / FREQ;
		time_min = time_sec / 60;
		time_sec %= 60;

		fprintf(stderr, "| %c %02u:%02u | %6.2f%%,%6.2f%% | %6.2f%%,%6.2f%% | %6.2f%%,%6.2f%% | \r",
			heartbeat,
			time_min, time_sec,
			distance[0] * 100. / (SMP_MAX - SMP_MIN),
			distance[1] * 100. / (SMP_MAX - SMP_MIN),
			nclip[0] * 100. / countof(samples), 
			nclip[1] * 100. / countof(samples),
			sum[0] * 100. / (65536. * BUFSZ),
			sum[1] * 100. / (65536. * BUFSZ));
	}
}
