You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

118 lines
3.3 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// FD_BufNMF, an NRT buffer NMF Processor
// A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Unions Horizon 2020 research and innovation programme (grant agreement No 725899)
#include "SC_PlugIn.h"
#include <vector>
#include <algorithm>
#include "stft.h"
#include "nmf.h"
#include <Eigen/Dense>
//Using statements for eigenmf. These will change
using stft::STFT;
using stft::ISTFT;
using stft::Spectrogram;
using stft:: audio_buffer_t;
using stft:: magnitude_t;
using nmf::NMF;
using nmf::NMFModel;
using Eigen::MatrixXcd;
using Eigen::MatrixXd;
using std::complex;
using util::stlVecVec2Eigen;
using util::Eigen2StlVecVec;
using std::numeric_limits;
static InterfaceTable *ft;
//namespace to gaffatape
namespace gaffatape {
void BufNMF(World *world, struct SndBuf *dstBuf, struct sc_msg_iter *msg)
{
int dstFrameCount = dstBuf->frames;
int dstChanCount = dstBuf->channels;
uint32 srcBufNum = msg->geti();
long rank = msg->geti();
long iterations = msg->geti();
long fftSize = msg->geti();
long windowSize = msg->geti();
long hopSize = msg->geti();
if (srcBufNum >= world->mNumSndBufs){
Print("fdNMF is not happy because the source buffer does not exist.\n");
return;
}
SndBuf* srcBuf = world->mSndBufs + srcBufNum;
if (srcBuf->data == dstBuf->data){
Print("fdNMF is not happy because the source buffer is the same as the destination buffer.\n");
return;
}
int srcFrameCount = srcBuf->frames;
int srcChanCount = srcBuf->channels;
if (dstChanCount < rank) {
Print("fdNMF is not happy because the destination buffer has a lower channel count than the number of ranks.\n");
return;
}
// check size of dstBuff
if (dstFrameCount < srcFrameCount) {
Print("fdNMF is not happy because the destination buffer shorter than the source buffer.\n");
return;
}
// make a vector of doubles for the samples
std::vector<double> audio_in(srcFrameCount);
//copied as is from max source (setting up the different variables and processes)
STFT stft(windowSize, fftSize, hopSize);
NMF nmfProcessor(rank, iterations);
ISTFT istft(windowSize, fftSize, hopSize);
//for each channels
// for (int j=0;j<srcChanCount;j++){
// just processing the first input channel instead of iterating through each channel, yet keeping the mechanism in there.
for (int j=0;j<1;j++){
//copies and casts to double the source samples
for (int i=0;i<srcFrameCount;i++){
audio_in[i] = srcBuf->data[(i*srcChanCount)+j];
}
Spectrogram spec = stft.process(audio_in);
magnitude_t mag = spec.magnitude();
NMFModel decomposition = nmfProcessor.process(mag);
MatrixXd W = stlVecVec2Eigen<double>(decomposition.W);
MatrixXd H = stlVecVec2Eigen<double>(decomposition.H);
MatrixXd V = W * H;
for (int i = 0; i < rank; i++)
{
MatrixXd source = W.col(i) * H.row(i);
MatrixXd filter = source.cwiseQuotient(V);
MatrixXcd specMatrix = stlVecVec2Eigen(spec.mData);
specMatrix = specMatrix.cwiseProduct(filter);
Spectrogram resultS(Eigen2StlVecVec<complex<double>>(specMatrix));
audio_buffer_t result = istft.process(resultS);
//writes the output
for (int k=0;k<srcFrameCount;k++){
dstBuf->data[(k*rank)+i] = (float)result[k];
}
}
}
}
PluginLoad(OfflineFluidDecompositionUGens) {
ft = inTable;
DefineBufGen("BufNMF", BufNMF);
}
}