summaryrefslogblamecommitdiffstats
path: root/zvok.c
blob: 079b1f3e7bae8737ca20e24f76972787ba3632f1 (plain) (tree)
1
2
3
4
5
6
7
8






                            
                  
























































































































































































































                                                                                                                                                                                                                                        
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <error.h>
#include <unistd.h>
#include <soundio/soundio.h>
#include <fcntl.h>
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define NUM "4"
struct record_context {
	int glasnost;
};
static enum SoundIoFormat prioritized_formats[] = {
	// SoundIoFormatFloat32NE,
	// SoundIoFormatFloat32FE,
	///SoundIoFormatS32NE,
	// SoundIoFormatS32FE,
	///SoundIoFormatS24NE,
	// SoundIoFormatS24FE,
	SoundIoFormatS16NE,
	// SoundIoFormatS16FE,
	// SoundIoFormatFloat64NE,
	// SoundIoFormatFloat64FE,
	///SoundIoFormatU32NE,
	// SoundIoFormatU32FE,
	///SoundIoFormatU24NE,
	// SoundIoFormatU24FE,
	// SoundIoFormatU16NE,
	// SoundIoFormatU16FE,
	///SoundIoFormatS8,
	///SoundIoFormatU8,
	SoundIoFormatInvalid
};
static void read_callback (struct SoundIoInStream * instream, int frame_count_min __attribute__((unused)), int frame_count_max) {
	struct record_context * rc = instream->userdata;
	struct SoundIoChannelArea * areas;
	int frame_count = frame_count_max;
	int err = soundio_instream_begin_read(instream, &areas, &frame_count);
	long long vzorcev = 0;
	long long glasnost = 0;
	if (!frame_count)
		return;
	if (!areas) // HOLE because of overrun!
		rc->glasnost = 0;
	else
		for (int frame = 0; frame < frame_count; frame++)
			for (int ch = 0; ch < instream->layout.channel_count; ch++) {
				glasnost += ABS(* (int16_t *) areas[ch].ptr);
				vzorcev++;
				areas[ch].ptr += areas[ch].step;
			}
	rc->glasnost = glasnost / vzorcev;
	if ((err = soundio_instream_end_read(instream)))
		error_at_line(0, 0, __FILE__, __LINE__, "soundio_instream_read_end: %s", soundio_strerror(err));
}
static void overflow_callback (struct SoundIoInStream * instream __attribute__((unused))) {
	static int count = 0;
	fprintf(stderr, "overflow %d\n", ++count);
}
static void error_callback (struct SoundIoInStream * instream __attribute__((unused)), int err) {
	fprintf(stderr, "error %s\n", soundio_strerror(err)); // TODO this is unrecoverable, make exit of program
}
int main (void) {
	struct SoundIoInStream * instream = NULL;
	struct SoundIoDevice * selected_device = NULL;
	int r = 0;
	fprintf(stderr, "z okoljsko spremenljivko ID nastaviš id naprave -- idje izpiše program naprave\nz okoljsko spremenljivko ZALEDJE nastaviš zaledje -- program naprave izpiše možna zaledja\n");
	enum SoundIoBackend backend = SoundIoBackendNone;
	char * device_id = getenv("ID");
	if (getenv("ZALEDJE")) {
		switch (getenv("ZALEDJE")[0]) {
			case 'd':
				backend = SoundIoBackendDummy;
				break;
			case 'a':
				backend = SoundIoBackendAlsa;
				break;
			case 'p':
				backend = SoundIoBackendPulseAudio;
				break;
			case 'j':
				backend = SoundIoBackendJack;
				break;
			case 'c':
				backend = SoundIoBackendCoreAudio;
				break;
			case 'w':
				backend = SoundIoBackendWasapi;
				break;
		}
	}
	struct SoundIo * soundio = soundio_create();
	if (!soundio)
		error_at_line(1, ENOMEM, __FILE__, __LINE__, "soundio_create()");
	int err = (backend == SoundIoBackendNone) ? soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
	if (err) {
		error_at_line(0, 0, __FILE__, __LINE__, "soundio_connect: %s", soundio_strerror(err));
		r = 2;
		goto r;
	}
	soundio_flush_events(soundio);
	if (device_id) {
		for (int i = 0; i < soundio_input_device_count(soundio); i++) {
			struct SoundIoDevice * device = soundio_get_input_device(soundio, i);
			if (!strcmp(device_id, device->id)) {
				selected_device = device;
				break;
			}
			soundio_device_unref(device);
		}
	} else {
		int device_index = soundio_default_input_device_index(soundio);
		selected_device = soundio_get_input_device(soundio, device_index);
	}
	if (!selected_device) {
		error_at_line(0, 0, __FILE__, __LINE__, "!selected_device");
		r = 3;
		goto r;
	}
	fprintf(stderr, "izbrana naprava je %s\n", selected_device->name);
	if (selected_device->probe_error) {
		error_at_line(0, 0, __FILE__, __LINE__, "unable to probe device: %s", soundio_strerror(selected_device->probe_error));
		r = 4;
		goto r;
	}
	soundio_device_sort_channel_layouts(selected_device); // TODO poskusi brez
	int sample_rate = 0;
	for (int i = 0; i < selected_device->sample_rate_count; i++) {
		if (selected_device->sample_rates[i].max > sample_rate)
			sample_rate = selected_device->sample_rates[i].max;
	}
	if (!sample_rate) {
		error_at_line(0, 0, __FILE__, __LINE__, "naprava ne podpira vzorčenja");
		r = 5;
		goto r;
	}
	if (!selected_device->format_count) {
		error_at_line(0, 0, __FILE__, __LINE__, "naprava ne podpira oblik");
		r = 6;
		goto r;
	}
	enum SoundIoFormat fmt = SoundIoFormatInvalid;
	for (unsigned i = 0; i < sizeof prioritized_formats/sizeof prioritized_formats[0]; i++) {
		if (soundio_device_supports_format(selected_device, prioritized_formats[i])) {
			fmt = prioritized_formats[i];
			break;
		}
	}
	if (fmt == SoundIoFormatInvalid) {
		// fmt = selected_device->formats[0];
		error_at_line(0, 0, __FILE__, __LINE__, "naprava ne podpira podprte oblike");
		r = 7;
		goto r;
	}
	instream = soundio_instream_create(selected_device);
	if (!instream) {
		error_at_line(0, 0, __FILE__, __LINE__, "oom");
		r = 8;
		goto r;
	}
	sample_rate = 8000;
	fprintf(stderr, "hitrost vzorčenja je %d Hz, %s (prepleten)\n", sample_rate, soundio_format_string(fmt));
	instream->format = fmt;
	instream->sample_rate = sample_rate;
	instream->read_callback = read_callback;
	instream->overflow_callback = overflow_callback;
	instream->error_callback = error_callback;
	struct record_context rc = { 0 };
	instream->userdata = &rc;
	if ((err = soundio_instream_open(instream))) {
		error_at_line(0, 0, __FILE__, __LINE__, "soundio_instream_open: %s (%d)", soundio_strerror(err), err);
		r = 9;
		goto r;
	}
	if (instream->bytes_per_sample != 2) {
		error_at_line(0, 0, __FILE__, __LINE__, "pričakoval sem osembitne vzorce, nisem jih dobil (%d bajtov na vzorec)", instream->bytes_per_sample);
		r = 10;
		goto r;
	}
	fprintf(stderr, "pretok: %s\n", instream->layout.name);
	if ((err = soundio_instream_start(instream))) {
		error_at_line(0, 0, __FILE__, __LINE__, "soundio_instream_start: %s", soundio_strerror(err));
		r = 11;
		goto r;
	}
	int najv_gl = 1;
	int leds[] = { open("/sys/class/leds/input" NUM "::numlock/brightness", O_WRONLY), open("/sys/class/leds/input" NUM "::capslock/brightness", O_WRONLY), open("/sys/class/leds/input" NUM "::scrolllock/brightness", O_WRONLY) };
	while (1) {
		soundio_flush_events(soundio);
		usleep(10000);
		if (rc.glasnost > najv_gl)
			najv_gl = rc.glasnost;
		if (najv_gl < 1)
			najv_gl = 1;
		printf("glasnost: ");
		for (int i = 0; i < 64; i++)
			if (((double) rc.glasnost/najv_gl)*64 > i)
				printf("@");
			else
				printf(" ");
		if ((double) rc.glasnost/najv_gl > 0.2)
			write(leds[0], "1", 1);
		else
			write(leds[0], "0", 1);
		if ((double) rc.glasnost/najv_gl > 0.5)
			write(leds[1], "1", 1);
		else
			write(leds[1], "0", 1);
		if ((double) rc.glasnost/najv_gl > 0.7)
			write(leds[2], "1", 1);
		else
			write(leds[2], "0", 1);
		printf("\n");
		if (rc.glasnost < najv_gl/2)
			najv_gl -= 5;
	}
	r:
	if (instream)
		soundio_instream_destroy(instream);
	if (selected_device)
		soundio_device_unref(selected_device);
	soundio_destroy(soundio);
	return r;
}