andrewm@5: /* andrewm@5: * RTAudioCommandLine.cpp andrewm@5: * andrewm@5: * Created on: Nov 8, 2014 andrewm@5: * Author: parallels andrewm@5: */ andrewm@5: andrewm@5: #include andrewm@5: #include andrewm@5: #include andrewm@5: #include giuliomoro@301: #include "../include/Bela.h" giuliomoro@24: giuliomoro@171: #define OPT_PRU_FILE 1000 giuliomoro@171: #define OPT_PGA_GAIN_LEFT 1001 giuliomoro@171: #define OPT_PGA_GAIN_RIGHT 1002 andrewm@280: #define OPT_PRU_NUMBER 1003 giuliomoro@171: andrewm@5: andrewm@47: enum { andrewm@47: kAmplifierMutePin = 61 // P8-26 controls amplifier mute andrewm@47: }; andrewm@47: andrewm@5: // Default command-line options for RTAudio andrewm@5: struct option gDefaultLongOptions[] = andrewm@5: { andrewm@5: {"period", 1, NULL, 'p'}, andrewm@5: {"verbose", 0, NULL, 'v'}, andrewm@50: {"use-analog", 1, NULL, 'N'}, andrewm@50: {"use-digital", 1, NULL, 'G'}, giuliomoro@19: {"analog-channels", 1, NULL, 'C'}, andrewm@50: {"digital-channels", 1, NULL, 'B'}, andrewm@5: {"mute-speaker", 1, NULL, 'M'}, andrewm@5: {"dac-level", 1, NULL, 'D'}, andrewm@5: {"adc-level", 1, NULL, 'A'}, giuliomoro@171: {"pga-gain-left", 1, NULL, OPT_PGA_GAIN_LEFT}, giuliomoro@171: {"pga-gain-right", 1, NULL, OPT_PGA_GAIN_RIGHT}, andrewm@5: {"hp-level", 1, NULL, 'H'}, andrewm@50: {"receive-port", 1, NULL, 'R'}, andrewm@50: {"transmit-port", 1, NULL, 'T'}, andrewm@50: {"server-name", 1, NULL, 'S'}, andrewm@45: {"pru-file", 1, NULL, OPT_PRU_FILE}, andrewm@280: {"pru-number", 1, NULL, OPT_PRU_NUMBER}, andrewm@5: {NULL, 0, NULL, 0} andrewm@5: }; giuliomoro@24: andrewm@50: const char gDefaultShortOptions[] = "p:vN:M:C:D:A:H:G:B:R:T:S:"; andrewm@5: giuliomoro@301: // This function sets the default settings for the BelaInitSettings structure giuliomoro@301: void Bela_defaultSettings(BelaInitSettings *settings) andrewm@5: { andrewm@5: // Set default values for settings giuliomoro@178: settings->periodSize = 16; andrewm@45: settings->useAnalog = 1; andrewm@45: settings->useDigital = 1; giuliomoro@537: settings->numAudioInChannels = 2; giuliomoro@537: settings->numAudioOutChannels = 2; giuliomoro@537: giuliomoro@537: settings->numAnalogInChannels = 8; giuliomoro@537: settings->numAnalogOutChannels = 8; andrewm@45: settings->numDigitalChannels = 16; andrewm@45: andrewm@5: settings->beginMuted = 0; andrewm@5: settings->dacLevel = DEFAULT_DAC_LEVEL; andrewm@5: settings->adcLevel = DEFAULT_ADC_LEVEL; giuliomoro@171: for(int n = 0; n < 2; n++) giuliomoro@171: settings->pgaGain[n] = DEFAULT_PGA_GAIN; andrewm@5: settings->headphoneLevel = DEFAULT_HP_LEVEL; andrewm@280: settings->numMuxChannels = 0; andrewm@45: andrewm@5: settings->verbose = 0; andrewm@280: settings->pruNumber = 0; andrewm@45: settings->pruFilename[0] = '\0'; andrewm@45: andrewm@45: // These two deliberately have no command-line flags by default. andrewm@45: // A given program might prefer one mode or another, but it's unlikely andrewm@45: // the user would want to switch at runtime andrewm@45: settings->interleave = 1; andrewm@45: settings->analogOutputsPersist = 1; andrewm@45: andrewm@5: settings->codecI2CAddress = CODEC_I2C_ADDRESS; andrewm@45: settings->receivePort = 9998; andrewm@45: settings->transmitPort = 9999; giuliomoro@24: strcpy(settings->serverName, "127.0.0.1"); andrewm@5: settings->ampMutePin = kAmplifierMutePin; andrewm@5: } andrewm@5: andrewm@5: // This function drops in place of getopt() in the main() function andrewm@5: // and handles the initialisation of the RTAudio settings using andrewm@5: // standard command-line arguments. System default arguments will andrewm@5: // be stored in settings, otherwise arguments will be returned andrewm@5: // as getopt() normally does. andrewm@5: giuliomoro@301: int Bela_getopt_long(int argc, char *argv[], const char *customShortOptions, const struct option *customLongOptions, BelaInitSettings *settings) andrewm@5: { andrewm@5: static int firstRun = 1; andrewm@5: static char totalShortOptions[256]; andrewm@5: static struct option totalLongOptions[256]; andrewm@5: andrewm@5: int c; andrewm@5: andrewm@5: // Prep total option string the first time this is andrewm@5: // run. As a getopt() substitute, it will be called repeatedly working its andrewm@5: // way through argc and argv. andrewm@5: if(firstRun) { andrewm@5: firstRun = 0; andrewm@5: andrewm@5: // Copy short options into one string andrewm@5: strcpy(totalShortOptions, gDefaultShortOptions); andrewm@5: strncat(totalShortOptions, customShortOptions, 256 - strlen(gDefaultShortOptions) - 1); andrewm@5: andrewm@5: // Copy long options into one array andrewm@5: int n = 0; andrewm@5: while(1) { andrewm@5: if(gDefaultLongOptions[n].name == NULL) andrewm@5: break; andrewm@5: totalLongOptions[n].name = gDefaultLongOptions[n].name; andrewm@5: totalLongOptions[n].has_arg = gDefaultLongOptions[n].has_arg; andrewm@5: totalLongOptions[n].flag = gDefaultLongOptions[n].flag; andrewm@5: totalLongOptions[n].val = gDefaultLongOptions[n].val; andrewm@5: n++; andrewm@5: } andrewm@5: andrewm@5: // Copy custom options into the array, if present andrewm@5: if(customLongOptions == 0) { andrewm@5: // Terminate the array andrewm@5: totalLongOptions[n].name = NULL; andrewm@5: totalLongOptions[n].has_arg = 0; andrewm@5: totalLongOptions[n].flag = NULL; andrewm@5: totalLongOptions[n].val = 0; andrewm@5: } andrewm@5: else { andrewm@5: int customIndex = 0; andrewm@5: while(n < 256) { andrewm@5: if(customLongOptions[customIndex].name == NULL) andrewm@5: break; andrewm@5: totalLongOptions[n].name = customLongOptions[customIndex].name; andrewm@5: totalLongOptions[n].has_arg = customLongOptions[customIndex].has_arg; andrewm@5: totalLongOptions[n].flag = customLongOptions[customIndex].flag; andrewm@5: totalLongOptions[n].val = customLongOptions[customIndex].val; andrewm@5: n++; andrewm@5: customIndex++; andrewm@5: } andrewm@5: andrewm@5: // Terminate the array andrewm@5: totalLongOptions[n].name = NULL; andrewm@5: totalLongOptions[n].has_arg = 0; andrewm@5: totalLongOptions[n].flag = NULL; andrewm@5: totalLongOptions[n].val = 0; andrewm@5: } andrewm@5: } andrewm@5: andrewm@5: while(1) { andrewm@5: if ((c = getopt_long(argc, argv, totalShortOptions, totalLongOptions, NULL)) < 0) andrewm@5: return c; andrewm@5: andrewm@5: switch (c) { andrewm@5: case 'p': andrewm@5: settings->periodSize = atoi(optarg); andrewm@5: if(settings->periodSize < 1) andrewm@5: settings->periodSize = 1; andrewm@5: break; andrewm@5: case 'v': andrewm@5: settings->verbose = 1; andrewm@5: break; andrewm@50: case 'N': giuliomoro@19: settings->useAnalog = atoi(optarg); andrewm@5: break; andrewm@50: case 'G': giuliomoro@19: settings->useDigital = atoi(optarg); giuliomoro@240: if(settings->useDigital == 0){ giuliomoro@240: settings->numDigitalChannels = 0; giuliomoro@240: } giuliomoro@16: break; giuliomoro@537: case 'C': { giuliomoro@537: // TODO: a different number of channels for inputs and outputs is not yet supported giuliomoro@537: unsigned int numAnalogChannels = atoi(optarg); giuliomoro@537: settings->numAnalogInChannels = numAnalogChannels; giuliomoro@537: settings->numAnalogOutChannels = numAnalogChannels; giuliomoro@537: if(numAnalogChannels >= 8) { giuliomoro@537: // TODO: a different number of channels for inputs and outputs is not yet supported giuliomoro@537: andrewm@280: // Use multiplexer capelet to run larger numbers of channels giuliomoro@537: if(settings->numAnalogInChannels >= 64) andrewm@280: settings->numMuxChannels = 8; giuliomoro@537: else if(settings->numAnalogInChannels >= 32) andrewm@280: settings->numMuxChannels = 4; giuliomoro@537: else if(settings->numAnalogInChannels >= 16) andrewm@280: settings->numMuxChannels = 2; giuliomoro@537: settings->numAnalogInChannels = 8; andrewm@280: } giuliomoro@537: else if(numAnalogChannels >= 4){ giuliomoro@537: // TODO: a different number of channels for inputs and outputs is not yet supported giuliomoro@537: settings->numAnalogInChannels = 4; giuliomoro@537: settings->numAnalogOutChannels = 4; giuliomoro@537: } giuliomoro@537: else{ giuliomoro@537: // TODO: a different number of channels for inputs and outputs is not yet supported giuliomoro@537: settings->numAnalogInChannels = 2; giuliomoro@537: settings->numAnalogOutChannels = 2; giuliomoro@537: } andrewm@12: break; giuliomoro@537: } andrewm@50: case 'B': giuliomoro@19: settings->numDigitalChannels = atoi(optarg); giuliomoro@19: if(settings->numDigitalChannels >= 16) giuliomoro@19: settings->numDigitalChannels = 16; giuliomoro@19: else if (settings->numDigitalChannels < 1){ giuliomoro@19: settings->numDigitalChannels = 0; giuliomoro@19: settings->useDigital = 0; //TODO: this actually works only if -G 0 is specified after -g 1. giuliomoro@19: //No worries, though: disabling numDigital will only prevent the pins from being exported. giuliomoro@16: } giuliomoro@16: break; andrewm@5: case 'M': andrewm@5: settings->beginMuted = atoi(optarg); andrewm@5: break; andrewm@5: case 'D': andrewm@5: settings->dacLevel = atof(optarg); andrewm@5: break; andrewm@5: case 'A': andrewm@5: settings->adcLevel = atof(optarg); andrewm@5: break; andrewm@5: case 'H': andrewm@5: settings->headphoneLevel = atof(optarg); andrewm@5: break; andrewm@50: case 'R': giuliomoro@24: settings->receivePort = atoi(optarg); giuliomoro@24: break; andrewm@50: case 'T': giuliomoro@24: settings->transmitPort = atoi(optarg); giuliomoro@24: break; andrewm@50: case 'S': giuliomoro@24: if(strlen(optarg)serverName, optarg); giuliomoro@24: else giuliomoro@24: std::cerr << "Warning: server name is too long (>" << MAX_SERVERNAME_LENGTH << " characters)." giuliomoro@24: " Using default severName Instead ( " << settings->serverName << " ).\n"; giuliomoro@24: break; giuliomoro@29: case OPT_PRU_FILE: andrewm@45: if(strlen(optarg) < MAX_PRU_FILENAME_LENGTH) giuliomoro@16: strcpy(settings->pruFilename, optarg); giuliomoro@16: else giuliomoro@16: std::cerr << "Warning: filename for the PRU code is too long (>" << MAX_PRU_FILENAME_LENGTH << " characters). Using embedded PRU code instead\n"; giuliomoro@16: break; giuliomoro@171: case OPT_PGA_GAIN_LEFT: giuliomoro@171: settings->pgaGain[0] = atof(optarg); giuliomoro@171: break; giuliomoro@171: case OPT_PGA_GAIN_RIGHT: giuliomoro@171: settings->pgaGain[1] = atof(optarg); giuliomoro@171: break; andrewm@280: case OPT_PRU_NUMBER: andrewm@280: settings->pruNumber = atoi(optarg); andrewm@280: break; andrewm@5: case '?': andrewm@5: default: andrewm@5: return c; andrewm@5: } andrewm@5: } andrewm@5: } andrewm@5: andrewm@5: // This function prints standard usage information for default arguments andrewm@5: // Call from within your own usage function giuliomoro@301: void Bela_usage() andrewm@5: { giuliomoro@19: std::cerr << " --period [-p] period: Set the hardware period (buffer) size in analog samples\n"; giuliomoro@16: std::cerr << " --dac-level [-D] dBs: Set the DAC output level (0dB max; -63.5dB min)\n"; giuliomoro@16: std::cerr << " --adc-level [-A] dBs: Set the ADC input level (0dB max; -12dB min)\n"; giuliomoro@171: std::cerr << " --pga-gain-left dBs: Set the Programmable Gain Amplifier for the left audio channel (0dBmin; 59.5dB max; default: 16dB)\n"; giuliomoro@171: std::cerr << " --pga-gain-right dBs: Set the Programmable Gain Amplifier for the right audio channel (0dBmin; 59.5dB max; default: 16dB)\n"; giuliomoro@16: std::cerr << " --hp-level [-H] dBs: Set the headphone output level (0dB max; -63.5dB min)\n"; giuliomoro@16: std::cerr << " --mute-speaker [-M] val: Set whether to mute the speaker initially (default: no)\n"; andrewm@52: std::cerr << " --use-analog [-N] val: Set whether to use ADC/DAC analog (default: yes)\n"; andrewm@52: std::cerr << " --use-digital [-G] val: Set whether to use digital GPIO channels (default: yes)\n"; giuliomoro@19: std::cerr << " --analog-channels [-C] val: Set the number of ADC/DAC channels (default: 8)\n"; andrewm@52: std::cerr << " --digital-channels [-B] val: Set the number of GPIO channels (default: 16)\n"; andrewm@52: std::cerr << " --receive-port [-R] val: Set the receive port (default: 9998)\n"; andrewm@52: std::cerr << " --transmit-port [-T] val: Set the transmit port (default: 9999)\n"; andrewm@52: std::cerr << " --server-name [-S] val: Set the destination server name (default: '127.0.0.1')\n"; giuliomoro@24: std::cerr << " --pru-file val: Set an optional external file to use for the PRU binary code\n"; andrewm@280: std::cerr << " --pru-number val: Set the PRU to use for I/O (options: 0 or 1, default: 0)\n"; giuliomoro@16: std::cerr << " --verbose [-v]: Enable verbose logging information\n"; andrewm@5: } giuliomoro@16: