Main Page   Class Hierarchy   Compound List   File List   Compound Members   Related Pages  

gapeaudiooutput.cpp

00001 //gapeaudiooutput.cpp
00002 //Dave Chisholm dkc@ccrma.stanford.edu 12/1/00
00003 #include "gapeaudiooutput.h"
00004 
00005 GapeAudioOutput::GapeAudioOutput(GapeController* c, int numChannels, int device)
00006 : GapeUnit(c, numChannels) {
00007     properlyInitialized = true;
00008     if (numChannels > GAPE_MAX_NUM_CHANNELS) {
00009         numChannels = GAPE_MAX_NUM_CHANNELS;
00010         GapeConsts::reportError("GapeAudioOutput does not support the requested number of channels - the max number of channels is being used instead. Redefine GAPE_MAX_NUM_CHANNELS and re-compile if necesary.");
00011     }
00012     try {
00013         output = new RtAudio(numChannels, GapeConsts::sampleRate, "play", device);
00014     } catch (StkError& e) {
00015         QString message("GapeAudioOutput - unable to initialize - ");
00016         message.append(e.getMessage());
00017         GapeConsts::reportError(message.latin1());
00018         properlyInitialized = false;
00019     }
00020     soundBufferSize =   GAPE_RT_IO_BUFFER_SIZE * numChannels;
00021     soundBuffer = new GapeIntSample[soundBufferSize];
00022     currentBufferPosition = 0;
00023     //setNumChannels(numChannels);
00024 }
00025 
00026 GapeAudioOutput::~GapeAudioOutput() {
00027     if (currentBufferPosition != 0) {
00028         output->playBuffer(soundBuffer, currentBufferPosition);
00029     }
00030     delete []soundBuffer;
00031     soundBuffer = NULL;
00032     delete output;
00033     output = NULL;
00034 }
00035 
00036 
00037 void GapeAudioOutput::setMute(bool b) {
00038     if (muted == b) return;
00039     if (b) {
00040         stop();
00041     } else {
00042         start();
00043     }
00044     muted = b;
00045     emit emitMute(b);
00046 }
00047 
00048 
00049 void GapeAudioOutput::stop() {
00050     #ifdef DIRECTX_API
00051         output->stopPlay();
00052     #endif
00053 }
00054 
00055 
00056 void GapeAudioOutput::start() {
00057     #ifdef DIRECTX_API
00058         output->startPlay();
00059     #endif
00060 }
00061 
00062 
00063 
00064 void GapeAudioOutput::receiveTick(const GapeFloat* values, int numValues) {
00065     static bool wrongNumberOfChannelsFlag = false;
00066     static bool waitingForGoodInput = false;
00067     static bool properInitializtionReportedFlag = false;
00068     int numToCopy, i;
00069     //char error[256];
00070 //sprintf(error,"GAO rectick values[0] = %f, num val = %d\n",values[0],numValues);
00071 //GapeConsts::reportError(error);
00072 
00073 
00074 //this next bit of code works around the property of windows audio where if it recieves no new input,
00075 //it will repeat the last buffer of data over and over again. We try to intelligently see if our sound has
00076 //been muted or otherwise shut off, and (temporarily) stop the windows audio thread if necesary
00077 //I also considered just sending zeros to the windows audio thread. Hmm.
00078     if ((values == NULL) || (numValues == 0)) {
00079         if (!waitingForGoodInput) {
00080             output->playBuffer(soundBuffer, soundBufferSize);
00081             currentBufferPosition = 0;
00082             stop();
00083             waitingForGoodInput = true;
00084             GapeConsts::reportError("GapeAudioOutput received a null tick and muted itself!\n");
00085         }
00086         emit emitTick(values, numValues);
00087         return;
00088 
00089     } else {
00090         if (waitingForGoodInput) {
00091             GapeConsts::reportError("GapeAudioOutput unmuted itself\n");
00092             start();
00093             waitingForGoodInput = false;
00094         }
00095     }
00096 
00097     if (!properlyInitialized) {
00098             if (!properInitializtionReportedFlag) {
00099                 properInitializtionReportedFlag = true;
00100                 GapeConsts::reportError("GapeAudioOutput was not properly initialized - *not* outputting sound to DAC!\n");
00101             }
00102         emit emitTick(values, numValues);
00103         return;
00104     }
00105 
00106     if (muted) {
00107             emit emitTick(values, numValues);
00108             return;
00109     }
00110 
00111     if (numValues == numChannels) {//if we have the right # of channels just play the sample and then emit it
00112         while (numValues > 0) {//some logic to ensure we have no buffer overflows
00113             if (numValues < (soundBufferSize - currentBufferPosition)) {
00114                 numToCopy = numValues;
00115             } else {
00116                 numToCopy = soundBufferSize - currentBufferPosition;
00117             }
00118             for (i = 0; i < numToCopy; i++) {
00119                 soundBuffer[currentBufferPosition + i] = GapeConsts::floatToInt(values[i]);//convert to integer and store
00120             }
00121             currentBufferPosition += numToCopy;
00122             numValues -= numToCopy;
00123             if (currentBufferPosition == (soundBufferSize)) {//if our internal buffer is full, we play the sample
00124                 output->playBuffer(soundBuffer, soundBufferSize);
00125                 currentBufferPosition = 0;
00126             }
00127         }/*
00128         for (i = 0;i < numValues; i++)
00129             soundBuffer[currentBufferPosition++] = (short)(values[i] * 32000.0);
00130         if (currentBufferPosition == (soundBufferSize - 1)) {//if our internal buffer is full, we play the sample
00131             output->playBuffer(soundBuffer, soundBufferSize);
00132             currentBufferPosition = 0;
00133         }*/
00134         emit emitTick(values,numValues);
00135 
00136     } else {//otherwise, we must copy the data into an acceptably sized sample
00137         GapeFloat sample[GAPE_MAX_NUM_CHANNELS] = {0.0};//this will init everything to 0
00138 
00139         if (!wrongNumberOfChannelsFlag) {//print an error if we haven't already
00140             GapeConsts::reportError("GapeAudioOutput was sent the wrong number of channels to play!\n");
00141             wrongNumberOfChannelsFlag = true;
00142         }
00143 
00144         if (numValues > numChannels) {//if we have too much data, only use as many channels as we can handle
00145             for (i = 0; i < numChannels; i++) {
00146                 sample[i] = values[i];
00147             }
00148 
00149         } else {//otherwise, only copy in the valid data, and leave the rest of the channels at 0
00150             for (i = 0; i < numValues; i++) {
00151                 sample[i] = values[i];
00152             }
00153         }
00154         receiveTick(sample, numChannels);//neatly use recursion to handle our acceptable converted sample
00155     }
00156 }

Generated at Thu Jun 21 13:28:49 2001 for GAPE by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001