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