Skip to content

Instantly share code, notes, and snippets.

@Jacajack
Created January 9, 2019 00:19
Show Gist options
  • Save Jacajack/55231fb5abdd4d617743dc969eb14e01 to your computer and use it in GitHub Desktop.
Save Jacajack/55231fb5abdd4d617743dc969eb14e01 to your computer and use it in GitHub Desktop.
A utility to compute DFT of aplay data stream (WIP)
#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