| giuliomoro@250 | 1 /* | 
| giuliomoro@250 | 2  * main.cpp | 
| giuliomoro@250 | 3  * | 
| giuliomoro@250 | 4  *  Created on: Oct 24, 2014 | 
| giuliomoro@250 | 5  *      Author: parallels | 
| giuliomoro@250 | 6  */ | 
| giuliomoro@250 | 7 | 
| giuliomoro@250 | 8 #include <iostream> | 
| giuliomoro@250 | 9 #include <cstdlib> | 
| giuliomoro@250 | 10 #include <cstdio> | 
| giuliomoro@250 | 11 #include <libgen.h> | 
| giuliomoro@250 | 12 #include <signal.h> | 
| giuliomoro@250 | 13 #include <getopt.h> | 
| giuliomoro@250 | 14 #include <unistd.h> | 
| giuliomoro@250 | 15 #include <sys/time.h> | 
| giuliomoro@250 | 16 #include <sndfile.h>				// to load audio files | 
| giuliomoro@250 | 17 #include "SampleData.h" | 
| giuliomoro@301 | 18 #include <Bela.h> | 
| giuliomoro@250 | 19 | 
| giuliomoro@250 | 20 using namespace std; | 
| giuliomoro@250 | 21 | 
| giuliomoro@250 | 22 // Global variables used by getCurrentTime() | 
| giuliomoro@250 | 23 unsigned long long gFirstSeconds, gFirstMicroseconds; | 
| giuliomoro@250 | 24 | 
| giuliomoro@250 | 25 // Load samples from file | 
| giuliomoro@250 | 26 int initFile(string file, SampleData *smp)//float *& smp) | 
| giuliomoro@250 | 27 { | 
| giuliomoro@250 | 28   	SNDFILE *sndfile ; | 
| giuliomoro@250 | 29 	SF_INFO sfinfo ; | 
| giuliomoro@250 | 30 | 
| giuliomoro@250 | 31 	if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { | 
| giuliomoro@250 | 32 		cout << "Couldn't open file " << file << endl; | 
| giuliomoro@250 | 33 		return 1; | 
| giuliomoro@250 | 34 	} | 
| giuliomoro@250 | 35 | 
| giuliomoro@250 | 36 	int numChan = sfinfo.channels; | 
| giuliomoro@250 | 37 	if(numChan != 1) | 
| giuliomoro@250 | 38 	{ | 
| giuliomoro@250 | 39 		cout << "Error: " << file << " is not a mono file" << endl; | 
| giuliomoro@250 | 40 		return 1; | 
| giuliomoro@250 | 41 	} | 
| giuliomoro@250 | 42 | 
| giuliomoro@250 | 43 	smp->sampleLen = sfinfo.frames * numChan; | 
| giuliomoro@250 | 44 	smp->samples = new float[smp->sampleLen]; | 
| giuliomoro@250 | 45 	if(smp == NULL){ | 
| giuliomoro@250 | 46 		cout << "Could not allocate buffer" << endl; | 
| giuliomoro@250 | 47 		return 1; | 
| giuliomoro@250 | 48 	} | 
| giuliomoro@250 | 49 | 
| giuliomoro@250 | 50 	int subformat = sfinfo.format & SF_FORMAT_SUBMASK; | 
| giuliomoro@250 | 51 	int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); | 
| giuliomoro@250 | 52 | 
| giuliomoro@250 | 53 	// Pad with zeros in case we couldn't read whole file | 
| giuliomoro@250 | 54 	for(int k = readcount; k <smp->sampleLen; k++) | 
| giuliomoro@250 | 55 		smp->samples[k] = 0; | 
| giuliomoro@250 | 56 | 
| giuliomoro@250 | 57 	if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { | 
| giuliomoro@250 | 58 		double	scale ; | 
| giuliomoro@250 | 59 		int 	m ; | 
| giuliomoro@250 | 60 | 
| giuliomoro@250 | 61 		sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; | 
| giuliomoro@250 | 62 		if (scale < 1e-10) | 
| giuliomoro@250 | 63 			scale = 1.0 ; | 
| giuliomoro@250 | 64 		else | 
| giuliomoro@250 | 65 			scale = 32700.0 / scale ; | 
| giuliomoro@250 | 66 		cout << "File samples scale = " << scale << endl; | 
| giuliomoro@250 | 67 | 
| giuliomoro@250 | 68 		for (m = 0; m < smp->sampleLen; m++) | 
| giuliomoro@250 | 69 			smp->samples[m] *= scale; | 
| giuliomoro@250 | 70 	} | 
| giuliomoro@250 | 71 | 
| giuliomoro@250 | 72 	sf_close(sndfile); | 
| giuliomoro@250 | 73 | 
| giuliomoro@250 | 74 	return 0; | 
| giuliomoro@250 | 75 } | 
| giuliomoro@250 | 76 | 
| giuliomoro@250 | 77 | 
| giuliomoro@250 | 78 // Handle Ctrl-C by requesting that the audio rendering stop | 
| giuliomoro@250 | 79 void interrupt_handler(int var) | 
| giuliomoro@250 | 80 { | 
| giuliomoro@250 | 81 	gShouldStop = true; | 
| giuliomoro@250 | 82 } | 
| giuliomoro@250 | 83 | 
| giuliomoro@250 | 84 // Print usage information | 
| giuliomoro@250 | 85 void usage(const char * processName) | 
| giuliomoro@250 | 86 { | 
| giuliomoro@250 | 87 	cerr << "Usage: " << processName << " [options]" << endl; | 
| giuliomoro@250 | 88 | 
| giuliomoro@301 | 89 	Bela_usage(); | 
| giuliomoro@250 | 90 | 
| giuliomoro@250 | 91 	cerr << "   --help [-h]:                Print this menu\n"; | 
| giuliomoro@250 | 92 } | 
| giuliomoro@250 | 93 | 
| giuliomoro@250 | 94 /* Function which returns the time since start of the program | 
| giuliomoro@250 | 95  * in (fractional) seconds. | 
| giuliomoro@250 | 96  */ | 
| giuliomoro@250 | 97 double getCurrentTime(void) { | 
| giuliomoro@250 | 98 	unsigned long long result; | 
| giuliomoro@250 | 99 	struct timeval tv; | 
| giuliomoro@250 | 100 | 
| giuliomoro@250 | 101 	gettimeofday(&tv, NULL); | 
| giuliomoro@250 | 102 	result = (tv.tv_sec - gFirstSeconds) * 1000000ULL + (tv.tv_usec - gFirstMicroseconds); | 
| giuliomoro@250 | 103 	return (double)result / 1000000.0; | 
| giuliomoro@250 | 104 } | 
| giuliomoro@250 | 105 extern SampleData gSampleData; | 
| giuliomoro@250 | 106 int main(int argc, char *argv[]) | 
| giuliomoro@250 | 107 { | 
| giuliomoro@301 | 108 	BelaInitSettings settings;	// Standard audio settings | 
| giuliomoro@250 | 109 	struct timeval tv; | 
| giuliomoro@250 | 110 	string fileName;			// Name of the sample to load | 
| giuliomoro@250 | 111 | 
| giuliomoro@250 | 112 	struct option customOptions[] = | 
| giuliomoro@250 | 113 	{ | 
| giuliomoro@250 | 114 		{"help", 0, NULL, 'h'}, | 
| giuliomoro@250 | 115 		{"file", 1, NULL, 'f'}, | 
| giuliomoro@250 | 116 		{NULL, 0, NULL, 0} | 
| giuliomoro@250 | 117 	}; | 
| giuliomoro@250 | 118 | 
| giuliomoro@250 | 119 	gSampleData.samples = 0; | 
| giuliomoro@250 | 120 	gSampleData.sampleLen = -1; | 
| giuliomoro@250 | 121 | 
| giuliomoro@250 | 122 	// Set default settings | 
| giuliomoro@301 | 123 	Bela_defaultSettings(&settings); | 
| giuliomoro@250 | 124 | 
| giuliomoro@250 | 125 	settings.periodSize = 32; // Larger period size by default, for testing | 
| giuliomoro@250 | 126 | 
| giuliomoro@250 | 127 	// Parse command-line arguments | 
| giuliomoro@250 | 128 	while (1) { | 
| giuliomoro@250 | 129 		int c; | 
| giuliomoro@301 | 130 		if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) | 
| giuliomoro@250 | 131 				break; | 
| giuliomoro@250 | 132 		switch (c) { | 
| giuliomoro@250 | 133 		case 'h': | 
| giuliomoro@250 | 134 				usage(basename(argv[0])); | 
| giuliomoro@250 | 135 				exit(0); | 
| giuliomoro@250 | 136 		case 'f': | 
| giuliomoro@250 | 137 				fileName = string((char *)optarg); | 
| giuliomoro@250 | 138 				break; | 
| giuliomoro@250 | 139 		case '?': | 
| giuliomoro@250 | 140 		default: | 
| giuliomoro@250 | 141 				usage(basename(argv[0])); | 
| giuliomoro@250 | 142 				exit(1); | 
| giuliomoro@250 | 143 		} | 
| giuliomoro@250 | 144 	} | 
| giuliomoro@250 | 145 | 
| giuliomoro@250 | 146 	if(fileName.empty()){ | 
| giuliomoro@250 | 147 		fileName = "sample.wav"; | 
| giuliomoro@250 | 148 	} | 
| giuliomoro@250 | 149 | 
| giuliomoro@250 | 150 | 
| giuliomoro@250 | 151 	// Load file | 
| giuliomoro@250 | 152 	if(initFile(fileName, &gSampleData) != 0) | 
| giuliomoro@250 | 153 	{ | 
| giuliomoro@250 | 154 		cout << "Error: unable to load samples " << endl; | 
| giuliomoro@250 | 155 		return -1; | 
| giuliomoro@250 | 156 	} | 
| giuliomoro@250 | 157 | 
| giuliomoro@250 | 158 	if(settings.verbose) | 
| giuliomoro@250 | 159 		cout << "File contains " << gSampleData.sampleLen << " samples" << endl; | 
| giuliomoro@250 | 160 | 
| giuliomoro@250 | 161 | 
| giuliomoro@250 | 162 	// Initialise the PRU audio device | 
| giuliomoro@301 | 163 	if(Bela_initAudio(&settings, &gSampleData) != 0) { | 
| giuliomoro@250 | 164 		cout << "Error: unable to initialise audio" << endl; | 
| giuliomoro@250 | 165 		return -1; | 
| giuliomoro@250 | 166 	} | 
| giuliomoro@250 | 167 | 
| giuliomoro@250 | 168 	// Initialise time | 
| giuliomoro@250 | 169 	gettimeofday(&tv, NULL); | 
| giuliomoro@250 | 170 	gFirstSeconds = tv.tv_sec; | 
| giuliomoro@250 | 171 	gFirstMicroseconds = tv.tv_usec; | 
| giuliomoro@250 | 172 | 
| giuliomoro@250 | 173 	// Start the audio device running | 
| giuliomoro@301 | 174 	if(Bela_startAudio()) { | 
| giuliomoro@250 | 175 		cout << "Error: unable to start real-time audio" << endl; | 
| giuliomoro@250 | 176 		return -1; | 
| giuliomoro@250 | 177 	} | 
| giuliomoro@250 | 178 | 
| giuliomoro@250 | 179 	// Set up interrupt handler to catch Control-C | 
| giuliomoro@250 | 180 	signal(SIGINT, interrupt_handler); | 
| giuliomoro@250 | 181 	signal(SIGTERM, interrupt_handler); | 
| giuliomoro@250 | 182 | 
| giuliomoro@250 | 183 	// Run until told to stop | 
| giuliomoro@250 | 184 	while(!gShouldStop) { | 
| giuliomoro@250 | 185 		usleep(100000); | 
| giuliomoro@250 | 186 	} | 
| giuliomoro@250 | 187 | 
| giuliomoro@250 | 188 	// Stop the audio device | 
| giuliomoro@301 | 189 	Bela_stopAudio(); | 
| giuliomoro@250 | 190 | 
| giuliomoro@250 | 191 	// Clean up any resources allocated for audio | 
| giuliomoro@301 | 192 	Bela_cleanupAudio(); | 
| giuliomoro@250 | 193 | 
| giuliomoro@250 | 194 	// All done! | 
| giuliomoro@250 | 195 	return 0; | 
| giuliomoro@250 | 196 } |