You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.5 KiB
79 lines
2.5 KiB
#include "input/fifo.h" |
|
#include "input/common.h" |
|
|
|
#include <time.h> |
|
|
|
#define SAMPLES_PER_BUFFER 512 |
|
|
|
int open_fifo(const char *path) { |
|
int fd = open(path, O_RDONLY); |
|
int flags = fcntl(fd, F_GETFL, 0); |
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK); |
|
return fd; |
|
} |
|
|
|
// input: FIFO |
|
void *input_fifo(void *data) { |
|
struct audio_data *audio = (struct audio_data *)data; |
|
int bytes_per_sample = audio->format / 8; |
|
__attribute__((aligned(sizeof(uint16_t)))) uint8_t buf[SAMPLES_PER_BUFFER * bytes_per_sample]; |
|
uint16_t *samples = |
|
bytes_per_sample == 2 ? (uint16_t *)&buf : calloc(SAMPLES_PER_BUFFER, sizeof(uint16_t)); |
|
|
|
int fd = open_fifo(audio->source); |
|
|
|
while (!audio->terminate) { |
|
int time_since_last_input = 0; |
|
unsigned int offset = 0; |
|
do { |
|
int num_read = read(fd, buf + offset, sizeof(buf) - offset); |
|
|
|
if (num_read < 1) { // if no bytes read sleep 10ms and zero shared buffer |
|
nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 10000000}, NULL); |
|
time_since_last_input++; |
|
|
|
if (time_since_last_input > 10) { |
|
reset_output_buffers(audio); |
|
close(fd); |
|
|
|
fd = open_fifo(audio->source); |
|
time_since_last_input = 0; |
|
offset = 0; |
|
} |
|
} else { |
|
offset += num_read; |
|
time_since_last_input = 0; |
|
} |
|
} while (offset < sizeof(buf)); |
|
|
|
switch (bytes_per_sample) { |
|
case 2: |
|
// [samples] = [buf] so there's nothing to do here. |
|
break; |
|
case 3: |
|
for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { |
|
// Really, a sample is composed of buf[3i + 2] | buf[3i + 1] | buf[3i], but our FFT |
|
// only takes 16-bit samples. Since we need to scale them eventually, we can just |
|
// do so here by taking the top 2 bytes. |
|
samples[i] = (buf[3 * i + 2] << 8) | buf[3 * i + 1]; |
|
} |
|
break; |
|
case 4: |
|
for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { |
|
samples[i] = (buf[4 * i + 3] << 8) | buf[4 * i + 2]; |
|
} |
|
break; |
|
} |
|
|
|
// We worked with unsigned ints up until now to save on sign extension, but the FFT wants |
|
// signed ints. |
|
write_to_fftw_input_buffers((int16_t *)samples, SAMPLES_PER_BUFFER / 2, audio); |
|
} |
|
|
|
close(fd); |
|
if (bytes_per_sample != 2) { |
|
free(samples); |
|
} |
|
|
|
return 0; |
|
}
|
|
|