summaryrefslogtreecommitdiff
path: root/input
diff options
context:
space:
mode:
Diffstat (limited to 'input')
-rw-r--r--input/alsa.c165
-rw-r--r--input/alsa.h5
-rw-r--r--input/common.c53
-rw-r--r--input/common.h36
-rw-r--r--input/fifo.c79
-rw-r--r--input/fifo.h5
-rw-r--r--input/portaudio.c204
-rw-r--r--input/portaudio.h3
-rw-r--r--input/pulse.c142
-rw-r--r--input/pulse.h6
-rw-r--r--input/shmem.c82
-rw-r--r--input/shmem.h5
-rw-r--r--input/sndio.c63
-rw-r--r--input/sndio.h5
14 files changed, 853 insertions, 0 deletions
diff --git a/input/alsa.c b/input/alsa.c
new file mode 100644
index 0000000..8fcbc28
--- /dev/null
+++ b/input/alsa.c
@@ -0,0 +1,165 @@
+// input: ALSA
+#include "input/alsa.h"
+#include "debug.h"
+#include "input/common.h"
+
+#include <alloca.h>
+#include <alsa/asoundlib.h>
+#include <math.h>
+
+// assuming stereo
+#define CHANNELS_COUNT 2
+#define SAMPLE_RATE 44100
+
+static void initialize_audio_parameters(snd_pcm_t **handle, struct audio_data *audio,
+ snd_pcm_uframes_t *frames) {
+ // alsa: open device to capture audio
+ int err = snd_pcm_open(handle, audio->source, SND_PCM_STREAM_CAPTURE, 0);
+ if (err < 0) {
+ fprintf(stderr, "error opening stream: %s\n", snd_strerror(err));
+ exit(EXIT_FAILURE);
+ } else
+ debug("open stream successful\n");
+
+ snd_pcm_hw_params_t *params;
+ snd_pcm_hw_params_alloca(&params); // assembling params
+ snd_pcm_hw_params_any(*handle, params); // setting defaults or something
+ // interleaved mode right left right left
+ snd_pcm_hw_params_set_access(*handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ // trying to set 16bit
+ snd_pcm_hw_params_set_format(*handle, params, SND_PCM_FORMAT_S16_LE);
+ snd_pcm_hw_params_set_channels(*handle, params, CHANNELS_COUNT);
+ unsigned int sample_rate = SAMPLE_RATE;
+ // trying our rate
+ snd_pcm_hw_params_set_rate_near(*handle, params, &sample_rate, NULL);
+ // number of frames pr read
+ snd_pcm_hw_params_set_period_size_near(*handle, params, frames, NULL);
+ err = snd_pcm_hw_params(*handle, params); // attempting to set params
+ if (err < 0) {
+ fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(err));
+ exit(EXIT_FAILURE);
+ }
+
+ if ((err = snd_pcm_prepare(*handle)) < 0) {
+ fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err));
+ exit(EXIT_FAILURE);
+ }
+
+ // getting actual format
+ snd_pcm_hw_params_get_format(params, (snd_pcm_format_t *)&sample_rate);
+ // converting result to number of bits
+ if (sample_rate <= 5)
+ audio->format = 16;
+ else if (sample_rate <= 9)
+ audio->format = 24;
+ else
+ audio->format = 32;
+ snd_pcm_hw_params_get_rate(params, &audio->rate, NULL);
+ snd_pcm_hw_params_get_period_size(params, frames, NULL);
+ // snd_pcm_hw_params_get_period_time(params, &sample_rate, &dir);
+}
+
+static int get_certain_frame(signed char *buffer, int buffer_index, int adjustment) {
+ // using the 10 upper bits this would give me a vert res of 1024, enough...
+ int temp = buffer[buffer_index + adjustment - 1] << 2;
+ int lo = buffer[buffer_index + adjustment - 2] >> 6;
+ if (lo < 0)
+ lo = abs(lo) + 1;
+ if (temp >= 0)
+ temp += lo;
+ else
+ temp -= lo;
+ return temp;
+}
+/*
+static void fill_audio_outs(struct audio_data* audio, signed char* buffer,
+const int size) {
+ int radj = audio->format / 4; // adjustments for interleaved
+ int ladj = audio->format / 8;
+ static int audio_out_buffer_index = 0;
+ // sorting out one channel and only biggest octet
+ for (int buffer_index = 0; buffer_index < size; buffer_index += ladj * 2) {
+ // first channel
+ int tempr = get_certain_frame(buffer, buffer_index, radj);
+ // second channel
+ int templ = get_certain_frame(buffer, buffer_index, ladj);
+
+ // mono: adding channels and storing it in the buffer
+ if (audio->channels == 1)
+ audio->audio_out_l[audio_out_buffer_index] = (templ + tempr) / 2;
+ else { // stereo storing channels in buffer
+ audio->audio_out_l[audio_out_buffer_index] = templ;
+ audio->audio_out_r[audio_out_buffer_index] = tempr;
+ }
+
+ ++audio_out_buffer_index;
+ audio_out_buffer_index %= audio->FFTbufferSize;
+ }
+}
+*/
+#define FRAMES_NUMBER 256
+
+void *input_alsa(void *data) {
+ int err;
+ struct audio_data *audio = (struct audio_data *)data;
+ snd_pcm_t *handle;
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_uframes_t period_size;
+ snd_pcm_uframes_t frames = FRAMES_NUMBER;
+
+ initialize_audio_parameters(&handle, audio, &frames);
+ snd_pcm_get_params(handle, &buffer_size, &period_size);
+
+ int radj = audio->format / 4; // adjustments for interleaved
+ int ladj = audio->format / 8;
+ int16_t buf[period_size];
+ int32_t buffer32[period_size];
+ frames = period_size / ((audio->format / 8) * CHANNELS_COUNT);
+ // printf("period size: %lu\n", period_size);
+ // exit(0);
+
+ // frames * bits/8 * channels
+ // const int size = frames * (audio->format / 8) * CHANNELS_COUNT;
+ signed char *buffer = malloc(period_size);
+
+ while (!audio->terminate) {
+ switch (audio->format) {
+ case 16:
+ err = snd_pcm_readi(handle, buf, frames);
+ break;
+ case 32:
+ err = snd_pcm_readi(handle, buffer32, frames);
+ for (uint16_t i = 0; i < frames * 2; i++) {
+ buf[i] = buffer32[i] / pow(2, 16);
+ }
+ break;
+ default:
+ err = snd_pcm_readi(handle, buffer, frames);
+ // sorting out one channel and only biggest octet
+ for (uint16_t i = 0; i < period_size * 2; i += ladj * 2) {
+ // first channel
+ buf[i] = get_certain_frame(buffer, i, ladj);
+ // second channel
+ buf[i + 1] = get_certain_frame(buffer, i, radj);
+ }
+ // fill_audio_outs(audio, buffer, period_size);
+ break;
+ }
+
+ if (err == -EPIPE) {
+ /* EPIPE means overrun */
+ debug("overrun occurred\n");
+ snd_pcm_prepare(handle);
+ } else if (err < 0) {
+ debug("error from read: %s\n", snd_strerror(err));
+ } else if (err != (int)frames) {
+ debug("short read, read %d %d frames\n", err, (int)frames);
+ }
+
+ write_to_fftw_input_buffers(buf, frames, data);
+ }
+
+ free(buffer);
+ snd_pcm_close(handle);
+ return NULL;
+}
diff --git a/input/alsa.h b/input/alsa.h
new file mode 100644
index 0000000..daa2f58
--- /dev/null
+++ b/input/alsa.h
@@ -0,0 +1,5 @@
+// header file for alsa, part of cava.
+
+#pragma once
+
+void *input_alsa(void *data);
diff --git a/input/common.c b/input/common.c
new file mode 100644
index 0000000..29fdc89
--- /dev/null
+++ b/input/common.c
@@ -0,0 +1,53 @@
+#include "input/common.h"
+
+#include <string.h>
+
+void reset_output_buffers(struct audio_data *data) {
+ memset(data->in_bass_r, 0, sizeof(double) * 2 * (data->FFTbassbufferSize / 2 + 1));
+ memset(data->in_bass_l, 0, sizeof(double) * 2 * (data->FFTbassbufferSize / 2 + 1));
+ memset(data->in_mid_r, 0, sizeof(double) * 2 * (data->FFTmidbufferSize / 2 + 1));
+ memset(data->in_mid_l, 0, sizeof(double) * 2 * (data->FFTmidbufferSize / 2 + 1));
+ memset(data->in_treble_r, 0, sizeof(double) * 2 * (data->FFTtreblebufferSize / 2 + 1));
+ memset(data->in_treble_l, 0, sizeof(double) * 2 * (data->FFTtreblebufferSize / 2 + 1));
+}
+
+int write_to_fftw_input_buffers(int16_t buf[], int16_t frames, void *data) {
+ struct audio_data *audio = (struct audio_data *)data;
+
+ for (uint16_t i = 0; i < frames * 2; i += 2) {
+ if (audio->channels == 1) {
+ if (audio->average) {
+ audio->in_bass_l[audio->bass_index] = (buf[i] + buf[i + 1]) / 2;
+ }
+ if (audio->left) {
+ audio->in_bass_l[audio->bass_index] = buf[i];
+ }
+ if (audio->right) {
+ audio->in_bass_l[audio->bass_index] = buf[i + 1];
+ }
+ }
+ // stereo storing channels in buffer
+ if (audio->channels == 2) {
+ audio->in_bass_l[audio->bass_index] = buf[i];
+ audio->in_bass_r[audio->bass_index] = buf[i + 1];
+
+ audio->in_mid_r[audio->mid_index] = audio->in_bass_r[audio->bass_index];
+ audio->in_treble_r[audio->treble_index] = audio->in_bass_r[audio->bass_index];
+ }
+
+ audio->in_mid_l[audio->mid_index] = audio->in_bass_l[audio->bass_index];
+ audio->in_treble_l[audio->treble_index] = audio->in_bass_l[audio->bass_index];
+
+ audio->bass_index++;
+ audio->mid_index++;
+ audio->treble_index++;
+ if (audio->bass_index == audio->FFTbassbufferSize - 1)
+ audio->bass_index = 0;
+ if (audio->mid_index == audio->FFTmidbufferSize - 1)
+ audio->mid_index = 0;
+ if (audio->treble_index == audio->FFTtreblebufferSize - 1)
+ audio->treble_index = 0;
+ }
+
+ return 0;
+}
diff --git a/input/common.h b/input/common.h
new file mode 100644
index 0000000..3737f2b
--- /dev/null
+++ b/input/common.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct audio_data {
+ int FFTbassbufferSize;
+ int FFTmidbufferSize;
+ int FFTtreblebufferSize;
+ int bass_index;
+ int mid_index;
+ int treble_index;
+ double *in_bass_r, *in_bass_l;
+ double *in_mid_r, *in_mid_l;
+ double *in_treble_r, *in_treble_l;
+ int format;
+ unsigned int rate;
+ char *source; // alsa device, fifo path or pulse source
+ int im; // input mode alsa, fifo or pulse
+ unsigned int channels;
+ bool left, right, average;
+ int terminate; // shared variable used to terminate audio thread
+ char error_message[1024];
+};
+
+void reset_output_buffers(struct audio_data *data);
+
+int write_to_fftw_input_buffers(int16_t buf[], int16_t frames, void *data);
diff --git a/input/fifo.c b/input/fifo.c
new file mode 100644
index 0000000..870785c
--- /dev/null
+++ b/input/fifo.c
@@ -0,0 +1,79 @@
+#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;
+}
diff --git a/input/fifo.h b/input/fifo.h
new file mode 100644
index 0000000..52b6ba6
--- /dev/null
+++ b/input/fifo.h
@@ -0,0 +1,5 @@
+// header files for fifo, part of cava
+
+#pragma once
+
+void *input_fifo(void *data);
diff --git a/input/portaudio.c b/input/portaudio.c
new file mode 100644
index 0000000..21ad188
--- /dev/null
+++ b/input/portaudio.c
@@ -0,0 +1,204 @@
+#include "input/portaudio.h"
+#include "input/common.h"
+
+#include <portaudio.h>
+#define PORTBUFSIZE 512
+
+#define SAMPLE_SILENCE -32767
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+
+typedef struct {
+ int frameIndex; /* Index into sample array. */
+ int maxFrameIndex;
+ SAMPLE *recordedSamples;
+} paTestData;
+
+static struct audio_data *audio;
+// static int n = 0;
+
+static int recordCallback(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ PaStreamCallbackFlags statusFlags, void *userData) {
+ paTestData *data = (paTestData *)userData;
+ SAMPLE *rptr = (SAMPLE *)inputBuffer;
+ long framesToCalc;
+ // long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+ int16_t silence_buffer[PORTBUFSIZE] = {SAMPLE_SILENCE};
+ (void)outputBuffer; // Prevent unused variable warnings.
+ (void)timeInfo;
+ (void)statusFlags;
+ (void)userData;
+
+ if (framesLeft < framesPerBuffer) {
+ framesToCalc = framesLeft;
+ finished = paComplete;
+ } else {
+ framesToCalc = framesPerBuffer;
+ finished = paContinue;
+ }
+
+ if (inputBuffer == NULL) {
+ write_to_fftw_input_buffers(silence_buffer, framesToCalc, audio);
+ /*
+ for(i=0; i<framesToCalc; i++) {
+ if(audio->channels == 1) audio->audio_out_l[n] = SAMPLE_SILENCE;
+ if(audio->channels == 2) {
+ audio->audio_out_l[n] = SAMPLE_SILENCE;
+ audio->audio_out_r[n] = SAMPLE_SILENCE;
+ }
+ if(n == PORTBUFSIZE-1) n = 0;
+ }
+ */
+ } else {
+ write_to_fftw_input_buffers(rptr, framesToCalc, audio);
+ /*
+ for(i=0; i<framesToCalc; i++) {
+ if(audio->channels == 1) {
+ audio->audio_out_l[n] = (rptr[0] + rptr[1]) / 2;
+ rptr += 2;
+ }
+ if(audio->channels == 2) {
+ audio->audio_out_l[n] = *rptr++;
+ audio->audio_out_r[n] = *rptr++;
+ }
+ n++;
+ if(n == PORTBUFSIZE-1) n = 0;
+ }
+ */
+ }
+
+ data->frameIndex += framesToCalc;
+ if (finished == paComplete) {
+ data->frameIndex = 0;
+ finished = paContinue;
+ }
+ return finished;
+}
+
+void portaudio_simple_free(paTestData data) {
+ Pa_Terminate();
+ free(data.recordedSamples);
+}
+
+void *input_portaudio(void *audiodata) {
+ audio = (struct audio_data *)audiodata;
+
+ PaStreamParameters inputParameters;
+ PaStream *stream;
+ PaError err = paNoError;
+ paTestData data;
+
+ // start portaudio
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ fprintf(stderr, "Error: unable to initilize portaudio - %s\n", Pa_GetErrorText(err));
+ exit(EXIT_FAILURE);
+ }
+
+ // get portaudio device
+ int deviceNum = -1, numOfDevices = Pa_GetDeviceCount();
+ if (!strcmp(audio->source, "list")) {
+ if (numOfDevices < 0) {
+ fprintf(stderr, "Error: portaudio was unable to find a audio device! Code: 0x%x\n",
+ numOfDevices);
+ exit(EXIT_FAILURE);
+ }
+ for (int i = 0; i < numOfDevices; i++) {
+ const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i);
+ printf("Device #%d: %s\n"
+ "\tInput Channels: %d\n"
+ "\tOutput Channels: %d\n"
+ "\tDefault SampleRate: %lf\n",
+ i + 1, deviceInfo->name, deviceInfo->maxInputChannels,
+ deviceInfo->maxOutputChannels, deviceInfo->defaultSampleRate);
+ }
+ exit(EXIT_SUCCESS);
+ } else if (!strcmp(audio->source, "auto")) {
+ deviceNum = Pa_GetDefaultInputDevice();
+
+ if (deviceNum == paNoDevice) {
+ fprintf(stderr, "Error: no portaudio input device found\n");
+ exit(EXIT_FAILURE);
+ }
+ } else if (sscanf(audio->source, "%d", &deviceNum)) {
+ if (deviceNum > numOfDevices) {
+ fprintf(stderr, "Error: Invalid input device!\n");
+ exit(EXIT_FAILURE);
+ }
+ deviceNum--;
+ } else {
+ for (int i = 0; i < numOfDevices; i++) {
+ const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i);
+ if (!strcmp(audio->source, deviceInfo->name)) {
+ deviceNum = i;
+ break;
+ }
+ }
+ if (deviceNum == -1) {
+ fprintf(stderr, "Error: No such device '%s'!\n", audio->source);
+ exit(EXIT_FAILURE);
+ }
+ }
+ inputParameters.device = deviceNum;
+
+ // set parameters
+ data.maxFrameIndex = PORTBUFSIZE;
+ data.recordedSamples = (SAMPLE *)malloc(2 * PORTBUFSIZE * sizeof(SAMPLE));
+ if (data.recordedSamples == NULL) {
+ fprintf(stderr, "Error: failure in memory allocation!\n");
+ exit(EXIT_FAILURE);
+ } else
+ memset(data.recordedSamples, 0x00, 2 * PORTBUFSIZE);
+
+ inputParameters.channelCount = 2;
+ inputParameters.sampleFormat = PA_SAMPLE_TYPE;
+ inputParameters.suggestedLatency =
+ Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ // set it to work
+ err = Pa_OpenStream(&stream, &inputParameters, NULL, audio->rate, PORTBUFSIZE, paClipOff,
+ recordCallback, &data);
+ if (err != paNoError) {
+ fprintf(stderr, "Error: failure in opening stream (%x)\n", err);
+ exit(EXIT_FAILURE);
+ }
+
+ // main loop
+ while (1) {
+ // start recording
+ data.frameIndex = 0;
+ err = Pa_StartStream(stream);
+ if (err != paNoError) {
+ fprintf(stderr, "Error: failure in starting stream (%x)\n", err);
+ exit(EXIT_FAILURE);
+ }
+
+ // record
+ while ((err = Pa_IsStreamActive(stream)) == 1) {
+ Pa_Sleep(5);
+ if (audio->terminate == 1)
+ break;
+ }
+ // check for errors
+ if (err < 0) {
+ fprintf(stderr, "Error: failure in recording audio (%x)\n", err);
+ exit(EXIT_FAILURE);
+ }
+
+ // check if it bailed
+ if (audio->terminate == 1)
+ break;
+ }
+ // close stream
+ if ((err = Pa_CloseStream(stream)) != paNoError) {
+ fprintf(stderr, "Error: failure in closing stream (%x)\n", err);
+ exit(EXIT_FAILURE);
+ }
+
+ portaudio_simple_free(data);
+ return 0;
+}
diff --git a/input/portaudio.h b/input/portaudio.h
new file mode 100644
index 0000000..1953e7f
--- /dev/null
+++ b/input/portaudio.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void *input_portaudio(void *audiodata);
diff --git a/input/pulse.c b/input/pulse.c
new file mode 100644
index 0000000..97907db
--- /dev/null
+++ b/input/pulse.c
@@ -0,0 +1,142 @@
+#include "input/pulse.h"
+#include "input/common.h"
+
+#include <pulse/error.h>
+#include <pulse/pulseaudio.h>
+#include <pulse/simple.h>
+
+#define BUFFERSIZE 4096
+
+pa_mainloop *m_pulseaudio_mainloop;
+
+void cb(__attribute__((unused)) pa_context *pulseaudio_context, const pa_server_info *i,
+ void *userdata) {
+
+ // getting default sink name
+ struct audio_data *audio = (struct audio_data *)userdata;
+ audio->source = malloc(sizeof(char) * 1024);
+
+ strcpy(audio->source, i->default_sink_name);
+
+ // appending .monitor suufix
+ audio->source = strcat(audio->source, ".monitor");
+
+ // quiting mainloop
+ pa_context_disconnect(pulseaudio_context);
+ pa_context_unref(pulseaudio_context);
+ pa_mainloop_quit(m_pulseaudio_mainloop, 0);
+ pa_mainloop_free(m_pulseaudio_mainloop);
+}
+
+void pulseaudio_context_state_callback(pa_context *pulseaudio_context, void *userdata) {
+
+ // make sure loop is ready
+ switch (pa_context_get_state(pulseaudio_context)) {
+ case PA_CONTEXT_UNCONNECTED:
+ // printf("UNCONNECTED\n");
+ break;
+ case PA_CONTEXT_CONNECTING:
+ // printf("CONNECTING\n");
+ break;
+ case PA_CONTEXT_AUTHORIZING:
+ // printf("AUTHORIZING\n");
+ break;
+ case PA_CONTEXT_SETTING_NAME:
+ // printf("SETTING_NAME\n");
+ break;
+ case PA_CONTEXT_READY: // extract default sink name
+ // printf("READY\n");
+ pa_operation_unref(pa_context_get_server_info(pulseaudio_context, cb, userdata));
+ break;
+ case PA_CONTEXT_FAILED:
+ printf("failed to connect to pulseaudio server\n");
+ exit(EXIT_FAILURE);
+ break;
+ case PA_CONTEXT_TERMINATED:
+ // printf("TERMINATED\n");
+ pa_mainloop_quit(m_pulseaudio_mainloop, 0);
+ break;
+ }
+}
+
+void getPulseDefaultSink(void *data) {
+
+ struct audio_data *audio = (struct audio_data *)data;
+ pa_mainloop_api *mainloop_api;
+ pa_context *pulseaudio_context;
+ int ret;
+
+ // Create a mainloop API and connection to the default server
+ m_pulseaudio_mainloop = pa_mainloop_new();
+
+ mainloop_api = pa_mainloop_get_api(m_pulseaudio_mainloop);
+ pulseaudio_context = pa_context_new(mainloop_api, "cava device list");
+
+ // This function connects to the pulse server
+ pa_context_connect(pulseaudio_context, NULL, PA_CONTEXT_NOFLAGS, NULL);
+
+ // printf("connecting to server\n");
+
+ // This function defines a callback so the server will tell us its state.
+ pa_context_set_state_callback(pulseaudio_context, pulseaudio_context_state_callback,
+ (void *)audio);
+
+ // starting a mainloop to get default sink
+
+ // starting with one nonblokng iteration in case pulseaudio is not able to run
+ if (!(ret = pa_mainloop_iterate(m_pulseaudio_mainloop, 0, &ret))) {
+ printf("Could not open pulseaudio mainloop to "
+ "find default device name: %d\n"
+ "check if pulseaudio is running\n",
+ ret);
+
+ exit(EXIT_FAILURE);
+ }
+
+ pa_mainloop_run(m_pulseaudio_mainloop, &ret);
+}
+
+void *input_pulse(void *data) {
+
+ struct audio_data *audio = (struct audio_data *)data;
+ int16_t buf[BUFFERSIZE / 2];
+
+ /* The sample type to use */
+ static const pa_sample_spec ss = {.format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2};
+
+ audio->format = 16;
+
+ static const pa_buffer_attr pb = {.maxlength = (uint32_t)-1, // BUFSIZE * 2,
+ .fragsize = BUFFERSIZE};
+
+ uint16_t frames = BUFFERSIZE / 4;
+
+ pa_simple *s = NULL;
+ int error;
+
+ if (!(s = pa_simple_new(NULL, "cava", PA_STREAM_RECORD, audio->source, "audio for cava", &ss,
+ NULL, &pb, &error))) {
+ sprintf(audio->error_message, __FILE__ ": Could not open pulseaudio source: %s, %s. \
+ To find a list of your pulseaudio sources run 'pacmd list-sources'\n",
+ audio->source, pa_strerror(error));
+
+ audio->terminate = 1;
+ pthread_exit(NULL);
+ }
+
+ while (!audio->terminate) {
+ if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
+ sprintf(audio->error_message, __FILE__ ": pa_simple_read() failed: %s\n",
+ pa_strerror(error));
+ audio->terminate = 1;
+ pthread_exit(NULL);
+ }
+
+ // sorting out channels
+
+ write_to_fftw_input_buffers(buf, frames, data);
+ }
+
+ pa_simple_free(s);
+ return 0;
+}
diff --git a/input/pulse.h b/input/pulse.h
new file mode 100644
index 0000000..155da47
--- /dev/null
+++ b/input/pulse.h
@@ -0,0 +1,6 @@
+// header file for pulse, part of cava.
+
+#pragma once
+
+void *input_pulse(void *data);
+void getPulseDefaultSink();
diff --git a/input/shmem.c b/input/shmem.c
new file mode 100644
index 0000000..c7bf040
--- /dev/null
+++ b/input/shmem.c
@@ -0,0 +1,82 @@
+#include "input/shmem.h"
+#include "input/common.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+typedef unsigned int u32_t;
+typedef short s16_t;
+
+// #define BUFSIZE 1024
+#define BUFSIZE 2048
+
+int rc;
+
+#define VIS_BUF_SIZE 16384
+#define VB_OFFSET 8192 + 4096
+
+typedef struct {
+ pthread_rwlock_t rwlock;
+ u32_t buf_size;
+ u32_t buf_index;
+ bool running;
+ u32_t rate;
+ time_t updated;
+ s16_t buffer[VIS_BUF_SIZE];
+} vis_t;
+
+// input: SHMEM
+void *input_shmem(void *data) {
+ struct audio_data *audio = (struct audio_data *)data;
+ vis_t *mmap_area;
+ int fd; /* file descriptor to mmaped area */
+ int mmap_count = sizeof(vis_t);
+
+ printf("input_shmem: source: %s", audio->source);
+
+ fd = shm_open(audio->source, O_RDWR, 0666);
+
+ if (fd < 0) {
+ printf("Could not open source '%s': %s\n", audio->source, strerror(errno));
+ exit(EXIT_FAILURE);
+ } else {
+ mmap_area = mmap(NULL, sizeof(vis_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if ((intptr_t)mmap_area == -1) {
+ printf("mmap failed - check if squeezelite is running with visualization enabled\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ // printf("bufs: %u / run: %u / rate: %u\n",mmap_area->buf_size, mmap_area->running,
+ // mmap_area->rate);
+ audio->rate = mmap_area->rate;
+
+ while (!audio->terminate) {
+ write_to_fftw_input_buffers(mmap_area->buffer, BUFSIZE, audio);
+ /*
+ for (i = VB_OFFSET; i < BUFSIZE+VB_OFFSET; i += 2) {
+ if (audio->channels == 1) {
+ audio->audio_out_l[n] = (mmap_area->buffer[i] +
+ mmap_area->buffer[i + 1]) / 2; } else if (audio->channels == 2) { audio->audio_out_l[n] =
+ mmap_area->buffer[i]; audio->audio_out_r[n] = mmap_area->buffer[i + 1];
+ }
+ n++;
+ if (n == audio->FFTbufferSize - 1) n = 0;
+ }
+ */
+ }
+
+ // cleanup
+ if (fd > 0) {
+ if (close(fd) != 0) {
+ printf("Could not close file descriptor %d: %s", fd, strerror(errno));
+ }
+ } else {
+ printf("Wrong file descriptor %d", fd);
+ }
+
+ if (munmap(mmap_area, mmap_count) != 0) {
+ printf("Could not munmap() area %p+%d. %s", mmap_area, mmap_count, strerror(errno));
+ }
+ return 0;
+}
diff --git a/input/shmem.h b/input/shmem.h
new file mode 100644
index 0000000..d02da8d
--- /dev/null
+++ b/input/shmem.h
@@ -0,0 +1,5 @@
+// header file for shmem, part of cava.
+
+#pragma once
+
+void *input_shmem(void *data);
diff --git a/input/sndio.c b/input/sndio.c
new file mode 100644
index 0000000..5d13784
--- /dev/null
+++ b/input/sndio.c
@@ -0,0 +1,63 @@
+#include "input/sndio.h"
+#include "input/common.h"
+
+#include <sndio.h>
+
+void *input_sndio(void *data) {
+ struct audio_data *audio = (struct audio_data *)data;
+ struct sio_par par;
+ struct sio_hdl *hdl;
+ int16_t buf[256];
+ unsigned int channels;
+
+ sio_initpar(&par);
+ par.sig = 1;
+ par.bits = 16;
+ par.le = 1;
+ par.rate = 44100;
+ par.rchan = 2;
+ par.appbufsz = sizeof(buf) / par.rchan;
+
+ if ((hdl = sio_open(audio->source, SIO_REC, 0)) == NULL) {
+ fprintf(stderr, __FILE__ ": Could not open sndio source: %s\n", audio->source);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par) || par.sig != 1 || par.le != 1 ||
+ par.rate != 44100 || par.rchan != audio->channels) {
+ fprintf(stderr, __FILE__ ": Could not set required audio parameters\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (!sio_start(hdl)) {
+ fprintf(stderr, __FILE__ ": sio_start() failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ uint16_t frames = (sizeof(buf) / sizeof(buf[0])) / channels;
+ while (audio->terminate != 1) {
+ if (sio_read(hdl, buf, sizeof(buf)) == 0) {
+ fprintf(stderr, __FILE__ ": sio_read() failed: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ write_to_fftw_input_buffers(buf, frames, audio);
+ /*
+ for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i += 2) {
+ if (par.rchan == 1) {
+ // sndiod has already taken care of averaging the samples
+ audio->audio_out_l[n] = buf[i];
+ } else if (par.rchan == 2) {
+ audio->audio_out_l[n] = buf[i];
+ audio->audio_out_r[n] = buf[i + 1];
+ }
+ n = (n + 1) % audio->FFTbufferSize;
+ }
+ */
+ }
+
+ sio_stop(hdl);
+ sio_close(hdl);
+
+ return 0;
+}
diff --git a/input/sndio.h b/input/sndio.h
new file mode 100644
index 0000000..61801a5
--- /dev/null
+++ b/input/sndio.h
@@ -0,0 +1,5 @@
+// header file for sndio, part of cava.
+
+#pragma once
+
+void *input_sndio(void *data);