annotate core/RTAudio.cpp @ 68:59edd5780fef

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