diff options
Diffstat (limited to 'input')
-rw-r--r-- | input/alsa.c | 165 | ||||
-rw-r--r-- | input/alsa.h | 5 | ||||
-rw-r--r-- | input/common.c | 53 | ||||
-rw-r--r-- | input/common.h | 36 | ||||
-rw-r--r-- | input/fifo.c | 79 | ||||
-rw-r--r-- | input/fifo.h | 5 | ||||
-rw-r--r-- | input/portaudio.c | 204 | ||||
-rw-r--r-- | input/portaudio.h | 3 | ||||
-rw-r--r-- | input/pulse.c | 142 | ||||
-rw-r--r-- | input/pulse.h | 6 | ||||
-rw-r--r-- | input/shmem.c | 82 | ||||
-rw-r--r-- | input/shmem.h | 5 | ||||
-rw-r--r-- | input/sndio.c | 63 | ||||
-rw-r--r-- | input/sndio.h | 5 |
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(¶ms); // 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); |