mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
- Added DirectSoundOut plugin for Windows
- Updated WasapiOut to pre-calculate the stream latency
This commit is contained in:
parent
60f8d5ab50
commit
d27b911ede
@ -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
|
||||
|
399
src/contrib/directsoundout/DirectSoundOut.cpp
Normal file
399
src/contrib/directsoundout/DirectSoundOut.cpp
Normal 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;
|
||||
}
|
93
src/contrib/directsoundout/DirectSoundOut.h
Normal file
93
src/contrib/directsoundout/DirectSoundOut.h
Normal 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;
|
||||
};
|
116
src/contrib/directsoundout/directsoundout.vcxproj
Normal file
116
src/contrib/directsoundout/directsoundout.vcxproj
Normal 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>
|
32
src/contrib/directsoundout/directsoundout.vcxproj.filters
Normal file
32
src/contrib/directsoundout/directsoundout.vcxproj.filters
Normal 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>
|
50
src/contrib/directsoundout/directsoundout_plugin.cpp
Normal file
50
src/contrib/directsoundout/directsoundout_plugin.cpp
Normal 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();
|
||||
}
|
35
src/contrib/directsoundout/pch.cpp
Normal file
35
src/contrib/directsoundout/pch.cpp
Normal 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"
|
38
src/contrib/directsoundout/pch.h
Normal file
38
src/contrib/directsoundout/pch.h
Normal 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>
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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() \
|
||||
|
Loading…
Reference in New Issue
Block a user