diff --git a/RS_ASIO/AsioSharedHost.cpp b/RS_ASIO/AsioSharedHost.cpp index b6cd48a..4b4c882 100644 --- a/RS_ASIO/AsioSharedHost.cpp +++ b/RS_ASIO/AsioSharedHost.cpp @@ -487,11 +487,13 @@ bool AsioSharedHost::IsWaveFormatSupported(const WAVEFORMATEX& format, bool outp return false; } - // we currently don't support IEEE float... if (wfe.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) { - rslog::error_ts() << " IEEE Float format is not supported" << std::endl; - return false; + if (sampleType != ASIOSTFloat32LSB && sampleType != ASIOSTFloat64LSB) + { + rslog::error_ts() << " rejecting IEEE Float as it's incompatible with current ASIO sample type " << sampleType << std::endl; + return false; + } } // check bit depth @@ -503,21 +505,17 @@ bool AsioSharedHost::IsWaveFormatSupported(const WAVEFORMATEX& format, bool outp bitsPerSample = wfe.Samples.wValidBitsPerSample; } - // check bit depth - if (format.nBlockAlign != (4 * format.nChannels)) + switch (sampleType) { - rslog::error_ts() << " nBlockAlign unsupported: " << format.nBlockAlign << std::endl; - return false; - } - if (bitsPerSample != 24) - { - rslog::error_ts() << " bitsPerSample unsupported: " << bitsPerSample << std::endl; - return false; - } - if (sampleType != ASIOSTInt32LSB) - { - rslog::error_ts() << " ASIO sample type " << sampleType << " is not currently supported" << std::endl; - return false; + case ASIOSTInt16LSB: + case ASIOSTInt24LSB: + case ASIOSTInt32LSB: + case ASIOSTFloat32LSB: + case ASIOSTFloat64LSB: + break; + default: + rslog::error_ts() << " ASIO sample type " << sampleType << " is not currently supported" << std::endl; + return false; } return true; @@ -593,6 +591,20 @@ ASIOBufferInfo* AsioSharedHost::GetInputBuffer(unsigned channel) return &m_AsioBuffers[m_AsioOutChannelInfo.size() + channel]; } +const ASIOChannelInfo* AsioSharedHost::GetOutputChannelInfo(unsigned channel) const +{ + if (channel >= m_AsioOutChannelInfo.size()) + return nullptr; + return &m_AsioOutChannelInfo[channel]; +} + +const ASIOChannelInfo* AsioSharedHost::GetInputChannelInfo(unsigned channel) const +{ + if (channel >= m_AsioInChannelInfo.size()) + return nullptr; + return &m_AsioInChannelInfo[channel]; +} + void AsioSharedHost::DisplayCurrentError() const { if (!m_Driver) diff --git a/RS_ASIO/AsioSharedHost.h b/RS_ASIO/AsioSharedHost.h index fba9b71..068c27e 100644 --- a/RS_ASIO/AsioSharedHost.h +++ b/RS_ASIO/AsioSharedHost.h @@ -35,6 +35,8 @@ class AsioSharedHost : public ComBaseUnknown ASIOBufferInfo* GetOutputBuffer(unsigned channel); ASIOBufferInfo* GetInputBuffer(unsigned channel); + const ASIOChannelInfo* GetOutputChannelInfo(unsigned channel) const; + const ASIOChannelInfo* GetInputChannelInfo(unsigned channel) const; unsigned GetNumInputChannels() const { return m_AsioInChannelInfo.size(); } unsigned GetNumOutputChannels() const { return m_AsioOutChannelInfo.size(); } diff --git a/RS_ASIO/AudioProcessing.cpp b/RS_ASIO/AudioProcessing.cpp new file mode 100644 index 0000000..f9bf076 --- /dev/null +++ b/RS_ASIO/AudioProcessing.cpp @@ -0,0 +1,297 @@ +#include "stdafx.h" +#include + +#include "AudioProcessing.h" + +using TFuncConvert = void(const BYTE* inData, const WORD inStride, BYTE* outData, const WORD outStride, const DWORD numSamples); +using TFuncConvertMatrix = std::array, ASIOSTLastEntry>; + +static TFuncConvertMatrix s_FuncConvertMatrix{}; + +static const TFuncConvertMatrix& GetFuncConvertMatrix(); + +template +static TIntRet ReadAudioSampleInt(const BYTE* inData) +{ + if (bytes != sizeof(TIntRet)) + { + TIntRet val = 0; + + unsigned i = 0; + for (; i < bytes; ++i) + { + val <<= 8; + val |= inData[i]; + } + for (; i < sizeof(TIntRet); ++i) + { + val <<= 8; + } + + return val; + } + else + { + return *(TIntRet*)inData; + } +} + +template +static void WriteAudioSampleInt(TInt sample, BYTE* outData) +{ + if (bytes != sizeof(TInt)) + { + for (unsigned i = 1; i <= bytes; ++i) + { + outData[bytes - i] = sample & 0xff; + sample >>= 8; + } + } + else + { + *reinterpret_cast(outData) = sample; + } +} + +static bool AudioBlit(const BYTE* inData, const WORD inStride, BYTE* outData, const WORD outStride, const unsigned bytesPerSample, const DWORD numSamples) +{ + if (bytesPerSample == 1) + { + for (DWORD i = 0; i < numSamples; ++i) + { + *outData = *inData; + inData += inStride; + outData += outStride; + } + return true; + } + else if (bytesPerSample == 2) + { + for (DWORD i = 0; i < numSamples; ++i) + { + *reinterpret_cast(outData) = *reinterpret_cast(inData); + inData += inStride; + outData += outStride; + } + return true; + } + else if (bytesPerSample == 3) + { + for (DWORD i = 0; i < numSamples; ++i) + { + *reinterpret_cast(outData) = *reinterpret_cast(inData); + outData[2] = inData[2]; + inData += inStride; + outData += outStride; + } + } + else if (bytesPerSample == 4) + { + for (DWORD i = 0; i < numSamples; ++i) + { + *reinterpret_cast(outData) = *reinterpret_cast(inData); + inData += inStride; + outData += outStride; + } + } + else if (bytesPerSample == 8) + { + for (DWORD i = 0; i < numSamples; ++i) + { + *reinterpret_cast(outData) = *reinterpret_cast(inData); + inData += inStride; + outData += outStride; + } + } + + return false; +} + +template +static void AudioCopyConvert(const BYTE* inData, const WORD inStride, BYTE* outData, const WORD outStride, const DWORD numSamples) +{ + using TSampleType = typename std::conditional::type; + + for (DWORD i = 0; i < numSamples; ++i) + { + const auto sample = ReadAudioSampleInt(inData); + WriteAudioSampleInt(sample, outData); + inData += inStride; + outData += outStride; + } +} + +template +static void AudioCopyConvertF2I(const BYTE* inData, const WORD inStride, BYTE* outData, const WORD outStride, const DWORD numSamples) +{ + const auto Max32 = (std::numeric_limits::max)() - 1; + const double Max32_d = (double)Max32; + + for (DWORD i = 0; i < numSamples; ++i) + { + const double sample_f = *(const TFloatType*)inData * Max32_d; + const std::int32_t sample_i = (std::int32_t)sample_f; + WriteAudioSampleInt(sample_i, outData); + inData += inStride; + outData += outStride; + } +} + +template +static void AudioCopyConvertI2F(const BYTE* inData, const WORD inStride, BYTE* outData, const WORD outStride, const DWORD numSamples) +{ + using TSampleType = typename std::conditional::type; + + const auto SampleTypeMax = (std::numeric_limits::max)(); + const auto SampleTypeMax_d = 1.0 / (double)SampleTypeMax; + + for (DWORD i = 0; i < numSamples; ++i) + { + const auto sample_i = ReadAudioSampleInt(inData); + const double sample_f = (double)sample_i * SampleTypeMax_d; + *(TFloatType*)outData = (TFloatType)sample_f; + inData += inStride; + outData += outStride; + } +} + +template +static void AudioCopyConvertF2F(const BYTE* inData, const WORD inStride, BYTE* outData, const WORD outStride, const DWORD numSamples) +{ + for (DWORD i = 0; i < numSamples; ++i) + { + const auto sample = *(const TInFloatType*)inData; + *(TOutFloatType*)outData = (TOutFloatType)sample; + inData += inStride; + outData += outStride; + } +} + +bool AudioProcessing::CopyConvertFormat(const BYTE* inData, ASIOSampleType inSampleType, const WORD inStride, DWORD numFrames, BYTE* outData, ASIOSampleType outSampleType, const WORD outStride) +{ + const WORD inSampleSize = GetAsioSampleTypeNumBytes(inSampleType); + const WORD outSampleSize = GetAsioSampleTypeNumBytes(outSampleType); + + if (!inSampleType || !outSampleType) + return false; + + // simple copy case; no conversion needed here + if (inSampleType == outSampleType) + { + AudioBlit(inData, inStride, outData, outStride, inSampleSize, numFrames); + return true; + } + else + { + // get convert function to use + const auto& convFuncMatrix = GetFuncConvertMatrix(); + auto convFunc = convFuncMatrix[inSampleType][outSampleType]; + if (convFunc) + { + // call conversion function + convFunc(inData, inStride, outData, outStride, numFrames); + } + + return true; + } +} + +bool AudioProcessing::DoSoftwareVolumeDsp(BYTE* data, ASIOSampleType inSampleType, DWORD numSamples, float fVolumeScalar) +{ + if (inSampleType == ASIOSTInt16LSB) + { + const int scalarPercentPoints = (int)(fVolumeScalar * 100.f); + for (DWORD i = 0; i < numSamples; ++i, data += 2) + { + std::int64_t sample = *(std::int16_t*)data; + sample = (sample * scalarPercentPoints) / 100; + *(std::int16_t*)data = (std::int16_t)sample; + } + return true; + } + else if (inSampleType == ASIOSTInt24LSB) + { + const int scalarPercentPoints = (int)(fVolumeScalar * 100.f); + for (DWORD i = 0; i < numSamples; ++i, data += 3) + { + std::int64_t sample = ((*(std::int16_t*)data) << 8) | data[2]; + sample = (sample * scalarPercentPoints) / 100; + *(std::int16_t*)data = (std::int16_t)((sample >> 8) & 0xffff); + data[2] = sample & 0xff; + } + return true; + } + else if (inSampleType == ASIOSTInt32LSB) + { + const int scalarPercentPoints = (int)(fVolumeScalar * 100.f); + for (DWORD i = 0; i < numSamples; ++i, data += 4) + { + std::int64_t sample = *(std::int32_t*)data; + sample = (sample * scalarPercentPoints) / 100; + *(std::int32_t*)data = (std::int32_t)sample; + } + return true; + } + else if (inSampleType == ASIOSTFloat32LSB) + { + for (DWORD i = 0; i < numSamples; ++i, data += 4) + { + (*(float*)data) *= fVolumeScalar; + } + } + else if (inSampleType == ASIOSTFloat64LSB) + { + const double v = (double)fVolumeScalar; + for (DWORD i = 0; i < numSamples; ++i, data += 4) + { + (*(double*)data) *= v; + } + return true; + } + return false; +} + +static const TFuncConvertMatrix& GetFuncConvertMatrix() +{ + static bool initialized = false; + if (!initialized) + { + initialized = true; + + s_FuncConvertMatrix[ASIOSTInt16LSB][ASIOSTInt16LSB] = &AudioCopyConvert<2, 2>; + s_FuncConvertMatrix[ASIOSTInt16LSB][ASIOSTInt24LSB] = &AudioCopyConvert<2, 3>; + s_FuncConvertMatrix[ASIOSTInt16LSB][ASIOSTInt32LSB] = &AudioCopyConvert<2, 4>; + s_FuncConvertMatrix[ASIOSTInt16LSB][ASIOSTFloat32LSB] = &AudioCopyConvertI2F<2, float>; + s_FuncConvertMatrix[ASIOSTInt16LSB][ASIOSTFloat64LSB] = &AudioCopyConvertI2F<2, double>; + + s_FuncConvertMatrix[ASIOSTInt24LSB][ASIOSTInt16LSB] = &AudioCopyConvert<3, 2>; + s_FuncConvertMatrix[ASIOSTInt24LSB][ASIOSTInt24LSB] = &AudioCopyConvert<3, 3>; + s_FuncConvertMatrix[ASIOSTInt24LSB][ASIOSTInt32LSB] = &AudioCopyConvert<3, 4>; + s_FuncConvertMatrix[ASIOSTInt24LSB][ASIOSTFloat32LSB] = &AudioCopyConvertI2F<3, float>; + s_FuncConvertMatrix[ASIOSTInt24LSB][ASIOSTFloat64LSB] = &AudioCopyConvertI2F<3, double>; + + s_FuncConvertMatrix[ASIOSTInt32LSB][ASIOSTInt16LSB] = &AudioCopyConvert<4, 2>; + s_FuncConvertMatrix[ASIOSTInt32LSB][ASIOSTInt24LSB] = &AudioCopyConvert<4, 3>; + s_FuncConvertMatrix[ASIOSTInt32LSB][ASIOSTInt32LSB] = &AudioCopyConvert<4, 4>; + s_FuncConvertMatrix[ASIOSTInt32LSB][ASIOSTFloat32LSB] = &AudioCopyConvertI2F<4, float>; + s_FuncConvertMatrix[ASIOSTInt32LSB][ASIOSTFloat64LSB] = &AudioCopyConvertI2F<5, double>; + + s_FuncConvertMatrix[ASIOSTFloat32LSB][ASIOSTInt16LSB] = &AudioCopyConvertF2I; + s_FuncConvertMatrix[ASIOSTFloat32LSB][ASIOSTInt24LSB] = &AudioCopyConvertF2I; + s_FuncConvertMatrix[ASIOSTFloat32LSB][ASIOSTInt32LSB] = &AudioCopyConvertF2I; + s_FuncConvertMatrix[ASIOSTFloat32LSB][ASIOSTFloat32LSB] = &AudioCopyConvertF2F; + s_FuncConvertMatrix[ASIOSTFloat32LSB][ASIOSTFloat64LSB] = &AudioCopyConvertF2F; + + s_FuncConvertMatrix[ASIOSTFloat64LSB][ASIOSTInt16LSB] = &AudioCopyConvertF2I; + s_FuncConvertMatrix[ASIOSTFloat64LSB][ASIOSTInt24LSB] = &AudioCopyConvertF2I; + s_FuncConvertMatrix[ASIOSTFloat64LSB][ASIOSTInt32LSB] = &AudioCopyConvertF2I; + s_FuncConvertMatrix[ASIOSTFloat64LSB][ASIOSTFloat32LSB] = &AudioCopyConvertF2F; + s_FuncConvertMatrix[ASIOSTFloat64LSB][ASIOSTFloat64LSB] = &AudioCopyConvertF2F; + } + + return s_FuncConvertMatrix; +} \ No newline at end of file diff --git a/RS_ASIO/AudioProcessing.h b/RS_ASIO/AudioProcessing.h new file mode 100644 index 0000000..e1c9a15 --- /dev/null +++ b/RS_ASIO/AudioProcessing.h @@ -0,0 +1,7 @@ +#pragma once + +namespace AudioProcessing +{ + bool CopyConvertFormat(const BYTE* inData, ASIOSampleType inSampleType, const WORD inStride, DWORD numFrames, BYTE* outData, ASIOSampleType outSampleType, const WORD outStride); + bool DoSoftwareVolumeDsp(BYTE* data, ASIOSampleType inSampleType, DWORD numSamples, float fVolumeScalar); +} \ No newline at end of file diff --git a/RS_ASIO/RSAsioAudioClient.cpp b/RS_ASIO/RSAsioAudioClient.cpp index fe3e4d3..7da8fba 100644 --- a/RS_ASIO/RSAsioAudioClient.cpp +++ b/RS_ASIO/RSAsioAudioClient.cpp @@ -4,6 +4,7 @@ #include "RSAsioAudioClient.h" #include "RSAsioAudioRenderClient.h" #include "RSAsioAudioCaptureClient.h" +#include "AudioProcessing.h" RSAsioAudioClient::RSAsioAudioClient(RSAsioDevice& asioDevice) : m_AsioDevice(asioDevice) @@ -97,6 +98,7 @@ HRESULT RSAsioAudioClient::Initialize(AUDCLNT_SHAREMODE ShareMode, DWORD StreamF if (pFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { m_WaveFormat = *(WAVEFORMATEXTENSIBLE*)pFormat; + m_WaveFormatIsFloat = (m_WaveFormat.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); } else { @@ -436,55 +438,6 @@ void RSAsioAudioClient::SwapBuffers() m_bufferHasUpdatedData = true; } -template -static void CopyDeinterleaveChannel(BYTE* inInterleaved, BYTE* outDeinterleaved, WORD inputChannel, WORD inputFrameSize, DWORD numFrames) -{ - inInterleaved += sizeof(TSample) * inputChannel; - - for (DWORD frame = 0; frame < numFrames; ++frame) - { - *(TSample*)outDeinterleaved = *(TSample*)inInterleaved; - inInterleaved += inputFrameSize; - outDeinterleaved += sizeof(TSample); - } -} - -template -static void CopyInterleaveChannel(BYTE* inDeinterleaved, BYTE* outInterleaved, WORD outputChannel, WORD outputFrameSize, DWORD numFrames) -{ - outInterleaved += sizeof(TSample) * outputChannel; - - for (DWORD frame = 0; frame < numFrames; ++frame) - { - *(TSample*)outInterleaved = *(TSample*)inDeinterleaved; - inDeinterleaved += sizeof(TSample); - outInterleaved += outputFrameSize; - } -} - -template -static void DoSoftwareVolumeDsp(TSample* inSamples, DWORD numSamples, float fVolumeScalar) -{ - int scalarPercentPoints = (int)(fVolumeScalar * 100.f); - - for (DWORD i = 0; i < numSamples; ++i, ++inSamples) - { - std::int64_t sample = *inSamples; - sample = (sample * scalarPercentPoints) / 100; - *inSamples = (TSample)sample; - } -} - -template<> -static void DoSoftwareVolumeDsp(float* inSamples, DWORD numSamples, float fVolumeScalar) -{ - for (DWORD i = 0; i < numSamples; ++i, ++inSamples) - { - *inSamples *= fVolumeScalar; - } -} - - void RSAsioAudioClient::OnAsioBufferSwitch(unsigned buffIdx) { std::lock_guard g(m_bufferMutex); @@ -502,6 +455,14 @@ void RSAsioAudioClient::OnAsioBufferSwitch(unsigned buffIdx) if (m_ChannelMap.size() < m_WaveFormat.Format.nChannels) return; + // get game sample type + ASIOSampleType gameSampleType = ASIOSTFloat32LSB; + if (!AsioSampleTypeFromFormat(&gameSampleType, m_WaveFormat.Format.wBitsPerSample, m_WaveFormatIsFloat)) + return; + const WORD gameSampleTypeSize = GetAsioSampleTypeNumBytes(gameSampleType); + if (!gameSampleTypeSize) + return; + // check if and how we want to do software volume processing float fSoftwareVolumeScalar = 1.0f; bool doSoftwareVolume = m_AsioDevice.GetSoftwareVolumeScalar(&fSoftwareVolumeScalar); @@ -513,11 +474,7 @@ void RSAsioAudioClient::OnAsioBufferSwitch(unsigned buffIdx) if (doSoftwareVolume) { const DWORD totalSamples = m_bufferNumFrames * m_WaveFormat.Format.nChannels; - - if (m_WaveFormat.Format.wBitsPerSample == 16) - DoSoftwareVolumeDsp((std::int16_t*)m_frontBuffer.data(), totalSamples, fSoftwareVolumeScalar); - else if (m_WaveFormat.Format.wBitsPerSample == 32) - DoSoftwareVolumeDsp((std::int32_t*)m_frontBuffer.data(), totalSamples, fSoftwareVolumeScalar); + AudioProcessing::DoSoftwareVolumeDsp(m_frontBuffer.data(), gameSampleType, totalSamples, fSoftwareVolumeScalar); } for (WORD ch = 0; ch < m_WaveFormat.Format.nChannels; ++ch) @@ -525,13 +482,20 @@ void RSAsioAudioClient::OnAsioBufferSwitch(unsigned buffIdx) const int asioCh = m_ChannelMap[ch]; if (asioCh >= 0) { + const ASIOChannelInfo* asioChannelInfo = m_AsioSharedHost.GetOutputChannelInfo(asioCh); ASIOBufferInfo* bufferInfo = m_AsioSharedHost.GetOutputBuffer(asioCh); - if (bufferInfo) + if (bufferInfo && asioChannelInfo) { - if (m_WaveFormat.Format.wBitsPerSample == 16) - CopyDeinterleaveChannel(m_frontBuffer.data(), (BYTE*)bufferInfo->buffers[buffIdx], ch, m_WaveFormat.Format.nBlockAlign, m_bufferNumFrames); - else if (m_WaveFormat.Format.wBitsPerSample == 32) - CopyDeinterleaveChannel(m_frontBuffer.data(), (BYTE*)bufferInfo->buffers[buffIdx], ch, m_WaveFormat.Format.nBlockAlign, m_bufferNumFrames); + const WORD asioSampleTypeSize = GetAsioSampleTypeNumBytes(asioChannelInfo->type); + + if (asioSampleTypeSize) + { + AudioProcessing::CopyConvertFormat( + m_frontBuffer.data() + ch * gameSampleTypeSize, gameSampleType, m_WaveFormat.Format.nBlockAlign, + m_bufferNumFrames, + (BYTE*)bufferInfo->buffers[buffIdx], asioChannelInfo->type, asioSampleTypeSize + ); + } } } } @@ -544,13 +508,20 @@ void RSAsioAudioClient::OnAsioBufferSwitch(unsigned buffIdx) const int asioCh = m_ChannelMap[ch]; if (asioCh >= 0) { + const ASIOChannelInfo* asioChannelInfo = m_AsioSharedHost.GetInputChannelInfo(asioCh); ASIOBufferInfo* bufferInfo = m_AsioSharedHost.GetInputBuffer(asioCh); - if (bufferInfo) + if (bufferInfo && asioChannelInfo) { - if (m_WaveFormat.Format.wBitsPerSample == 16) - CopyInterleaveChannel((BYTE*)bufferInfo->buffers[buffIdx], m_frontBuffer.data(), ch, m_WaveFormat.Format.nBlockAlign, m_bufferNumFrames); - else if (m_WaveFormat.Format.wBitsPerSample == 32) - CopyInterleaveChannel((BYTE*)bufferInfo->buffers[buffIdx], m_frontBuffer.data(), ch, m_WaveFormat.Format.nBlockAlign, m_bufferNumFrames); + const WORD asioSampleTypeSize = GetAsioSampleTypeNumBytes(asioChannelInfo->type); + + if (asioSampleTypeSize) + { + AudioProcessing::CopyConvertFormat( + (BYTE*)bufferInfo->buffers[buffIdx], asioChannelInfo->type, asioSampleTypeSize, + m_bufferNumFrames, + m_frontBuffer.data() + ch * gameSampleTypeSize, gameSampleType, m_WaveFormat.Format.nBlockAlign + ); + } } } } @@ -558,11 +529,7 @@ void RSAsioAudioClient::OnAsioBufferSwitch(unsigned buffIdx) if (doSoftwareVolume) { const DWORD totalSamples = m_bufferNumFrames * m_WaveFormat.Format.nChannels; - - if (m_WaveFormat.Format.wBitsPerSample == 16) - DoSoftwareVolumeDsp((std::int16_t*)m_frontBuffer.data(), totalSamples, fSoftwareVolumeScalar); - else if (m_WaveFormat.Format.wBitsPerSample == 32) - DoSoftwareVolumeDsp((std::int32_t*)m_frontBuffer.data(), totalSamples, fSoftwareVolumeScalar); + AudioProcessing::DoSoftwareVolumeDsp(m_frontBuffer.data(), gameSampleType, totalSamples, fSoftwareVolumeScalar); } } diff --git a/RS_ASIO/RSAsioAudioClient.h b/RS_ASIO/RSAsioAudioClient.h index f1d4ac0..10b4604 100644 --- a/RS_ASIO/RSAsioAudioClient.h +++ b/RS_ASIO/RSAsioAudioClient.h @@ -58,6 +58,7 @@ class RSAsioAudioClient : public ComBaseUnknown, protected IAsioB AsioSharedHost& m_AsioSharedHost; WAVEFORMATEXTENSIBLE m_WaveFormat; + bool m_WaveFormatIsFloat = false; bool m_IsInitialized = false; bool m_IsStarted = false; diff --git a/RS_ASIO/RS_ASIO.vcxproj b/RS_ASIO/RS_ASIO.vcxproj index b5ce0c0..aea7314 100644 --- a/RS_ASIO/RS_ASIO.vcxproj +++ b/RS_ASIO/RS_ASIO.vcxproj @@ -157,6 +157,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/RS_ASIO/RS_ASIO.vcxproj.filters b/RS_ASIO/RS_ASIO.vcxproj.filters index aeaec38..1777d2b 100644 --- a/RS_ASIO/RS_ASIO.vcxproj.filters +++ b/RS_ASIO/RS_ASIO.vcxproj.filters @@ -102,6 +102,9 @@ Header Files + + Header Files + @@ -176,6 +179,9 @@ Source Files + + Source Files + diff --git a/RS_ASIO/Utils.cpp b/RS_ASIO/Utils.cpp index 895227c..1912c1d 100644 --- a/RS_ASIO/Utils.cpp +++ b/RS_ASIO/Utils.cpp @@ -360,4 +360,65 @@ LONGLONG DurationToAudioFrames(const REFERENCE_TIME& time, DWORD sampleRate) REFERENCE_TIME AudioFramesToDuration(const LONGLONG& frames, DWORD sampleRate) { return (frames * 10000000) / sampleRate; +} + +bool AsioSampleTypeFromFormat(ASIOSampleType* out, WORD bitsPerSample, bool isFloat) +{ + bool ret = true; + ASIOSampleType type = ASIOSTInt32LSB; + + if (!isFloat) + { + switch (bitsPerSample) + { + case 16: + type = ASIOSTInt16LSB; + break; + case 24: + type = ASIOSTInt24LSB; + break; + case 32: + type = ASIOSTInt32LSB; + break; + default: + return false; + } + } + else + { + switch (bitsPerSample) + { + case 32: + type = ASIOSTFloat32LSB; + break; + case 64: + type = ASIOSTFloat64LSB; + break; + default: + return false; + } + } + + if (out) + *out = type; + + return ret; +} + +WORD GetAsioSampleTypeNumBytes(ASIOSampleType sampleType) +{ + switch (sampleType) + { + case ASIOSTInt16LSB: + return 2; + case ASIOSTInt24LSB: + return 3; + case ASIOSTInt32LSB: + case ASIOSTFloat32LSB: + return 4; + case ASIOSTFloat64LSB: + return 8; + } + + return 0; } \ No newline at end of file diff --git a/RS_ASIO/Utils.h b/RS_ASIO/Utils.h index f362948..8cfddf4 100644 --- a/RS_ASIO/Utils.h +++ b/RS_ASIO/Utils.h @@ -48,3 +48,6 @@ REFERENCE_TIME MilisecsToRefTime(LONGLONG ms); LONGLONG RefTimeToMilisecs(const REFERENCE_TIME& time); LONGLONG DurationToAudioFrames(const REFERENCE_TIME& time, DWORD sampleRate); REFERENCE_TIME AudioFramesToDuration(const LONGLONG& frames, DWORD sampleRate); + +bool AsioSampleTypeFromFormat(ASIOSampleType* out, WORD bitsPerSample, bool isFloat); +WORD GetAsioSampleTypeNumBytes(ASIOSampleType sampleType); diff --git a/RS_ASIO/asio.h b/RS_ASIO/asio.h index 28af96a..2945912 100644 --- a/RS_ASIO/asio.h +++ b/RS_ASIO/asio.h @@ -195,7 +195,7 @@ enum ASIOSampleType : long { // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these - ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment + ASIOSTInt32LSB16 = 24, // 32 bit data with 16 bit alignment ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment