From a797d4db9dd666d0bbd063c3383293f277d5e8b9 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 4 Dec 2016 18:43:11 -0800 Subject: [PATCH] Added an initial WASAPI output plugin implementation. Down with waveout! (maybe). --- musikcube.sln | 7 + src/contrib/wasapiout/WasapiOut.cpp | 316 ++++++++++++++++++ src/contrib/wasapiout/WasapiOut.h | 89 +++++ src/contrib/wasapiout/pch.cpp | 35 ++ src/contrib/wasapiout/pch.h | 38 +++ src/contrib/wasapiout/wasapiout.vcproj | 217 ++++++++++++ src/contrib/wasapiout/wasapiout.vcxproj | 114 +++++++ .../wasapiout/wasapiout.vcxproj.filters | 32 ++ src/contrib/wasapiout/wasapiout_plugin.cpp | 57 ++++ 9 files changed, 905 insertions(+) create mode 100644 src/contrib/wasapiout/WasapiOut.cpp create mode 100644 src/contrib/wasapiout/WasapiOut.h create mode 100644 src/contrib/wasapiout/pch.cpp create mode 100644 src/contrib/wasapiout/pch.h create mode 100644 src/contrib/wasapiout/wasapiout.vcproj create mode 100644 src/contrib/wasapiout/wasapiout.vcxproj create mode 100644 src/contrib/wasapiout/wasapiout.vcxproj.filters create mode 100644 src/contrib/wasapiout/wasapiout_plugin.cpp diff --git a/musikcube.sln b/musikcube.sln index 66ef73760..2109834a7 100644 --- a/musikcube.sln +++ b/musikcube.sln @@ -6,6 +6,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "musikbox", "src\musikbox\mu ProjectSection(ProjectDependencies) = postProject {68AA481E-3CCE-440F-8CCE-69F1B371C89D} = {68AA481E-3CCE-440F-8CCE-69F1B371C89D} {3E30064E-B9C4-4690-8AC2-2C694176A319} = {3E30064E-B9C4-4690-8AC2-2C694176A319} + {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304} = {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304} {54764854-5A73-4329-9BAD-9AF22C72D9E2} = {54764854-5A73-4329-9BAD-9AF22C72D9E2} {465EF178-91C1-4068-BE1D-F9616ECCB6DE} = {465EF178-91C1-4068-BE1D-F9616ECCB6DE} {4F10C17A-8AF7-4FAC-A4E2-087AE6E8F9D8} = {4F10C17A-8AF7-4FAC-A4E2-087AE6E8F9D8} @@ -37,6 +38,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32globalhotkeys", "src\c EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32gdivis", "src\contrib\win32gdivis\GdiVis-musikcube.vcxproj", "{68AA481E-3CCE-440F-8CCE-69F1B371C89D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wasapiout", "src\contrib\wasapiout\wasapiout.vcxproj", "{EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -91,6 +94,10 @@ Global {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Debug|Win32.Build.0 = Debug|Win32 {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Release|Win32.ActiveCfg = Release|Win32 {68AA481E-3CCE-440F-8CCE-69F1B371C89D}.Release|Win32.Build.0 = Release|Win32 + {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304}.Debug|Win32.ActiveCfg = Debug|Win32 + {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304}.Debug|Win32.Build.0 = Debug|Win32 + {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304}.Release|Win32.ActiveCfg = Release|Win32 + {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/contrib/wasapiout/WasapiOut.cpp b/src/contrib/wasapiout/WasapiOut.cpp new file mode 100644 index 000000000..403b96312 --- /dev/null +++ b/src/contrib/wasapiout/WasapiOut.cpp @@ -0,0 +1,316 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "WasapiOut.h" +#include +#include +#include +#include + +#define MAX_BUFFERS_PER_OUTPUT 32 + +/* NOTE! device init and deinit logic was stolen and modified from +QMMP's WASABI output plugin! http://qmmp.ylsoftware.com/ */ + +#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM +#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000 +#endif + +using Lock = std::unique_lock; + +WasapiOut::WasapiOut() +: enumerator(nullptr) +, device(nullptr) +, audioClient(nullptr) +, renderClient(nullptr) +, simpleAudioVolume(nullptr) +, outputBufferSize(0) +, state(Stopped) { + memset(&waveFormat, 0, sizeof(WAVEFORMATEXTENSIBLE)); +} + +WasapiOut::~WasapiOut() { +} + +void WasapiOut::Destroy() { + this->Reset(); + delete this; +} + +void WasapiOut::Pause() { + Lock lock(this->stateMutex); + + if (this->audioClient) { + this->state = Paused; + this->audioClient->Stop(); + } +} + +void WasapiOut::Resume() { + Lock lock(this->stateMutex); + + if (this->audioClient) { + this->state = Playing; + this->audioClient->Start(); + } +} + +void WasapiOut::SetVolume(double volume) { + Lock lock(this->stateMutex); + + if (this->simpleAudioVolume) { + simpleAudioVolume->SetMasterVolume((float) volume, 0); + } +} + +void WasapiOut::Stop() { + { + Lock lock(this->stateMutex); + + if (this->audioClient) { + this->audioClient->Stop(); + this->audioClient->Reset(); + this->audioClient->Start(); + } + } + + std::deque> toRelease; + + { + Lock lock(this->bufferQueueMutex); + std::swap(this->pendingQueue, toRelease); + } + + auto it = toRelease.begin(); + while (it != toRelease.end()) { + (*it)->provider->OnBufferProcessed((*it)->buffer); + ++it; + } +} + +bool WasapiOut::Play(IBuffer *buffer, IBufferProvider *provider) { + { + Lock lock(this->stateMutex); + + if (!this->Configure(buffer)) { + this->Reset(); + return false; + } + + this->state = Playing; + + UINT32 availableFrames; + UINT32 frameOffset = 0; + UINT32 samples = (UINT32)buffer->Samples(); + UINT32 framesToWrite = samples / (UINT32)buffer->Channels(); + int channels = buffer->Channels(); + + do { + this->audioClient->GetCurrentPadding(&frameOffset); + availableFrames = (this->outputBufferSize - frameOffset); + + if (availableFrames < framesToWrite) { + UINT32 delta = framesToWrite - availableFrames; + REFERENCE_TIME sleepTime = (delta * 1000 * 1000) / buffer->SampleRate(); + std::this_thread::sleep_for(std::chrono::microseconds(sleepTime)); + } + } while (this->state == Playing && availableFrames < framesToWrite); + + if (state != Playing) { + return false; + } + + if (availableFrames >= framesToWrite) { + BYTE *data = 0; + HRESULT result = this->renderClient->GetBuffer(framesToWrite, &data); + + if (result != S_OK) { + return false; + } + + memcpy(data, buffer->BufferPointer(), sizeof(float) * samples); + this->renderClient->ReleaseBuffer(framesToWrite, 0); + } + } + + { + Lock lock(this->bufferQueueMutex); + + std::shared_ptr context(new BufferContext()); + context->buffer = buffer; + context->provider = provider; + pendingQueue.push_back(context); + + if (pendingQueue.size() >= MAX_BUFFERS_PER_OUTPUT) { + context = pendingQueue.front(); + pendingQueue.pop_front(); + context->provider->OnBufferProcessed(context->buffer); + } + } + + return true; +} + +void WasapiOut::Reset() { + if (this->audioClient) { + this->audioClient->Stop(); + this->audioClient->Release(); + this->audioClient = nullptr; + } + + if (this->enumerator) { + this->enumerator->Release(); + this->enumerator = nullptr; + } + + if (this->device) { + this->device->Release(); + this->device = 0; + } + + if (this->renderClient) { + this->renderClient->Release(); + this->renderClient = nullptr; + } + + if (this->simpleAudioVolume) { + this->simpleAudioVolume->Release(); + this->simpleAudioVolume = nullptr; + } +} + +bool WasapiOut::Configure(IBuffer *buffer) { + HRESULT result; + + if (!this->audioClient) { + CoInitialize(nullptr); + + result = CoCreateInstance( + __uuidof(MMDeviceEnumerator), + NULL, + CLSCTX_ALL, + __uuidof(IMMDeviceEnumerator), + (void**) &this->enumerator); + + if (result != S_OK) { + std::cerr << "WasapiOut: CoCreateInstance failed, error code = " << result << "\n"; + return false; + } + + if ((result = this->enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &this->device)) != S_OK) { + std::cerr << "WasapiOut: IMMDeviceEnumerator::GetDefaultAudioEndpoint failed, error code = " << result << "\n"; + return false; + } + + if ((result = this->device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**) &this->audioClient)) != S_OK) { + std::cerr << "WasapiOut: IMMDevice::Activate failed, error code = " << result << "\n"; + return false; + } + } + + if (waveFormat.Format.nChannels == buffer->Channels() && + waveFormat.Format.nSamplesPerSec == buffer->SampleRate()) + { + return true; + } + + DWORD speakerConfig = 0; + + switch (buffer->Channels()) { + case 1: + speakerConfig = KSAUDIO_SPEAKER_MONO; + break; + case 2: + speakerConfig = KSAUDIO_SPEAKER_STEREO; + break; + case 4: + speakerConfig = KSAUDIO_SPEAKER_QUAD; + break; + case 5: + speakerConfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT); + break; + case 6: + speakerConfig = KSAUDIO_SPEAKER_5POINT1; + break; + } + + WAVEFORMATEXTENSIBLE &wf = this->waveFormat; + wf.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE); + wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wf.Format.nChannels = (WORD) buffer->Channels(); + wf.Format.wBitsPerSample = 8 * sizeof(float); + wf.Format.nSamplesPerSec = (DWORD) buffer->SampleRate(); + wf.Samples.wValidBitsPerSample = 8 * sizeof(float); + wf.Format.nBlockAlign = (wf.Format.wBitsPerSample / 8) * wf.Format.nChannels; + wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign; + wf.dwChannelMask = speakerConfig; + wf.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + + DWORD streamFlags = 0; + + if (this->audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX *) &wf, 0) != S_OK) { + streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; + std::cerr << "WasapiOut: format is not supported, using converter\n"; + } + + long totalMillis = (long) round((buffer->Samples() * 1000) / buffer->SampleRate()) * MAX_BUFFERS_PER_OUTPUT; + REFERENCE_TIME hundredNanos = totalMillis * 1000 * 10; + + if ((result = this->audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, streamFlags, hundredNanos, 0, (WAVEFORMATEX *) &wf, NULL)) != S_OK) { + std::cerr << "WasapiOut: IAudioClient::Initialize failed, error code = " << result << "\n"; + return false; + } + + if ((result = this->audioClient->GetBufferSize(&this->outputBufferSize)) != S_OK) { + std::cerr << "WasapiOut: IAudioClient::GetBufferSize failed, error code = " << result << "\n"; + return false; + } + + if ((result = this->audioClient->GetService(__uuidof(IAudioRenderClient), (void**) &this->renderClient)) != S_OK) { + std::cerr << "WasapiOut: IAudioClient::GetService failed, error code = " << result << "\n"; + return false; + } + + if ((result = this->audioClient->GetService(__uuidof(ISimpleAudioVolume), (void**) &this->simpleAudioVolume)) != S_OK) { + std::cerr << "WasapiOut: IAudioClient::GetService failed, error code = " << result << "\n"; + return false; + } + + if ((result = this->audioClient->Start()) != S_OK) { + std::cerr << "WasapiOut: IAudioClient::Start failed, error code = " << result << "\n"; + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/contrib/wasapiout/WasapiOut.h b/src/contrib/wasapiout/WasapiOut.h new file mode 100644 index 000000000..cfd0838e7 --- /dev/null +++ b/src/contrib/wasapiout/WasapiOut.h @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "pch.h" + +#include +#include +#include + +#include +#include + +#include + +using namespace musik::core::sdk; + +class WasapiOut : public IOutput { + public: + WasapiOut(); + ~WasapiOut(); + + virtual void Destroy(); + virtual void Pause(); + virtual void Resume(); + virtual void SetVolume(double volume); + virtual void Stop(); + virtual bool Play(IBuffer *buffer, IBufferProvider *provider); + + private: + enum State { + Stopped, + Playing, + Paused + }; + + struct BufferContext { + IBuffer *buffer; + IBufferProvider *provider; + }; + + bool Configure(IBuffer *buffer); + void Reset(); + + IMMDeviceEnumerator *enumerator; + IMMDevice *device; + IAudioClient *audioClient; + IAudioRenderClient *renderClient; + ISimpleAudioVolume *simpleAudioVolume; + WAVEFORMATEXTENSIBLE waveFormat; + UINT32 outputBufferSize; + UINT64 totalSamplesWritten; + State state; + + std::recursive_mutex bufferQueueMutex; + std::recursive_mutex stateMutex; + std::deque> pendingQueue; +}; diff --git a/src/contrib/wasapiout/pch.cpp b/src/contrib/wasapiout/pch.cpp new file mode 100644 index 000000000..9e3cc1e2e --- /dev/null +++ b/src/contrib/wasapiout/pch.cpp @@ -0,0 +1,35 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "pch.h" \ No newline at end of file diff --git a/src/contrib/wasapiout/pch.h b/src/contrib/wasapiout/pch.h new file mode 100644 index 000000000..147dccaec --- /dev/null +++ b/src/contrib/wasapiout/pch.h @@ -0,0 +1,38 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + diff --git a/src/contrib/wasapiout/wasapiout.vcproj b/src/contrib/wasapiout/wasapiout.vcproj new file mode 100644 index 000000000..90951c267 --- /dev/null +++ b/src/contrib/wasapiout/wasapiout.vcproj @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/contrib/wasapiout/wasapiout.vcxproj b/src/contrib/wasapiout/wasapiout.vcxproj new file mode 100644 index 000000000..4386b3f33 --- /dev/null +++ b/src/contrib/wasapiout/wasapiout.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {ebd2e652-aa1b-4b8b-8d03-ccecb9bf3304} + wasapiout + + + + DynamicLibrary + v140 + Unicode + + + DynamicLibrary + v140 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>14.0.25123.0 + + + $(SolutionDir)/bin/$(Configuration)/plugins\ + ./obj/$(Configuration)\ + true + MinimumRecommendedRules.ruleset + + + + + $(SolutionDir)/bin/$(Configuration)/plugins\ + ./obj/$(Configuration)\ + MinimumRecommendedRules.ruleset + + + + + + Disabled + ../..;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + EditAndContinue + $(IntDir) + $(IntDir) + $(IntDir)vc$(PlatformToolsetVersion).pdb + + + winmm.lib;%(AdditionalDependencies) + ../../3rdparty/lib;../../../../boost_1_60_0/lib32-msvc-14.0;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + false + + + + + AnySuitable + true + ../..;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + Level3 + + $(IntDir) + $(IntDir) + $(IntDir)vc$(PlatformToolsetVersion).pdb + + + winmm.lib;%(AdditionalDependencies) + ../../3rdparty/lib;../../../../boost_1_60_0/lib32-msvc-14.0;%(AdditionalLibraryDirectories) + Windows + true + true + UseLinkTimeCodeGeneration + MachineX86 + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/contrib/wasapiout/wasapiout.vcxproj.filters b/src/contrib/wasapiout/wasapiout.vcxproj.filters new file mode 100644 index 000000000..ca583540d --- /dev/null +++ b/src/contrib/wasapiout/wasapiout.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + plugin + + + plugin + + + plugin + + + + + plugin + + + plugin + + + \ No newline at end of file diff --git a/src/contrib/wasapiout/wasapiout_plugin.cpp b/src/contrib/wasapiout/wasapiout_plugin.cpp new file mode 100644 index 000000000..a42970d11 --- /dev/null +++ b/src/contrib/wasapiout/wasapiout_plugin.cpp @@ -0,0 +1,57 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "pch.h" + +#include +#include "WasapiOut.h" + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + return true; +} + +class WasapiOutPlugin : public musik::core::sdk::IPlugin { + void Destroy() { delete this; }; + const char* Name() { return "WASAPI IOutput"; }; + const char* Version() { return "0.1"; }; + const char* Author() { return "clangen"; }; +}; + +extern "C" __declspec(dllexport) musik::core::sdk::IPlugin* GetPlugin() { + return new WasapiOutPlugin(); +} + +extern "C" __declspec(dllexport) musik::core::sdk::IOutput* GetAudioOutput() { + return new WasapiOut(); +}