Skip to content

Commit

Permalink
Handle channel selection
Browse files Browse the repository at this point in the history
  • Loading branch information
npostavs committed Feb 5, 2021
1 parent 88af567 commit 0883a5b
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 10 deletions.
113 changes: 103 additions & 10 deletions src/portaudiosound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ CSound::CSound( void (*fpNewProcessCallback) ( CVector<short>& psData,
const QString& ) :
CSoundBase ( "portaudio", fpNewProcessCallback, arg, strMIDISetup ),
deviceIndex (-1),
deviceStream (NULL)
deviceStream (NULL),
vSelectedInputChannels ( NUM_IN_OUT_CHANNELS ),
vSelectedOutputChannels ( NUM_IN_OUT_CHANNELS )
{
pThisSound = this;

Expand Down Expand Up @@ -136,7 +138,7 @@ int CSound::Init ( const int iNewPrefMonoBufferSize )
iPrefMonoBufferSize = iNewPrefMonoBufferSize;
}

vecsAudioData.Init ( iPrefMonoBufferSize * 2 );
vecsAudioData.Init ( iPrefMonoBufferSize * NUM_IN_OUT_CHANNELS );
if ( deviceStream && deviceIndex >= 0 )
{
LoadAndInitializeDriver ( deviceIndex );
Expand Down Expand Up @@ -165,6 +167,82 @@ PaDeviceIndex CSound::DeviceIndexFromName (const QString& strDriverName )
return -1;
}

int CSound::GetNumInputChannels()
{
if (deviceIndex >= 0)
{
const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo ( deviceIndex );
return deviceInfo->maxInputChannels;
}
return CSoundBase::GetNumInputChannels();
}
int CSound::GetNumOutputChannels()
{
if (deviceIndex >= 0)
{
const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo ( deviceIndex );
return deviceInfo->maxOutputChannels;
}
return CSoundBase::GetNumOutputChannels();
}

QString CSound::GetInputChannelName ( const int channel )
{
if (deviceIndex >= 0)
{
const char* channelName;
PaError err = PaAsio_GetInputChannelName ( deviceIndex, channel, &channelName );
if ( err == paNoError )
{
return QString ( channelName );
}
}
return CSoundBase::GetInputChannelName ( channel );
}
QString CSound::GetOutputChannelName ( const int channel )
{
if (deviceIndex >= 0)
{
const char* channelName;
PaError err = PaAsio_GetOutputChannelName ( deviceIndex, channel, &channelName );
if ( err == paNoError )
{
return QString ( channelName );
}
}
return CSoundBase::GetOutputChannelName ( channel );
}

void CSound::SetLeftInputChannel ( const int channel )
{
if ( channel < GetNumInputChannels() )
{
vSelectedInputChannels[0] = channel;
}
}
void CSound::SetRightInputChannel ( const int channel )
{
if ( channel < GetNumInputChannels() )
{
vSelectedInputChannels[1] = channel;
}
}

void CSound::SetLeftOutputChannel ( const int channel )
{
if ( channel < GetNumOutputChannels() )
{
vSelectedOutputChannels[0] = channel;
}
}
void CSound::SetRightOutputChannel ( const int channel )
{
if ( channel < GetNumOutputChannels() )
{
vSelectedOutputChannels[1] = channel;
}
}

QString CSound::LoadAndInitializeDriver ( QString strDriverName, bool bOpenDriverSetup )
{
(void) bOpenDriverSetup; // FIXME: respect this
Expand All @@ -181,10 +259,11 @@ QString CSound::LoadAndInitializeDriver ( int devIndex )
{
const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo ( devIndex );

if ( deviceInfo->maxInputChannels < 2 || deviceInfo->maxOutputChannels < 2 )
if ( deviceInfo->maxInputChannels < NUM_IN_OUT_CHANNELS ||
deviceInfo->maxOutputChannels < NUM_IN_OUT_CHANNELS )
{
// FIXME: handle mono devices.
return tr ( "Less than 2 channels supported" );
return tr ( "Less than 2 channels not supported" );
}

if ( deviceStream != NULL )
Expand All @@ -195,18 +274,30 @@ QString CSound::LoadAndInitializeDriver ( int devIndex )
}

PaStreamParameters paInputParams;
PaAsioStreamInfo asioInputInfo;
paInputParams.device = devIndex;
paInputParams.channelCount = std::min (2, deviceInfo->maxInputChannels);
paInputParams.channelCount = std::min (NUM_IN_OUT_CHANNELS, deviceInfo->maxInputChannels);
paInputParams.sampleFormat = paInt16;
paInputParams.suggestedLatency = deviceInfo->defaultLowInputLatency;
paInputParams.hostApiSpecificStreamInfo = NULL;
paInputParams.hostApiSpecificStreamInfo = &asioInputInfo;
asioInputInfo.size = sizeof asioInputInfo;
asioInputInfo.hostApiType = paASIO;
asioInputInfo.version = 1;
asioInputInfo.flags = paAsioUseChannelSelectors;
asioInputInfo.channelSelectors = &vSelectedInputChannels[0];

PaStreamParameters paOutputParams;
PaAsioStreamInfo asioOutputInfo;
paOutputParams.device = devIndex;
paOutputParams.channelCount = std::min (2, deviceInfo->maxOutputChannels);
paOutputParams.channelCount = std::min (NUM_IN_OUT_CHANNELS, deviceInfo->maxOutputChannels);
paOutputParams.sampleFormat = paInt16;
paOutputParams.suggestedLatency = deviceInfo->defaultLowOutputLatency;
paOutputParams.hostApiSpecificStreamInfo = NULL;
paOutputParams.hostApiSpecificStreamInfo = &asioOutputInfo;
asioOutputInfo.size = sizeof asioOutputInfo;
asioOutputInfo.hostApiType = paASIO;
asioOutputInfo.version = 1;
asioOutputInfo.flags = paAsioUseChannelSelectors;
asioOutputInfo.channelSelectors = &vSelectedOutputChannels[0];

PaError err = Pa_OpenStream ( &deviceStream,
&paInputParams,
Expand All @@ -224,6 +315,8 @@ QString CSound::LoadAndInitializeDriver ( int devIndex )
( Pa_GetLastHostErrorInfo () ->errorText );
}

strCurDevName = deviceInfo->name;

deviceIndex = devIndex;
return "";
}
Expand All @@ -249,12 +342,12 @@ int CSound::paStreamCallback(const void *input, void *output, unsigned long fram
CVector<int16_t>& vecsAudioData = pSound->vecsAudioData;

// CAPTURE ---------------------------------
memcpy (&vecsAudioData[0], input, sizeof (int16_t) * frameCount * 2);
memcpy (&vecsAudioData[0], input, sizeof (int16_t) * frameCount * NUM_IN_OUT_CHANNELS);

pSound->ProcessCallback ( vecsAudioData );

// PLAYBACK ------------------------------------------------------------
memcpy (output, &vecsAudioData[0], sizeof (int16_t) * frameCount * 2);
memcpy (output, &vecsAudioData[0], sizeof (int16_t) * frameCount * NUM_IN_OUT_CHANNELS);

return paContinue;
}
Expand Down
18 changes: 18 additions & 0 deletions src/portaudiosound.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@

#include <portaudio.h>

#define NUM_IN_OUT_CHANNELS 2 // always stereo

class CSound : public CSoundBase
{
public:
Expand All @@ -56,6 +58,20 @@ class CSound : public CSoundBase
virtual void Start ();
virtual void Stop ();

virtual int GetNumInputChannels();
virtual QString GetInputChannelName ( const int );
virtual void SetLeftInputChannel ( const int );
virtual void SetRightInputChannel ( const int );
virtual int GetLeftInputChannel() { return vSelectedInputChannels[0]; }
virtual int GetRightInputChannel() { return vSelectedInputChannels[1]; }

virtual int GetNumOutputChannels();
virtual QString GetOutputChannelName ( const int );
virtual void SetLeftOutputChannel ( const int );
virtual void SetRightOutputChannel ( const int );
virtual int GetLeftOutputChannel() { return vSelectedOutputChannels[0]; }
virtual int GetRightOutputChannel() { return vSelectedOutputChannels[1]; }

#ifdef WIN32
// Portaudio's function for this takes a device index as a parameter. So it
// needs to reopen ASIO in order to get the right driver loaded. Because of
Expand All @@ -79,6 +95,8 @@ class CSound : public CSoundBase
PaHostApiIndex asioIndex;
PaDeviceIndex deviceIndex;
PaStream* deviceStream;
CVector<int> vSelectedInputChannels;
CVector<int> vSelectedOutputChannels;
int iPrefMonoBufferSize;
CVector<int16_t> vecsAudioData;
};

0 comments on commit 0883a5b

Please sign in to comment.