Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/soundmanager.cpp

Go to the documentation of this file.
00001 
00008 /***************************************************************************
00009 *                                                                         *
00010 *   This program is free software; you can redistribute it and/or modify  *
00011 *   it under the terms of the GNU General Public License as published by  *
00012 *   the Free Software Foundation; either version 2 of the License, or     *
00013 *   (at your option) any later version.                                   *
00014 *                                                                         *
00015 ***************************************************************************/
00016 
00017 #include <QtDebug>
00018 #include <QtCore>
00019 #include <cstring> // for memcpy and strcmp
00020 
00021 #ifdef __PORTAUDIO__
00022 #include <portaudio.h>
00023 #endif // ifdef __PORTAUDIO__
00024 
00025 #include "soundmanager.h"
00026 #include "sounddevice.h"
00027 #include "sounddeviceportaudio.h"
00028 #include "engine/enginemaster.h"
00029 #include "engine/enginebuffer.h"
00030 #include "controlobjectthreadmain.h"
00031 #include "soundmanagerutil.h"
00032 #include "controlobject.h"
00033 
00034 #ifdef __PORTAUDIO__
00035 typedef PaError (*SetJackClientName)(const char *name);
00036 #endif
00037 
00042 SoundManager::SoundManager(ConfigObject<ConfigValue> *pConfig, EngineMaster *pMaster)
00043     : QObject()
00044     , m_pMaster(pMaster)
00045     , m_pConfig(pConfig)
00046     , m_pClkRefDevice(NULL)
00047     , m_outputDevicesOpened(0)
00048     , m_inputDevicesOpened(0)
00049     , m_pErrorDevice(NULL)
00050 #ifdef __PORTAUDIO__
00051    , m_paInitialized(false)
00052    , m_jackSampleRate(-1)
00053 #endif
00054 {
00055     //These are ControlObjectThreadMains because all the code that
00056     //uses them is called from the GUI thread (stuff like opening soundcards).
00057     // TODO(xxx) some of these ControlObject are not needed by soundmanager, or are unused here.
00058     // It is possible to take them out?    
00059     m_pControlObjectLatency = new ControlObjectThreadMain(ControlObject::getControl(ConfigKey("[Master]", "latency")));
00060     m_pControlObjectSampleRate = new ControlObjectThreadMain(ControlObject::getControl(ConfigKey("[Master]", "samplerate")));
00061     m_pControlObjectVinylControlMode = new ControlObjectThreadMain(new ControlObject(ConfigKey("[VinylControl]", "mode")));
00062     m_pControlObjectVinylControlMode1 = new ControlObjectThreadMain(ControlObject::getControl(ConfigKey("[Channel1]", "vinylcontrol_mode")));
00063     m_pControlObjectVinylControlMode2 = new ControlObjectThreadMain(ControlObject::getControl(ConfigKey("[Channel2]", "vinylcontrol_mode")));
00064     m_pControlObjectVinylControlGain = new ControlObjectThreadMain(new ControlObject(ConfigKey("[VinylControl]", "gain")));
00065 
00066     //Hack because PortAudio samplerate enumeration is slow as hell on Linux (ALSA dmix sucks, so we can't blame PortAudio)
00067     m_samplerates.push_back(44100);
00068     m_samplerates.push_back(48000);
00069     m_samplerates.push_back(96000);
00070 
00071     queryDevices(); // initializes PortAudio so SMConfig:loadDefaults can do
00072                     // its thing if it needs to
00073 
00074     if (!m_config.readFromDisk()) {
00075         m_config.loadDefaults(this, SoundManagerConfig::ALL);
00076     }
00077     checkConfig();
00078     m_config.writeToDisk(); // in case anything changed by applying defaults
00079 
00080     // TODO(bkgood) do these really need to be here? they're set in
00081     // SoundDevicePortAudio::open
00082     m_pControlObjectLatency->slotSet(
00083         m_config.getFramesPerBuffer() / m_config.getSampleRate() * 1000);
00084     m_pControlObjectSampleRate->slotSet(m_config.getSampleRate());
00085 }
00086 
00089 SoundManager::~SoundManager()
00090 {
00091     //Clean up devices.
00092     clearDeviceList();
00093 
00094 #ifdef __PORTAUDIO__
00095     if (m_paInitialized) {
00096         Pa_Terminate();
00097         m_paInitialized = false;
00098     }
00099 #endif
00100     // vinyl control proxies and input buffers are freed in closeDevices, called
00101     // by clearDeviceList -- bkgood
00102 
00103     delete m_pControlObjectLatency;
00104     delete m_pControlObjectSampleRate;
00105     delete m_pControlObjectVinylControlMode;
00106     delete m_pControlObjectVinylControlMode1;
00107     delete m_pControlObjectVinylControlMode2;
00108     delete m_pControlObjectVinylControlGain;
00109 }
00110 
00115 void SoundManager::clearOperativeVariables()
00116 {
00117     m_outputDevicesOpened = 0;
00118     m_inputDevicesOpened = 0;
00119     m_pClkRefDevice = NULL;
00120 }
00121 
00131 const EngineMaster* SoundManager::getEngine() const
00132 {
00133     return m_pMaster;
00134 }
00135 
00146 QList<SoundDevice*> SoundManager::getDeviceList(QString filterAPI, bool bOutputDevices, bool bInputDevices)
00147 {
00148     //qDebug() << "SoundManager::getDeviceList";
00149     bool bMatchedCriteria = true;   //Whether or not the current device matched the filtering criteria
00150 
00151     if (m_devices.empty())
00152         this->queryDevices();
00153 
00154     if (filterAPI == "None")
00155     {
00156         QList<SoundDevice*> emptyList;
00157         return emptyList;
00158     }
00159     else
00160     {
00161         //Create a list of sound devices filtered to match given API and input/output .
00162         QList<SoundDevice*> filteredDeviceList;
00163         QListIterator<SoundDevice*> dev_it(m_devices);
00164         while (dev_it.hasNext())
00165         {
00166             bMatchedCriteria = true;                //Reset this for the next device.
00167             SoundDevice *device = dev_it.next();
00168             if (device->getHostAPI() != filterAPI)
00169                 bMatchedCriteria = false;
00170             if (bOutputDevices)
00171             {
00172                  if (device->getNumOutputChannels() <= 0)
00173                     bMatchedCriteria = false;
00174             }
00175             if (bInputDevices)
00176             {
00177                 if (device->getNumInputChannels() <= 1) //Ignore mono input and no-input devices
00178                     bMatchedCriteria = false;
00179             }
00180 
00181             if (bMatchedCriteria)
00182                 filteredDeviceList.push_back(device);
00183         }
00184         return filteredDeviceList;
00185     }
00186 
00187     return m_devices;
00188 }
00189 
00193 QList<QString> SoundManager::getHostAPIList() const
00194 {
00195     QList<QString> apiList;
00196 
00197     for (PaHostApiIndex i = 0; i < Pa_GetHostApiCount(); i++)
00198     {
00199         const PaHostApiInfo *api = Pa_GetHostApiInfo(i);
00200         if (api) {
00201             if (QString(api->name) != "skeleton implementation") apiList.push_back(api->name);
00202         }
00203     }
00204 
00205     return apiList;
00206 }
00207 
00215 void SoundManager::closeDevices()
00216 {
00217     //qDebug() << "SoundManager::closeDevices()";
00218     QListIterator<SoundDevice*> dev_it(m_devices);
00219 
00220     //requestBufferMutex.lock(); //Ensures we don't kill a stream in the middle of a callback call.
00221                                  //Note: if we're using Pa_StopStream() (like now), we don't need
00222                                  //      to lock. PortAudio stops the threads nicely.
00223     while (dev_it.hasNext())
00224     {
00225         //qDebug() << "closing a device...";
00226         dev_it.next()->close();
00227     }
00228     //requestBufferMutex.unlock();
00229 
00230     //requestBufferMutex.lock();
00231     clearOperativeVariables();
00232     //requestBufferMutex.unlock();
00233 
00234     m_outputBuffers.clear(); // anti-cruft (safe because outputs only have
00235                              // pointers to memory owned by EngineMaster)
00236 
00237     foreach (AudioInput in, m_inputBuffers.keys()) {
00238         // Need to tell all registered AudioDestinations for this AudioInput
00239         // that the input was disconnected.
00240         if (m_registeredDestinations.contains(in)) {
00241             m_registeredDestinations[in]->onInputDisconnected(in);
00242         }
00243 
00244         short *buffer = m_inputBuffers[in];
00245         if (buffer != NULL) {
00246             delete [] buffer;
00247             m_inputBuffers[in] = buffer = NULL;
00248         }
00249     }
00250     m_inputBuffers.clear();
00251 }
00252 
00254 void SoundManager::clearDeviceList()
00255 {
00256     //qDebug() << "SoundManager::clearDeviceList()";
00257 
00258     //Close the devices first.
00259     closeDevices();
00260 
00261     //Empty out the list of devices we currently have.
00262     while (!m_devices.empty())
00263     {
00264         SoundDevice* dev = m_devices.takeLast();
00265         delete dev;
00266     }
00267 
00268 #ifdef __PORTAUDIO__
00269     if (m_paInitialized) {
00270         Pa_Terminate();
00271         m_paInitialized = false;
00272     }
00273 #endif
00274 }
00275 
00281 QList<unsigned int> SoundManager::getSampleRates(QString api) const
00282 {
00283 #ifdef __PORTAUDIO__
00284     if (api == MIXXX_PORTAUDIO_JACK_STRING) {
00285         // queryDevices must have been called for this to work, but the
00286         // ctor calls it -bkgood
00287         QList<unsigned int> samplerates;
00288         samplerates.append(m_jackSampleRate);
00289         return samplerates;
00290     }
00291 #endif
00292     return m_samplerates;
00293 }
00294 
00298 QList<unsigned int> SoundManager::getSampleRates() const
00299 {
00300     return getSampleRates("");
00301 }
00302 
00303 //Creates a list of sound devices that PortAudio sees.
00304 void SoundManager::queryDevices()
00305 {
00306     //qDebug() << "SoundManager::queryDevices()";
00307     clearDeviceList();
00308 
00309 #ifdef __PORTAUDIO__
00310     PaError err = paNoError;
00311     if (!m_paInitialized) {
00312 #ifdef Q_OS_LINUX
00313         setJACKName();
00314 #endif
00315         err = Pa_Initialize();
00316         m_paInitialized = true;
00317     }
00318     if (err != paNoError)
00319     {
00320         qDebug() << "Error:" << Pa_GetErrorText(err);
00321         m_paInitialized = false;
00322         return;
00323     }
00324 
00325     int iNumDevices;
00326     iNumDevices = Pa_GetDeviceCount();
00327     if(iNumDevices < 0)
00328     {
00329         qDebug() << "ERROR: Pa_CountDevices returned" << iNumDevices;
00330         return;
00331     }
00332 
00333     const PaDeviceInfo* deviceInfo;
00334     for (int i = 0; i < iNumDevices; i++)
00335     {
00336         deviceInfo = Pa_GetDeviceInfo(i);
00337         if (!deviceInfo)
00338             continue;
00339         /* deviceInfo fields for quick reference:
00340             int         structVersion
00341             const char *        name
00342             PaHostApiIndex      hostApi
00343             int         maxInputChannels
00344             int         maxOutputChannels
00345             PaTime      defaultLowInputLatency
00346             PaTime      defaultLowOutputLatency
00347             PaTime      defaultHighInputLatency
00348             PaTime      defaultHighOutputLatency
00349             double      defaultSampleRate
00350          */
00351         SoundDevicePortAudio *currentDevice = new SoundDevicePortAudio(m_pConfig, this, deviceInfo, i);
00352         m_devices.push_back(currentDevice);
00353         if (!strcmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name,
00354                     MIXXX_PORTAUDIO_JACK_STRING)) {
00355             m_jackSampleRate = deviceInfo->defaultSampleRate;
00356         }
00357     }
00358 #endif
00359     // now tell the prefs that we updated the device list -- bkgood
00360     emit(devicesUpdated());
00361 }
00362 
00363 //Opens all the devices chosen by the user in the preferences dialog, and establishes
00364 //the proper connections between them and the mixing engine.
00365 int SoundManager::setupDevices()
00366 {
00367     qDebug() << "SoundManager::setupDevices()";
00368     int err = 0;
00369     clearOperativeVariables();
00370     int devicesAttempted = 0;
00371     int devicesOpened = 0;
00372     // pair is isInput, isOutput
00373     QHash<SoundDevice*, QPair<bool, bool> > toOpen;
00374 
00375     // filter out any devices in the config we don't actually have
00376     m_config.filterOutputs(this);
00377     m_config.filterInputs(this);
00378 
00379     // close open devices, close running vinyl control proxies
00380     closeDevices();
00381     foreach (SoundDevice *device, m_devices) {
00382         bool isInput = false;
00383         bool isOutput = false;
00384         device->clearInputs();
00385         device->clearOutputs();
00386         m_pErrorDevice = device;
00387         foreach (AudioInput in, m_config.getInputs().values(device->getInternalName())) {
00388             isInput = true;
00389             err = device->addInput(in);
00390             if (err != OK) goto closeAndError;
00391             if (!m_inputBuffers.contains(in)) {
00392                 // TODO(bkgood) look into allocating this with the frames per
00393                 // buffer value from SMConfig
00394                 m_inputBuffers[in] = new short[MAX_BUFFER_LEN];
00395             }
00396 
00397             // Check if any AudioDestination is registered for this AudioInput,
00398             // and call the onInputConnected method.
00399             if (m_registeredDestinations.contains(in)) {
00400                 m_registeredDestinations[in]->onInputConnected(in);
00401             }
00402         }
00403         foreach (AudioOutput out, m_config.getOutputs().values(device->getInternalName())) {
00404             isOutput = true;
00405             // following keeps us from asking for a channel buffer EngineMaster
00406             // doesn't have -- bkgood
00407             if (m_registeredSources[out]->buffer(out) == NULL) {
00408                 qDebug() << "AudioSource returned null for" << out.getString();
00409                 continue;
00410             }
00411             err = device->addOutput(out);
00412             if (err != OK) goto closeAndError;
00413             m_outputBuffers[out] = m_registeredSources[out]->buffer(out);
00414             if (out.getType() == AudioOutput::MASTER) {
00415                 m_pClkRefDevice = device;
00416             } else if (out.getType() == AudioOutput::DECK
00417                     && !m_pClkRefDevice) {
00418                 m_pClkRefDevice = device;
00419             }
00420         }
00421         if (isInput || isOutput) {
00422             device->setSampleRate(m_config.getSampleRate());
00423             device->setFramesPerBuffer(m_config.getFramesPerBuffer());
00424             toOpen[device] = QPair<bool, bool>(isInput, isOutput);
00425         }
00426     }
00427     foreach (SoundDevice *device, toOpen.keys()) {
00428         QPair<bool, bool> mode(toOpen[device]);
00429         bool isInput(mode.first);
00430         bool isOutput(mode.second);
00431         ++devicesAttempted;
00432         m_pErrorDevice = device;
00433         err = device->open();
00434         if (err != OK) {
00435             goto closeAndError;
00436         } else {
00437             ++devicesOpened;
00438             if (isOutput)
00439                 ++m_outputDevicesOpened;
00440             if (isInput)
00441                 ++m_inputDevicesOpened;
00442         }
00443     }
00444 
00445     if (!m_pClkRefDevice && m_outputDevicesOpened > 0) {
00446         QList<SoundDevice*> outputDevices = getDeviceList(m_config.getAPI(), true, false);
00447         Q_ASSERT(outputDevices.length());
00448         SoundDevice* device = outputDevices.first();
00449         qWarning() << "Output sound device clock reference not set! Using"
00450             << device->getDisplayName();
00451         m_pClkRefDevice = device;
00452     } else if (m_outputDevicesOpened > 0) {
00453         qDebug() << "Using" << m_pClkRefDevice->getDisplayName()
00454             << "as output sound device clock reference";
00455     } else {
00456         qDebug() << "No output devices opened, no clock reference device set";
00457     }
00458 
00459     qDebug() << m_outputDevicesOpened << "output sound devices opened";
00460     qDebug() << m_inputDevicesOpened << "input  sound devices opened";
00461 
00462     // returns OK if we were able to open all the devices the user
00463     // wanted
00464     if (devicesAttempted == devicesOpened) {
00465         emit(devicesSetup());
00466         return OK;
00467     }
00468     m_pErrorDevice = NULL;
00469     return ERR;
00470 closeAndError:
00471     closeDevices();
00472     return err;
00473 }
00474 
00475 SoundDevice* SoundManager::getErrorDevice() const {
00476     return m_pErrorDevice;
00477 }
00478 
00479 SoundManagerConfig SoundManager::getConfig() const {
00480     return m_config;
00481 }
00482 
00483 int SoundManager::setConfig(SoundManagerConfig config) {
00484     int err = OK;
00485     m_config = config;
00486     checkConfig();
00487 
00488     // certain parts of mixxx rely on this being here, for the time being, just
00489     // letting those be -- bkgood
00490     // Do this first so vinyl control gets the right samplerate -- Owen W.
00491     m_pConfig->set(ConfigKey("[Soundcard]","Samplerate"), ConfigValue(m_config.getSampleRate()));
00492 
00493     err = setupDevices();
00494     if (err == OK) {
00495         m_config.writeToDisk();
00496     }
00497     return err;
00498 }
00499 
00500 void SoundManager::checkConfig() {
00501     if (!m_config.checkAPI(*this)) {
00502         m_config.setAPI(SoundManagerConfig::kDefaultAPI);
00503         m_config.loadDefaults(this, SoundManagerConfig::API | SoundManagerConfig::DEVICES);
00504     }
00505     if (!m_config.checkSampleRate(*this)) {
00506         m_config.setSampleRate(SoundManagerConfig::kDefaultSampleRate);
00507         m_config.loadDefaults(this, SoundManagerConfig::OTHER);
00508     }
00509     // latency checks itself for validity on SMConfig::setLatency()
00510 }
00511 
00512 //Requests a buffer in the proper format, if we're prepared to give one.
00513 QHash<AudioOutput, const CSAMPLE*>
00514 SoundManager::requestBuffer(QList<AudioOutput> outputs,
00515     unsigned long iFramesPerBuffer, SoundDevice* device,
00516     double streamTime /* = 0 */)
00517 {
00518     Q_UNUSED(outputs); // unused, we just give the caller the full hash -bkgood
00519     //qDebug() << "SoundManager::requestBuffer()";
00520 
00521     /*
00522     // Display when sound cards drop or duplicate buffers (use for testing only)
00523     if (iNumDevicesOpenedForOutput>1) {
00524         // Running total of requested frames
00525         long currentFrameCount = 0;
00526         if (m_deviceFrameCount.contains(device)) currentFrameCount=m_deviceFrameCount.value(device);
00527         m_deviceFrameCount.insert(device, currentFrameCount+iFramesPerBuffer);  // Overwrites existing value if already present
00528         // Get current time in milliseconds
00529 //         uint t = QDateTime::currentDateTime().toTime_t()*1000+QDateTime::currentDateTime().toString("zzz").toUint();
00530 
00531         if (device != m_pClkRefDevice) {  // If not the reference device,
00532             // Detect dropped frames/buffers
00533             long sdifference = m_deviceFrameCount.value(m_pClkRefDevice)-m_deviceFrameCount.value(device);
00534             QString message = "dropped";
00535             if (sdifference < 0) message = "duplicated";
00536             if (sdifference != 0) {
00537                 m_deviceFrameCount.clear();
00538                 message = QString("%1 %2 %3 frames (%4 buffers)")
00539                             .arg(device->getDisplayName())
00540                             .arg(message)
00541                             .arg(fabs(sdifference))
00542                             .arg(fabs(sdifference)/iFramesPerBuffer);
00543                 qWarning() << message;
00544             }
00545         }
00546     }
00547     //  End dropped/duped buffer display
00548     */
00549 
00550     //When the clock reference device requests a buffer...
00551     if (device == m_pClkRefDevice && requestBufferMutex.tryLock())
00552     {
00553         // Only generate a new buffer for the clock reference card
00554 //         qDebug() << "New buffer for" << device->getDisplayName() << "of size" << iFramesPerBuffer;
00555 
00556         //Process a block of samples for output. iFramesPerBuffer is the
00557         //number of samples for one channel, but the EngineObject
00558         //architecture expects number of samples for two channels
00559         //as input (buffer size) so...
00560         m_pMaster->process(0, 0, iFramesPerBuffer*2);
00561 
00562         requestBufferMutex.unlock();
00563     }
00564     return m_outputBuffers;
00565 }
00566 
00567 //Used by SoundDevices to "push" any audio from their inputs that they have into the mixing engine.
00568 void SoundManager::pushBuffer(QList<AudioInput> inputs, short * inputBuffer,
00569                               unsigned long iFramesPerBuffer, unsigned int iFrameSize)
00570 {
00571     //This function is called a *lot* and is a big source of CPU usage.
00572     //It needs to be very fast.
00573 
00574 //    m_inputBuffers[RECEIVER_VINYLCONTROL_ONE]
00575 
00576     //short vinylControlBuffer1[iFramesPerBuffer * 2];
00577     //short vinylControlBuffer2[iFramesPerBuffer * 2];
00578     //short *vinylControlBuffer1 = (short*) alloca(iFramesPerBuffer * 2 * sizeof(short));
00579     //short *vinylControlBuffer2 = (short*) alloca(iFramesPerBuffer * 2 * sizeof(short));
00580 
00581     //memset(vinylControlBuffer1, 0, iFramesPerBuffer * iFrameSize * sizeof(*vinylControlBuffer1));
00582 
00583     // IMPORTANT -- Mixxx should ALWAYS be the owner of whatever input buffer we're using,
00584     // otherwise we double-free (well, PortAudio frees and then we free) and everything
00585     // goes to hell -- bkgood
00586 
00590     // this special casing is probably not worth keeping around. It had a speed
00591     // advantage before because it just assigned a pointer instead of copying data,
00592     // but this meant we couldn't free all the receiver buffer pointers, because some
00593     // of them might potentially be owned by portaudio. Not freeing them means we leak
00594     // memory in certain cases -- bkgood
00595     if (iFrameSize == 2)
00596     {
00597         for (QList<AudioInput>::const_iterator i = inputs.begin(),
00598                      e = inputs.end(); i != e; ++i) {
00599             const AudioInput& in = *i;
00600             memcpy(m_inputBuffers[in], inputBuffer,
00601                    sizeof(*inputBuffer) * iFrameSize * iFramesPerBuffer);
00602         }
00603     }
00604 
00605 /*
00606     //If we have two stereo input streams (interlaced as one), then
00607     //break them up into two separate interlaced streams
00608     if (iFrameSize == 4)
00609     {
00610         for (int i = 0; i < iFramesPerBuffer; i++) //For each frame of audio
00611         {
00612             m_inputBuffers[RECEIVER_VINYLCONTROL_ONE][i*2    ] = inputBuffer[i*iFrameSize    ];
00613             m_inputBuffers[RECEIVER_VINYLCONTROL_ONE][i*2 + 1] = inputBuffer[i*iFrameSize + 1];
00614             m_inputBuffers[RECEIVER_VINYLCONTROL_TWO][i*2    ] = inputBuffer[i*iFrameSize + 2];
00615             m_inputBuffers[RECEIVER_VINYLCONTROL_TWO][i*2 + 1] = inputBuffer[i*iFrameSize + 3];
00616         }
00617         //Set the pointers to point to the de-interlaced input audio
00618         vinylControlBuffer1 = m_inputBuffers[RECEIVER_VINYLCONTROL_ONE];
00619         vinylControlBuffer2 = m_inputBuffers[RECEIVER_VINYLCONTROL_TWO];
00620     }
00621 */
00622     else { //More than two channels of input (iFrameSize > 2)
00623 
00624         // Do crazy deinterleaving of the audio into the correct m_inputBuffers.
00625 
00626         for (QList<AudioInput>::const_iterator i = inputs.begin(),
00627                      e = inputs.end(); i != e; ++i) {
00628             const AudioInput& in = *i;
00629             short* pInputBuffer = m_inputBuffers[in];
00630             ChannelGroup chanGroup = in.getChannelGroup();
00631             int iChannelCount = chanGroup.getChannelCount();
00632             int iChannelBase = chanGroup.getChannelBase();
00633 
00634             for (unsigned int iFrameNo = 0; iFrameNo < iFramesPerBuffer; ++iFrameNo) {
00635                 // iFrameBase is the "base sample" in a frame (ie. the first
00636                 // sample in a frame)
00637                 unsigned int iFrameBase = iFrameNo * iFrameSize;
00638                 unsigned int iLocalFrameBase = iFrameNo * iChannelCount;
00639 
00640                 // this will make sure a sample from each channel is copied
00641                 for (int iChannel = 0; iChannel < iChannelCount; ++iChannel) {
00642                     //output[iFrameBase + src.channelBase + iChannel] +=
00643                     //  outputAudio[src.type][iLocalFrameBase + iChannel] * SHRT_CONVERSION_FACTOR;
00644 
00645                     pInputBuffer[iLocalFrameBase + iChannel] =
00646                             inputBuffer[iFrameBase + iChannelBase + iChannel];
00647                 }
00648             }
00649         }
00650     }
00651 
00652     if (inputBuffer)
00653     {
00654         for (QList<AudioInput>::ConstIterator i = inputs.begin(),
00655                      e = inputs.end(); i != e; ++i) {
00656             const AudioInput& in = *i;
00657 
00658             // Sanity check.
00659             if (!m_inputBuffers.contains(in)) {
00660                 continue;
00661             }
00662 
00663             short* pInputBuffer = m_inputBuffers[in];
00664 
00665             if (m_registeredDestinations.contains(in)) {
00666                 AudioDestination* destination = m_registeredDestinations[in];
00667                 if (destination) {
00668                     destination->receiveBuffer(in, pInputBuffer, iFramesPerBuffer);
00669                 }
00670             }
00671         }
00672     }
00673     //TODO: Add pass-through option here (and push it into EngineMaster)...
00674     //      (or maybe save it, and then have requestBuffer() push it into EngineMaster)...
00675 }
00676 
00677 void SoundManager::registerOutput(AudioOutput output, const AudioSource *src) {
00678     if (m_registeredSources.contains(output)) {
00679         qDebug() << "WARNING: AudioOutput already registered!";
00680     }
00681     m_registeredSources[output] = src;
00682     emit(outputRegistered(output, src));
00683 }
00684 
00685 void SoundManager::registerInput(AudioInput input, AudioDestination *dest) {
00686     if (m_registeredDestinations.contains(input)) {
00687         // note that this can be totally ok if we just want a certain
00688         // AudioInput to be going to a different AudioDest -bkgood
00689         qDebug() << "WARNING: AudioInput already registered!";
00690     }
00691     m_registeredDestinations[input] = dest;
00692     emit(inputRegistered(input, dest));
00693 }
00694 
00695 QList<AudioOutput> SoundManager::registeredOutputs() const {
00696     return m_registeredSources.keys();
00697 }
00698 
00699 QList<AudioInput> SoundManager::registeredInputs() const {
00700     return m_registeredDestinations.keys();
00701 }
00702 
00703 void SoundManager::setJACKName() const {
00704 #ifdef __PORTAUDIO__
00705 #ifdef Q_OS_LINUX
00706     typedef PaError (*SetJackClientName)(const char *name);
00707     QLibrary portaudio("libportaudio.so.2");
00708     if (portaudio.load()) {
00709         SetJackClientName func(
00710             reinterpret_cast<SetJackClientName>(
00711                 portaudio.resolve("PaJack_SetClientName")));
00712         if (func) {
00713             if (!func("Mixxx")) qDebug() << "JACK client name set";
00714         } else {
00715             qWarning() << "failed to resolve JACK name method";
00716         }
00717     } else {
00718         qWarning() << "failed to load portaudio for JACK rename";
00719     }
00720 #endif
00721 #endif
00722 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines