Created
January 9, 2019 00:19
-
-
Save Jacajack/55231fb5abdd4d617743dc969eb14e01 to your computer and use it in GitHub Desktop.
A utility to compute DFT of aplay data stream (WIP)
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 <math.h> | |
#include <complex.h> | |
#include <argp.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <signal.h> | |
#include <assert.h> | |
enum dft_status | |
{ | |
REQUEST, // DFT is requested | |
PENDING, // DFT is pending (parent) | |
DONE, // DFT is done, wait for request | |
}; | |
// Global state and configuration | |
struct | |
{ | |
float sample_rate; | |
long sample_count; | |
enum dft_status dft_status; | |
} conf; | |
// Argp configuration | |
const char *argp_program_version = "apdft v0.1"; | |
const char *argp_program_bug_address = "<[email protected]>"; | |
char argp_doc[] = "apdft - A utility to compute DFT of data streamed to aplay."; | |
char argp_keydoc[] = ""; | |
struct argp_option argp_options[] = | |
{ | |
{ "rate", 'r', "FREQUENCY", 0, "Sampling frequency" }, | |
{ "count", 'c', "COUNT", 0, "Number of samples to process" }, | |
{ 0 } | |
}; | |
// Argp callback - affects global `conf` struct | |
error_t argp_parse_opt( int key, char *arg, struct argp_state *state ) | |
{ | |
switch ( key ) | |
{ | |
// Sampling rate | |
case 'r': | |
sscanf( arg, "%f", &conf.sample_rate ); | |
break; | |
// Sample count | |
case 'c': | |
sscanf( arg, "%ld", &conf.sample_count ); | |
break; | |
default: | |
return ARGP_ERR_UNKNOWN; | |
} | |
return 0; | |
} | |
// Computations on child side | |
void child_compute( double *data, int outfd ) | |
{ | |
write( outfd, "asdf", 5 ); | |
fprintf( stderr, "hohohoho\n" ); | |
fflush( stderr ); | |
// Close pipe | |
if ( close( outfd ) == -1 ) | |
{ | |
fprintf( stderr, "child: close() failed - %s\n", strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
// Successful exit | |
exit( EXIT_SUCCESS ); | |
} | |
// Retrieve and present DFT result from the child | |
void retrieve_dft_result( int fd ) | |
{ | |
} | |
// SIGINT handler | |
void sigint_handler( int signum ) | |
{ | |
if ( conf.dft_status == DONE ) conf.dft_status = REQUEST; | |
signal( SIGINT, sigint_handler ); | |
} | |
int main( int argc, char **argv ) | |
{ | |
static struct argp argp = {argp_options, argp_parse_opt, argp_keydoc, argp_doc }; | |
argp_parse( &argp, argc, argv, 0, 0, NULL ); | |
// Signal handling | |
signal( SIGINT, sigint_handler ); | |
// Default configuration | |
conf.sample_rate = 8000; | |
conf.sample_count = 1024; | |
conf.dft_status = REQUEST; | |
// Allocate buffer | |
double *buffer = malloc( conf.sample_count * sizeof( double ) ); | |
if ( buffer == NULL ) | |
{ | |
fprintf( stderr, "%s: malloc() failed - %s\n", argv[0], strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
// Buffer write pointer | |
double *buffer_wp = buffer; | |
// Child process PID | |
pid_t pid; | |
int pipefd[2]; // 0 - parent, 1 - child | |
// Main data pass-through loop | |
int b; | |
while ( ( b = getchar( ) ) != EOF ) | |
{ | |
// Write normalized data | |
*buffer_wp++ = b / 255.0; | |
// Reset write pointer and check if there's DFT request | |
if ( buffer_wp == buffer + conf.sample_count ) | |
{ | |
buffer_wp = buffer; | |
// DFT requested | |
if ( conf.dft_status == REQUEST ) | |
{ | |
// Create pipe for communication | |
if ( pipe( pipefd ) == -1 ) | |
{ | |
fprintf( stderr, "%s: pipe() failed - %s\n", argv[0], strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
fprintf( stderr, "fork()\n" ); | |
pid = fork( ); | |
if ( pid == -1 ) // fork() failed | |
{ | |
fprintf( stderr, "%s: fork() failed - %s\n", argv[0], strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
else if ( pid == 0 ) // The child | |
{ | |
child_compute( buffer, pipefd[1] ); | |
} | |
else // The parent | |
{ | |
conf.dft_status = PENDING; | |
} | |
} | |
} | |
// If DFT is pending, check if child has terminated | |
if ( conf.dft_status == PENDING ) | |
{ | |
int status; | |
if ( waitpid( pid, &status, WNOHANG ) == -1 ) | |
{ | |
fprintf( stderr, "%s: waitpid() failed - %s\n", argv[0], strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
// Upon child termination | |
if ( WIFEXITED( status ) && WEXITSTATUS( status ) == 0 ) | |
{ | |
char buf[100]; | |
int ec = read( pipefd[0], buf, 100 ); | |
if ( ec == -1 ) | |
{ | |
fprintf( stderr, "%s: close() failed - %s\n", argv[0], strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
buf[ec] = 0; | |
fprintf( stderr, "DFT DONE %s\n", buf ); | |
fflush( stderr ); | |
// Reset PID and close file descriptors | |
pid = -1; | |
if ( close( pipefd[0] ) == -1 ) | |
{ | |
fprintf( stderr, "%s: close() failed - %s\n", argv[0], strerror( errno ) ); | |
exit( EXIT_FAILURE ); | |
} | |
conf.dft_status = DONE; | |
} | |
} | |
} | |
free( buffer ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment