andrewm@10: /*
andrewm@10:  * main.cpp
andrewm@10:  *
andrewm@10:  *  Created on: Oct 24, 2014
andrewm@10:  *      Author: parallels
andrewm@10:  */
andrewm@10: 
andrewm@10: #include <iostream>
andrewm@10: #include <cstdlib>
andrewm@10: #include <libgen.h>
andrewm@10: #include <signal.h>
andrewm@10: #include <getopt.h>
andrewm@22: #include <sndfile.h>
andrewm@56: #include <BeagleRT.h>
andrewm@10: 
andrewm@10: extern int gScreenFramesPerSecond;
andrewm@10: 
andrewm@22: float *gMusicBuffer = 0;
andrewm@22: int gMusicBufferLength = 0;
andrewm@22: float *gSoundBoomBuffer = 0;
andrewm@22: int gSoundBoomBufferLength = 0;
andrewm@22: 
andrewm@10: using namespace std;
andrewm@10: 
andrewm@22: // Load a sound sample from file
andrewm@22: int loadSoundFile(const string& path, float **buffer, int *bufferLength)
andrewm@22: {
andrewm@22: 	SNDFILE *sndfile ;
andrewm@22: 	SF_INFO sfinfo ;
andrewm@22: 
andrewm@22: 	if (!(sndfile = sf_open (path.c_str(), SFM_READ, &sfinfo))) {
andrewm@22: 		cout << "Couldn't open file " << path << endl;
andrewm@22: 		return 1;
andrewm@22: 	}
andrewm@22: 
andrewm@22: 	int numChan = sfinfo.channels;
andrewm@22: 	if(numChan != 1)
andrewm@22: 	{
andrewm@22: 		cout << "Error: " << path << " is not a mono file" << endl;
andrewm@22: 		return 1;
andrewm@22: 	}
andrewm@22: 
andrewm@22: 	*bufferLength = sfinfo.frames * numChan;
andrewm@22: 	*buffer = new float[*bufferLength];
andrewm@22: 	if(*buffer == 0){
andrewm@22: 		cout << "Could not allocate buffer" << endl;
andrewm@22: 		return 1;
andrewm@22: 	}
andrewm@22: 
andrewm@22: 	int subformat = sfinfo.format & SF_FORMAT_SUBMASK;
andrewm@22: 	int readcount = sf_read_float(sndfile, *buffer, *bufferLength);
andrewm@22: 
andrewm@22: 	// Pad with zeros in case we couldn't read whole file
andrewm@22: 	for(int k = readcount; k < *bufferLength; k++)
andrewm@22: 		(*buffer)[k] = 0;
andrewm@22: 
andrewm@22: 	sf_close(sndfile);
andrewm@22: 	return 0;
andrewm@22: }
andrewm@22: 
andrewm@10: // Handle Ctrl-C by requesting that the audio rendering stop
andrewm@10: void interrupt_handler(int var)
andrewm@10: {
andrewm@10: 	gShouldStop = true;
andrewm@10: }
andrewm@10: 
andrewm@10: // Print usage information
andrewm@10: void usage(const char * processName)
andrewm@10: {
andrewm@10: 	cerr << "Usage: " << processName << " [options]" << endl;
andrewm@10: 
andrewm@10: 	BeagleRT_usage();
andrewm@10: 
andrewm@10: 	cerr << "   --fps [-f] value:           Set target frames per second\n";
andrewm@10: 	cerr << "   --help [-h]:                Print this menu\n";
andrewm@10: }
andrewm@10: 
andrewm@10: int main(int argc, char *argv[])
andrewm@10: {
andrewm@56: 	BeagleRTInitSettings settings;	// Standard audio settings
andrewm@22: 	string musicFileName = "music.wav";
andrewm@22: 	string soundBoomFileName = "boom.wav";
andrewm@10: 
andrewm@10: 	struct option customOptions[] =
andrewm@10: 	{
andrewm@10: 		{"help", 0, NULL, 'h'},
andrewm@10: 		{"fps", 1, NULL, 'f'},
andrewm@10: 		{NULL, 0, NULL, 0}
andrewm@10: 	};
andrewm@10: 
andrewm@10: 	// Set default settings
andrewm@10: 	BeagleRT_defaultSettings(&settings);
andrewm@10: 
andrewm@10: 	// Parse command-line arguments
andrewm@10: 	while (1) {
andrewm@10: 		int c;
andrewm@10: 		if ((c = BeagleRT_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0)
andrewm@10: 				break;
andrewm@10: 		switch (c) {
andrewm@10: 		case 'f':
andrewm@10: 				gScreenFramesPerSecond = atoi(optarg);
andrewm@10: 				if(gScreenFramesPerSecond < 1)
andrewm@10: 					gScreenFramesPerSecond = 1;
andrewm@10: 				if(gScreenFramesPerSecond > 100)
andrewm@10: 					gScreenFramesPerSecond = 100;
andrewm@10: 				break;
andrewm@10: 		case 'h':
andrewm@10: 				usage(basename(argv[0]));
andrewm@10: 				exit(0);
andrewm@10: 		case '?':
andrewm@10: 		default:
andrewm@10: 				usage(basename(argv[0]));
andrewm@10: 				exit(1);
andrewm@10: 		}
andrewm@10: 	}
andrewm@10: 
andrewm@22: 	// Load the sound files
andrewm@22: 	if(loadSoundFile(musicFileName, &gMusicBuffer, &gMusicBufferLength) != 0) {
andrewm@22: 		cout << "Warning: unable to load sound file " << musicFileName << endl;
andrewm@22: 	}
andrewm@22: 	if(loadSoundFile(soundBoomFileName, &gSoundBoomBuffer, &gSoundBoomBufferLength) != 0) {
andrewm@22: 		cout << "Warning: unable to load sound file " << soundBoomFileName << endl;
andrewm@22: 	}
andrewm@22: 
andrewm@10: 	// Initialise the PRU audio device
andrewm@10: 	if(BeagleRT_initAudio(&settings, 0) != 0) {
andrewm@10: 		cout << "Error: unable to initialise audio" << endl;
andrewm@10: 		return -1;
andrewm@10: 	}
andrewm@10: 
andrewm@10: 	// Start the audio device running
andrewm@10: 	if(BeagleRT_startAudio()) {
andrewm@10: 		cout << "Error: unable to start real-time audio" << endl;
andrewm@10: 		return -1;
andrewm@10: 	}
andrewm@10: 
andrewm@15: 	// Set up interrupt handler to catch Control-C and SIGTERM
andrewm@10: 	signal(SIGINT, interrupt_handler);
andrewm@15: 	signal(SIGTERM, interrupt_handler);
andrewm@10: 
andrewm@10: 	// Run until told to stop
andrewm@10: 	while(!gShouldStop) {
andrewm@10: 		usleep(100000);
andrewm@10: 	}
andrewm@10: 
andrewm@10: 	// Stop the audio device
andrewm@10: 	BeagleRT_stopAudio();
andrewm@10: 
andrewm@10: 	// Clean up any resources allocated for audio
andrewm@10: 	BeagleRT_cleanupAudio();
andrewm@10: 
andrewm@22: 	// Release sound files
andrewm@22: 	if(gMusicBuffer != 0)
andrewm@22: 		free(gMusicBuffer);
andrewm@22: 	if(gSoundBoomBuffer != 0)
andrewm@22: 		free(gSoundBoomBuffer);
andrewm@22: 
andrewm@10: 	// All done!
andrewm@10: 	return 0;
andrewm@10: }