- Added DirectSoundOut plugin for Windows

- Updated WasapiOut to pre-calculate the stream latency
This commit is contained in:
casey langen 2016-12-18 17:15:00 -08:00
parent 60f8d5ab50
commit d27b911ede
11 changed files with 774 additions and 8 deletions

View File

@ -5,6 +5,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "musikbox", "src\musikbox\musikbox.vcxproj", "{C7102EB1-7311-4B36-A7FF-89DD7F077FF9}"
ProjectSection(ProjectDependencies) = postProject
{68AA481E-3CCE-440F-8CCE-69F1B371C89D} = {68AA481E-3CCE-440F-8CCE-69F1B371C89D}
{51C18730-DC48-411A-829D-F2B3B7AC4C97} = {51C18730-DC48-411A-829D-F2B3B7AC4C97}
{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}
@ -40,6 +41,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wasapiout", "src\contrib\wa
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nomaddecoder", "src\contrib\nomaddecoder\nomaddecoder.vcxproj", "{CA56A398-7F9A-493A-A7FC-C6B4D550B674}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directsoundout", "src\contrib\directsoundout\directsoundout.vcxproj", "{51C18730-DC48-411A-829D-F2B3B7AC4C97}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -98,6 +101,10 @@ Global
{CA56A398-7F9A-493A-A7FC-C6B4D550B674}.Debug|Win32.Build.0 = Debug|Win32
{CA56A398-7F9A-493A-A7FC-C6B4D550B674}.Release|Win32.ActiveCfg = Release|Win32
{CA56A398-7F9A-493A-A7FC-C6B4D550B674}.Release|Win32.Build.0 = Release|Win32
{51C18730-DC48-411A-829D-F2B3B7AC4C97}.Debug|Win32.ActiveCfg = Debug|Win32
{51C18730-DC48-411A-829D-F2B3B7AC4C97}.Debug|Win32.Build.0 = Debug|Win32
{51C18730-DC48-411A-829D-F2B3B7AC4C97}.Release|Win32.ActiveCfg = Release|Win32
{51C18730-DC48-411A-829D-F2B3B7AC4C97}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,399 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 "DirectSoundOut.h"
#include <ks.h>
#include <ksmedia.h>
#include <iostream>
#include <chrono>
#include <thread>
#define MAX_BUFFERS_PER_OUTPUT 8
#define BUFFER_SIZE_BYTES_PER_CHANNEL \
(2048 * sizeof(float) * MAX_BUFFERS_PER_OUTPUT)
using Lock = std::unique_lock<std::recursive_mutex>;
inline DWORD getAvailableBytes(
IDirectSoundBuffer8 *secondaryBuffer,
DWORD writeOffset,
DWORD bufferSize)
{
DWORD readOffset = 0;
secondaryBuffer->GetCurrentPosition(&readOffset, nullptr);
if (writeOffset == readOffset) {
return 0;
}
DWORD available = 0;
if (writeOffset > readOffset) {
available = (bufferSize - writeOffset) + readOffset;
}
else {
available = readOffset - writeOffset;
}
return available;
}
DirectSoundOut::DirectSoundOut()
: state(StateStopped)
, outputContext(nullptr)
, primaryBuffer(nullptr)
, secondaryBuffer(nullptr)
, bufferSize(0)
, writeOffset(0)
, latency(0)
, rate(0)
, channels(0)
, volume(1.0f) {
ZeroMemory(&waveFormat, sizeof(WAVEFORMATEXTENSIBLE));
}
DirectSoundOut::~DirectSoundOut() {
}
void DirectSoundOut::Destroy() {
this->Reset();
delete this;
}
void DirectSoundOut::Pause() {
this->state = StatePaused;
Lock lock(this->stateMutex);
if (this->primaryBuffer) {
this->primaryBuffer->Stop();
}
if (this->secondaryBuffer) {
this->secondaryBuffer->Stop();
}
}
void DirectSoundOut::Resume() {
this->state = StatePlaying;
Lock lock(this->stateMutex);
if (this->secondaryBuffer) {
this->secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
}
if (this->primaryBuffer) {
this->primaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
}
}
void DirectSoundOut::SetVolume(double volume) {
Lock lock(this->stateMutex);
this->volume = volume;
if (this->state != StateStopped) {
if (this->secondaryBuffer) {
double db = 20 * log(this->volume) * 100;
this->secondaryBuffer->SetVolume((LONG) db);
}
}
}
void DirectSoundOut::Stop() {
Lock lock(this->stateMutex);
this->ResetBuffers();
this->state = StateStopped;
}
bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) {
{
Lock lock(this->stateMutex);
if (!this->Configure(buffer)) {
this->Reset();
return false;
}
unsigned char *dst1 = nullptr, *dst2 = nullptr;
DWORD size1 = 0, size2 = 0;
DWORD availableBytes = 0;
DWORD bufferBytes = buffer->Bytes();
do {
availableBytes = getAvailableBytes(
this->secondaryBuffer,
this->writeOffset,
this->bufferSize);
if (bufferBytes > availableBytes) {
int samples = (bufferBytes - availableBytes) / sizeof(float) / channels;
int sleepMs = ((long long)(samples * 1000) / rate) + 1;
Sleep(sleepMs);
}
} while (this->state == StatePlaying && availableBytes < bufferBytes);
if (this->state != StatePlaying) {
return false;
}
HRESULT result =
this->secondaryBuffer->Lock(
writeOffset,
bufferBytes,
(void **) &dst1, &size1,
(void **) &dst2, &size2,
0);
if (result == DSERR_BUFFERLOST) {
this->secondaryBuffer->Restore();
result = this->secondaryBuffer->Lock(
writeOffset,
bufferBytes,
(void **) &dst1, &size1,
(void **) &dst2, &size2,
0);
}
if (result != DS_OK) {
return false;
}
char* bufferPointer = (char *) buffer->BufferPointer();
memcpy(dst1, bufferPointer, size1);
if (size2 > 0) {
memcpy(dst2, bufferPointer + size1, size2);
}
writeOffset += bufferBytes;
writeOffset %= this->bufferSize;
this->secondaryBuffer->Unlock((void *)dst1, size1, (void *)dst2, size2);
}
provider->OnBufferProcessed(buffer);
return true;
}
void DirectSoundOut::Reset() {
this->ResetBuffers();
if (this->outputContext) {
this->outputContext->Release();
this->outputContext = nullptr;
}
}
void DirectSoundOut::ResetBuffers() {
ZeroMemory(&waveFormat, sizeof(WAVEFORMATEXTENSIBLE));
this->bufferSize = 0;
this->writeOffset = 0;
if (this->secondaryBuffer) {
this->secondaryBuffer->Stop();
this->secondaryBuffer->Release();
this->secondaryBuffer = nullptr;
}
if (this->primaryBuffer) {
this->primaryBuffer->Stop();
this->primaryBuffer->Release();
this->primaryBuffer = nullptr;
}
}
double DirectSoundOut::Latency() {
return (double) latency / 1000;
}
bool DirectSoundOut::Configure(IBuffer *buffer) {
/* do a quick check up front to see if we're already in a valid state.
if so, return immediately without changing anything else! */
if (this->outputContext &&
this->primaryBuffer &&
this->secondaryBuffer &&
this->rate == buffer->SampleRate() &&
this->channels == buffer->Channels())
{
return true;
}
HRESULT result;
if (!this->outputContext) {
result = DirectSoundCreate8(nullptr, &this->outputContext, nullptr);
if (result != DS_OK) {
return false;
}
/* DSSCL_PRIORITY allows us to change the sample format */
result = this->outputContext->
SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY);
if (result != DS_OK) {
return false;
}
}
/* this is our "primary" buffer. we set this thing up, but end up
writing all data to the secondary buffer. the system takes care
of mixing the secondary buffer(s) into the primary before writing
it back to the sound system. */
if (this->primaryBuffer == nullptr) {
DSBUFFERDESC bufferInfo;
ZeroMemory(&bufferInfo, sizeof(DSBUFFERDESC));
/* LOCHARDWARE means we want the audio hardware (not software) to
do the mixing for us. */
bufferInfo.dwFlags =
DSBCAPS_PRIMARYBUFFER |
DSBCAPS_CTRLVOLUME |
DSBCAPS_LOCHARDWARE;
bufferInfo.dwSize = sizeof(DSBUFFERDESC);
bufferInfo.dwBufferBytes = 0;
bufferInfo.lpwfxFormat = nullptr;
result = this->outputContext->CreateSoundBuffer(&bufferInfo, &this->primaryBuffer, nullptr);
if (result != DS_OK) {
return false;
}
}
/* if the channels or sampling rate has changed, reset the secondary
buffer so we can re-create it with the correct attributes */
if (this->rate != buffer->SampleRate() ||
this->channels != buffer->Channels())
{
if (this->secondaryBuffer) {
this->secondaryBuffer->Stop();
this->secondaryBuffer->Release();
this->secondaryBuffer = nullptr;
}
this->rate = buffer->SampleRate();
this->channels = buffer->Channels();
}
/* the secondary buffer is where we actually write data. the runtime
will take care of mixing it into the buffer we register with the
DSBCAPS_PRIMARYBUFFER (this->primaryBuffer) */
if (this->secondaryBuffer == nullptr) {
DSBUFFERDESC bufferInfo;
ZeroMemory(&bufferInfo, sizeof(DSBUFFERDESC));
bufferInfo.dwSize = sizeof(DSBUFFERDESC);
bufferInfo.dwFlags =
DSBCAPS_CTRLFREQUENCY |
DSBCAPS_CTRLPAN |
DSBCAPS_CTRLVOLUME |
DSBCAPS_GLOBALFOCUS |
DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_CTRLPOSITIONNOTIFY;
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;
bufferInfo.lpwfxFormat = (WAVEFORMATEX*) &wf;
bufferInfo.dwBufferBytes = BUFFER_SIZE_BYTES_PER_CHANNEL * buffer->Channels();
this->bufferSize = bufferInfo.dwBufferBytes;
IDirectSoundBuffer *tempBuffer;
result = this->outputContext->CreateSoundBuffer(&bufferInfo, &tempBuffer, nullptr);
if (result != DS_OK) {
return false;
}
result = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**) &this->secondaryBuffer);
if (result != DS_OK) {
tempBuffer->Release();
return false;
}
tempBuffer->Release();
}
this->primaryBuffer->SetCurrentPosition(0);
this->primaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
this->secondaryBuffer->SetCurrentPosition(0);
this->secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
int samples = this->bufferSize / sizeof(float) / channels;
this->latency = (float)samples / (float)rate;
this->state = StatePlaying;
this->SetVolume(this->volume);
return true;
}

View File

@ -0,0 +1,93 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 <deque>
#include <memory>
#include <mutex>
#include <atomic>
#include <mmreg.h>
#include <dsound.h>
#include <core/sdk/IOutput.h>
using namespace musik::core::sdk;
class DirectSoundOut : public IOutput {
public:
DirectSoundOut();
~DirectSoundOut();
/* IPlugin */
const char* Name() { return "DirectSound IOutput"; };
const char* Version() { return "0.1"; };
const char* Author() { return "clangen"; };
virtual void Destroy();
/* IOutput */
virtual void Pause();
virtual void Resume();
virtual void SetVolume(double volume);
virtual void Stop();
virtual bool Play(IBuffer *buffer, IBufferProvider *provider);
virtual double Latency();
private:
enum State {
StateStopped,
StatePlaying,
StatePaused
};
bool Configure(IBuffer *buffer);
void Reset();
void ResetBuffers();
State state;
WAVEFORMATEXTENSIBLE waveFormat;
IDirectSound8 *outputContext;
IDirectSoundBuffer *primaryBuffer;
IDirectSoundBuffer8 *secondaryBuffer;
DWORD bufferSize;
DWORD writeOffset;
int rate;
int channels;
double volume;
double latency;
std::recursive_mutex stateMutex;
};

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{51c18730-dc48-411a-829d-f2b3b7ac4c97}</ProjectGuid>
<RootNamespace>directsoundout</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)/bin/$(Configuration)/plugins\</OutDir>
<IntDir>./obj/$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
<CodeAnalysisRuleAssemblies />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)/bin/$(Configuration)/plugins\</OutDir>
<IntDir>./obj/$(Configuration)\</IntDir>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
<CodeAnalysisRuleAssemblies />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../..;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>dsound.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../3rdparty/lib;../../../../boost_1_60_0/lib32-msvc-14.0;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>../..;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat />
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>dsound.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../3rdparty/lib;../../../../boost_1_60_0/lib32-msvc-14.0;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>false</GenerateDebugInformation>
<FullProgramDatabaseFile>false</FullProgramDatabaseFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="DirectSoundOut.cpp" />
<ClCompile Include="directsoundout_plugin.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="DirectSoundOut.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="plugin">
<UniqueIdentifier>{aaeaedc0-8213-46c7-8e9d-2c56ce4b6325}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{ce86be01-a456-4ff6-b915-9a7c062f57b1}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>plugin</Filter>
</ClCompile>
<ClCompile Include="directsoundout_plugin.cpp">
<Filter>plugin</Filter>
</ClCompile>
<ClCompile Include="DirectSoundOut.cpp">
<Filter>plugin</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>plugin</Filter>
</ClInclude>
<ClInclude Include="DirectSoundOut.h">
<Filter>plugin</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 <core/sdk/IPlugin.h>
#include "DirectSoundOut.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
return true;
}
extern "C" __declspec(dllexport) musik::core::sdk::IPlugin* GetPlugin() {
return new DirectSoundOut();
}
extern "C" __declspec(dllexport) musik::core::sdk::IOutput* GetAudioOutput() {
return new DirectSoundOut();
}

