![]() |
Mixxx
|
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 }