Files
tlib/oversampling/WDL/audiobuffercontainer.cpp
2024-05-24 13:28:31 +02:00

244 lines
6.0 KiB
C++

#include "audiobuffercontainer.h"
#include "queue.h"
#include <assert.h>
void ChannelPinMapper::Reset()
{
for (int i=0; i < CHANNELPINMAPPER_MAXPINS; ++i)
m_mapping[i].set_excl(i);
}
void ChannelPinMapper::SetNPins(int nPins)
{
if (nPins<0) nPins=0;
else if (nPins>CHANNELPINMAPPER_MAXPINS) nPins=CHANNELPINMAPPER_MAXPINS;
int i;
for (i = m_nPins; i < nPins; ++i)
{
ClearPin(i);
if (i < m_nCh)
{
SetPin(i, i, true);
}
}
m_nPins = nPins;
}
void ChannelPinMapper::SetNChannels(int nCh, bool auto_passthru)
{
if (auto_passthru) for (int i = m_nCh; i < nCh && i < m_nPins; ++i) {
SetPin(i, i, true);
}
m_nCh = nCh;
}
void ChannelPinMapper::Init(const PinMapPin * pMapping, int nPins)
{
if (nPins<0) nPins=0;
else if (nPins>CHANNELPINMAPPER_MAXPINS) nPins=CHANNELPINMAPPER_MAXPINS;
memcpy(m_mapping, pMapping, nPins*sizeof(PinMapPin));
memset(m_mapping+nPins, 0, (CHANNELPINMAPPER_MAXPINS-nPins)*sizeof(PinMapPin));
m_nPins = m_nCh = nPins;
}
#define BITMASK64(bitIdx) (((WDL_UINT64)1)<<(bitIdx))
void ChannelPinMapper::ClearPin(int pinIdx)
{
if (pinIdx >=0 && pinIdx < CHANNELPINMAPPER_MAXPINS) m_mapping[pinIdx].clear();
}
void ChannelPinMapper::SetPin(int pinIdx, int chIdx, bool on)
{
if (pinIdx >=0 && pinIdx < CHANNELPINMAPPER_MAXPINS)
{
if (on)
{
m_mapping[pinIdx].set_chan(chIdx);
}
else
{
m_mapping[pinIdx].clear_chan(chIdx);
}
}
}
bool ChannelPinMapper::TogglePin(int pinIdx, int chIdx)
{
bool on = GetPin(pinIdx, chIdx);
on = !on;
SetPin(pinIdx, chIdx, on);
return on;
}
bool ChannelPinMapper::GetPin(int pinIdx, int chIdx) const
{
if (pinIdx >= 0 && pinIdx < CHANNELPINMAPPER_MAXPINS)
{
return m_mapping[pinIdx].has_chan(chIdx);
}
return false;
}
bool ChannelPinMapper::IsStraightPassthrough() const
{
if (m_nCh != m_nPins) return false;
PinMapPin tmp;
tmp.clear();
for (int i = 0; i < m_nPins; ++i)
{
tmp.set_chan(i);
if (!tmp.equal_to(m_mapping[i])) return false;
tmp.clear_chan(i);
}
return true;
}
#define PINMAPPER_MAGIC 1000
const char *ChannelPinMapper::SaveStateNew(int* pLen)
{
m_cfgret.Clear();
int magic = PINMAPPER_MAGIC;
WDL_Queue__AddToLE(&m_cfgret, &magic);
WDL_Queue__AddToLE(&m_cfgret, &m_nCh);
WDL_Queue__AddToLE(&m_cfgret, &m_nPins);
const int num64 = wdl_max(1,(wdl_min(m_nCh,CHANNELPINMAPPER_MAXPINS) + 63)/64);
for (int y = 0; y < num64; y ++)
{
for (int x = 0; x < m_nPins; x ++)
{
const WDL_UINT64 v = m_mapping[x].get_64(y);
WDL_Queue__AddToLE(&m_cfgret, &v);
}
}
*pLen = m_cfgret.GetSize();
return (const char*)m_cfgret.Get();
}
bool ChannelPinMapper::LoadState(const char* buf, int len)
{
WDL_Queue chunk;
chunk.Add(buf, len);
int* pMagic = WDL_Queue__GetTFromLE(&chunk, (int*)0);
if (!pMagic || *pMagic != PINMAPPER_MAGIC) return false;
int* pNCh = WDL_Queue__GetTFromLE(&chunk, (int*) 0);
int* pNPins = WDL_Queue__GetTFromLE(&chunk, (int*) 0);
if (!pNCh || !pNPins) return false;
const int src_pins = *pNPins;
SetNPins(src_pins);
SetNChannels(*pNCh);
const int num64 = wdl_max(1,(wdl_min(m_nCh,CHANNELPINMAPPER_MAXPINS)+63)/64);
const int maplen = src_pins * sizeof(WDL_UINT64);
for (int y = 0; y < num64; y ++)
{
if (chunk.Available() < maplen) return y>0;
const WDL_UINT64 *pMap = (const WDL_UINT64 *)WDL_Queue__GetDataFromLE(&chunk, maplen, sizeof(WDL_UINT64));
const int sz = wdl_min(m_nPins,src_pins);
for (int x = 0; x < sz; x ++)
{
m_mapping[x].set_64(pMap[x], y);
}
}
return true;
}
AudioBufferContainer::AudioBufferContainer()
{
m_nCh = 0;
m_nFrames = 0;
m_fmt = FMT_32FP;
m_interleaved = true;
m_hasData = false;
}
// converts interleaved buffer to interleaved buffer, using min(len_in,len_out) and zeroing any extra samples
// isInput means it reads from track channels and writes to plugin pins
// wantZeroExcessOutput=false means that untouched channels will be preserved in buf_out
void PinMapperConvertBuffers(const double *buf, int len_in, int nch_in,
double *buf_out, int len_out, int nch_out,
const ChannelPinMapper *pinmap, bool isInput, bool wantZeroExcessOutput)
{
if (pinmap->IsStraightPassthrough() || !pinmap->GetNPins())
{
int x;
char *op = (char *)buf_out;
const char *ip = (const char *)buf;
const int ip_adv = nch_in * sizeof(double);
const int clen = wdl_min(nch_in, nch_out) * sizeof(double);
const int zlen = nch_out > nch_in ? (nch_out - nch_in) * sizeof(double) : 0;
const int cplen = wdl_min(len_in,len_out);
for (x=0;x<cplen;x++)
{
memcpy(op,ip,clen);
op += clen;
if (zlen)
{
if (wantZeroExcessOutput) memset(op,0,zlen);
op += zlen;
}
ip += ip_adv;
}
if (x < len_out && wantZeroExcessOutput) memset(op, 0, (len_out-x)*sizeof(double)*nch_out);
}
else
{
if (wantZeroExcessOutput) memset(buf_out,0,len_out*nch_out*sizeof(double));
const int npins = wdl_min(pinmap->GetNPins(),isInput ? nch_out : nch_in);
const int nchan = isInput ? nch_in : nch_out;
int p;
PinMapPin clearmask;
clearmask.clear();
for (p = 0; p < npins; p ++)
{
const PinMapPin &map = pinmap->m_mapping[p];
for (unsigned int x = 0; map.enum_chans(&x,nchan); x ++)
{
int i=len_in;
const double *ip = buf + (isInput ? x : p);
const int out_idx = (isInput ? p : x);
bool want_zero=false;
if (!wantZeroExcessOutput)
{
if (!clearmask.has_chan(out_idx))
{
clearmask.set_chan(out_idx);
want_zero=true;
}
}
double *op = buf_out + out_idx;
if (want_zero)
{
while (i-- > 0)
{
*op = *ip;
op += nch_out;
ip += nch_in;
}
}
else
{
while (i-- > 0)
{
*op += *ip;
op += nch_out;
ip += nch_in;
}
}
}
}
}
}