Mercurial > hg > beaglert
comparison core/RTAudio.cpp @ 5:09f03ac40fcc
API improvements and cleanups. Now all common audio command-line options can be parsed automatically.
author | andrewm |
---|---|
date | Sat, 08 Nov 2014 16:16:55 +0100 |
parents | 8a575ba3ab52 |
children | a6beeba3a648 |
comparison
equal
deleted
inserted
replaced
4:f34c63568523 | 5:09f03ac40fcc |
---|---|
42 char *name; | 42 char *name; |
43 int priority; | 43 int priority; |
44 } InternalAuxiliaryTask; | 44 } InternalAuxiliaryTask; |
45 | 45 |
46 const char gRTAudioThreadName[] = "beaglert-audio"; | 46 const char gRTAudioThreadName[] = "beaglert-audio"; |
47 const char gRTCalculationThreadNameMedium[] = "dbox-calculation-medium"; | |
48 const char gRTCalculationThreadNameLow[] = "dbox-calculation-low"; | |
49 | 47 |
50 // Real-time tasks and objects | 48 // Real-time tasks and objects |
51 RT_TASK gRTAudioThread; | 49 RT_TASK gRTAudioThread; |
52 PRU *gPRU = 0; | 50 PRU *gPRU = 0; |
53 I2c_Codec *gAudioCodec = 0; | 51 I2c_Codec *gAudioCodec = 0; |
59 | 57 |
60 // general settings | 58 // general settings |
61 int gRTAudioVerbose = 0; // Verbosity level for debugging | 59 int gRTAudioVerbose = 0; // Verbosity level for debugging |
62 char gPRUFilename[256] = "pru_rtaudio.bin"; // path to PRU binary file | 60 char gPRUFilename[256] = "pru_rtaudio.bin"; // path to PRU binary file |
63 int gAmplifierMutePin = -1; | 61 int gAmplifierMutePin = -1; |
62 int gAmplifierShouldBeginMuted = 0; | |
64 | 63 |
65 | 64 |
66 // initAudio() prepares the infrastructure for running PRU-based real-time | 65 // initAudio() prepares the infrastructure for running PRU-based real-time |
67 // audio, but does not actually start the calculations. | 66 // audio, but does not actually start the calculations. |
68 // periodSize indicates the number of _sensor_ frames per period: the audio period size | 67 // periodSize indicates the number of _sensor_ frames per period: the audio period size |
72 // userData is an opaque pointer which will be passed through to the initialise_render() | 71 // userData is an opaque pointer which will be passed through to the initialise_render() |
73 // function for application-specific use | 72 // function for application-specific use |
74 // | 73 // |
75 // Returns 0 on success. | 74 // Returns 0 on success. |
76 | 75 |
77 int initAudio(int periodSize, int useMatrix, | 76 int BeagleRT_initAudio(RTAudioSettings *settings, void *userData) |
78 void *userData, | |
79 int codecI2CAddress, int ampMutePin) | |
80 { | 77 { |
81 rt_print_auto_init(1); | 78 rt_print_auto_init(1); |
79 setVerboseLevel(settings->verbose); | |
80 | |
82 if(gRTAudioVerbose == 1) | 81 if(gRTAudioVerbose == 1) |
83 rt_printf("Running with Xenomai\n"); | 82 rt_printf("Running with Xenomai\n"); |
84 | 83 |
85 if(gRTAudioVerbose == 1) | 84 if(gRTAudioVerbose) { |
86 cout << "---------------->Init Audio Thread" << endl; | 85 cout << "Starting with period size " << settings->periodSize << "; "; |
86 if(settings->useMatrix) | |
87 cout << "matrix enabled\n"; | |
88 else | |
89 cout << "matrix disabled\n"; | |
90 cout << "DAC level " << settings->dacLevel << "dB; ADC level " << settings->adcLevel; | |
91 cout << "dB; headphone level " << settings->headphoneLevel << "dB\n"; | |
92 if(settings->beginMuted) | |
93 cout << "Beginning with speaker muted\n"; | |
94 } | |
87 | 95 |
88 // Prepare GPIO pins for amplifier mute and status LED | 96 // Prepare GPIO pins for amplifier mute and status LED |
89 if(ampMutePin >= 0) { | 97 if(settings->ampMutePin >= 0) { |
90 gAmplifierMutePin = ampMutePin; | 98 gAmplifierMutePin = settings->ampMutePin; |
91 | 99 gAmplifierShouldBeginMuted = settings->beginMuted; |
92 if(gpio_export(ampMutePin)) { | 100 |
101 if(gpio_export(settings->ampMutePin)) { | |
93 if(gRTAudioVerbose) | 102 if(gRTAudioVerbose) |
94 cout << "Warning: couldn't export amplifier mute pin\n"; | 103 cout << "Warning: couldn't export amplifier mute pin\n"; |
95 } | 104 } |
96 if(gpio_set_dir(ampMutePin, OUTPUT_PIN)) { | 105 if(gpio_set_dir(settings->ampMutePin, OUTPUT_PIN)) { |
97 if(gRTAudioVerbose) | 106 if(gRTAudioVerbose) |
98 cout << "Couldn't set direction on amplifier mute pin\n"; | 107 cout << "Couldn't set direction on amplifier mute pin\n"; |
99 return -1; | 108 return -1; |
100 } | 109 } |
101 if(gpio_set_value(ampMutePin, LOW)) { | 110 if(gpio_set_value(settings->ampMutePin, LOW)) { |
102 if(gRTAudioVerbose) | 111 if(gRTAudioVerbose) |
103 cout << "Couldn't set value on amplifier mute pin\n"; | 112 cout << "Couldn't set value on amplifier mute pin\n"; |
104 return -1; | 113 return -1; |
105 } | 114 } |
106 } | 115 } |
107 | 116 |
108 // Use PRU for audio | 117 // Use PRU for audio |
109 gPRU = new PRU(); | 118 gPRU = new PRU(); |
110 gAudioCodec = new I2c_Codec(); | 119 gAudioCodec = new I2c_Codec(); |
111 | 120 |
112 if(gPRU->prepareGPIO(useMatrix, 1, 1)) { | 121 if(gPRU->prepareGPIO(settings->useMatrix, 1, 1)) { |
113 cout << "Error: unable to prepare GPIO for PRU audio\n"; | 122 cout << "Error: unable to prepare GPIO for PRU audio\n"; |
114 return 1; | 123 return 1; |
115 } | 124 } |
116 if(gPRU->initialise(0, periodSize, true)) { | 125 if(gPRU->initialise(0, settings->periodSize, true)) { |
117 cout << "Error: unable to initialise PRU\n"; | 126 cout << "Error: unable to initialise PRU\n"; |
118 return 1; | 127 return 1; |
119 } | 128 } |
120 if(gAudioCodec->initI2C_RW(2, codecI2CAddress, -1)) { | 129 if(gAudioCodec->initI2C_RW(2, settings->codecI2CAddress, -1)) { |
121 cout << "Unable to open codec I2C\n"; | 130 cout << "Unable to open codec I2C\n"; |
122 return 1; | 131 return 1; |
123 } | 132 } |
124 if(gAudioCodec->initCodec()) { | 133 if(gAudioCodec->initCodec()) { |
125 cout << "Error: unable to initialise audio codec\n"; | 134 cout << "Error: unable to initialise audio codec\n"; |
126 return 1; | 135 return 1; |
127 } | 136 } |
128 gAudioCodec->setDACVolume(0); // Set the DAC volume to full-scale | 137 |
129 gAudioCodec->setHPVolume(-12); // Headphones 6dB down | 138 // Set default volume levels |
130 gAudioCodec->setADCVolume(-12); // Set the ADC volume to 6dB down | 139 BeagleRT_setDACLevel(settings->dacLevel); |
131 | 140 BeagleRT_setADCLevel(settings->adcLevel); |
132 if(!initialise_render(2, useMatrix ? periodSize : 0, periodSize * 2, 22050.0, 44100.0, userData)) { | 141 BeagleRT_setHeadphoneLevel(settings->headphoneLevel); |
142 | |
143 if(!initialise_render(2, settings->useMatrix ? settings->periodSize : 0, settings->periodSize * 2, 22050.0, 44100.0, userData)) { | |
133 cout << "Couldn't initialise audio rendering\n"; | 144 cout << "Couldn't initialise audio rendering\n"; |
134 return 1; | 145 return 1; |
135 } | 146 } |
136 | 147 |
137 return 0; | 148 return 0; |
159 rt_printf("Error: unable to start PRU from file %s\n", gPRUFilename); | 170 rt_printf("Error: unable to start PRU from file %s\n", gPRUFilename); |
160 gShouldStop = 1; | 171 gShouldStop = 1; |
161 } | 172 } |
162 else { | 173 else { |
163 // All systems go. Run the loop; it will end when gShouldStop is set to 1 | 174 // All systems go. Run the loop; it will end when gShouldStop is set to 1 |
164 // First unmute the amplifier | 175 |
165 if(gpio_set_value(gAmplifierMutePin, HIGH)) { | 176 if(!gAmplifierShouldBeginMuted) { |
166 if(gRTAudioVerbose) | 177 // First unmute the amplifier |
167 rt_printf("Warning: couldn't set value (high) on amplifier mute pin\n"); | 178 if(BeagleRT_muteSpeakers(0)) { |
179 if(gRTAudioVerbose) | |
180 rt_printf("Warning: couldn't set value (high) on amplifier mute pin\n"); | |
181 } | |
168 } | 182 } |
169 | 183 |
170 gPRU->loop(); | 184 gPRU->loop(); |
171 | 185 |
172 // Now clean up | 186 // Now clean up |
240 | 254 |
241 // startAudio() should be called only after initAudio() successfully completes. | 255 // startAudio() should be called only after initAudio() successfully completes. |
242 // It launches the real-time Xenomai task which runs the audio loop. Returns 0 | 256 // It launches the real-time Xenomai task which runs the audio loop. Returns 0 |
243 // on success. | 257 // on success. |
244 | 258 |
245 int startAudio() | 259 int BeagleRT_startAudio() |
246 { | 260 { |
247 // Create audio thread with the highest priority | 261 // Create audio thread with the highest priority |
248 if(rt_task_create(&gRTAudioThread, gRTAudioThreadName, 0, 99, T_JOINABLE | T_FPU)) { | 262 if(rt_task_create(&gRTAudioThread, gRTAudioThreadName, 0, 99, T_JOINABLE | T_FPU)) { |
249 cout << "Error: unable to create Xenomai audio thread" << endl; | 263 cout << "Error: unable to create Xenomai audio thread" << endl; |
250 return -1; | 264 return -1; |
271 } | 285 } |
272 | 286 |
273 // Stop the PRU-based audio from running and wait | 287 // Stop the PRU-based audio from running and wait |
274 // for the tasks to complete before returning. | 288 // for the tasks to complete before returning. |
275 | 289 |
276 void stopAudio() | 290 void BeagleRT_stopAudio() |
277 { | 291 { |
278 // Tell audio thread to stop (if this hasn't been done already) | 292 // Tell audio thread to stop (if this hasn't been done already) |
279 gShouldStop = true; | 293 gShouldStop = true; |
294 | |
295 if(gRTAudioVerbose) | |
296 cout << "Stopping audio...\n"; | |
280 | 297 |
281 // Now wait for threads to respond and actually stop... | 298 // Now wait for threads to respond and actually stop... |
282 rt_task_join(&gRTAudioThread); | 299 rt_task_join(&gRTAudioThread); |
283 | 300 |
284 // Stop all the auxiliary threads too | 301 // Stop all the auxiliary threads too |
291 rt_task_join(&(taskStruct->task)); | 308 rt_task_join(&(taskStruct->task)); |
292 } | 309 } |
293 } | 310 } |
294 | 311 |
295 // Free any resources associated with PRU real-time audio | 312 // Free any resources associated with PRU real-time audio |
296 void cleanupAudio() | 313 void BeagleRT_cleanupAudio() |
297 { | 314 { |
298 cleanup_render(); | 315 cleanup_render(); |
299 | 316 |
300 // Clean up the auxiliary tasks | 317 // Clean up the auxiliary tasks |
301 vector<InternalAuxiliaryTask*>::iterator it; | 318 vector<InternalAuxiliaryTask*>::iterator it; |
316 if(gAmplifierMutePin >= 0) | 333 if(gAmplifierMutePin >= 0) |
317 gpio_unexport(gAmplifierMutePin); | 334 gpio_unexport(gAmplifierMutePin); |
318 gAmplifierMutePin = -1; | 335 gAmplifierMutePin = -1; |
319 } | 336 } |
320 | 337 |
338 // Set the level of the DAC; affects all outputs (headphone, line, speaker) | |
339 // 0dB is the maximum, -63.5dB is the minimum; 0.5dB steps | |
340 int BeagleRT_setDACLevel(float decibels) | |
341 { | |
342 if(gAudioCodec == 0) | |
343 return -1; | |
344 return gAudioCodec->setDACVolume((int)floorf(decibels * 2.0 + 0.5)); | |
345 } | |
346 | |
347 // Set the level of the ADC | |
348 // 0dB is the maximum, -12dB is the minimum; 1.5dB steps | |
349 int BeagleRT_setADCLevel(float decibels) | |
350 { | |
351 if(gAudioCodec == 0) | |
352 return -1; | |
353 return gAudioCodec->setADCVolume((int)floorf(decibels * 2.0 + 0.5)); | |
354 } | |
355 | |
356 // Set the level of the onboard headphone amplifier; affects headphone | |
357 // output only (not line out or speaker) | |
358 // 0dB is the maximum, -63.5dB is the minimum; 0.5dB steps | |
359 int BeagleRT_setHeadphoneLevel(float decibels) | |
360 { | |
361 if(gAudioCodec == 0) | |
362 return -1; | |
363 return gAudioCodec->setHPVolume((int)floorf(decibels * 2.0 + 0.5)); | |
364 } | |
365 | |
366 // Mute or unmute the onboard speaker amplifiers | |
367 // mute == 0 means unmute; otherwise mute | |
368 // Returns 0 on success | |
369 int BeagleRT_muteSpeakers(int mute) | |
370 { | |
371 int pinValue = mute ? LOW : HIGH; | |
372 | |
373 // Check that we have an enabled pin for controlling the mute | |
374 if(gAmplifierMutePin < 0) | |
375 return -1; | |
376 | |
377 return gpio_set_value(gAmplifierMutePin, pinValue); | |
378 } | |
379 | |
321 // Set the verbosity level | 380 // Set the verbosity level |
322 void setVerboseLevel(int level) | 381 void setVerboseLevel(int level) |
323 { | 382 { |
324 gRTAudioVerbose = level; | 383 gRTAudioVerbose = level; |
325 } | 384 } |