From d294dae6e0ec3188b5a6e64d5a11b34883223c94 Mon Sep 17 00:00:00 2001 From: Drahflow <drahflow@gmx.de> Date: Tue, 6 May 2014 14:52:05 +0200 Subject: [PATCH] Frequence analysis --- fastclient/Makefile | 3 + fastclient/snow.c | 1 + fastclient/spectrum.c | 211 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 fastclient/spectrum.c diff --git a/fastclient/Makefile b/fastclient/Makefile index 032ab9a..7c4c4bc 100644 --- a/fastclient/Makefile +++ b/fastclient/Makefile @@ -7,5 +7,8 @@ snow: snow.o client: client.o g++ -lzmq -o $@ $< +spectrum: spectrum.o + g++ -lzmq -lpthread -lasound -lfftw3 -o $@ $< + %.o: %.c g++ -W -Wall -Wextra -pedantic -std=c++11 -c -o $@ $< diff --git a/fastclient/snow.c b/fastclient/snow.c index 619bdfd..553ea68 100644 --- a/fastclient/snow.c +++ b/fastclient/snow.c @@ -90,5 +90,6 @@ int main (void) { zmq_close(requester); zmq_ctx_destroy(context); + return 0; } diff --git a/fastclient/spectrum.c b/fastclient/spectrum.c new file mode 100644 index 0000000..6b90577 --- /dev/null +++ b/fastclient/spectrum.c @@ -0,0 +1,211 @@ +/* Use the newer ALSA API */ +#define ALSA_PCM_NEW_HW_PARAMS_API + +#include <alsa/asoundlib.h> +#include <fftw3.h> +#include <zmq.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pthread.h> +#include <vector> +#include <math.h> + +#define FFTWSIZE 2048 +#define MINPOS 0 + +#define WIDTH 480 +#define HEIGHT 70 + +#define CMD_PIXEL 0 +#define CMD_BLIT 1 + +#define MAXPOS (FFTWSIZE / 8) + +struct msgBlit { + uint8_t cmd; + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; + volatile uint8_t data[0]; +} __attribute__ ((packed)); + +msgBlit *screen; + +void *blitScreen(void *) { + void *context = zmq_ctx_new (); + void *requester; + + requester = zmq_socket (context, ZMQ_REQ); + zmq_connect(requester, "tcp://mensadisplay:5556"); + // zmq_connect(requester, "tcp://192.168.178.147:5570"); + // zmq_connect(requester, "tcp://localhost:5556"); + + while(1) { + zmq_msg_t msg; + zmq_msg_init_size(&msg, sizeof(msgBlit) + WIDTH * HEIGHT); + + memcpy(zmq_msg_data(&msg), screen, sizeof(msgBlit) + WIDTH * HEIGHT); + zmq_msg_send(&msg, requester, ZMQ_SNDMORE); + + zmq_msg_init_size(&msg, 0); + zmq_msg_send(&msg, requester, 0); + zmq_recv(requester, NULL, 0, 0); + } + + zmq_close(requester); + zmq_ctx_destroy(context); + + return nullptr; +} + +int main() { + int rc; + int size; + snd_pcm_t *handle; + snd_pcm_hw_params_t *params; + unsigned int val; + int dir; + snd_pcm_uframes_t frames; + char *buffer; + + screen = reinterpret_cast<msgBlit *>(malloc(sizeof(msgBlit) + WIDTH * HEIGHT)); + screen->cmd = CMD_BLIT; + screen->x = 0; + screen->y = 0; + screen->w = WIDTH; + screen->h = HEIGHT; + + pthread_t blitter; + pthread_create(&blitter, nullptr, blitScreen, nullptr); + + fftw_complex *in, *out; + fftw_plan plan; + + in = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * FFTWSIZE); + out = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * FFTWSIZE); + plan = fftw_plan_dft_1d(FFTWSIZE, in, out, FFTW_FORWARD, FFTW_ESTIMATE); + + /* Open PCM device for recording (capture). */ + rc = snd_pcm_open(&handle, "hw:1,0", + SND_PCM_STREAM_CAPTURE, 0); + if (rc < 0) { + fprintf(stderr, + "unable to open pcm device: %s\n", + snd_strerror(rc)); + exit(1); + } + + /* Allocate a hardware parameters object. */ + snd_pcm_hw_params_alloca(¶ms); + + /* Fill it in with default values. */ + snd_pcm_hw_params_any(handle, params); + + /* Set the desired hardware parameters. */ + + /* Interleaved mode */ + snd_pcm_hw_params_set_access(handle, params, + SND_PCM_ACCESS_RW_INTERLEAVED); + + /* Signed 16-bit little-endian format */ + snd_pcm_hw_params_set_format(handle, params, + SND_PCM_FORMAT_S16_LE); + + /* Two channels (stereo) */ + snd_pcm_hw_params_set_channels(handle, params, 2); + + /* 44100 bits/second sampling rate (CD quality) */ + val = 44100; + snd_pcm_hw_params_set_rate_near(handle, params, + &val, &dir); + + /* Set period size to FFTWSIZE frames. */ + frames = FFTWSIZE; + snd_pcm_hw_params_set_period_size_near(handle, + params, &frames, &dir); + + /* Write the parameters to the driver */ + rc = snd_pcm_hw_params(handle, params); + if (rc < 0) { + fprintf(stderr, + "unable to set hw parameters: %s\n", + snd_strerror(rc)); + exit(1); + } + + /* Use a buffer large enough to hold one period */ + snd_pcm_hw_params_get_period_size(params, + &frames, &dir); + size = frames * 4; /* 2 bytes/sample, 2 channels */ + buffer = (char *) malloc(size); + +// /* We want to loop for 5 seconds */ +// snd_pcm_hw_params_get_period_time(params, +// &val, &dir); +// const long one_second = 1000000 / val; +// const long refresh = one_second / 30; + + double minVol[MAXPOS]; + double maxVol[MAXPOS]; + for(int i = 0; i < MAXPOS; ++i) { + minVol[i] = maxVol[i] = 0; + } + + while (1) { + rc = snd_pcm_readi(handle, buffer, frames); + if (rc == -EPIPE) { + /* EPIPE means overrun */ + fprintf(stderr, "overrun occurred\n"); + snd_pcm_prepare(handle); + continue; + } else if (rc < 0) { + fprintf(stderr, + "error from read: %s\n", + snd_strerror(rc)); + } else if (rc != (int)frames) { + fprintf(stderr, "short read, read %d frames\n", rc); + } else { + for(int pos = 0; pos < FFTWSIZE; ++pos) { + // printf("%d, %d, %d, %d\n", buffer[pos * 4], buffer[pos * 4 + 1], buffer[pos * 4 + 2], buffer[pos * 4 + 3]); + in[pos][0] = buffer[pos * 4 + 1]; + in[pos][1] = 0; + } + + fftw_execute(plan); + + for(int pos = 0; pos < MAXPOS; ++pos) { + double vol = 0; + for(int i = 0; i < 1; i++) { + vol += fabs(out[pos+i][0]) + fabs(out[pos+i][1]); + } + + if(vol < minVol[pos]) minVol[pos] = vol; + if(vol > maxVol[pos]) maxVol[pos] = vol; + + int level = log(1000 * (vol - minVol[pos]) / maxVol[pos]) * HEIGHT / 6.9; + + int xStart = pos * WIDTH / MAXPOS; + int xEnd = (pos + 1) * WIDTH / MAXPOS; + for(int x = xStart; x < xEnd; ++x) { + int yCross = std::min(HEIGHT, std::max(0, HEIGHT - level)); + + for(int y = 0; y < yCross; ++y) { + screen->data[y * WIDTH + x] = 0; + } + for(int y = yCross; y < HEIGHT; ++y) { + screen->data[y * WIDTH + x] = 1; + } + } + } + } + } + + snd_pcm_drain(handle); + snd_pcm_close(handle); + free(buffer); + + return 0; +} -- GitLab