Skip to content

Commit 14a8637

Browse files
prepared v 0.7.0b
1 parent 39fc156 commit 14a8637

20 files changed

+349
-217
lines changed

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
.vs
22
x64
3-
*.txt
43
*.iobj
54
*.ipdb
65
*.ipdb
7-
*.pdb
6+
*.pdb
7+
*.vcxproj.filters
8+
*.zip
9+
\[stuff\]/

CaptureLoop.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "CaptureLoop.h"
2+
3+
CaptureLoop::CaptureLoop(Config *pConfig, const AudioDevice *pRenderDevice, IAudioRenderClient *pRenderClient, IAudioCaptureClient *pCaptureClient, const std::vector<Input*> &inputs, const std::vector<Output*> &outputs) {
4+
_pConfig = pConfig;
5+
_pRenderDevice = pRenderDevice;
6+
_pRenderClient = pRenderClient;
7+
_pCaptureClient = pCaptureClient;
8+
_inputs = inputs;
9+
_outputs = outputs;
10+
_nChannelsIn = inputs.size();
11+
_nChannelsOut = outputs.size();
12+
13+
//Initialize clipping detection
14+
_pClippingChannels = new float[_nChannelsOut];
15+
memset(_pClippingChannels, 0, _nChannelsOut * sizeof(float));
16+
17+
//Initialize conditions
18+
_pUsedChannels = new time_t[_nChannelsIn];
19+
memset(_pUsedChannels, 0, _nChannelsIn * sizeof(time_t));
20+
Condition::init(_pUsedChannels);
21+
}
22+
23+
CaptureLoop::~CaptureLoop() {
24+
delete[] _pUsedChannels;
25+
delete[] _pClippingChannels;
26+
}
27+
28+
void CaptureLoop::capture() {
29+
UINT32 numFramesAvailable, i, j;
30+
HRESULT hr;
31+
DWORD flags;
32+
time_t now;
33+
float *pCaptureBuffer, *pRenderBuffer;
34+
size_t loopCounter = 0;
35+
size_t renderBlockSize = sizeof(float) * _nChannelsOut;
36+
37+
//Run infinite capture loop
38+
while (true) {
39+
//Check for samples in capture buffer
40+
hr = _pCaptureClient->GetNextPacketSize(&numFramesAvailable);
41+
assertHrResult(hr);
42+
43+
while (numFramesAvailable != 0) {
44+
//Get capture buffer pointer and number of available frames.
45+
hr = _pCaptureClient->GetBuffer((BYTE**)&pCaptureBuffer, &numFramesAvailable, &flags, NULL, NULL);
46+
assertHrResult(hr);
47+
48+
//Must read entire capture buffer at once. Wait until render buffer has enough space available.
49+
while (numFramesAvailable > _pRenderDevice->getBufferFrameCountAvailable()) {
50+
//Date::sleepMillis(1);
51+
}
52+
53+
//Get render buffer
54+
hr = _pRenderClient->GetBuffer(numFramesAvailable, (BYTE**)&pRenderBuffer);
55+
assertHrResult(hr);
56+
57+
//Set default value to 0 so we can add/mix values to it later
58+
memset(pRenderBuffer, 0, numFramesAvailable * renderBlockSize);
59+
60+
//Get current timestamp to mark playing channels with
61+
now = Date::getCurrentTimeMillis();
62+
63+
//Iterate all capture frames
64+
for (i = 0; i < numFramesAvailable; ++i) {
65+
for (j = 0; j < _nChannelsIn; ++j) {
66+
//Identify which channels are playing.
67+
if (pCaptureBuffer[j] != 0) {
68+
_pUsedChannels[j] = now;
69+
}
70+
71+
//Route sample to outputs
72+
_inputs[j]->route(pCaptureBuffer[j], pRenderBuffer);
73+
}
74+
75+
for (j = 0; j < _nChannelsOut; ++j) {
76+
//Apply output filters
77+
pRenderBuffer[j] = (float)_outputs[j]->process(pRenderBuffer[j]);
78+
79+
//Check for digital clipping
80+
if (abs(pRenderBuffer[j]) > 1.0) {
81+
_pClippingChannels[j] = max(_pClippingChannels[j], abs(pRenderBuffer[j]));
82+
}
83+
}
84+
85+
//Move buffers to next sample
86+
pCaptureBuffer += _nChannelsIn;
87+
pRenderBuffer += _nChannelsOut;
88+
}
89+
90+
//Release / flush buffers
91+
hr = _pCaptureClient->ReleaseBuffer(numFramesAvailable);
92+
assertHrResult(hr);
93+
hr = _pRenderClient->ReleaseBuffer(numFramesAvailable, 0);
94+
assertHrResult(hr);
95+
96+
//Check for more samples in capture buffer
97+
hr = _pCaptureClient->GetNextPacketSize(&numFramesAvailable);
98+
assertHrResult(hr);
99+
}
100+
101+
if (loopCounter == 1000) {
102+
loopCounter = 0;
103+
//Check if config file has changed
104+
checkConfig();
105+
//Check for unused channels
106+
checkUsedChannels();
107+
//Check for clipping out channels
108+
checkClippingChannels();
109+
}
110+
++loopCounter;
111+
112+
//Short sleep just to not busy wait all resources.
113+
Date::sleepMillis(1);
114+
}
115+
}

CaptureLoop.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#pragma once
2+
#include "Config.h"
3+
#include "ConfigChangedException.h"
4+
#include "Date.h"
5+
#include "Convert.h"
6+
7+
class CaptureLoop {
8+
public:
9+
10+
CaptureLoop(Config *pConfig, const AudioDevice *pRenderDevice, IAudioRenderClient *pRenderClient, IAudioCaptureClient *pCaptureClient, const std::vector<Input*> &inputs, const std::vector<Output*> &outputs);
11+
~CaptureLoop();
12+
13+
void capture();
14+
15+
private:
16+
Config *_pConfig;
17+
const AudioDevice *_pRenderDevice;
18+
IAudioRenderClient *_pRenderClient;
19+
IAudioCaptureClient *_pCaptureClient;
20+
std::vector<Input*> _inputs;
21+
std::vector<Output*> _outputs;
22+
size_t _nChannelsIn, _nChannelsOut;
23+
time_t *_pUsedChannels;
24+
float *_pClippingChannels;
25+
26+
inline void checkConfig() {
27+
if (_pConfig->hasChanged()) {
28+
throw ConfigChangedException();
29+
}
30+
}
31+
32+
inline void checkUsedChannels() {
33+
const time_t now = Date::getCurrentTimeMillis();
34+
//Compare now against last used timestamp and determine active channels
35+
for (size_t i = 0; i < _nChannelsIn; ++i) {
36+
if (now - _pUsedChannels[i] > 1000) {
37+
_pUsedChannels[i] = 0;
38+
}
39+
}
40+
//Update conditional routing
41+
for (const Input *pInut : _inputs) {
42+
pInut->evalConditions();
43+
}
44+
}
45+
46+
inline void checkClippingChannels() {
47+
for (size_t i = 0; i < _nChannelsOut; ++i) {
48+
if (_pClippingChannels[i] != 0) {
49+
printf("WARNING: Output(%s) - Clipping detected: +%0.2f dBFS\n", _pConfig->getChannelName(i).c_str(), Convert::levelToDb(_pClippingChannels[i]));
50+
_pClippingChannels[i] = 0;
51+
}
52+
}
53+
}
54+
55+
};

Condition.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include "Condition.h"
2+
3+
const time_t* Condition::_pUsedChannels = nullptr;
4+
5+
void Condition::init(const time_t *pUsedChannels) {
6+
_pUsedChannels = pUsedChannels;
7+
}
8+
9+
Condition::Condition(const ConditionType type, const int value) {
10+
_type = type;
11+
_value = value;
12+
}
13+
14+
const bool Condition::eval() const {
15+
switch (_type) {
16+
case ConditionType::SILENT:
17+
return _pUsedChannels[_value] == 0;
18+
break;
19+
default:
20+
throw Error("Route - Unknown condition: %d", _type);
21+
}
22+
}