View File

@ -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"

View File

@ -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 <core/config.h>

View File

@ -198,7 +198,7 @@ void WasapiOut::Reset() {
}
double WasapiOut::Latency() {
return (double) latency / 1000;
return this->latency;
}
bool WasapiOut::Configure(IBuffer *buffer) {
@ -237,7 +237,6 @@ bool WasapiOut::Configure(IBuffer *buffer) {
}
DWORD speakerConfig = 0;
switch (buffer->Channels()) {
case 1:
speakerConfig = KSAUDIO_SPEAKER_MONO;
@ -288,7 +287,7 @@ bool WasapiOut::Configure(IBuffer *buffer) {
return false;
}
this->latency = (outputBufferFrames * 1000) / buffer->SampleRate();
this->latency = (float) outputBufferFrames / (float) buffer->SampleRate();
if ((result = this->audioClient->GetService(__uuidof(IAudioRenderClient), (void**) &this->renderClient)) != S_OK) {
std::cerr << "WasapiOut: IAudioClient::GetService failed, error code = " << result << "\n";

View File

@ -76,8 +76,6 @@ class WasapiOut : public IOutput {
bool Configure(IBuffer *buffer);
void Reset();
void EventThread();
IMMDeviceEnumerator *enumerator;
IMMDevice *device;
IAudioClient *audioClient;
@ -88,7 +86,6 @@ class WasapiOut : public IOutput {
std::atomic<State> state;
WAVEFORMATEXTENSIBLE waveFormat;
double volume;
double latency;
std::recursive_mutex stateMutex;
INT64 latency;
};

View File

@ -41,7 +41,7 @@
using namespace cursespp;
#define VERTICAL_PADDING 2
#define DEFAULT_WIDTH 22
#define DEFAULT_WIDTH 26
#define MAX_HEIGHT 12
#define DISMISS() \