andrewm@5
|
1 /*
|
andrewm@5
|
2 * RTAudioCommandLine.cpp
|
andrewm@5
|
3 *
|
andrewm@5
|
4 * Created on: Nov 8, 2014
|
andrewm@5
|
5 * Author: parallels
|
andrewm@5
|
6 */
|
andrewm@5
|
7
|
andrewm@5
|
8 #include <iostream>
|
andrewm@5
|
9 #include <cstdlib>
|
andrewm@5
|
10 #include <cstring>
|
andrewm@5
|
11 #include <getopt.h>
|
giuliomoro@301
|
12 #include "../include/Bela.h"
|
giuliomoro@24
|
13
|
giuliomoro@171
|
14 #define OPT_PRU_FILE 1000
|
giuliomoro@171
|
15 #define OPT_PGA_GAIN_LEFT 1001
|
giuliomoro@171
|
16 #define OPT_PGA_GAIN_RIGHT 1002
|
andrewm@280
|
17 #define OPT_PRU_NUMBER 1003
|
giuliomoro@171
|
18
|
andrewm@5
|
19
|
andrewm@47
|
20 enum {
|
andrewm@47
|
21 kAmplifierMutePin = 61 // P8-26 controls amplifier mute
|
andrewm@47
|
22 };
|
andrewm@47
|
23
|
andrewm@5
|
24 // Default command-line options for RTAudio
|
andrewm@5
|
25 struct option gDefaultLongOptions[] =
|
andrewm@5
|
26 {
|
andrewm@5
|
27 {"period", 1, NULL, 'p'},
|
andrewm@5
|
28 {"verbose", 0, NULL, 'v'},
|
andrewm@50
|
29 {"use-analog", 1, NULL, 'N'},
|
andrewm@50
|
30 {"use-digital", 1, NULL, 'G'},
|
giuliomoro@19
|
31 {"analog-channels", 1, NULL, 'C'},
|
andrewm@50
|
32 {"digital-channels", 1, NULL, 'B'},
|
andrewm@5
|
33 {"mute-speaker", 1, NULL, 'M'},
|
andrewm@5
|
34 {"dac-level", 1, NULL, 'D'},
|
andrewm@5
|
35 {"adc-level", 1, NULL, 'A'},
|
giuliomoro@171
|
36 {"pga-gain-left", 1, NULL, OPT_PGA_GAIN_LEFT},
|
giuliomoro@171
|
37 {"pga-gain-right", 1, NULL, OPT_PGA_GAIN_RIGHT},
|
andrewm@5
|
38 {"hp-level", 1, NULL, 'H'},
|
andrewm@50
|
39 {"receive-port", 1, NULL, 'R'},
|
andrewm@50
|
40 {"transmit-port", 1, NULL, 'T'},
|
andrewm@50
|
41 {"server-name", 1, NULL, 'S'},
|
andrewm@45
|
42 {"pru-file", 1, NULL, OPT_PRU_FILE},
|
andrewm@280
|
43 {"pru-number", 1, NULL, OPT_PRU_NUMBER},
|
andrewm@5
|
44 {NULL, 0, NULL, 0}
|
andrewm@5
|
45 };
|
giuliomoro@24
|
46
|
andrewm@50
|
47 const char gDefaultShortOptions[] = "p:vN:M:C:D:A:H:G:B:R:T:S:";
|
andrewm@5
|
48
|
giuliomoro@301
|
49 // This function sets the default settings for the BelaInitSettings structure
|
giuliomoro@301
|
50 void Bela_defaultSettings(BelaInitSettings *settings)
|
andrewm@5
|
51 {
|
andrewm@5
|
52 // Set default values for settings
|
giuliomoro@178
|
53 settings->periodSize = 16;
|
andrewm@45
|
54 settings->useAnalog = 1;
|
andrewm@45
|
55 settings->useDigital = 1;
|
giuliomoro@537
|
56 settings->numAudioInChannels = 2;
|
giuliomoro@537
|
57 settings->numAudioOutChannels = 2;
|
giuliomoro@537
|
58
|
giuliomoro@537
|
59 settings->numAnalogInChannels = 8;
|
giuliomoro@537
|
60 settings->numAnalogOutChannels = 8;
|
andrewm@45
|
61 settings->numDigitalChannels = 16;
|
andrewm@45
|
62
|
andrewm@5
|
63 settings->beginMuted = 0;
|
andrewm@5
|
64 settings->dacLevel = DEFAULT_DAC_LEVEL;
|
andrewm@5
|
65 settings->adcLevel = DEFAULT_ADC_LEVEL;
|
giuliomoro@171
|
66 for(int n = 0; n < 2; n++)
|
giuliomoro@171
|
67 settings->pgaGain[n] = DEFAULT_PGA_GAIN;
|
andrewm@5
|
68 settings->headphoneLevel = DEFAULT_HP_LEVEL;
|
andrewm@280
|
69 settings->numMuxChannels = 0;
|
andrewm@45
|
70
|
andrewm@5
|
71 settings->verbose = 0;
|
andrewm@280
|
72 settings->pruNumber = 0;
|
andrewm@45
|
73 settings->pruFilename[0] = '\0';
|
andrewm@45
|
74
|
andrewm@45
|
75 // These two deliberately have no command-line flags by default.
|
andrewm@45
|
76 // A given program might prefer one mode or another, but it's unlikely
|
andrewm@45
|
77 // the user would want to switch at runtime
|
andrewm@45
|
78 settings->interleave = 1;
|
andrewm@45
|
79 settings->analogOutputsPersist = 1;
|
andrewm@45
|
80
|
andrewm@5
|
81 settings->codecI2CAddress = CODEC_I2C_ADDRESS;
|
andrewm@45
|
82 settings->receivePort = 9998;
|
andrewm@45
|
83 settings->transmitPort = 9999;
|
giuliomoro@24
|
84 strcpy(settings->serverName, "127.0.0.1");
|
andrewm@5
|
85 settings->ampMutePin = kAmplifierMutePin;
|
andrewm@5
|
86 }
|
andrewm@5
|
87
|
andrewm@5
|
88 // This function drops in place of getopt() in the main() function
|
andrewm@5
|
89 // and handles the initialisation of the RTAudio settings using
|
andrewm@5
|
90 // standard command-line arguments. System default arguments will
|
andrewm@5
|
91 // be stored in settings, otherwise arguments will be returned
|
andrewm@5
|
92 // as getopt() normally does.
|
andrewm@5
|
93
|
giuliomoro@301
|
94 int Bela_getopt_long(int argc, char *argv[], const char *customShortOptions, const struct option *customLongOptions, BelaInitSettings *settings)
|
andrewm@5
|
95 {
|
andrewm@5
|
96 static int firstRun = 1;
|
andrewm@5
|
97 static char totalShortOptions[256];
|
andrewm@5
|
98 static struct option totalLongOptions[256];
|
andrewm@5
|
99
|
andrewm@5
|
100 int c;
|
andrewm@5
|
101
|
andrewm@5
|
102 // Prep total option string the first time this is
|
andrewm@5
|
103 // run. As a getopt() substitute, it will be called repeatedly working its
|
andrewm@5
|
104 // way through argc and argv.
|
andrewm@5
|
105 if(firstRun) {
|
andrewm@5
|
106 firstRun = 0;
|
andrewm@5
|
107
|
andrewm@5
|
108 // Copy short options into one string
|
andrewm@5
|
109 strcpy(totalShortOptions, gDefaultShortOptions);
|
andrewm@5
|
110 strncat(totalShortOptions, customShortOptions, 256 - strlen(gDefaultShortOptions) - 1);
|
andrewm@5
|
111
|
andrewm@5
|
112 // Copy long options into one array
|
andrewm@5
|
113 int n = 0;
|
andrewm@5
|
114 while(1) {
|
andrewm@5
|
115 if(gDefaultLongOptions[n].name == NULL)
|
andrewm@5
|
116 break;
|
andrewm@5
|
117 totalLongOptions[n].name = gDefaultLongOptions[n].name;
|
andrewm@5
|
118 totalLongOptions[n].has_arg = gDefaultLongOptions[n].has_arg;
|
andrewm@5
|
119 totalLongOptions[n].flag = gDefaultLongOptions[n].flag;
|
andrewm@5
|
120 totalLongOptions[n].val = gDefaultLongOptions[n].val;
|
andrewm@5
|
121 n++;
|
andrewm@5
|
122 }
|
andrewm@5
|
123
|
andrewm@5
|
124 // Copy custom options into the array, if present
|
andrewm@5
|
125 if(customLongOptions == 0) {
|
andrewm@5
|
126 // Terminate the array
|
andrewm@5
|
127 totalLongOptions[n].name = NULL;
|
andrewm@5
|
128 totalLongOptions[n].has_arg = 0;
|
andrewm@5
|
129 totalLongOptions[n].flag = NULL;
|
andrewm@5
|
130 totalLongOptions[n].val = 0;
|
andrewm@5
|
131 }
|
andrewm@5
|
132 else {
|
andrewm@5
|
133 int customIndex = 0;
|
andrewm@5
|
134 while(n < 256) {
|
andrewm@5
|
135 if(customLongOptions[customIndex].name == NULL)
|
andrewm@5
|
136 break;
|
andrewm@5
|
137 totalLongOptions[n].name = customLongOptions[customIndex].name;
|
andrewm@5
|
138 totalLongOptions[n].has_arg = customLongOptions[customIndex].has_arg;
|
andrewm@5
|
139 totalLongOptions[n].flag = customLongOptions[customIndex].flag;
|
andrewm@5
|
140 totalLongOptions[n].val = customLongOptions[customIndex].val;
|
andrewm@5
|
141 n++;
|
andrewm@5
|
142 customIndex++;
|
andrewm@5
|
143 }
|
andrewm@5
|
144
|
andrewm@5
|
145 // Terminate the array
|
andrewm@5
|
146 totalLongOptions[n].name = NULL;
|
andrewm@5
|
147 totalLongOptions[n].has_arg = 0;
|
andrewm@5
|
148 totalLongOptions[n].flag = NULL;
|
andrewm@5
|
149 totalLongOptions[n].val = 0;
|
andrewm@5
|
150 }
|
andrewm@5
|
151 }
|
andrewm@5
|
152
|
andrewm@5
|
153 while(1) {
|
andrewm@5
|
154 if ((c = getopt_long(argc, argv, totalShortOptions, totalLongOptions, NULL)) < 0)
|
andrewm@5
|
155 return c;
|
andrewm@5
|
156
|
andrewm@5
|
157 switch (c) {
|
andrewm@5
|
158 case 'p':
|
andrewm@5
|
159 settings->periodSize = atoi(optarg);
|
andrewm@5
|
160 if(settings->periodSize < 1)
|
andrewm@5
|
161 settings->periodSize = 1;
|
andrewm@5
|
162 break;
|
andrewm@5
|
163 case 'v':
|
andrewm@5
|
164 settings->verbose = 1;
|
andrewm@5
|
165 break;
|
andrewm@50
|
166 case 'N':
|
giuliomoro@19
|
167 settings->useAnalog = atoi(optarg);
|
andrewm@5
|
168 break;
|
andrewm@50
|
169 case 'G':
|
giuliomoro@19
|
170 settings->useDigital = atoi(optarg);
|
giuliomoro@240
|
171 if(settings->useDigital == 0){
|
giuliomoro@240
|
172 settings->numDigitalChannels = 0;
|
giuliomoro@240
|
173 }
|
giuliomoro@16
|
174 break;
|
giuliomoro@537
|
175 case 'C': {
|
giuliomoro@537
|
176 // TODO: a different number of channels for inputs and outputs is not yet supported
|
giuliomoro@537
|
177 unsigned int numAnalogChannels = atoi(optarg);
|
giuliomoro@537
|
178 settings->numAnalogInChannels = numAnalogChannels;
|
giuliomoro@537
|
179 settings->numAnalogOutChannels = numAnalogChannels;
|
giuliomoro@537
|
180 if(numAnalogChannels >= 8) {
|
giuliomoro@537
|
181 // TODO: a different number of channels for inputs and outputs is not yet supported
|
giuliomoro@537
|
182
|
andrewm@280
|
183 // Use multiplexer capelet to run larger numbers of channels
|
giuliomoro@537
|
184 if(settings->numAnalogInChannels >= 64)
|
andrewm@280
|
185 settings->numMuxChannels = 8;
|
giuliomoro@537
|
186 else if(settings->numAnalogInChannels >= 32)
|
andrewm@280
|
187 settings->numMuxChannels = 4;
|
giuliomoro@537
|
188 else if(settings->numAnalogInChannels >= 16)
|
andrewm@280
|
189 settings->numMuxChannels = 2;
|
giuliomoro@537
|
190 settings->numAnalogInChannels = 8;
|
andrewm@280
|
191 }
|
giuliomoro@537
|
192 else if(numAnalogChannels >= 4){
|
giuliomoro@537
|
193 // TODO: a different number of channels for inputs and outputs is not yet supported
|
giuliomoro@537
|
194 settings->numAnalogInChannels = 4;
|
giuliomoro@537
|
195 settings->numAnalogOutChannels = 4;
|
giuliomoro@537
|
196 }
|
giuliomoro@537
|
197 else{
|
giuliomoro@537
|
198 // TODO: a different number of channels for inputs and outputs is not yet supported
|
giuliomoro@537
|
199 settings->numAnalogInChannels = 2;
|
giuliomoro@537
|
200 settings->numAnalogOutChannels = 2;
|
giuliomoro@537
|
201 }
|
andrewm@12
|
202 break;
|
giuliomoro@537
|
203 }
|
andrewm@50
|
204 case 'B':
|
giuliomoro@19
|
205 settings->numDigitalChannels = atoi(optarg);
|
giuliomoro@19
|
206 if(settings->numDigitalChannels >= 16)
|
giuliomoro@19
|
207 settings->numDigitalChannels = 16;
|
giuliomoro@19
|
208 else if (settings->numDigitalChannels < 1){
|
giuliomoro@19
|
209 settings->numDigitalChannels = 0;
|
giuliomoro@19
|
210 settings->useDigital = 0; //TODO: this actually works only if -G 0 is specified after -g 1.
|
giuliomoro@19
|
211 //No worries, though: disabling numDigital will only prevent the pins from being exported.
|
giuliomoro@16
|
212 }
|
giuliomoro@16
|
213 break;
|
andrewm@5
|
214 case 'M':
|
andrewm@5
|
215 settings->beginMuted = atoi(optarg);
|
andrewm@5
|
216 break;
|
andrewm@5
|
217 case 'D':
|
andrewm@5
|
218 settings->dacLevel = atof(optarg);
|
andrewm@5
|
219 break;
|
andrewm@5
|
220 case 'A':
|
andrewm@5
|
221 settings->adcLevel = atof(optarg);
|
andrewm@5
|
222 break;
|
andrewm@5
|
223 case 'H':
|
andrewm@5
|
224 settings->headphoneLevel = atof(optarg);
|
andrewm@5
|
225 break;
|
andrewm@50
|
226 case 'R':
|
giuliomoro@24
|
227 settings->receivePort = atoi(optarg);
|
giuliomoro@24
|
228 break;
|
andrewm@50
|
229 case 'T':
|
giuliomoro@24
|
230 settings->transmitPort = atoi(optarg);
|
giuliomoro@24
|
231 break;
|
andrewm@50
|
232 case 'S':
|
giuliomoro@24
|
233 if(strlen(optarg)<MAX_SERVERNAME_LENGTH)
|
giuliomoro@24
|
234 strcpy(settings->serverName, optarg);
|
giuliomoro@24
|
235 else
|
giuliomoro@24
|
236 std::cerr << "Warning: server name is too long (>" << MAX_SERVERNAME_LENGTH << " characters)."
|
giuliomoro@24
|
237 " Using default severName Instead ( " << settings->serverName << " ).\n";
|
giuliomoro@24
|
238 break;
|
giuliomoro@29
|
239 case OPT_PRU_FILE:
|
andrewm@45
|
240 if(strlen(optarg) < MAX_PRU_FILENAME_LENGTH)
|
giuliomoro@16
|
241 strcpy(settings->pruFilename, optarg);
|
giuliomoro@16
|
242 else
|
giuliomoro@16
|
243 std::cerr << "Warning: filename for the PRU code is too long (>" << MAX_PRU_FILENAME_LENGTH << " characters). Using embedded PRU code instead\n";
|
giuliomoro@16
|
244 break;
|
giuliomoro@171
|
245 case OPT_PGA_GAIN_LEFT:
|
giuliomoro@171
|
246 settings->pgaGain[0] = atof(optarg);
|
giuliomoro@171
|
247 break;
|
giuliomoro@171
|
248 case OPT_PGA_GAIN_RIGHT:
|
giuliomoro@171
|
249 settings->pgaGain[1] = atof(optarg);
|
giuliomoro@171
|
250 break;
|
andrewm@280
|
251 case OPT_PRU_NUMBER:
|
andrewm@280
|
252 settings->pruNumber = atoi(optarg);
|
andrewm@280
|
253 break;
|
andrewm@5
|
254 case '?':
|
andrewm@5
|
255 default:
|
andrewm@5
|
256 return c;
|
andrewm@5
|
257 }
|
andrewm@5
|
258 }
|
andrewm@5
|
259 }
|
andrewm@5
|
260
|
andrewm@5
|
261 // This function prints standard usage information for default arguments
|
andrewm@5
|
262 // Call from within your own usage function
|
giuliomoro@301
|
263 void Bela_usage()
|
andrewm@5
|
264 {
|
giuliomoro@19
|
265 std::cerr << " --period [-p] period: Set the hardware period (buffer) size in analog samples\n";
|
giuliomoro@16
|
266 std::cerr << " --dac-level [-D] dBs: Set the DAC output level (0dB max; -63.5dB min)\n";
|
giuliomoro@16
|
267 std::cerr << " --adc-level [-A] dBs: Set the ADC input level (0dB max; -12dB min)\n";
|
giuliomoro@171
|
268 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
|
269 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
|
270 std::cerr << " --hp-level [-H] dBs: Set the headphone output level (0dB max; -63.5dB min)\n";
|
giuliomoro@16
|
271 std::cerr << " --mute-speaker [-M] val: Set whether to mute the speaker initially (default: no)\n";
|
andrewm@52
|
272 std::cerr << " --use-analog [-N] val: Set whether to use ADC/DAC analog (default: yes)\n";
|
andrewm@52
|
273 std::cerr << " --use-digital [-G] val: Set whether to use digital GPIO channels (default: yes)\n";
|
giuliomoro@19
|
274 std::cerr << " --analog-channels [-C] val: Set the number of ADC/DAC channels (default: 8)\n";
|
andrewm@52
|
275 std::cerr << " --digital-channels [-B] val: Set the number of GPIO channels (default: 16)\n";
|
andrewm@52
|
276 std::cerr << " --receive-port [-R] val: Set the receive port (default: 9998)\n";
|
andrewm@52
|
277 std::cerr << " --transmit-port [-T] val: Set the transmit port (default: 9999)\n";
|
andrewm@52
|
278 std::cerr << " --server-name [-S] val: Set the destination server name (default: '127.0.0.1')\n";
|
giuliomoro@24
|
279 std::cerr << " --pru-file val: Set an optional external file to use for the PRU binary code\n";
|
andrewm@280
|
280 std::cerr << " --pru-number val: Set the PRU to use for I/O (options: 0 or 1, default: 0)\n";
|
giuliomoro@16
|
281 std::cerr << " --verbose [-v]: Enable verbose logging information\n";
|
andrewm@5
|
282 }
|
giuliomoro@16
|
283
|