Condition.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
#include "Error.h"
3+
4+
enum class ConditionType {
5+
SILENT
6+
};
7+
8+
class Condition {
9+
public:
10+
11+
static void init(const time_t *pUsedChannels);
12+
13+
Condition(const ConditionType type, const int value);
14+
15+
const bool eval() const;
16+
17+
private:
18+
static const time_t *_pUsedChannels;
19+
20+
ConditionType _type;
21+
int _value;
22+
23+
};
24+

Config.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void Config::parseMisc() {
7878
}
7979
}
8080
else {
81-
_channelNames = { "L", "R", "C", "SW", "SL", "SR","SBL", "SBR" };
81+
_channelNames = { "L", "R", "C", "SW", "SBL", "SBR" ,"SL", "SR" };
8282
}
8383
}
8484

@@ -150,6 +150,18 @@ void Config::parseRoute(std::vector<Route*> &routes, const JsonNode *pRoutes, co
150150
Route *pRoute = new Route(channelOut);
151151
routes.push_back(pRoute);
152152
parseFilters(pRoute->filters, pRouteNode, path);
153+
parseConditions(pRoute, pRouteNode, path);
154+
}
155+
}
156+
157+
void Config::parseConditions(Route *pRoute, const JsonNode *pRouteNode, std::string path) {
158+
if (pRouteNode->has("if")) {
159+
const JsonNode *pIfNode = getNode(pRouteNode, "if", path);
160+
if (pIfNode->has("silent")) {
161+
std::string channelName = textValue(pIfNode, "silent", path);
162+
size_t channel = getChannelIndex(channelName, path + "/silent");
163+
pRoute->conditions.push_back(Condition(ConditionType::SILENT, (int)channel));
164+
}
153165
}
154166
}
155167

@@ -207,7 +219,7 @@ void Config::validateLevels(const std::string &path) const {
207219
printf("WARNING: Config(%s) - Sum of routed channel levels is above 0dBFS on output channel. CLIPPING CAN OCCUR!\n", path.c_str());
208220
first = false;
209221
}
210-
printf("\t%s: +%.2f dBFS\n", getChannelName(i, path).c_str(), 20 * log10(levels[i]));
222+
printf("\t%s: +%.2f dBFS\n", getChannelName(i, path).c_str(), Convert::levelToDb(levels[i]));
211223
}
212224
}
213225
}
@@ -664,6 +676,13 @@ const std::string Config::getChannelName(const size_t channelIndex, const std::s
664676
return _channelNames[channelIndex];
665677
}
666678

679+
const std::string Config::getChannelName(const size_t channelIndex) const {
680+
if (channelIndex >= _channelNames.size()) {
681+
throw Error("Unknown channel index: %d", channelIndex);
682+
}
683+
return _channelNames[channelIndex];
684+
}
685+
667686
void Config::load() {
668687
_pJsonNode = JsonParser::fromFile(_configFile);
669688
_lastModified = _configFile.getLastModifiedTime();

Config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Config {
2222
const std::vector<Output*>& getOutputs() const;
2323
const bool hasChanged() const;
2424
const bool minimize() const;
25+
const std::string getChannelName(const size_t channelIndex) const;
2526

2627
private:
2728
File _configFile;
@@ -43,6 +44,7 @@ class Config {
4344
void parseInputs();
4445
void parseInput(const JsonNode *pInputs, const std::string &channelName, std::string path);
4546
void parseRoute(std::vector<Route*> &routes, const JsonNode *pRoutes, const size_t index, std::string path);
47+
void parseConditions(Route *pRoute, const JsonNode *pRouteNode, std::string path);
4648
void parseOutputs();
4749
void parseOutput(const JsonNode *pOutputs, const std::string &channelName, std::string path);
4850
void validateLevels(const std::string &path) const;

Input.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ class Input {
1717
}
1818
}
1919

20-
inline void process(const double data, float *pRenderBuffer) const {
20+
inline void route(const double data, float *pRenderBuffer) const {
2121
for (const Route *p : routes) {
2222
p->process(data, pRenderBuffer);
2323
}
2424
}
2525

26+
inline void evalConditions() const {
27+
for (Route *pRoute : routes) {
28+
pRoute->evalConditions();
29+
}
30+
}
31+
2632
};

0 commit comments

Comments
 (0)