//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // // Implementation for KinectAudioStream methods. // KinectAudioStream wraps the Kinect audio stream and does proper format // conversion during read. // //------------------------------------------------------------------------------ #include "stdafx.h" #include "KinectAudioStream.h" #include /// /// KinectAudioStream constructor. /// KinectAudioStream::KinectAudioStream(IStream *p32BitAudio) : m_cRef(1), m_p32BitAudio(p32BitAudio), m_SpeechActive(false) { } /// /// SetSpeechState method /// void KinectAudioStream::SetSpeechState(bool state) { m_SpeechActive = state; } ///////////////////////////////////////////// // IStream methods __pragma(warning(push)) __pragma(warning(disable:6101)) // Suppress warning about returning uninitialized memory *pBuffer. It is written correctly. __pragma(warning(disable:6386)) // Suppress warning about buffer overrun while writing to 'pByteBuffer'. There are no overruns. STDMETHODIMP KinectAudioStream::Read( _Out_writes_bytes_to_(cbBuffer, *pcbRead) void *pBuffer, _In_ ULONG cbBuffer, _Out_opt_ ULONG *pcbRead) { if (pBuffer == NULL || pcbRead == NULL || cbBuffer == 0) { return E_INVALIDARG; } HRESULT hr = S_OK; // 32bit -> 16bit conversion support INT16* p16Buffer = (INT16*)pBuffer; int factor = sizeof(float)/sizeof(INT16); // 32 bit read support float* p32Buffer = new float[cbBuffer/factor]; byte* pByteBuffer = (byte*)p32Buffer; ULONG bytesRead = 0; ULONG bytesRemaining = cbBuffer * factor; // Speech reads at high frequency - this slows down the process int sleepDuration = 50; // Speech Service isn't tolerant of partial reads while (bytesRemaining > 0) { // Stop returning Audio data if Speech isn't active if (!m_SpeechActive) { *pcbRead = 0; hr = S_FALSE; goto exit; } // bytesRead will always be a multiple of 4 ( = sizeof(float)) hr = m_p32BitAudio->Read(pByteBuffer, bytesRemaining, &bytesRead); pByteBuffer += bytesRead; bytesRemaining -= bytesRead; // All Audio buffers drained - wait for buffers to fill if (bytesRemaining != 0) { Sleep(sleepDuration); } } // Convert float value [-1,1] to int16 [SHRT_MIN, SHRT_MAX] and copy to output butter for (UINT i = 0; i < cbBuffer/factor; i++) { float sample = p32Buffer[i]; // Make sure it is in the range [-1, +1] if (sample > 1.0f) { sample = 1.0f; } else if (sample < -1.0f) { sample = -1.0f; } // Scale float to the range (SHRT_MIN, SHRT_MAX] and then // convert to 16-bit signed with proper rounding float sampleScaled = sample * (float)SHRT_MAX; p16Buffer[i] = (sampleScaled > 0.f) ? (INT16)(sampleScaled + 0.5f) : (INT16)(sampleScaled - 0.5f); } *pcbRead = cbBuffer; exit: delete[] p32Buffer; return hr; } __pragma(warning(pop)) STDMETHODIMP KinectAudioStream::Write(_In_reads_bytes_(cb) const void *pv, _In_ ULONG cb, _Out_opt_ ULONG *pcbWritten) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::Seek(LARGE_INTEGER /* dlibMove */, DWORD /* dwOrigin */, _Out_opt_ ULARGE_INTEGER *plibNewPosition) { // Speech seeks and expects a seek implementation - but the NUIAudio stream doesn't support seeking if (plibNewPosition != NULL) { plibNewPosition->QuadPart = 0; } return S_OK; } STDMETHODIMP KinectAudioStream::SetSize(ULARGE_INTEGER) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::CopyTo(_In_ IStream *, ULARGE_INTEGER, _Out_opt_ ULARGE_INTEGER *, _Out_opt_ ULARGE_INTEGER *) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::Commit(DWORD) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::Revert() { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::Stat(__RPC__out STATSTG *, DWORD) { return E_NOTIMPL; } STDMETHODIMP KinectAudioStream::Clone(__RPC__deref_out_opt IStream **) { return E_NOTIMPL; }