annotate projects/d-box/main.cpp @ 151:e9c9404e3d1f ClockSync

Pff partially working. No PID. When setting the audio clock on the bbb to 44098 the master and slave clock keep diverging instead of converging ...
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 22 Sep 2015 04:10:07 +0100
parents 59edd5780fef
children
rev   line source
andrewm@0 1 /*
andrewm@0 2 * RTAudio.cpp
andrewm@0 3 *
andrewm@0 4 * Central control code for hard real-time audio on BeagleBone Black
andrewm@0 5 * using PRU and Xenomai Linux extensions. This code began as part
andrewm@0 6 * of the Hackable Instruments project (EPSRC) at Queen Mary University
andrewm@0 7 * of London, 2013-14.
andrewm@0 8 *
andrewm@0 9 * (c) 2014 Victor Zappi and Andrew McPherson
andrewm@0 10 * Queen Mary University of London
andrewm@0 11 */
andrewm@0 12
andrewm@0 13
andrewm@0 14 #include <stdio.h>
andrewm@0 15 #include <stdlib.h>
andrewm@0 16 #include <string.h>
andrewm@0 17 #include <strings.h>
andrewm@0 18 #include <math.h>
andrewm@0 19 #include <iostream>
andrewm@0 20 #include <signal.h> // interrupt handler
andrewm@0 21 #include <assert.h>
andrewm@0 22 #include <vector>
andrewm@0 23 #include <dirent.h> // to handle files in dirs
andrewm@0 24 #include <mntent.h> // to check if device is mounted
andrewm@0 25 #include <sys/mount.h> // mount()
andrewm@0 26 #include <sys/time.h> // elapsed time
andrewm@0 27 #include <NE10.h> // neon library
andrewm@0 28
andrewm@0 29 // thread priority
andrewm@0 30 #include <pthread.h>
andrewm@0 31 #include <sched.h>
andrewm@0 32
andrewm@0 33 // get_opt_long
andrewm@0 34 #include <getopt.h>
andrewm@0 35
andrewm@56 36 #include <BeagleRT.h>
andrewm@0 37 #include "config.h"
andrewm@0 38 #include "sensors.h"
andrewm@0 39 #include "OscillatorBank.h"
andrewm@0 40 #include "StatusLED.h"
andrewm@0 41 #include "logger.h"
andrewm@0 42
andrewm@0 43 using namespace std;
andrewm@0 44
andrewm@0 45 //----------------------------------------
andrewm@0 46 // main variables
andrewm@0 47 //----------------------------------------
andrewm@0 48 vector<OscillatorBank*> gOscBanks;
andrewm@0 49 int gCurrentOscBank = 0;
andrewm@0 50 int gNextOscBank = 0;
andrewm@0 51 int oscBnkOversampling = 1; // oscillator bank frame oversampling
andrewm@0 52
andrewm@0 53 const int kStatusLEDPin = 30; // P9-11 controls status LED
andrewm@0 54 StatusLED gStatusLED;
andrewm@0 55
andrewm@0 56 pthread_t keyboardThread;
andrewm@0 57 pthread_t logThread;
andrewm@0 58
andrewm@0 59 // general settings
andrewm@0 60 int gVerbose = 0; // verbose flag
andrewm@0 61 bool forceKeyboard = true; // activate/deactivate keyboard control
andrewm@0 62 bool forceSensors = false; // activate/deactivate sensor control
andrewm@0 63 bool forceLog = true; // activate/deactivate log on boot partition
andrewm@0 64 bool useSD = true; // activate/deactivate file loading from SD [as opposed to emmc]
andrewm@0 65 bool useAudioTest = false; // activate/deactivate sensors and test audio only
andrewm@0 66
andrewm@0 67 // audio settings
andrewm@0 68 unsigned int gPeriodSize = 8; // period size for audio
andrewm@0 69 char* gPartialFilename = 0; // name of the partials file to load
andrewm@0 70 bool gAudioIn = false; // stereo audio in status
andrewm@0 71
andrewm@0 72 int touchSensor0Address = 0x0C; // I2C addresses of touch sensors
andrewm@0 73 int touchSensor1Address = 0x0B;
andrewm@15 74 int sensorType = 0;
andrewm@0 75
andrewm@0 76 char sdPath[256] = "/dev/mmcblk0p2"; // system path of the SD, partition 2
andrewm@0 77 char mountPath[256] = "/root/d-box/usersounds"; // mount point of SD partition 2 [where user files are]
andrewm@0 78 char gUserDirName[256] = "usersounds"; // Directory in which user analysis files can be found [dir of mountPath]
andrewm@68 79 char gDefaultDirName[256] = "/root/d-box/sounds"; // Directory in which built in analysis files can be found
andrewm@0 80 char *gDirName;
andrewm@0 81 bool gIsLoading = false;
andrewm@0 82 int fileCnt = 0;
andrewm@0 83 std::vector <std::string> files;
andrewm@0 84
andrewm@0 85 char gId = 'f'; // from 0 to 14, hexadecimal [0-d]! f means not set
andrewm@0 86 char gGroup = '2'; // 0 is no info, 1 info. 2 is not set
andrewm@0 87
andrewm@0 88 // audio in filter
andrewm@0 89 extern ne10_float32_t *filterState[2];
andrewm@0 90 extern ne10_float32_t *filterIn[2];
andrewm@0 91 extern ne10_float32_t *filterOut[2];
andrewm@0 92
andrewm@0 93 struct arg_data
andrewm@0 94 {
andrewm@0 95 int argc;
andrewm@0 96 char **argv;
andrewm@0 97 };
andrewm@0 98
andrewm@0 99 arg_data args;
andrewm@0 100
andrewm@0 101
andrewm@0 102 int readFiles()
andrewm@0 103 {
andrewm@0 104 if(useSD)
andrewm@0 105 gDirName = gUserDirName;
andrewm@0 106 else
andrewm@0 107 gDirName = gDefaultDirName;
andrewm@0 108 DIR *dir;
andrewm@0 109 struct dirent *ent;
andrewm@0 110
andrewm@0 111 // From http://stackoverflow.com/questions/612097/how-can-i-get-a-list-of-files-in-a-directory-using-c-or-c
andrewm@0 112 if ((dir = opendir (gDirName)) != NULL) {
andrewm@0 113 /* print all the files and directories within directory */
andrewm@0 114 while ((ent = readdir (dir)) != NULL) {
andrewm@0 115 // Ignore dotfiles and . and .. paths
andrewm@0 116 if(!strncmp(ent->d_name, ".", 1))
andrewm@0 117 continue;
andrewm@0 118
andrewm@0 119 //dbox_printf("%s\n", ent->d_name);
andrewm@0 120
andrewm@0 121 // take only .dbx and .txt files
andrewm@0 122 string name = string(ent->d_name);
andrewm@0 123 int len = name.length();
andrewm@0 124
andrewm@0 125 bool dboxFile = false;
andrewm@0 126
andrewm@0 127 if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') )
andrewm@0 128 dboxFile = true;
andrewm@0 129 if( (name[len-4]=='.') && (name[len-3]=='t') && (name[len-2]=='x') && (name[len-1]=='t') )
andrewm@0 130 dboxFile = true;
andrewm@0 131
andrewm@0 132 if(dboxFile)
andrewm@0 133 {
andrewm@0 134 fileCnt++;
andrewm@0 135 //dbox_printf("%s\n", ent->d_name);
andrewm@0 136 files.push_back( std::string( ent->d_name ) );
andrewm@0 137 }
andrewm@0 138 }
andrewm@0 139 closedir (dir);
andrewm@0 140 } else {
andrewm@0 141 /* could not open directory */
andrewm@0 142 printf("Could not open directory %s\n", gDirName);
andrewm@0 143 return 1;
andrewm@0 144 }
andrewm@0 145
andrewm@0 146 // order by name
andrewm@0 147 std::sort( files.begin(), files.end() );
andrewm@0 148
andrewm@0 149 if(fileCnt==0)
andrewm@0 150 {
andrewm@0 151 printf("No .dbx or .txt files in %s!\n", gDirName);
andrewm@0 152 return 1;
andrewm@0 153 }
andrewm@0 154
andrewm@0 155 return 0;
andrewm@0 156 }
andrewm@0 157
andrewm@0 158 /* Load sounds from the directory */
andrewm@0 159 void loadAudioFiles(bool loadFirstFile)
andrewm@0 160 {
andrewm@0 161 char fullFileName[256];
andrewm@0 162
andrewm@0 163 if(loadFirstFile) {
andrewm@0 164 strcpy(fullFileName, gDirName);
andrewm@0 165 strcat(fullFileName, "/");
andrewm@0 166 strncat(fullFileName, files[0].c_str(), 255 - strlen(gDirName));
andrewm@0 167 dbox_printf("Loading first file %s...\n", fullFileName);
andrewm@0 168 OscillatorBank *bank = new OscillatorBank(fullFileName);
andrewm@0 169 if(bank->initBank(oscBnkOversampling)) {
andrewm@0 170 bank->setLoopHops(100, bank->getLastHop());
andrewm@0 171 gOscBanks.push_back(bank);
andrewm@0 172 }
andrewm@0 173 }
andrewm@0 174
andrewm@0 175 else {
andrewm@0 176 for(int i=1; i<fileCnt; i++){
andrewm@0 177 strcpy(fullFileName, gDirName);
andrewm@0 178 strcat(fullFileName, "/");
andrewm@0 179 strncat(fullFileName, files[i].c_str(), 255 - strlen(gDirName));
andrewm@0 180 dbox_printf("Loading file %s...\n", fullFileName);
andrewm@0 181 OscillatorBank *bank = new OscillatorBank(fullFileName);
andrewm@0 182 if(bank->initBank(oscBnkOversampling)) {
andrewm@0 183 bank->setLoopHops(100, bank->getLastHop());
andrewm@0 184 gOscBanks.push_back(bank);
andrewm@0 185 }
andrewm@0 186 }
andrewm@0 187 }
andrewm@0 188 }
andrewm@0 189
andrewm@0 190 // adapted from http://program-nix.blogspot.co.uk/2008/08/c-language-check-filesystem-is-mounted.html
andrewm@0 191 int checkIfMounted (char * dev_path)
andrewm@0 192 {
andrewm@0 193 FILE * mtab = NULL;
andrewm@0 194 struct mntent * part = NULL;
andrewm@0 195 int is_mounted = 0;
andrewm@0 196
andrewm@0 197 if ( ( mtab = setmntent ("/etc/mtab", "r") ) != NULL)
andrewm@0 198 {
andrewm@0 199 while ( ( part = getmntent ( mtab) ) != NULL)
andrewm@0 200 {
andrewm@0 201 if ( ( part->mnt_fsname != NULL ) && ( strcmp ( part->mnt_fsname, dev_path ) ) == 0 )
andrewm@0 202 is_mounted = 1;
andrewm@0 203 }
andrewm@0 204 endmntent(mtab);
andrewm@0 205 }
andrewm@0 206 return is_mounted;
andrewm@0 207 }
andrewm@0 208
andrewm@0 209 int mountSDuserPartition()
andrewm@0 210 {
andrewm@0 211 if(checkIfMounted(sdPath))
andrewm@0 212 {
andrewm@0 213 printf("device %s already mounted, fair enough, let's move on\n", sdPath);
andrewm@0 214 return 0;
andrewm@0 215 }
andrewm@0 216 // if mount rootfs from SD [rootfs eMMC not used] or from eMMC via properly formatted SD [SD rootfs used as storage volume]
andrewm@0 217 // we always use rootfs on SD as storage volume ----> "/dev/mmcblk0p2"
andrewm@0 218 int ret = mount(sdPath, "/root/d-box/usersounds", "vfat", 0, NULL);
andrewm@0 219 if (ret!=0)
andrewm@0 220 {
andrewm@0 221 printf("Error in mount...%s\n", strerror(ret));
andrewm@0 222 return 1;
andrewm@0 223 }
andrewm@0 224 return 0;
andrewm@0 225 }
andrewm@0 226
andrewm@0 227 int initSoundFiles()
andrewm@0 228 {
andrewm@0 229 if(gVerbose==1)
andrewm@0 230 cout << "---------------->Init Audio Thread" << endl;
andrewm@0 231
andrewm@0 232 if(useSD)
andrewm@0 233 {
andrewm@0 234 // mount the SD partition where user sounds are located
andrewm@0 235 // [this is p2, p1 is already mounted and we will log data there]
andrewm@0 236 if(mountSDuserPartition()!=0)
andrewm@0 237 return -1;
andrewm@0 238 }
andrewm@0 239
andrewm@0 240 gIsLoading = true;
andrewm@0 241
andrewm@0 242 // read files from SD and order them alphabetically
andrewm@0 243 if(readFiles()!=0)
andrewm@0 244 return 1;
andrewm@0 245
andrewm@0 246 // load first file into oscBank
andrewm@0 247 loadAudioFiles(true);
andrewm@0 248
andrewm@0 249 return 0;
andrewm@0 250 }
andrewm@0 251
andrewm@0 252 //---------------------------------------------------------------------------------------------------------
andrewm@0 253
andrewm@0 254 // Handle Ctrl-C
andrewm@0 255 void interrupt_handler(int var)
andrewm@0 256 {
andrewm@0 257 // kill keyboard thread mercilessly
andrewm@0 258 if(forceKeyboard)
andrewm@0 259 pthread_cancel(keyboardThread);
andrewm@0 260
andrewm@0 261 gShouldStop = true;
andrewm@0 262 }
andrewm@0 263
andrewm@0 264
andrewm@50 265 void parseArguments(arg_data args, BeagleRTInitSettings *settings)
andrewm@0 266 {
andrewm@0 267 // Default filename;
andrewm@0 268 gPartialFilename = strdup("D-Box_sound_250_60_40_h88_2.txt");
andrewm@0 269
andrewm@50 270 const int kOptionAudioTest = 1000;
andrewm@50 271
andrewm@0 272 // TODO: complete this
andrewm@0 273 struct option long_option[] =
andrewm@0 274 {
andrewm@0 275 {"help", 0, NULL, 'h'},
andrewm@0 276 {"audioin", 1, NULL, 'i'},
andrewm@0 277 {"file", 1, NULL, 'f'},
andrewm@0 278 {"keyboard", 1, NULL, 'k'},
andrewm@50 279 {"audio-test", 0, NULL, kOptionAudioTest},
andrewm@50 280 {"sensor-type", 1, NULL, 't'},
andrewm@50 281 {"sensor0", 1, NULL, 'q'},
andrewm@50 282 {"sensor1", 1, NULL, 'r'},
andrewm@0 283 {"log", 1, NULL, 'l'},
andrewm@0 284 {"usesd", 1, NULL, 'u'},
andrewm@0 285 {"oversamp", 1, NULL, 'o'},
andrewm@0 286 {"boxnumber", 1, NULL, 'n'},
andrewm@0 287 {"group", 1, NULL, 'g'},
andrewm@0 288 {NULL, 0, NULL, 0},
andrewm@0 289 };
andrewm@0 290 int morehelp = 0;
andrewm@0 291 int tmp = -1;
andrewm@0 292
andrewm@5 293 BeagleRT_defaultSettings(settings);
andrewm@5 294
andrewm@0 295 while (1)
andrewm@0 296 {
andrewm@0 297 int c;
andrewm@50 298 if ((c = BeagleRT_getopt_long(args.argc, args.argv, "hf:ki:sq:r:t:l:u:o:n:g:", long_option, settings)) < 0)
andrewm@0 299 break;
andrewm@0 300 switch (c)
andrewm@0 301 {
andrewm@0 302 case 'h':
andrewm@0 303 morehelp++;
andrewm@0 304 break;
andrewm@0 305 case 'f':
andrewm@0 306 free(gPartialFilename);
andrewm@0 307 gPartialFilename = strdup(optarg);
andrewm@0 308 break;
andrewm@0 309 case 'k':
andrewm@0 310 forceKeyboard = true;
andrewm@0 311 break;
andrewm@0 312 case 'i':
andrewm@0 313 gAudioIn = (atoi(optarg)==0) ? false : true;
andrewm@0 314 break;
andrewm@0 315 case 's':
andrewm@0 316 forceSensors = true;
andrewm@0 317 break;
andrewm@50 318 case kOptionAudioTest:
andrewm@0 319 useAudioTest = true;
andrewm@0 320 break;
andrewm@50 321 case 't':
andrewm@15 322 sensorType = atoi(optarg);
andrewm@0 323 break;
andrewm@50 324 case 'q':
andrewm@0 325 touchSensor0Address = atoi(optarg);
andrewm@0 326 break;
andrewm@50 327 case 'r':
andrewm@0 328 touchSensor1Address = atoi(optarg);
andrewm@0 329 break;
andrewm@0 330 case 'l':
andrewm@0 331 tmp = atoi(optarg);
andrewm@0 332 if(tmp==0)
andrewm@0 333 forceLog = false;
andrewm@0 334 else if(tmp>0)
andrewm@0 335 forceLog = true;
andrewm@0 336 break;
andrewm@0 337 case 'u':
andrewm@0 338 tmp = atoi(optarg);
andrewm@0 339 if(tmp==0)
andrewm@0 340 useSD = false;
andrewm@0 341 else if(tmp>0)
andrewm@0 342 useSD = true;
andrewm@0 343 break;
andrewm@0 344 case 'o':
andrewm@0 345 oscBnkOversampling = atoi(optarg);
andrewm@0 346 break;
andrewm@0 347 case 'n':
andrewm@0 348 gId = *optarg;
andrewm@0 349 cout << "-set box number to: " << gId << endl;
andrewm@0 350 break;
andrewm@0 351 case 'g':
andrewm@0 352 gGroup = *optarg;
andrewm@0 353 cout << "-set group to: " << gId << endl;
andrewm@0 354 break;
andrewm@0 355 default:
andrewm@0 356 break;
andrewm@0 357 }
andrewm@0 358 }
andrewm@5 359
andrewm@5 360 gPeriodSize = settings->periodSize;
andrewm@5 361 gVerbose = settings->verbose;
andrewm@0 362 }
andrewm@0 363
andrewm@0 364 int main(int argc, char *argv[])
andrewm@0 365 {
andrewm@50 366 BeagleRTInitSettings settings; // Standard audio settings
andrewm@0 367 RT_TASK rtSensorThread;
andrewm@0 368 const char rtSensorThreadName[] = "dbox-sensor";
andrewm@0 369 int oscBankHopSize;
andrewm@0 370
andrewm@0 371 // Parse command-line arguments
andrewm@0 372 args.argc = argc;
andrewm@0 373 args.argv = argv;
andrewm@5 374 parseArguments(args, &settings);
andrewm@0 375
andrewm@50 376 BeagleRT_setVerboseLevel(gVerbose);
andrewm@0 377 if(gVerbose == 1 && useAudioTest)
andrewm@0 378 cout << "main() : running in audio test mode" << endl;
andrewm@0 379
andrewm@0 380 // Load sound files from directory
andrewm@0 381 if(initSoundFiles() != 0)
andrewm@0 382 return -1;
andrewm@0 383
andrewm@0 384 oscBankHopSize = gOscBanks[gCurrentOscBank]->getHopSize()/gOscBanks[gCurrentOscBank]->getMinSpeed();
andrewm@0 385
andrewm@0 386 // Initialise the audio device
andrewm@5 387 if(BeagleRT_initAudio(&settings, &oscBankHopSize) != 0)
andrewm@0 388 return -1;
andrewm@0 389
andrewm@0 390 // Initialise the status LED
andrewm@0 391 if(!gStatusLED.init(kStatusLEDPin)) {
andrewm@0 392 if(gVerbose)
andrewm@0 393 cout << "Couldn't initialise status LED pin\n";
andrewm@0 394 }
andrewm@0 395
andrewm@0 396 // Free file name string which is no longer needed
andrewm@0 397 if(gPartialFilename != 0)
andrewm@0 398 free(gPartialFilename);
andrewm@0 399
andrewm@0 400 if(!useAudioTest) {
andrewm@15 401 if(initSensorLoop(touchSensor0Address, touchSensor1Address, sensorType) != 0)
andrewm@0 402 return -1;
andrewm@0 403 }
andrewm@0 404
andrewm@0 405 if(gVerbose == 1)
andrewm@0 406 cout << "main() : creating audio thread" << endl;
andrewm@0 407
andrewm@5 408 if(BeagleRT_startAudio()) {
andrewm@0 409 cout << "Error: unable to start real-time audio" << endl;
andrewm@0 410 return -1;
andrewm@0 411 }
andrewm@0 412
andrewm@0 413 // LED on...
andrewm@0 414 gStatusLED.on();
andrewm@0 415
andrewm@0 416 if(forceSensors && !useAudioTest) {
andrewm@0 417 if(gVerbose==1)
andrewm@0 418 cout << "main() : creating control thread" << endl;
andrewm@0 419
andrewm@50 420 if(rt_task_create(&rtSensorThread, rtSensorThreadName, 0, BEAGLERT_AUDIO_PRIORITY - 5, T_JOINABLE | T_FPU)) {
andrewm@0 421 cout << "Error:unable to create Xenomai control thread" << endl;
andrewm@0 422 return -1;
andrewm@0 423 }
andrewm@0 424 if(rt_task_start(&rtSensorThread, &sensorLoop, 0)) {
andrewm@0 425 cout << "Error:unable to start Xenomai control thread" << endl;
andrewm@0 426 return -1;
andrewm@0 427 }
andrewm@0 428 }
andrewm@0 429
andrewm@0 430 if(forceKeyboard) {
andrewm@0 431 if(gVerbose==1)
andrewm@0 432 cout << "main() : creating keyboard thread" << endl;
andrewm@0 433
andrewm@0 434 if ( pthread_create(&keyboardThread, NULL, keyboardLoop, NULL) ) {
andrewm@0 435 cout << "Error:unable to create keyboard thread" << endl;
andrewm@0 436 return -1;
andrewm@0 437 }
andrewm@0 438 }
andrewm@0 439
andrewm@0 440 if(forceLog) {
andrewm@0 441 if(gVerbose==1)
andrewm@0 442 cout << "main() : creating log thread" << endl;
andrewm@0 443
andrewm@0 444 if(initLogLoop()!=0) {
andrewm@0 445 cout << "Error:unable to create log thread" << endl;
andrewm@0 446 return -1;
andrewm@0 447 }
andrewm@0 448
andrewm@0 449 if ( pthread_create(&logThread, NULL, logLoop, NULL) ) {
andrewm@0 450 cout << "Error:unable to create keyboard thread" << endl;
andrewm@0 451 return -1;
andrewm@0 452 }
andrewm@0 453 }
andrewm@0 454
andrewm@15 455 // Set up interrupt handler to catch Control-C and SIGTERM
andrewm@0 456 signal(SIGINT, interrupt_handler);
andrewm@15 457 signal(SIGTERM, interrupt_handler);
andrewm@0 458
andrewm@0 459 // load all other files into oscBanks
andrewm@0 460 loadAudioFiles(false);
andrewm@0 461 cout << "Finished loading analysis files\n";
andrewm@0 462 gIsLoading = false;
andrewm@0 463
andrewm@0 464 // Run until told to stop
andrewm@0 465 while(!gShouldStop) {
andrewm@0 466 usleep(100000);
andrewm@0 467 }
andrewm@0 468
andrewm@5 469 BeagleRT_stopAudio();
andrewm@0 470
andrewm@0 471 if(!useAudioTest)
andrewm@0 472 rt_task_join(&rtSensorThread);
andrewm@0 473
andrewm@5 474 BeagleRT_cleanupAudio();
andrewm@0 475
andrewm@0 476 pthread_join( keyboardThread, NULL);
andrewm@0 477 pthread_join( logThread, NULL);
andrewm@0 478
andrewm@0 479 for(unsigned int i = 0; i < gOscBanks.size(); i++)
andrewm@0 480 delete gOscBanks[i];
andrewm@0 481
andrewm@0 482 NE10_FREE(filterState[0]);
andrewm@0 483 NE10_FREE(filterState[1]);
andrewm@0 484 NE10_FREE(filterIn[0]);
andrewm@0 485 NE10_FREE(filterIn[1]);
andrewm@0 486 NE10_FREE(filterOut[0]);
andrewm@0 487 NE10_FREE(filterOut[1]);
andrewm@0 488
andrewm@0 489 printf("Program ended\nBye bye\n");
andrewm@0 490 return 0;
andrewm@0 491 }