annotate core/RTAudio.cpp @ 269:ac8eb07afcf5

Oxygen text added to each render.cpp file for the default projects. Text includes project explanation from Wiki, edited in places. Empty project added as a default project. Doxyfile updated. Each of the project locations added to INPUT configuration option. Consider just watching the whole project file so all new projects are automatically pulled through.
author Robert Jack <robert.h.jack@gmail.com>
date Tue, 17 May 2016 15:40:16 +0100
parents 18d03901f866
children 173978a5ab6a
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 <assert.h>
andrewm@0 21 #include <vector>
andrewm@0 22
andrewm@0 23 // Xenomai-specific includes
andrewm@0 24 #include <sys/mman.h>
andrewm@0 25 #include <native/task.h>
andrewm@0 26 #include <native/timer.h>
andrewm@45 27 #include <native/intr.h>
andrewm@0 28 #include <rtdk.h>
andrewm@0 29
andrewm@45 30 #include "../include/BeagleRT.h"
andrewm@0 31 #include "../include/PRU.h"
andrewm@0 32 #include "../include/I2c_Codec.h"
andrewm@0 33 #include "../include/GPIOcontrol.h"
andrewm@0 34
andrewm@45 35 // ARM interrupt number for PRU event EVTOUT7
andrewm@45 36 #define PRU_RTAUDIO_IRQ 21
andrewm@45 37
andrewm@0 38 using namespace std;
andrewm@0 39
andrewm@0 40 // Data structure to keep track of auxiliary tasks we
andrewm@0 41 // can schedule
andrewm@0 42 typedef struct {
andrewm@0 43 RT_TASK task;
andrewm@0 44 void (*function)(void);
andrewm@0 45 char *name;
andrewm@0 46 int priority;
giuliomoro@174 47 bool started;
andrewm@0 48 } InternalAuxiliaryTask;
andrewm@0 49
andrewm@0 50 const char gRTAudioThreadName[] = "beaglert-audio";
andrewm@45 51 const char gRTAudioInterruptName[] = "beaglert-pru-irq";
andrewm@0 52
andrewm@0 53 // Real-time tasks and objects
andrewm@0 54 RT_TASK gRTAudioThread;
andrewm@50 55 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
andrewm@45 56 RT_INTR gRTAudioInterrupt;
andrewm@50 57 #endif
andrewm@0 58 PRU *gPRU = 0;
andrewm@0 59 I2c_Codec *gAudioCodec = 0;
andrewm@0 60
giuliomoro@176 61 vector<InternalAuxiliaryTask*> &getAuxTasks(){
giuliomoro@176 62 static vector<InternalAuxiliaryTask*> auxTasks;
giuliomoro@176 63 return auxTasks;
giuliomoro@176 64 }
andrewm@0 65
andrewm@0 66 // Flag which tells the audio task to stop
giuliomoro@233 67 int gShouldStop = false;
andrewm@0 68
andrewm@0 69 // general settings
andrewm@45 70 char gPRUFilename[MAX_PRU_FILENAME_LENGTH]; // Path to PRU binary file (internal code if empty)_
andrewm@0 71 int gRTAudioVerbose = 0; // Verbosity level for debugging
andrewm@0 72 int gAmplifierMutePin = -1;
andrewm@5 73 int gAmplifierShouldBeginMuted = 0;
andrewm@0 74
andrewm@45 75 // Context which holds all the audio/sensor data passed to the render routines
andrewm@45 76 BeagleRTContext gContext;
andrewm@45 77
andrewm@45 78 // User data passed in from main()
andrewm@45 79 void *gUserData;
andrewm@0 80
andrewm@0 81 // initAudio() prepares the infrastructure for running PRU-based real-time
andrewm@0 82 // audio, but does not actually start the calculations.
giuliomoro@178 83 // periodSize indicates the number of audio frames per period: the analog period size
giuliomoro@178 84 // will depend on the number of analog channels, in such a way that
giuliomoro@178 85 // analogPeriodSize = 4*periodSize/numAnalogChannels
giuliomoro@178 86 // In total, the audio latency in frames will be 2*periodSize,
andrewm@0 87 // plus any latency inherent in the ADCs and DACs themselves.
giuliomoro@19 88 // useAnalog indicates whether to enable the ADC and DAC or just use the audio codec.
giuliomoro@19 89 // numAnalogChannels indicates how many ADC and DAC channels to use.
andrewm@56 90 // userData is an opaque pointer which will be passed through to the setup()
andrewm@0 91 // function for application-specific use
andrewm@0 92 //
andrewm@0 93 // Returns 0 on success.
andrewm@0 94
andrewm@45 95 int BeagleRT_initAudio(BeagleRTInitSettings *settings, void *userData)
andrewm@0 96 {
andrewm@0 97 rt_print_auto_init(1);
andrewm@45 98
andrewm@45 99 BeagleRT_setVerboseLevel(settings->verbose);
andrewm@45 100 strncpy(gPRUFilename, settings->pruFilename, MAX_PRU_FILENAME_LENGTH);
andrewm@45 101 gUserData = userData;
andrewm@45 102
andrewm@45 103 // Initialise context data structure
andrewm@45 104 memset(&gContext, 0, sizeof(BeagleRTContext));
andrewm@0 105
andrewm@5 106 if(gRTAudioVerbose) {
andrewm@5 107 cout << "Starting with period size " << settings->periodSize << "; ";
giuliomoro@19 108 if(settings->useAnalog)
giuliomoro@19 109 cout << "analog enabled\n";
andrewm@5 110 else
giuliomoro@19 111 cout << "analog disabled\n";
andrewm@5 112 cout << "DAC level " << settings->dacLevel << "dB; ADC level " << settings->adcLevel;
andrewm@5 113 cout << "dB; headphone level " << settings->headphoneLevel << "dB\n";
andrewm@5 114 if(settings->beginMuted)
andrewm@5 115 cout << "Beginning with speaker muted\n";
andrewm@5 116 }
andrewm@0 117
andrewm@0 118 // Prepare GPIO pins for amplifier mute and status LED
andrewm@5 119 if(settings->ampMutePin >= 0) {
andrewm@5 120 gAmplifierMutePin = settings->ampMutePin;
andrewm@5 121 gAmplifierShouldBeginMuted = settings->beginMuted;
andrewm@0 122
andrewm@5 123 if(gpio_export(settings->ampMutePin)) {
andrewm@0 124 if(gRTAudioVerbose)
giuliomoro@16 125 cout << "Warning: couldn't export amplifier mute pin " << settings-> ampMutePin << "\n";
andrewm@0 126 }
andrewm@5 127 if(gpio_set_dir(settings->ampMutePin, OUTPUT_PIN)) {
andrewm@0 128 if(gRTAudioVerbose)
andrewm@0 129 cout << "Couldn't set direction on amplifier mute pin\n";
andrewm@0 130 return -1;
andrewm@0 131 }
andrewm@5 132 if(gpio_set_value(settings->ampMutePin, LOW)) {
andrewm@0 133 if(gRTAudioVerbose)
andrewm@0 134 cout << "Couldn't set value on amplifier mute pin\n";
andrewm@0 135 return -1;
andrewm@0 136 }
andrewm@0 137 }
andrewm@0 138
giuliomoro@19 139 // Limit the analog channels to sane values
giuliomoro@19 140 if(settings->numAnalogChannels >= 8)
giuliomoro@19 141 settings->numAnalogChannels = 8;
giuliomoro@19 142 else if(settings->numAnalogChannels >= 4)
giuliomoro@19 143 settings->numAnalogChannels = 4;
andrewm@12 144 else
giuliomoro@19 145 settings->numAnalogChannels = 2;
andrewm@12 146
andrewm@45 147 // Initialise the rendering environment: sample rates, frame counts, numbers of channels
andrewm@45 148 gContext.audioSampleRate = 44100.0;
andrewm@45 149 gContext.audioChannels = 2;
andrewm@45 150
andrewm@45 151 if(settings->useAnalog) {
giuliomoro@178 152 gContext.audioFrames = settings->periodSize;
andrewm@45 153
giuliomoro@178 154 gContext.analogFrames = gContext.audioFrames * 4 / settings->numAnalogChannels;
andrewm@45 155 gContext.analogChannels = settings->numAnalogChannels;
andrewm@45 156 gContext.analogSampleRate = gContext.audioSampleRate * 4.0 / (float)settings->numAnalogChannels;
andrewm@45 157 }
andrewm@45 158 else {
giuliomoro@178 159 gContext.audioFrames = settings->periodSize;
andrewm@45 160
andrewm@45 161 gContext.analogFrames = 0;
andrewm@45 162 gContext.analogChannels = 0;
andrewm@45 163 gContext.analogSampleRate = 0;
andrewm@45 164 }
andrewm@45 165
giuliomoro@178 166 // Sanity check the combination of channels and period size
giuliomoro@210 167 if( gContext.analogChannels != 0 && ((gContext.analogChannels <= 4 && gContext.analogFrames < 2) ||
giuliomoro@210 168 (gContext.analogChannels <= 2 && gContext.analogFrames < 4)) )
giuliomoro@178 169 {
giuliomoro@178 170 cout << "Error: " << gContext.analogChannels << " channels and period size of " << gContext.analogFrames << " not supported.\n";
giuliomoro@178 171 return 1;
giuliomoro@178 172 }
giuliomoro@178 173
andrewm@45 174 // For now, digital frame rate is equal to audio frame rate
andrewm@45 175 if(settings->useDigital) {
andrewm@45 176 gContext.digitalFrames = gContext.audioFrames;
andrewm@45 177 gContext.digitalSampleRate = gContext.audioSampleRate;
andrewm@45 178 gContext.digitalChannels = settings->numDigitalChannels;
andrewm@45 179 }
andrewm@45 180 else {
andrewm@45 181 gContext.digitalFrames = 0;
andrewm@45 182 gContext.digitalSampleRate = 0;
andrewm@45 183 gContext.digitalChannels = 0;
andrewm@45 184 }
andrewm@45 185
andrewm@45 186 // Set flags based on init settings
andrewm@45 187 if(settings->interleave)
andrewm@45 188 gContext.flags |= BEAGLERT_FLAG_INTERLEAVED;
andrewm@45 189 if(settings->analogOutputsPersist)
andrewm@45 190 gContext.flags |= BEAGLERT_FLAG_ANALOG_OUTPUTS_PERSIST;
andrewm@45 191
andrewm@0 192 // Use PRU for audio
andrewm@45 193 gPRU = new PRU(&gContext);
andrewm@0 194 gAudioCodec = new I2c_Codec();
andrewm@0 195
andrewm@45 196 // Initialise the GPIO pins, including possibly the digital pins in the render routines
andrewm@45 197 if(gPRU->prepareGPIO(1, 1)) {
andrewm@0 198 cout << "Error: unable to prepare GPIO for PRU audio\n";
andrewm@0 199 return 1;
andrewm@0 200 }
andrewm@45 201
andrewm@45 202 // Get the PRU memory buffers ready to go
giuliomoro@178 203 if(gPRU->initialise(0, gContext.analogFrames, gContext.analogChannels, true)) {
andrewm@0 204 cout << "Error: unable to initialise PRU\n";
andrewm@0 205 return 1;
andrewm@0 206 }
andrewm@45 207
andrewm@45 208 // Prepare the audio codec, which clocks the whole system
andrewm@5 209 if(gAudioCodec->initI2C_RW(2, settings->codecI2CAddress, -1)) {
andrewm@0 210 cout << "Unable to open codec I2C\n";
andrewm@0 211 return 1;
andrewm@0 212 }
andrewm@0 213 if(gAudioCodec->initCodec()) {
andrewm@0 214 cout << "Error: unable to initialise audio codec\n";
andrewm@0 215 return 1;
andrewm@0 216 }
giuliomoro@172 217
andrewm@5 218 // Set default volume levels
andrewm@5 219 BeagleRT_setDACLevel(settings->dacLevel);
andrewm@5 220 BeagleRT_setADCLevel(settings->adcLevel);
giuliomoro@174 221 // TODO: add more argument checks
giuliomoro@171 222 for(int n = 0; n < 2; n++){
giuliomoro@172 223 if(settings->pgaGain[n] > 59.5){
giuliomoro@172 224 std::cerr << "PGA gain out of range [0,59.5]\n";
giuliomoro@172 225 exit(1);
giuliomoro@172 226 }
giuliomoro@171 227 BeagleRT_setPgaGain(settings->pgaGain[n], n);
giuliomoro@171 228 }
andrewm@5 229 BeagleRT_setHeadphoneLevel(settings->headphoneLevel);
andrewm@5 230
andrewm@45 231 // Call the user-defined initialisation function
andrewm@56 232 if(!setup(&gContext, userData)) {
andrewm@0 233 cout << "Couldn't initialise audio rendering\n";
andrewm@0 234 return 1;
andrewm@0 235 }
andrewm@0 236
andrewm@0 237 return 0;
andrewm@0 238 }
andrewm@0 239
andrewm@0 240 // audioLoop() is the main function which starts the PRU audio code
andrewm@0 241 // and then transfers control to the PRU object. The PRU object in
andrewm@0 242 // turn will call the audio render() callback function every time
andrewm@0 243 // there is new data to process.
andrewm@0 244
andrewm@0 245 void audioLoop(void *)
andrewm@0 246 {
andrewm@0 247 if(gRTAudioVerbose==1)
andrewm@0 248 rt_printf("_________________Audio Thread!\n");
andrewm@0 249
andrewm@0 250 // PRU audio
andrewm@0 251 assert(gAudioCodec != 0 && gPRU != 0);
andrewm@0 252
andrewm@0 253 if(gAudioCodec->startAudio(0)) {
andrewm@0 254 rt_printf("Error: unable to start I2C audio codec\n");
andrewm@0 255 gShouldStop = 1;
andrewm@0 256 }
andrewm@0 257 else {
giuliomoro@16 258 if(gPRU->start(gPRUFilename)) {
giuliomoro@16 259 rt_printf("Error: unable to start PRU from file %s\n", gPRUFilename);
andrewm@0 260 gShouldStop = 1;
andrewm@0 261 }
andrewm@0 262 else {
andrewm@0 263 // All systems go. Run the loop; it will end when gShouldStop is set to 1
andrewm@5 264
andrewm@5 265 if(!gAmplifierShouldBeginMuted) {
andrewm@5 266 // First unmute the amplifier
andrewm@5 267 if(BeagleRT_muteSpeakers(0)) {
andrewm@5 268 if(gRTAudioVerbose)
andrewm@5 269 rt_printf("Warning: couldn't set value (high) on amplifier mute pin\n");
andrewm@5 270 }
andrewm@0 271 }
andrewm@0 272
andrewm@50 273 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
andrewm@45 274 gPRU->loop(&gRTAudioInterrupt, gUserData);
andrewm@50 275 #else
andrewm@50 276 gPRU->loop(0, gUserData);
andrewm@50 277 #endif
andrewm@0 278 // Now clean up
andrewm@0 279 // gPRU->waitForFinish();
andrewm@0 280 gPRU->disable();
andrewm@0 281 gAudioCodec->stopAudio();
andrewm@0 282 gPRU->cleanupGPIO();
andrewm@0 283 }
andrewm@0 284 }
andrewm@0 285
andrewm@0 286 if(gRTAudioVerbose == 1)
andrewm@0 287 rt_printf("audio thread ended\n");
andrewm@0 288 }
andrewm@0 289
andrewm@0 290 // Create a calculation loop which can run independently of the audio, at a different
andrewm@45 291 // (equal or lower) priority. Audio priority is defined in BEAGLERT_AUDIO_PRIORITY;
andrewm@45 292 // priority should be generally be less than this.
andrewm@0 293 // Returns an (opaque) pointer to the created task on success; 0 on failure
andrewm@47 294 AuxiliaryTask BeagleRT_createAuxiliaryTask(void (*functionToCall)(void), int priority, const char *name)
andrewm@0 295 {
andrewm@0 296 InternalAuxiliaryTask *newTask = (InternalAuxiliaryTask*)malloc(sizeof(InternalAuxiliaryTask));
andrewm@0 297
andrewm@0 298 // Attempt to create the task
andrewm@0 299 if(rt_task_create(&(newTask->task), name, 0, priority, T_JOINABLE | T_FPU)) {
andrewm@0 300 cout << "Error: unable to create auxiliary task " << name << endl;
andrewm@0 301 free(newTask);
andrewm@0 302 return 0;
andrewm@0 303 }
andrewm@0 304
andrewm@0 305 // Populate the rest of the data structure and store it in the vector
andrewm@0 306 newTask->function = functionToCall;
andrewm@0 307 newTask->name = strdup(name);
andrewm@0 308 newTask->priority = priority;
giuliomoro@174 309 newTask->started = false;
andrewm@0 310
giuliomoro@176 311 getAuxTasks().push_back(newTask);
andrewm@0 312
andrewm@0 313 return (AuxiliaryTask)newTask;
andrewm@0 314 }
andrewm@0 315
giuliomoro@174 316 // Schedule a previously created (and started) auxiliary task. It will run when the priority rules next
andrewm@0 317 // allow it to be scheduled.
andrewm@47 318 void BeagleRT_scheduleAuxiliaryTask(AuxiliaryTask task)
andrewm@0 319 {
andrewm@0 320 InternalAuxiliaryTask *taskToSchedule = (InternalAuxiliaryTask *)task;
giuliomoro@174 321 if(taskToSchedule->started == false){ // Note: this is not the safest method to check if a task
giuliomoro@174 322 BeagleRT_startAuxiliaryTask(task); // is started (or ready to be resumed), but it probably is the fastest.
giuliomoro@174 323 // A safer approach would use rt_task_inquire()
giuliomoro@174 324 }
andrewm@0 325 rt_task_resume(&taskToSchedule->task);
andrewm@0 326 }
andrewm@0 327
andrewm@0 328 // Calculation loop that can be used for other tasks running at a lower
andrewm@0 329 // priority than the audio thread. Simple wrapper for Xenomai calls.
andrewm@0 330 // Treat the argument as containing the task structure
andrewm@0 331 void auxiliaryTaskLoop(void *taskStruct)
andrewm@0 332 {
andrewm@0 333 // Get function to call from the argument
andrewm@0 334 void (*auxiliary_function)(void) = ((InternalAuxiliaryTask *)taskStruct)->function;
andrewm@0 335 const char *name = ((InternalAuxiliaryTask *)taskStruct)->name;
andrewm@0 336
andrewm@0 337 // Wait for a notification
andrewm@0 338 rt_task_suspend(NULL);
andrewm@0 339
andrewm@0 340 while(!gShouldStop) {
andrewm@0 341 // Then run the calculations
andrewm@0 342 auxiliary_function();
andrewm@0 343
andrewm@0 344 // Wait for a notification
andrewm@0 345 rt_task_suspend(NULL);
andrewm@0 346 }
andrewm@0 347
andrewm@0 348 if(gRTAudioVerbose == 1)
andrewm@0 349 rt_printf("auxiliary task %s ended\n", name);
andrewm@0 350 }
andrewm@0 351
giuliomoro@174 352
giuliomoro@174 353 int BeagleRT_startAuxiliaryTask(AuxiliaryTask task){
giuliomoro@174 354 InternalAuxiliaryTask *taskStruct;
giuliomoro@174 355 taskStruct = (InternalAuxiliaryTask *)task;
giuliomoro@174 356 if(taskStruct->started == true)
giuliomoro@174 357 return 0;
giuliomoro@174 358 if(rt_task_start(&(taskStruct->task), &auxiliaryTaskLoop, taskStruct)) {
giuliomoro@174 359 cerr << "Error: unable to start Xenomai task " << taskStruct->name << endl;
giuliomoro@174 360 return -1;
giuliomoro@174 361 }
giuliomoro@174 362 taskStruct->started = true;
giuliomoro@174 363 return 0;
giuliomoro@174 364 }
giuliomoro@174 365
andrewm@0 366 // startAudio() should be called only after initAudio() successfully completes.
andrewm@0 367 // It launches the real-time Xenomai task which runs the audio loop. Returns 0
andrewm@0 368 // on success.
andrewm@0 369
andrewm@5 370 int BeagleRT_startAudio()
andrewm@0 371 {
andrewm@45 372 // Create audio thread with high Xenomai priority
andrewm@45 373 if(rt_task_create(&gRTAudioThread, gRTAudioThreadName, 0, BEAGLERT_AUDIO_PRIORITY, T_JOINABLE | T_FPU)) {
andrewm@0 374 cout << "Error: unable to create Xenomai audio thread" << endl;
andrewm@0 375 return -1;
andrewm@0 376 }
andrewm@0 377
andrewm@50 378 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
andrewm@45 379 // Create an interrupt which the audio thread receives from the PRU
andrewm@45 380 int result = 0;
andrewm@45 381 if((result = rt_intr_create(&gRTAudioInterrupt, gRTAudioInterruptName, PRU_RTAUDIO_IRQ, I_NOAUTOENA)) != 0) {
andrewm@45 382 cout << "Error: unable to create Xenomai interrupt for PRU (error " << result << ")" << endl;
andrewm@45 383 return -1;
andrewm@45 384 }
andrewm@50 385 #endif
andrewm@45 386
andrewm@0 387 // Start all RT threads
andrewm@0 388 if(rt_task_start(&gRTAudioThread, &audioLoop, 0)) {
andrewm@0 389 cout << "Error: unable to start Xenomai audio thread" << endl;
andrewm@0 390 return -1;
andrewm@0 391 }
andrewm@0 392
andrewm@0 393 // The user may have created other tasks. Start those also.
andrewm@0 394 vector<InternalAuxiliaryTask*>::iterator it;
giuliomoro@176 395 for(it = getAuxTasks().begin(); it != getAuxTasks().end(); it++) {
giuliomoro@177 396 int ret = BeagleRT_startAuxiliaryTask(*it);
giuliomoro@177 397 if(ret != 0)
giuliomoro@177 398 return -2;
andrewm@0 399 }
andrewm@0 400 return 0;
andrewm@0 401 }
andrewm@0 402
andrewm@0 403 // Stop the PRU-based audio from running and wait
andrewm@0 404 // for the tasks to complete before returning.
andrewm@0 405
andrewm@5 406 void BeagleRT_stopAudio()
andrewm@0 407 {
andrewm@0 408 // Tell audio thread to stop (if this hasn't been done already)
andrewm@0 409 gShouldStop = true;
andrewm@0 410
andrewm@5 411 if(gRTAudioVerbose)
andrewm@5 412 cout << "Stopping audio...\n";
andrewm@5 413
andrewm@0 414 // Now wait for threads to respond and actually stop...
andrewm@0 415 rt_task_join(&gRTAudioThread);
andrewm@0 416
andrewm@0 417 // Stop all the auxiliary threads too
andrewm@0 418 vector<InternalAuxiliaryTask*>::iterator it;
giuliomoro@176 419 for(it = getAuxTasks().begin(); it != getAuxTasks().end(); it++) {
andrewm@0 420 InternalAuxiliaryTask *taskStruct = *it;
andrewm@0 421
andrewm@0 422 // Wake up each thread and join it
andrewm@0 423 rt_task_resume(&(taskStruct->task));
andrewm@0 424 rt_task_join(&(taskStruct->task));
andrewm@0 425 }
andrewm@0 426 }
andrewm@0 427
andrewm@0 428 // Free any resources associated with PRU real-time audio
andrewm@5 429 void BeagleRT_cleanupAudio()
andrewm@0 430 {
andrewm@56 431 cleanup(&gContext, gUserData);
andrewm@0 432
andrewm@0 433 // Clean up the auxiliary tasks
andrewm@0 434 vector<InternalAuxiliaryTask*>::iterator it;
giuliomoro@176 435 for(it = getAuxTasks().begin(); it != getAuxTasks().end(); it++) {
andrewm@0 436 InternalAuxiliaryTask *taskStruct = *it;
andrewm@0 437
andrewm@45 438 // Delete the task
andrewm@45 439 rt_task_delete(&taskStruct->task);
andrewm@45 440
andrewm@0 441 // Free the name string and the struct itself
andrewm@0 442 free(taskStruct->name);
andrewm@0 443 free(taskStruct);
andrewm@0 444 }
giuliomoro@176 445 getAuxTasks().clear();
andrewm@0 446
andrewm@45 447 // Delete the audio task and its interrupt
andrewm@50 448 #ifdef BEAGLERT_USE_XENOMAI_INTERRUPTS
andrewm@45 449 rt_intr_delete(&gRTAudioInterrupt);
andrewm@50 450 #endif
andrewm@45 451 rt_task_delete(&gRTAudioThread);
andrewm@45 452
andrewm@0 453 if(gPRU != 0)
andrewm@0 454 delete gPRU;
andrewm@0 455 if(gAudioCodec != 0)
andrewm@0 456 delete gAudioCodec;
andrewm@0 457
andrewm@0 458 if(gAmplifierMutePin >= 0)
andrewm@0 459 gpio_unexport(gAmplifierMutePin);
andrewm@0 460 gAmplifierMutePin = -1;
andrewm@0 461 }
andrewm@0 462
andrewm@5 463 // Set the level of the DAC; affects all outputs (headphone, line, speaker)
andrewm@5 464 // 0dB is the maximum, -63.5dB is the minimum; 0.5dB steps
andrewm@5 465 int BeagleRT_setDACLevel(float decibels)
andrewm@5 466 {
andrewm@5 467 if(gAudioCodec == 0)
andrewm@5 468 return -1;
andrewm@5 469 return gAudioCodec->setDACVolume((int)floorf(decibels * 2.0 + 0.5));
andrewm@5 470 }
andrewm@5 471
andrewm@5 472 // Set the level of the ADC
andrewm@5 473 // 0dB is the maximum, -12dB is the minimum; 1.5dB steps
andrewm@5 474 int BeagleRT_setADCLevel(float decibels)
andrewm@5 475 {
andrewm@5 476 if(gAudioCodec == 0)
andrewm@5 477 return -1;
andrewm@5 478 return gAudioCodec->setADCVolume((int)floorf(decibels * 2.0 + 0.5));
andrewm@5 479 }
andrewm@5 480
giuliomoro@171 481 // Set the level of the Programmable Gain Amplifier
giuliomoro@171 482 // 59.5dB is maximum, 0dB is minimum; 0.5dB steps
giuliomoro@171 483 int BeagleRT_setPgaGain(float decibels, int channel){
giuliomoro@171 484 if(gAudioCodec == 0)
giuliomoro@171 485 return -1;
giuliomoro@171 486 return gAudioCodec->setPga(decibels, channel);
giuliomoro@171 487 }
giuliomoro@171 488
andrewm@5 489 // Set the level of the onboard headphone amplifier; affects headphone
andrewm@5 490 // output only (not line out or speaker)
andrewm@5 491 // 0dB is the maximum, -63.5dB is the minimum; 0.5dB steps
andrewm@5 492 int BeagleRT_setHeadphoneLevel(float decibels)
andrewm@5 493 {
andrewm@5 494 if(gAudioCodec == 0)
andrewm@5 495 return -1;
andrewm@5 496 return gAudioCodec->setHPVolume((int)floorf(decibels * 2.0 + 0.5));
andrewm@5 497 }
andrewm@5 498
andrewm@5 499 // Mute or unmute the onboard speaker amplifiers
andrewm@5 500 // mute == 0 means unmute; otherwise mute
andrewm@5 501 // Returns 0 on success
andrewm@5 502 int BeagleRT_muteSpeakers(int mute)
andrewm@5 503 {
andrewm@5 504 int pinValue = mute ? LOW : HIGH;
andrewm@5 505
andrewm@5 506 // Check that we have an enabled pin for controlling the mute
andrewm@5 507 if(gAmplifierMutePin < 0)
andrewm@5 508 return -1;
andrewm@5 509
andrewm@5 510 return gpio_set_value(gAmplifierMutePin, pinValue);
andrewm@5 511 }
andrewm@5 512
andrewm@0 513 // Set the verbosity level
andrewm@45 514 void BeagleRT_setVerboseLevel(int level)
andrewm@0 515 {
andrewm@0 516 gRTAudioVerbose = level;
andrewm@0 517 }