1 /******************************************************************************\
2 * Copyright (c) 2004-2020
3 *
4 * Author(s):
5 * Volker Fischer
6 *
7 * Description:
8 * Sound card interface for Windows operating systems
9 *
10 ******************************************************************************
11 *
12 * This program is free software; you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option) any later
15 * version.
16 *
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 *
26 \******************************************************************************/
27
28 #include "sound.h"
29
30 /* Implementation *************************************************************/
31 // external references
32 extern AsioDrivers* asioDrivers;
33 bool loadAsioDriver ( char* name );
34
35 // pointer to our sound object
36 CSound* pSound;
37
38 /******************************************************************************\
39 * Common *
40 \******************************************************************************/
LoadAndInitializeDriver(QString strDriverName,bool bOpenDriverSetup)41 QString CSound::LoadAndInitializeDriver ( QString strDriverName, bool bOpenDriverSetup )
42 {
43 // find and load driver
44 int iDriverIdx = INVALID_INDEX; // initialize with an invalid index
45
46 for ( int i = 0; i < MAX_NUMBER_SOUND_CARDS; i++ )
47 {
48 if ( strDriverName.compare ( cDriverNames[i] ) == 0 )
49 {
50 iDriverIdx = i;
51 }
52 }
53
54 // if the selected driver was not found, return an error message
55 if ( iDriverIdx == INVALID_INDEX )
56 {
57 return tr ( "The selected audio device is no longer present in the system. Please check your audio device." );
58 }
59
60 // Save number of channels from last driver
61 // Need to save these (but not the driver name) as CheckDeviceCapabilities() overwrites them
62 long lNumInChanPrev = lNumInChan;
63 long lNumOutChanPrev = lNumOutChan;
64
65 loadAsioDriver ( cDriverNames[iDriverIdx] );
66
67 // According to the docs, driverInfo.asioVersion and driverInfo.sysRef
68 // should be set, but we haven't being doing that and it seems to work
69 // okay...
70 memset ( &driverInfo, 0, sizeof driverInfo );
71
72 if ( ASIOInit ( &driverInfo ) != ASE_OK )
73 {
74 // clean up and return error string
75 asioDrivers->removeCurrentDriver();
76 return tr ( "Couldn't initialise the audio driver. Check if your audio hardware is plugged in and verify your driver settings." );
77 }
78
79 // check device capabilities if it fulfills our requirements
80 const QString strStat = CheckDeviceCapabilities(); // also sets lNumInChan and lNumOutChan
81
82 // check if device is capable
83 if ( strStat.isEmpty() )
84 {
85 // Reset channel mapping if the sound card name has changed or the number of channels has changed
86 if ( ( strCurDevName.compare ( strDriverNames[iDriverIdx] ) != 0 ) || ( lNumInChanPrev != lNumInChan ) || ( lNumOutChanPrev != lNumOutChan ) )
87 {
88 // In order to fix https://github.com/jamulussoftware/jamulus/issues/796
89 // this code runs after a change in the ASIO driver (not when changing the ASIO input selection.)
90
91 // mapping to the defaults (first two available channels)
92 ResetChannelMapping();
93
94 // store ID of selected driver if initialization was successful
95 strCurDevName = cDriverNames[iDriverIdx];
96 }
97 }
98 else
99 {
100 // if requested, open ASIO driver setup in case of an error
101 if ( bOpenDriverSetup )
102 {
103 OpenDriverSetup();
104 QMessageBox::question ( nullptr,
105 APP_NAME,
106 "Are you done with your ASIO driver settings of " + GetDeviceName ( iDriverIdx ) + "?",
107 QMessageBox::Yes );
108 }
109
110 // driver cannot be used, clean up
111 asioDrivers->removeCurrentDriver();
112 }
113
114 return strStat;
115 }
116
UnloadCurrentDriver()117 void CSound::UnloadCurrentDriver()
118 {
119 // clean up ASIO stuff
120 if ( bRun )
121 {
122 Stop();
123 }
124 if ( bufferInfos[0].buffers[0] )
125 {
126 ASIODisposeBuffers();
127 bufferInfos[0].buffers[0] = NULL;
128 }
129 ASIOExit();
130 asioDrivers->removeCurrentDriver();
131 }
132
CheckDeviceCapabilities()133 QString CSound::CheckDeviceCapabilities()
134 {
135 // This function checks if our required input/output channel
136 // properties are supported by the selected device. If the return
137 // string is empty, the device can be used, otherwise the error
138 // message is returned.
139
140 // check the sample rate
141 const ASIOError CanSaRateReturn = ASIOCanSampleRate ( SYSTEM_SAMPLE_RATE_HZ );
142
143 if ( ( CanSaRateReturn == ASE_NoClock ) || ( CanSaRateReturn == ASE_NotPresent ) )
144 {
145 // return error string
146 return QString ( tr ( "The selected audio device is incompatible "
147 "since it doesn't support a sample rate of %1 Hz. Please select another "
148 "device." ) )
149 .arg ( SYSTEM_SAMPLE_RATE_HZ );
150 }
151
152 // check if sample rate can be set
153 const ASIOError SetSaRateReturn = ASIOSetSampleRate ( SYSTEM_SAMPLE_RATE_HZ );
154
155 if ( ( SetSaRateReturn == ASE_NoClock ) || ( SetSaRateReturn == ASE_InvalidMode ) || ( SetSaRateReturn == ASE_NotPresent ) )
156 {
157 // return error string
158 return QString ( tr ( "The current audio device configuration is incompatible "
159 "because the sample rate couldn't be set to %2 Hz. Please check for a hardware switch or "
160 "driver setting to set the sample rate manually and restart %1." ) )
161 .arg ( APP_NAME )
162 .arg ( SYSTEM_SAMPLE_RATE_HZ );
163 }
164
165 // check the number of available channels
166 ASIOGetChannels ( &lNumInChan, &lNumOutChan );
167
168 if ( ( lNumInChan < NUM_IN_OUT_CHANNELS ) || ( lNumOutChan < NUM_IN_OUT_CHANNELS ) )
169 {
170 // return error string
171 return QString ( tr ( "The selected audio device is incompatible since it doesn't support "
172 "%1 in/out channels. Please select another device or configuration." ) )
173 .arg ( NUM_IN_OUT_CHANNELS );
174 }
175
176 // clip number of input/output channels to our maximum
177 if ( lNumInChan > MAX_NUM_IN_OUT_CHANNELS )
178 {
179 lNumInChan = MAX_NUM_IN_OUT_CHANNELS;
180 }
181 if ( lNumOutChan > MAX_NUM_IN_OUT_CHANNELS )
182 {
183 lNumOutChan = MAX_NUM_IN_OUT_CHANNELS;
184 }
185
186 // query channel infos for all available input channels
187 bool bInputChMixingSupported = true;
188
189 for ( int i = 0; i < lNumInChan; i++ )
190 {
191 // setup for input channels
192 channelInfosInput[i].isInput = ASIOTrue;
193 channelInfosInput[i].channel = i;
194
195 ASIOGetChannelInfo ( &channelInfosInput[i] );
196
197 // Check supported sample formats.
198 // Actually, it would be enough to have at least two channels which
199 // support the required sample format. But since we have support for
200 // all known sample types, the following check should always pass and
201 // therefore we throw the error message on any channel which does not
202 // fulfill the sample format requirement (quick hack solution).
203 if ( !CheckSampleTypeSupported ( channelInfosInput[i].type ) )
204 {
205 // return error string
206 return tr ( "The selected audio device is incompatible since "
207 "the required audio sample format isn't available. Please use another device." );
208 }
209
210 // store the name of the channel and check if channel mixing is supported
211 channelInputName[i] = channelInfosInput[i].name;
212
213 if ( !CheckSampleTypeSupportedForCHMixing ( channelInfosInput[i].type ) )
214 {
215 bInputChMixingSupported = false;
216 }
217 }
218
219 // query channel infos for all available output channels
220 for ( int i = 0; i < lNumOutChan; i++ )
221 {
222 // setup for output channels
223 channelInfosOutput[i].isInput = ASIOFalse;
224 channelInfosOutput[i].channel = i;
225
226 ASIOGetChannelInfo ( &channelInfosOutput[i] );
227
228 // Check supported sample formats.
229 // Actually, it would be enough to have at least two channels which
230 // support the required sample format. But since we have support for
231 // all known sample types, the following check should always pass and
232 // therefore we throw the error message on any channel which does not
233 // fulfill the sample format requirement (quick hack solution).
234 if ( !CheckSampleTypeSupported ( channelInfosOutput[i].type ) )
235 {
236 // return error string
237 return tr ( "The selected audio device is incompatible since "
238 "the required audio sample format isn't available. Please use another device." );
239 }
240 }
241
242 // special case with 4 input channels: support adding channels
243 if ( ( lNumInChan == 4 ) && bInputChMixingSupported )
244 {
245 // add four mixed channels (i.e. 4 normal, 4 mixed channels)
246 lNumInChanPlusAddChan = 8;
247
248 for ( int iCh = 0; iCh < lNumInChanPlusAddChan; iCh++ )
249 {
250 int iSelCH, iSelAddCH;
251
252 GetSelCHAndAddCH ( iCh, lNumInChan, iSelCH, iSelAddCH );
253
254 if ( iSelAddCH >= 0 )
255 {
256 // for mixed channels, show both audio channel names to be mixed
257 channelInputName[iCh] = channelInputName[iSelCH] + " + " + channelInputName[iSelAddCH];
258 }
259 }
260 }
261 else
262 {
263 // regular case: no mixing input channels used
264 lNumInChanPlusAddChan = lNumInChan;
265 }
266
267 // everything is ok, return empty string for "no error" case
268 return "";
269 }
270
SetLeftInputChannel(const int iNewChan)271 void CSound::SetLeftInputChannel ( const int iNewChan )
272 {
273 // apply parameter after input parameter check
274 if ( ( iNewChan >= 0 ) && ( iNewChan < lNumInChanPlusAddChan ) )
275 {
276 vSelectedInputChannels[0] = iNewChan;
277 }
278 }
279
SetRightInputChannel(const int iNewChan)280 void CSound::SetRightInputChannel ( const int iNewChan )
281 {
282 // apply parameter after input parameter check
283 if ( ( iNewChan >= 0 ) && ( iNewChan < lNumInChanPlusAddChan ) )
284 {
285 vSelectedInputChannels[1] = iNewChan;
286 }
287 }
288
SetLeftOutputChannel(const int iNewChan)289 void CSound::SetLeftOutputChannel ( const int iNewChan )
290 {
291 // apply parameter after input parameter check
292 if ( ( iNewChan >= 0 ) && ( iNewChan < lNumOutChan ) )
293 {
294 vSelectedOutputChannels[0] = iNewChan;
295 }
296 }
297
SetRightOutputChannel(const int iNewChan)298 void CSound::SetRightOutputChannel ( const int iNewChan )
299 {
300 // apply parameter after input parameter check
301 if ( ( iNewChan >= 0 ) && ( iNewChan < lNumOutChan ) )
302 {
303 vSelectedOutputChannels[1] = iNewChan;
304 }
305 }
306
GetActualBufferSize(const int iDesiredBufferSizeMono)307 int CSound::GetActualBufferSize ( const int iDesiredBufferSizeMono )
308 {
309 int iActualBufferSizeMono;
310
311 // query the usable buffer sizes
312 ASIOGetBufferSize ( &HWBufferInfo.lMinSize, &HWBufferInfo.lMaxSize, &HWBufferInfo.lPreferredSize, &HWBufferInfo.lGranularity );
313
314 // clang-format off
315 /*
316 // TEST
317 #include <QMessageBox>
318 QMessageBox::information ( 0, "APP_NAME", QString("lMinSize: %1, lMaxSize: %2, lPreferredSize: %3, lGranularity: %4").
319 arg(HWBufferInfo.lMinSize).arg(HWBufferInfo.lMaxSize).arg(HWBufferInfo.lPreferredSize).arg(HWBufferInfo.lGranularity) );
320 _exit(1);
321 */
322 // clang-format on
323
324 // clang-format off
325 // TODO see https://github.com/EddieRingle/portaudio/blob/master/src/hostapi/asio/pa_asio.cpp#L1654 (SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer)
326 // clang-format on
327
328 // calculate "nearest" buffer size and set internal parameter accordingly
329 // first check minimum and maximum values
330 if ( iDesiredBufferSizeMono <= HWBufferInfo.lMinSize )
331 {
332 iActualBufferSizeMono = HWBufferInfo.lMinSize;
333 }
334 else
335 {
336 if ( iDesiredBufferSizeMono >= HWBufferInfo.lMaxSize )
337 {
338 iActualBufferSizeMono = HWBufferInfo.lMaxSize;
339 }
340 else
341 {
342 // ASIO SDK 2.2: "Notes: When minimum and maximum buffer size are
343 // equal, the preferred buffer size has to be the same value as
344 // well; granularity should be 0 in this case."
345 if ( HWBufferInfo.lMinSize == HWBufferInfo.lMaxSize )
346 {
347 iActualBufferSizeMono = HWBufferInfo.lMinSize;
348 }
349 else
350 {
351 if ( ( HWBufferInfo.lGranularity < -1 ) || ( HWBufferInfo.lGranularity == 0 ) )
352 {
353 // Special case (seen for EMU audio cards): granularity is
354 // zero or less than zero (make sure to exclude the special
355 // case of -1).
356 // There is no definition of this case in the ASIO SDK
357 // document. We assume here that all buffer sizes in between
358 // minimum and maximum buffer sizes are allowed.
359 iActualBufferSizeMono = iDesiredBufferSizeMono;
360 }
361 else
362 {
363 // General case --------------------------------------------
364 // initialization
365 int iTrialBufSize = HWBufferInfo.lMinSize;
366 int iLastTrialBufSize = HWBufferInfo.lMinSize;
367 bool bSizeFound = false;
368
369 // test loop
370 while ( ( iTrialBufSize <= HWBufferInfo.lMaxSize ) && ( !bSizeFound ) )
371 {
372 if ( iTrialBufSize >= iDesiredBufferSizeMono )
373 {
374 // test which buffer size fits better: the old one or the
375 // current one
376 if ( ( iTrialBufSize - iDesiredBufferSizeMono ) > ( iDesiredBufferSizeMono - iLastTrialBufSize ) )
377 {
378 iTrialBufSize = iLastTrialBufSize;
379 }
380
381 // exit while loop
382 bSizeFound = true;
383 }
384
385 if ( !bSizeFound )
386 {
387 // store old trial buffer size
388 iLastTrialBufSize = iTrialBufSize;
389
390 // increment trial buffer size (check for special
391 // case first)
392 if ( HWBufferInfo.lGranularity == -1 )
393 {
394 // special case: buffer sizes are a power of 2
395 iTrialBufSize *= 2;
396 }
397 else
398 {
399 iTrialBufSize += HWBufferInfo.lGranularity;
400 }
401 }
402 }
403
404 // clip trial buffer size (it may happen in the while
405 // routine that "iTrialBufSize" is larger than "lMaxSize" in
406 // case "lMaxSize - lMinSize" is not divisible by the
407 // granularity)
408 if ( iTrialBufSize > HWBufferInfo.lMaxSize )
409 {
410 iTrialBufSize = HWBufferInfo.lMaxSize;
411 }
412
413 // set ASIO buffer size
414 iActualBufferSizeMono = iTrialBufSize;
415 }
416 }
417 }
418 }
419
420 return iActualBufferSizeMono;
421 }
422
Init(const int iNewPrefMonoBufferSize)423 int CSound::Init ( const int iNewPrefMonoBufferSize )
424 {
425 ASIOMutex.lock(); // get mutex lock
426 {
427 // get the actual sound card buffer size which is supported
428 // by the audio hardware
429 iASIOBufferSizeMono = GetActualBufferSize ( iNewPrefMonoBufferSize );
430
431 // init base class
432 CSoundBase::Init ( iASIOBufferSizeMono );
433
434 // set internal buffer size value and calculate stereo buffer size
435 iASIOBufferSizeStereo = 2 * iASIOBufferSizeMono;
436
437 // set the sample rate
438 ASIOSetSampleRate ( SYSTEM_SAMPLE_RATE_HZ );
439
440 // create memory for intermediate audio buffer
441 vecsMultChanAudioSndCrd.Init ( iASIOBufferSizeStereo );
442
443 // create and activate ASIO buffers (buffer size in samples),
444 // dispose old buffers (if any)
445 ASIODisposeBuffers();
446
447 // prepare input channels
448 for ( int i = 0; i < lNumInChan; i++ )
449 {
450 bufferInfos[i].isInput = ASIOTrue;
451 bufferInfos[i].channelNum = i;
452 bufferInfos[i].buffers[0] = 0;
453 bufferInfos[i].buffers[1] = 0;
454 }
455
456 // prepare output channels
457 for ( int i = 0; i < lNumOutChan; i++ )
458 {
459 bufferInfos[lNumInChan + i].isInput = ASIOFalse;
460 bufferInfos[lNumInChan + i].channelNum = i;
461 bufferInfos[lNumInChan + i].buffers[0] = 0;
462 bufferInfos[lNumInChan + i].buffers[1] = 0;
463 }
464
465 ASIOCreateBuffers ( bufferInfos, lNumInChan + lNumOutChan, iASIOBufferSizeMono, &asioCallbacks );
466
467 // query the latency of the driver
468 long lInputLatency = 0;
469 long lOutputLatency = 0;
470
471 if ( ASIOGetLatencies ( &lInputLatency, &lOutputLatency ) != ASE_NotPresent )
472 {
473 // add the input and output latencies (returned in number of
474 // samples) and calculate the time in ms
475 fInOutLatencyMs = ( static_cast<float> ( lInputLatency ) + lOutputLatency ) * 1000 / SYSTEM_SAMPLE_RATE_HZ;
476 }
477 else
478 {
479 // no latency available
480 fInOutLatencyMs = 0.0f;
481 }
482
483 // check whether the driver requires the ASIOOutputReady() optimization
484 // (can be used by the driver to reduce output latency by one block)
485 bASIOPostOutput = ( ASIOOutputReady() == ASE_OK );
486 }
487 ASIOMutex.unlock();
488
489 return iASIOBufferSizeMono;
490 }
491
Start()492 void CSound::Start()
493 {
494 // start audio
495 ASIOStart();
496
497 // call base class
498 CSoundBase::Start();
499 }
500
Stop()501 void CSound::Stop()
502 {
503 // stop audio
504 ASIOStop();
505
506 // call base class
507 CSoundBase::Stop();
508
509 // make sure the working thread is actually done
510 // (by checking the locked state)
511 if ( ASIOMutex.tryLock ( 5000 ) )
512 {
513 ASIOMutex.unlock();
514 }
515 }
516
CSound(void (* fpNewCallback)(CVector<int16_t> & psData,void * arg),void * arg,const QString & strMIDISetup,const bool,const QString &)517 CSound::CSound ( void ( *fpNewCallback ) ( CVector<int16_t>& psData, void* arg ),
518 void* arg,
519 const QString& strMIDISetup,
520 const bool,
521 const QString& ) :
522 CSoundBase ( "ASIO", fpNewCallback, arg, strMIDISetup ),
523 lNumInChan ( 0 ),
524 lNumInChanPlusAddChan ( 0 ),
525 lNumOutChan ( 0 ),
526 fInOutLatencyMs ( 0.0f ), // "0.0" means that no latency value is available
527 vSelectedInputChannels ( NUM_IN_OUT_CHANNELS ),
528 vSelectedOutputChannels ( NUM_IN_OUT_CHANNELS )
529 {
530 int i;
531
532 // init pointer to our sound object
533 pSound = this;
534
535 // We assume NULL'd pointers in this structure indicate that buffers are not
536 // allocated yet (see UnloadCurrentDriver).
537 memset ( bufferInfos, 0, sizeof bufferInfos );
538
539 // get available ASIO driver names in system
540 for ( i = 0; i < MAX_NUMBER_SOUND_CARDS; i++ )
541 {
542 // allocate memory for driver names
543 cDriverNames[i] = new char[32];
544 }
545
546 char cDummyName[] = "dummy";
547 loadAsioDriver ( cDummyName ); // to initialize external object
548 lNumDevs = asioDrivers->getDriverNames ( cDriverNames, MAX_NUMBER_SOUND_CARDS );
549
550 // in case we do not have a driver available, throw error
551 if ( lNumDevs == 0 )
552 {
553 throw CGenErr ( "<b>" + tr ( "No ASIO audio device driver found." ) + "</b><br><br>" +
554 QString ( tr ( "Please install an ASIO driver before running %1. "
555 "If you own a device with ASIO support, install its official ASIO driver. "
556 "If not, you'll need to install a universal driver like ASIO4ALL." ) )
557 .arg ( APP_NAME ) );
558 }
559 asioDrivers->removeCurrentDriver();
560
561 // copy driver names to base class but internally we still have to use
562 // the char* variable because of the ASIO API :-(
563 for ( i = 0; i < lNumDevs; i++ )
564 {
565 strDriverNames[i] = cDriverNames[i];
566 }
567
568 // init device index as not initialized (invalid)
569 strCurDevName = "";
570
571 // init channel mapping
572 ResetChannelMapping();
573
574 // set up the asioCallback structure
575 asioCallbacks.bufferSwitch = &bufferSwitch;
576 asioCallbacks.sampleRateDidChange = &sampleRateChanged;
577 asioCallbacks.asioMessage = &asioMessages;
578 asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
579 }
580
ResetChannelMapping()581 void CSound::ResetChannelMapping()
582 {
583 // init selected channel numbers with defaults: use first available
584 // channels for input and output
585 vSelectedInputChannels[0] = 0;
586 vSelectedInputChannels[1] = 1;
587 vSelectedOutputChannels[0] = 0;
588 vSelectedOutputChannels[1] = 1;
589 }
590
591 // ASIO callbacks -------------------------------------------------------------
bufferSwitchTimeInfo(ASIOTime *,long index,ASIOBool processNow)592 ASIOTime* CSound::bufferSwitchTimeInfo ( ASIOTime*, long index, ASIOBool processNow )
593 {
594 bufferSwitch ( index, processNow );
595 return 0L;
596 }
597
CheckSampleTypeSupported(const ASIOSampleType SamType)598 bool CSound::CheckSampleTypeSupported ( const ASIOSampleType SamType )
599 {
600 // check for supported sample types
601 return ( ( SamType == ASIOSTInt16LSB ) || ( SamType == ASIOSTInt24LSB ) || ( SamType == ASIOSTInt32LSB ) || ( SamType == ASIOSTFloat32LSB ) ||
602 ( SamType == ASIOSTFloat64LSB ) || ( SamType == ASIOSTInt32LSB16 ) || ( SamType == ASIOSTInt32LSB18 ) ||
603 ( SamType == ASIOSTInt32LSB20 ) || ( SamType == ASIOSTInt32LSB24 ) || ( SamType == ASIOSTInt16MSB ) || ( SamType == ASIOSTInt24MSB ) ||
604 ( SamType == ASIOSTInt32MSB ) || ( SamType == ASIOSTFloat32MSB ) || ( SamType == ASIOSTFloat64MSB ) || ( SamType == ASIOSTInt32MSB16 ) ||
605 ( SamType == ASIOSTInt32MSB18 ) || ( SamType == ASIOSTInt32MSB20 ) || ( SamType == ASIOSTInt32MSB24 ) );
606 }
607
CheckSampleTypeSupportedForCHMixing(const ASIOSampleType SamType)608 bool CSound::CheckSampleTypeSupportedForCHMixing ( const ASIOSampleType SamType )
609 {
610 // check for supported sample types for audio channel mixing (see bufferSwitch)
611 return ( ( SamType == ASIOSTInt16LSB ) || ( SamType == ASIOSTInt24LSB ) || ( SamType == ASIOSTInt32LSB ) );
612 }
613
bufferSwitch(long index,ASIOBool)614 void CSound::bufferSwitch ( long index, ASIOBool )
615 {
616 int iCurSample;
617
618 // get references to class members
619 int& iASIOBufferSizeMono = pSound->iASIOBufferSizeMono;
620 CVector<int16_t>& vecsMultChanAudioSndCrd = pSound->vecsMultChanAudioSndCrd;
621
622 // perform the processing for input and output
623 pSound->ASIOMutex.lock(); // get mutex lock
624 {
625 // CAPTURE -------------------------------------------------------------
626 for ( int i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
627 {
628 int iSelCH, iSelAddCH;
629
630 GetSelCHAndAddCH ( pSound->vSelectedInputChannels[i], pSound->lNumInChan, iSelCH, iSelAddCH );
631
632 // copy new captured block in thread transfer buffer (copy
633 // mono data interleaved in stereo buffer)
634 switch ( pSound->channelInfosInput[iSelCH].type )
635 {
636 case ASIOSTInt16LSB:
637 {
638 // no type conversion required, just copy operation
639 int16_t* pASIOBuf = static_cast<int16_t*> ( pSound->bufferInfos[iSelCH].buffers[index] );
640
641 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
642 {
643 vecsMultChanAudioSndCrd[2 * iCurSample + i] = pASIOBuf[iCurSample];
644 }
645
646 if ( iSelAddCH >= 0 )
647 {
648 // mix input channels case:
649 int16_t* pASIOBufAdd = static_cast<int16_t*> ( pSound->bufferInfos[iSelAddCH].buffers[index] );
650
651 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
652 {
653 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
654 Float2Short ( (float) vecsMultChanAudioSndCrd[2 * iCurSample + i] + (float) pASIOBufAdd[iCurSample] );
655 }
656 }
657 break;
658 }
659
660 case ASIOSTInt24LSB:
661 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
662 {
663 int iCurSam = 0;
664 memcpy ( &iCurSam, ( (char*) pSound->bufferInfos[iSelCH].buffers[index] ) + iCurSample * 3, 3 );
665 iCurSam >>= 8;
666
667 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> ( iCurSam );
668 }
669
670 if ( iSelAddCH >= 0 )
671 {
672 // mix input channels case:
673 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
674 {
675 int iCurSam = 0;
676 memcpy ( &iCurSam, ( (char*) pSound->bufferInfos[iSelAddCH].buffers[index] ) + iCurSample * 3, 3 );
677 iCurSam >>= 8;
678
679 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
680 Float2Short ( (float) vecsMultChanAudioSndCrd[2 * iCurSample + i] + (float) static_cast<int16_t> ( iCurSam ) );
681 }
682 }
683 break;
684
685 case ASIOSTInt32LSB:
686 {
687 int32_t* pASIOBuf = static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] );
688
689 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
690 {
691 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> ( pASIOBuf[iCurSample] >> 16 );
692 }
693
694 if ( iSelAddCH >= 0 )
695 {
696 // mix input channels case:
697 int32_t* pASIOBufAdd = static_cast<int32_t*> ( pSound->bufferInfos[iSelAddCH].buffers[index] );
698
699 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
700 {
701 vecsMultChanAudioSndCrd[2 * iCurSample + i] = Float2Short ( (float) vecsMultChanAudioSndCrd[2 * iCurSample + i] +
702 (float) static_cast<int16_t> ( pASIOBufAdd[iCurSample] >> 16 ) );
703 }
704 }
705 break;
706 }
707
708 case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
709 // clang-format off
710 // NOT YET TESTED
711 // clang-format on
712 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
713 {
714 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
715 static_cast<int16_t> ( static_cast<float*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] * _MAXSHORT );
716 }
717 break;
718
719 case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
720 // clang-format off
721 // NOT YET TESTED
722 // clang-format on
723 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
724 {
725 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
726 static_cast<int16_t> ( static_cast<double*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] * _MAXSHORT );
727 }
728 break;
729
730 case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
731 // clang-format off
732 // NOT YET TESTED
733 // clang-format on
734 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
735 {
736 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
737 static_cast<int16_t> ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] & 0xFFFF );
738 }
739 break;
740
741 case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
742 // clang-format off
743 // NOT YET TESTED
744 // clang-format on
745 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
746 {
747 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
748 static_cast<int16_t> ( ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] & 0x3FFFF ) >> 2 );
749 }
750 break;
751
752 case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
753 // clang-format off
754 // NOT YET TESTED
755 // clang-format on
756 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
757 {
758 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
759 static_cast<int16_t> ( ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] & 0xFFFFF ) >> 4 );
760 }
761 break;
762
763 case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
764 // clang-format off
765 // NOT YET TESTED
766 // clang-format on
767 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
768 {
769 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
770 static_cast<int16_t> ( ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] & 0xFFFFFF ) >> 8 );
771 }
772 break;
773
774 case ASIOSTInt16MSB:
775 // clang-format off
776 // NOT YET TESTED
777 // clang-format on
778 // flip bits
779 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
780 {
781 vecsMultChanAudioSndCrd[2 * iCurSample + i] =
782 Flip16Bits ( ( static_cast<int16_t*> ( pSound->bufferInfos[iSelCH].buffers[index] ) )[iCurSample] );
783 }
784 break;
785
786 case ASIOSTInt24MSB:
787 // clang-format off
788 // NOT YET TESTED
789 // clang-format on
790 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
791 {
792 // because the bits are flipped, we do not have to perform the
793 // shift by 8 bits
794 int iCurSam = 0;
795 memcpy ( &iCurSam, ( (char*) pSound->bufferInfos[iSelCH].buffers[index] ) + iCurSample * 3, 3 );
796
797 vecsMultChanAudioSndCrd[2 * iCurSample + i] = Flip16Bits ( static_cast<int16_t> ( iCurSam ) );
798 }
799 break;
800
801 case ASIOSTInt32MSB:
802 // clang-format off
803 // NOT YET TESTED
804 // clang-format on
805 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
806 {
807 // flip bits and convert to 16 bit
808 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
809 Flip32Bits ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) >> 16 );
810 }
811 break;
812
813 case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
814 // clang-format off
815 // NOT YET TESTED
816 // clang-format on
817 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
818 {
819 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
820 static_cast<float> ( Flip32Bits ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) ) *
821 _MAXSHORT );
822 }
823 break;
824
825 case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
826 // clang-format off
827 // NOT YET TESTED
828 // clang-format on
829 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
830 {
831 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
832 static_cast<double> ( Flip64Bits ( static_cast<int64_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) ) *
833 _MAXSHORT );
834 }
835 break;
836
837 case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
838 // clang-format off
839 // NOT YET TESTED
840 // clang-format on
841 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
842 {
843 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
844 Flip32Bits ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) & 0xFFFF );
845 }
846 break;
847
848 case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
849 // clang-format off
850 // NOT YET TESTED
851 // clang-format on
852 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
853 {
854 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
855 ( Flip32Bits ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) & 0x3FFFF ) >> 2 );
856 }
857 break;
858
859 case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
860 // clang-format off
861 // NOT YET TESTED
862 // clang-format on
863 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
864 {
865 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
866 ( Flip32Bits ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) & 0xFFFFF ) >> 4 );
867 }
868 break;
869
870 case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
871 // clang-format off
872 // NOT YET TESTED
873 // clang-format on
874 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
875 {
876 vecsMultChanAudioSndCrd[2 * iCurSample + i] = static_cast<int16_t> (
877 ( Flip32Bits ( static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] ) & 0xFFFFFF ) >> 8 );
878 }
879 break;
880 }
881 }
882
883 // call processing callback function
884 pSound->ProcessCallback ( vecsMultChanAudioSndCrd );
885
886 // PLAYBACK ------------------------------------------------------------
887 for ( int i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
888 {
889 const int iSelCH = pSound->lNumInChan + pSound->vSelectedOutputChannels[i];
890
891 // copy data from sound card in output buffer (copy
892 // interleaved stereo data in mono sound card buffer)
893 switch ( pSound->channelInfosOutput[pSound->vSelectedOutputChannels[i]].type )
894 {
895 case ASIOSTInt16LSB:
896 {
897 // no type conversion required, just copy operation
898 int16_t* pASIOBuf = static_cast<int16_t*> ( pSound->bufferInfos[iSelCH].buffers[index] );
899
900 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
901 {
902 pASIOBuf[iCurSample] = vecsMultChanAudioSndCrd[2 * iCurSample + i];
903 }
904 break;
905 }
906
907 case ASIOSTInt24LSB:
908 // clang-format off
909 // NOT YET TESTED
910 // clang-format on
911 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
912 {
913 // convert current sample in 24 bit format
914 int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
915
916 iCurSam <<= 8;
917
918 memcpy ( ( (char*) pSound->bufferInfos[iSelCH].buffers[index] ) + iCurSample * 3, &iCurSam, 3 );
919 }
920 break;
921
922 case ASIOSTInt32LSB:
923 {
924 int32_t* pASIOBuf = static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] );
925
926 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
927 {
928 // convert to 32 bit
929 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
930
931 pASIOBuf[iCurSample] = ( iCurSam << 16 );
932 }
933 break;
934 }
935
936 case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
937 // clang-format off
938 // NOT YET TESTED
939 // clang-format on
940 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
941 {
942 const float fCurSam = static_cast<float> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
943
944 static_cast<float*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = fCurSam / _MAXSHORT;
945 }
946 break;
947
948 case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
949 // clang-format off
950 // NOT YET TESTED
951 // clang-format on
952 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
953 {
954 const double fCurSam = static_cast<double> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
955
956 static_cast<double*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = fCurSam / _MAXSHORT;
957 }
958 break;
959
960 case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
961 // clang-format off
962 // NOT YET TESTED
963 // clang-format on
964 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
965 {
966 // convert to 32 bit
967 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
968
969 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = iCurSam;
970 }
971 break;
972
973 case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
974 // clang-format off
975 // NOT YET TESTED
976 // clang-format on
977 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
978 {
979 // convert to 32 bit
980 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
981
982 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = ( iCurSam << 2 );
983 }
984 break;
985
986 case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
987 // clang-format off
988 // NOT YET TESTED
989 // clang-format on
990 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
991 {
992 // convert to 32 bit
993 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
994
995 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = ( iCurSam << 4 );
996 }
997 break;
998
999 case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
1000 // clang-format off
1001 // NOT YET TESTED
1002 // clang-format on
1003 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1004 {
1005 // convert to 32 bit
1006 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1007
1008 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = ( iCurSam << 8 );
1009 }
1010 break;
1011
1012 case ASIOSTInt16MSB:
1013 // clang-format off
1014 // NOT YET TESTED
1015 // clang-format on
1016 // flip bits
1017 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1018 {
1019 ( (int16_t*) pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] =
1020 Flip16Bits ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1021 }
1022 break;
1023
1024 case ASIOSTInt24MSB:
1025 // clang-format off
1026 // NOT YET TESTED
1027 // clang-format on
1028 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1029 {
1030 // because the bits are flipped, we do not have to perform the
1031 // shift by 8 bits
1032 int32_t iCurSam = static_cast<int32_t> ( Flip16Bits ( vecsMultChanAudioSndCrd[2 * iCurSample + i] ) );
1033
1034 memcpy ( ( (char*) pSound->bufferInfos[iSelCH].buffers[index] ) + iCurSample * 3, &iCurSam, 3 );
1035 }
1036 break;
1037
1038 case ASIOSTInt32MSB:
1039 // clang-format off
1040 // NOT YET TESTED
1041 // clang-format on
1042 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1043 {
1044 // convert to 32 bit and flip bits
1045 int iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1046
1047 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = Flip32Bits ( iCurSam << 16 );
1048 }
1049 break;
1050
1051 case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
1052 // clang-format off
1053 // NOT YET TESTED
1054 // clang-format on
1055 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1056 {
1057 const float fCurSam = static_cast<float> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1058
1059 static_cast<float*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] =
1060 static_cast<float> ( Flip32Bits ( static_cast<int32_t> ( fCurSam / _MAXSHORT ) ) );
1061 }
1062 break;
1063
1064 case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
1065 // clang-format off
1066 // NOT YET TESTED
1067 // clang-format on
1068 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1069 {
1070 const double fCurSam = static_cast<double> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1071
1072 static_cast<float*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] =
1073 static_cast<double> ( Flip64Bits ( static_cast<int64_t> ( fCurSam / _MAXSHORT ) ) );
1074 }
1075 break;
1076
1077 case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
1078 // clang-format off
1079 // NOT YET TESTED
1080 // clang-format on
1081 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1082 {
1083 // convert to 32 bit
1084 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1085
1086 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = Flip32Bits ( iCurSam );
1087 }
1088 break;
1089
1090 case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
1091 // clang-format off
1092 // NOT YET TESTED
1093 // clang-format on
1094 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1095 {
1096 // convert to 32 bit
1097 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1098
1099 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = Flip32Bits ( iCurSam << 2 );
1100 }
1101 break;
1102
1103 case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
1104 // clang-format off
1105 // NOT YET TESTED
1106 // clang-format on
1107 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1108 {
1109 // convert to 32 bit
1110 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1111
1112 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = Flip32Bits ( iCurSam << 4 );
1113 }
1114 break;
1115
1116 case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
1117 // clang-format off
1118 // NOT YET TESTED
1119 // clang-format on
1120 for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
1121 {
1122 // convert to 32 bit
1123 const int32_t iCurSam = static_cast<int32_t> ( vecsMultChanAudioSndCrd[2 * iCurSample + i] );
1124
1125 static_cast<int32_t*> ( pSound->bufferInfos[iSelCH].buffers[index] )[iCurSample] = Flip32Bits ( iCurSam << 8 );
1126 }
1127 break;
1128 }
1129 }
1130
1131 // Finally if the driver supports the ASIOOutputReady() optimization,
1132 // do it here, all data are in place -----------------------------------
1133 if ( pSound->bASIOPostOutput )
1134 {
1135 ASIOOutputReady();
1136 }
1137 }
1138 pSound->ASIOMutex.unlock();
1139 }
1140
asioMessages(long selector,long,void *,double *)1141 long CSound::asioMessages ( long selector, long, void*, double* )
1142 {
1143 long ret = 0;
1144
1145 switch ( selector )
1146 {
1147 case kAsioEngineVersion:
1148 // return the supported ASIO version of the host application
1149 ret = 2L; // Host ASIO implementation version, 2 or higher
1150 break;
1151
1152 // both messages might be send if the buffer size changes
1153 case kAsioBufferSizeChange:
1154 pSound->EmitReinitRequestSignal ( RS_ONLY_RESTART_AND_INIT );
1155 ret = 1L; // 1L if request is accepted or 0 otherwise
1156 break;
1157
1158 case kAsioResetRequest:
1159 pSound->EmitReinitRequestSignal ( RS_RELOAD_RESTART_AND_INIT );
1160 ret = 1L; // 1L if request is accepted or 0 otherwise
1161 break;
1162 }
1163
1164 return ret;
1165 }
1166
Flip16Bits(const int16_t iIn)1167 int16_t CSound::Flip16Bits ( const int16_t iIn )
1168 {
1169 uint16_t iMask = ( 1 << 15 );
1170 int16_t iOut = 0;
1171
1172 for ( unsigned int i = 0; i < 16; i++ )
1173 {
1174 // copy current bit to correct position
1175 iOut |= ( iIn & iMask ) ? 1 : 0;
1176
1177 // shift out value and mask by one bit
1178 iOut <<= 1;
1179 iMask >>= 1;
1180 }
1181
1182 return iOut;
1183 }
1184
Flip32Bits(const int32_t iIn)1185 int32_t CSound::Flip32Bits ( const int32_t iIn )
1186 {
1187 uint32_t iMask = ( static_cast<uint32_t> ( 1 ) << 31 );
1188 int32_t iOut = 0;
1189
1190 for ( unsigned int i = 0; i < 32; i++ )
1191 {
1192 // copy current bit to correct position
1193 iOut |= ( iIn & iMask ) ? 1 : 0;
1194
1195 // shift out value and mask by one bit
1196 iOut <<= 1;
1197 iMask >>= 1;
1198 }
1199
1200 return iOut;
1201 }
1202
Flip64Bits(const int64_t iIn)1203 int64_t CSound::Flip64Bits ( const int64_t iIn )
1204 {
1205 uint64_t iMask = ( static_cast<uint64_t> ( 1 ) << 63 );
1206 int64_t iOut = 0;
1207
1208 for ( unsigned int i = 0; i < 64; i++ )
1209 {
1210 // copy current bit to correct position
1211 iOut |= ( iIn & iMask ) ? 1 : 0;
1212
1213 // shift out value and mask by one bit
1214 iOut <<= 1;
1215 iMask >>= 1;
1216 }
1217
1218 return iOut;
1219 }
1220