Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fluid.voiceallocator community testing build #249

Open
wants to merge 55 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
4a7d9da
ampfeatureclient - default value fix
tremblap Feb 23, 2023
da1cb2f
skeleton of voiceallocator, to troubleshoot multi control in management
tremblap Feb 27, 2023
4944184
added a better monitoring of 3 x 3 input
tremblap Feb 27, 2023
51376a4
clang'd
tremblap Feb 27, 2023
f694a36
Merge pull request #230 from flucoma/pre-production
tremblap Mar 28, 2023
7ca651f
Merge branch 'main' into feature/voice-allocator
tremblap Aug 9, 2023
734c48b
allocate fixed arrays for the output to see if that helps...
tremblap Aug 14, 2023
23f1a72
Merge branch 'main' into feature/voice-allocator
tremblap Aug 14, 2023
b1af337
fix for dynamic mem alloc but breaks stats - pushed at @aharker's req…
tremblap Aug 16, 2023
e90830b
Merge remote-tracking branch 'origin/main' into feature/voice-allocator
tremblap Aug 17, 2023
26635b3
new const needs
tremblap Aug 17, 2023
e2ece72
Changes for how clients determine if the output follows the input size
AlexHarker Aug 17, 2023
d5b4a7c
remove duplicate
tremblap Aug 17, 2023
d6c2c20
VoiceAllocator.hpp -> VoiceAllocatorClient.hpp
fearn-e Aug 20, 2023
77c04d4
names & boilerplate
fearn-e Aug 20, 2023
8954b29
partialTracking new getActiveVoices function
fearn-e Aug 20, 2023
246eb25
parameter list for voiceallocator
fearn-e Aug 20, 2023
d6813d6
functional allocator but still bad track IDs
fearn-e Aug 20, 2023
6a9ae43
allocator algo somewhat implemented, compiles but weird behaviour
fearn-e Aug 21, 2023
0a45601
past me apparently hoping a non-looped IF can clear a queue
fearn-e Aug 21, 2023
be7af8e
proper conversion from amp to dB + convert back to amp
fearn-e Aug 21, 2023
61d6cb5
removing mInputSize
fearn-e Aug 21, 2023
4713d3c
comments
fearn-e Aug 21, 2023
af2c896
allows existing voices to change their freq/mag
fearn-e Aug 21, 2023
d12ae68
fully removed mInputSize
fearn-e Aug 21, 2023
51cde4d
fixed bug with allocator loop for removing voices ending too early
fearn-e Aug 21, 2023
dca9460
output proper sorted voiceID instead of partialTracking ID
fearn-e Aug 21, 2023
15f6b41
voice stealing comment
fearn-e Aug 21, 2023
ab1ccf0
states & stealing, imperfect
fearn-e Aug 21, 2023
d938027
proper init for queues/deques
fearn-e Aug 21, 2023
2757d7a
add pruning
fearn-e Aug 21, 2023
f0b1d4a
readability
fearn-e Aug 21, 2023
6360dd1
init() call for clear messagess
fearn-e Aug 21, 2023
af0938c
replaced stealing with sorting
fearn-e Aug 21, 2023
c6c6351
clearer layout of function calls in process + resize outgoingVoices
fearn-e Aug 21, 2023
02c26a5
temp removal of trackMethod param, switching to hung causes issues
fearn-e Aug 23, 2023
57a5051
consistency of an enumparam with other flucoma objects
fearn-e Aug 23, 2023
6a308c6
Merge remote-tracking branch 'origin/main' into feature/voice-allocator
fearn-e Aug 23, 2023
f7ddbf5
removing random comments
fearn-e Aug 23, 2023
03fcf68
Merge branch 'main' into feature/voice-allocator
tremblap Sep 1, 2023
1a536f4
algo-client file code split
fearn-e Sep 11, 2023
e1d5950
Merge branch 'feature/voice-allocator' of https://github.com/fearn-e/…
tremblap Sep 17, 2023
d49c1dd
Merge branch 'main' into pre-production
tremblap Mar 19, 2024
e08caed
Merge branch 'main' into pre-production
tremblap Mar 19, 2024
60c944d
Merge pull request #267 from flucoma/pre-production
tremblap Apr 2, 2024
09221ee
Merge branch 'main' into feature/voice-allocator
tremblap Apr 3, 2024
633ff8f
implement reset/init
tremblap Apr 4, 2024
c0c14df
instantiation initialisation was needed
tremblap Apr 6, 2024
c684d83
cleaned the order of initialisation
tremblap Apr 7, 2024
618fd10
first working NRT adaptor
tremblap Jul 17, 2024
c81e050
Merge branch 'production' into feature/voice-allocator
tremblap Jul 17, 2024
e15fd18
forgot the cmake
tremblap Jul 17, 2024
17a49b2
added task evolution
tremblap Jul 17, 2024
a2d385e
Merge branch 'main' into feature/voice-allocator
tremblap Jul 17, 2024
536215d
clang_formatted
tremblap Aug 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions FlucomaClients.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ add_client(BufThreadDemo clients/nrt/FluidThreadTestClient.hpp CLASS NRTThreaded
add_client(BufThresh clients/nrt/BufThreshClient.hpp CLASS NRTThreadedBufferThreshClient )
add_client(BufTransientSlice clients/rt/TransientSliceClient.hpp CLASS NRTThreadedTransientSliceClient )
add_client(BufTransients clients/rt/TransientClient.hpp CLASS NRTThreadedTransientsClient )
add_kr_in_client(BufVoiceAllocator clients/rt/VoiceAllocatorClient.hpp CLASS NRTThreadedVoiceAllocatorClient )
add_client(Chroma clients/rt/ChromaClient.hpp CLASS RTChromaClient )
add_client(Gain clients/rt/GainClient.hpp CLASS RTGainClient NOINSTALL)
add_client(HPSS clients/rt/HPSSClient.hpp CLASS RTHPSSClient )
Expand All @@ -139,6 +140,7 @@ add_client(SpectralShape clients/rt/SpectralShapeClient.hpp CLASS RTSpectralShap
add_kr_in_client(Stats clients/rt/RunningStatsClient.hpp CLASS RunningStatsClient )
add_client(TransientSlice clients/rt/TransientSliceClient.hpp CLASS RTTransientSliceClient )
add_client(Transients clients/rt/TransientClient.hpp CLASS RTTransientClient )
add_kr_in_client(VoiceAllocator clients/rt/VoiceAllocatorClient.hpp CLASS VoiceAllocatorClient )

#lib manipulation client group
add_client(DataSet clients/nrt/DataSetClient.hpp CLASS NRTThreadedDataSetClient GROUP MANIPULATION)
Expand Down
163 changes: 163 additions & 0 deletions include/algorithms/public/VoiceAllocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/)
Copyright University of Huddersfield.
Licensed under the BSD-3 License.
See license.md file in the project root for full license information.
This project has received funding from the European Research Council (ERC)
under the European Union’s Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/

#pragma once

#include "../util/PartialTracking.hpp"

namespace fluid {
namespace algorithm {

class VoiceAllocator
{
template <typename T>
using vector = rt::vector<T>;

public:
VoiceAllocator(index nVoices, Allocator& alloc)
: mTracking(alloc), mVoices{nVoices}, mFreeVoices(alloc),
mActiveVoices(alloc), mActiveVoiceData(0, alloc)
{}

void init(index nVoices, Allocator& alloc)
{
mVoices = nVoices;
while (!mActiveVoices.empty()) { mActiveVoices.pop_back(); }
while (!mFreeVoices.empty()) { mFreeVoices.pop(); }
for (index i = 0; i < nVoices; ++i) { mFreeVoices.push(i); }
mActiveVoiceData.resize(nVoices);
for (VoicePeak each : mActiveVoiceData) { each = {0, 0, 0}; }
mTracking.init();
mInitialized = true;
}

void processFrame(vector<SinePeak> incomingVoices,
vector<VoicePeak>& outgoingVoices, index minTrackLen,
double birthLowTreshold, double birthHighTreshold,
index trackMethod, double trackMagRange,
double trackFreqRange, double trackProb, index sortMethod,
Allocator& alloc)
{
assert(mInitialized);

double maxAmp = -144;
for (const SinePeak& voice : incomingVoices)
{
if (voice.logMag > maxAmp) { maxAmp = voice.logMag; }
}

mTracking.processFrame(incomingVoices, maxAmp, minTrackLen,
birthLowTreshold, birthHighTreshold, trackMethod,
trackMagRange, trackFreqRange, trackProb, alloc);

outgoingVoices = mTracking.getActiveVoices(alloc);
outgoingVoices = sortVoices(outgoingVoices, sortMethod);
if (outgoingVoices.size() > mVoices) outgoingVoices.resize(mVoices);
outgoingVoices = assignVoices(outgoingVoices, alloc);

mTracking.prune();
}

void reset() { mInitialized = false; }

bool initialized() const { return mInitialized; }

private:
vector<VoicePeak> sortVoices(vector<VoicePeak>& incomingVoices,
index sortingMethod)
{
switch (sortingMethod)
{
case 0: // lowest
std::sort(incomingVoices.begin(), incomingVoices.end(),
[](const VoicePeak& voice1, const VoicePeak& voice2) {
return voice1.freq < voice2.freq;
});
break;
case 1: // loudest
std::sort(incomingVoices.begin(), incomingVoices.end(),
[](const VoicePeak& voice1, const VoicePeak& voice2) {
return voice1.logMag > voice2.logMag;
});
break;
}
return incomingVoices;
}

vector<VoicePeak> assignVoices(vector<VoicePeak>& incomingVoices,
Allocator& alloc)
{
// move released to free
for (index existing = 0; existing < mActiveVoiceData.size(); ++existing)
{
if (mActiveVoiceData[existing].state ==
algorithm::VoiceState::kReleaseState)
mActiveVoiceData[existing].state = algorithm::VoiceState::kFreeState;
}

// handle existing voices - killing or sustaining
for (index existing = 0; existing < mActiveVoices.size(); ++existing)
{
bool killVoice = true;
for (index incoming = 0; incoming < incomingVoices.size(); ++incoming)
{
// remove incoming voice events & allows corresponding voice to live if
// it already exists
if (mActiveVoiceData[mActiveVoices[existing]].voiceID ==
incomingVoices[incoming].voiceID)
{
killVoice = false;
mActiveVoiceData[mActiveVoices[existing]] =
incomingVoices[incoming]; // update freq/mag
mActiveVoiceData[mActiveVoices[existing]].state =
algorithm::VoiceState::kSustainState;
incomingVoices.erase(incomingVoices.begin() + incoming);
break;
}
}
if (killVoice) // voice off
{
mActiveVoiceData[mActiveVoices[existing]].state =
algorithm::VoiceState::kReleaseState;
mFreeVoices.push(mActiveVoices[existing]);
mActiveVoices.erase(mActiveVoices.begin() + existing);
--existing;
}
}

// handle new voice allocation
for (index incoming = 0; incoming < incomingVoices.size(); ++incoming)
{
if (!mFreeVoices.empty()) // voice on
{
index newVoiceIndex = mFreeVoices.front();
mFreeVoices.pop();
mActiveVoices.push_back(newVoiceIndex);
algorithm::VoiceState prevState = mActiveVoiceData[newVoiceIndex].state;
mActiveVoiceData[newVoiceIndex] = incomingVoices[incoming];
if (prevState == algorithm::VoiceState::kReleaseState) // mark as stolen
mActiveVoiceData[newVoiceIndex].state =
algorithm::VoiceState::kStolenState;
}
}

return mActiveVoiceData;
}

PartialTracking mTracking;
index mVoices;
rt::queue<index> mFreeVoices;
rt::deque<index> mActiveVoices;
vector<VoicePeak> mActiveVoiceData;

bool mInitialized{false};
};
} // namespace algorithm
} // namespace fluid
43 changes: 41 additions & 2 deletions include/algorithms/util/PartialTracking.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,38 @@ Capability through Linear Programming". Proceedings of DAFx-2018.
namespace fluid {
namespace algorithm {

enum class VoiceState {
kFreeState,
kAttackState,
kSustainState,
kReleaseState,
kStolenState
};

struct SinePeak
{
double freq;
double logMag;
bool assigned;
};

struct VoicePeak
{
double freq;
double logMag;
index voiceID;
VoiceState state;
};

struct SineTrack
{

SineTrack(Allocator& alloc) : peaks(alloc) {}

SineTrack(rt::vector<SinePeak>&& p, index s, index e, bool a, bool ass,
index t)
: peaks{p}, startFrame{s}, endFrame{e}, active{a}, assigned{ass}, trackId{
t}
: peaks{p}, startFrame{s}, endFrame{e}, active{a}, assigned{ass},
trackId{t}
{}

rt::vector<SinePeak> peaks;
Expand Down Expand Up @@ -134,6 +150,29 @@ class PartialTracking
return sinePeaks;
}

// todo - refactor this function with the one above
vector<VoicePeak> getActiveVoices(Allocator& alloc)
{
vector<VoicePeak> voicePeaks(0, alloc);
index latencyFrame = mCurrentFrame - mMinTrackLength;
if (latencyFrame < 0) return voicePeaks;
for (auto&& track : mTracks)
{
if (track.startFrame > latencyFrame) continue;
if (track.endFrame >= 0 && track.endFrame <= latencyFrame) continue;
if (track.endFrame >= 0 &&
track.endFrame - track.startFrame < mMinTrackLength)
continue;
voicePeaks.push_back(
{track.peaks[asUnsigned(latencyFrame - track.startFrame)].freq,
pow(10,
track.peaks[asUnsigned(latencyFrame - track.startFrame)].logMag /
20),
track.trackId, VoiceState::kAttackState});
}
return voicePeaks;
}

private:
void updateVariances()
{
Expand Down
Loading
Loading