Last active
April 26, 2023 19:07
-
-
Save xsbee/98fb7be0d47b6588c3f0e7ada11a7ad3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <inttypes.h> | |
#include <cairo.h> | |
/** | |
* Loads single channel 32-bit little-endian single precision | |
* floating point PCM data. | |
*/ | |
static void | |
load_f32le (uint8_t *block, float *pcm, int num) | |
{ | |
int i; | |
union { | |
uint32_t z; | |
float f; | |
} s; | |
uint8_t *seq; | |
for (i = 0; i < num; ++i) | |
{ | |
seq = block + sizeof(float) * i; | |
s.z = (int)seq[0] | | |
(int)seq[1] << 8 | | |
(int)seq[2] << 16 | | |
(int)seq[3] << 24; | |
pcm[i] = s.f; | |
} | |
} | |
static int | |
push_into_sliding_win (float *window, int winsz, float* buf, int bufsz) | |
{ | |
if (winsz < bufsz) | |
return -1; | |
int winoff = winsz - bufsz; | |
memmove (window, window + bufsz, winoff * sizeof(float)); | |
memcpy (window + winoff, buf, bufsz * sizeof(float)); | |
return 0; | |
} | |
static size_t | |
dump_cairo_argb_data (FILE* out, unsigned char* data, int width, int height, int stride) | |
{ | |
int j; | |
size_t written = 0; | |
for (j = 0; j < height; ++j) | |
written += fwrite (data + j*stride, 4, width, out); | |
return written; | |
} | |
int main (int argc, char **argv) | |
{ | |
/* These values are placeholders. */ | |
const double xstep = 2.0 / (float)WV_WINSZ; | |
/* No need for double buffering. */ | |
setbuf (stdout, NULL); | |
setbuf (stdin, NULL); | |
uint8_t *block = NULL; | |
unsigned char *frame; | |
size_t blocksz; | |
float *pcm = NULL, *window = NULL; | |
int pcmsz, i, stride; | |
double x; | |
cairo_surface_t *surface = NULL; | |
cairo_status_t status; | |
cairo_t *cr = NULL; | |
blocksz = WV_NSAMPLES * sizeof(float); | |
block = malloc (blocksz); | |
if (!block) | |
goto cleanup; | |
pcm = malloc (blocksz); | |
if (!pcm) | |
goto cleanup; | |
window = calloc (WV_WINSZ, sizeof(float)); | |
if (!window) | |
goto cleanup; | |
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, WV_WIDTH); | |
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WV_WIDTH, WV_HEIGHT); | |
status = cairo_surface_status (surface); | |
if (status == CAIRO_STATUS_NO_MEMORY) | |
goto cleanup; | |
cr = cairo_create (surface); | |
status = cairo_status (cr); | |
if (status == CAIRO_STATUS_NO_MEMORY) | |
goto cleanup; | |
cairo_set_line_width (cr, WV_LINE_WIDTH); | |
cairo_scale (cr, WV_WIDTH / 2.0, WV_HEIGHT / 2.0); | |
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); | |
for (;;) | |
{ | |
pcmsz = fread (block, sizeof (float), WV_NSAMPLES, stdin); | |
if (pcmsz == 0) | |
break; | |
load_f32le (block, pcm, pcmsz); | |
push_into_sliding_win (window, WV_WINSZ, pcm, pcmsz); | |
// TODO fill with zero samples if required at end | |
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); | |
cairo_paint (cr); | |
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); | |
cairo_move_to (cr, 0, 1 - window[0]); | |
x = xstep; | |
for (i = 1; i < WV_WINSZ; ++i) | |
{ | |
cairo_line_to (cr, x, 1 - window[i]); | |
x += xstep; | |
} | |
cairo_stroke (cr); | |
cairo_surface_flush (surface); | |
frame = cairo_image_surface_get_data (surface); | |
dump_cairo_argb_data (stdout, frame, WV_WIDTH, WV_HEIGHT, stride); | |
} | |
cleanup: | |
if (window) | |
free (window); | |
if (pcm) | |
free (pcm); | |
if (block) | |
free (block); | |
if (cr) | |
cairo_destroy (cr); | |
if (surface) | |
cairo_surface_finish (surface); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment