#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;
}