Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / audiobuffercontainer.cpp
blob1e013281345cc9dc12d9b5228dd773b92f0d5fc0
1 #include "audiobuffercontainer.h"
2 #include "queue.h"
3 #include <assert.h>
5 void ChannelPinMapper::SetNPins(int nPins)
7 if (nPins<0) nPins=0;
8 else if (nPins>CHANNELPINMAPPER_MAXPINS) nPins=CHANNELPINMAPPER_MAXPINS;
9 int i;
10 for (i = m_nPins; i < nPins; ++i) {
11 ClearPin(i);
12 if (i < m_nCh) {
13 SetPin(i, i, true);
16 m_nPins = nPins;
19 void ChannelPinMapper::SetNChannels(int nCh)
21 int i;
22 for (i = m_nCh; i < nCh && i < m_nPins; ++i) {
23 SetPin(i, i, true);
25 m_nCh = nCh;
28 void ChannelPinMapper::Init(const WDL_UINT64* pMapping, int nPins)
30 if (nPins<0) nPins=0;
31 else if (nPins>CHANNELPINMAPPER_MAXPINS) nPins=CHANNELPINMAPPER_MAXPINS;
32 memcpy(m_mapping, pMapping, nPins*sizeof(WDL_UINT64));
33 memset(m_mapping+nPins, 0, (CHANNELPINMAPPER_MAXPINS-nPins)*sizeof(WDL_UINT64));
34 m_nPins = m_nCh = nPins;
37 #define BITMASK64(bitIdx) (((WDL_UINT64)1)<<(bitIdx))
39 void ChannelPinMapper::ClearPin(int pinIdx)
41 if (pinIdx >=0 && pinIdx < CHANNELPINMAPPER_MAXPINS) m_mapping[pinIdx] = 0;
44 void ChannelPinMapper::SetPin(int pinIdx, int chIdx, bool on)
46 if (pinIdx >=0 && pinIdx < CHANNELPINMAPPER_MAXPINS)
48 if (on)
50 m_mapping[pinIdx] |= BITMASK64(chIdx);
52 else
54 m_mapping[pinIdx] &= ~BITMASK64(chIdx);
59 bool ChannelPinMapper::TogglePin(int pinIdx, int chIdx)
61 bool on = GetPin(pinIdx, chIdx);
62 on = !on;
63 SetPin(pinIdx, chIdx, on);
64 return on;
67 bool ChannelPinMapper::GetPin(int pinIdx, int chIdx) const
69 if (pinIdx >= 0 && pinIdx < CHANNELPINMAPPER_MAXPINS)
71 WDL_UINT64 map = m_mapping[pinIdx];
72 return !!(map & BITMASK64(chIdx));
74 return false;
77 bool ChannelPinMapper::PinHasMoreMappings(int pinIdx, int chIdx) const
79 if (pinIdx >= 0 && pinIdx < CHANNELPINMAPPER_MAXPINS)
81 WDL_UINT64 map = m_mapping[pinIdx];
82 return (chIdx < 63 && map >= BITMASK64(chIdx+1));
84 return false;
87 bool ChannelPinMapper::IsStraightPassthrough() const
89 if (m_nCh != m_nPins) return false;
90 const WDL_UINT64* pMap = m_mapping;
91 int i;
92 for (i = 0; i < m_nPins; ++i, ++pMap) {
93 if (*pMap != BITMASK64(i)) return false;
95 return true;
98 #define PINMAPPER_MAGIC 1000
100 // return is on the heap
101 char* ChannelPinMapper::SaveStateNew(int* pLen)
103 m_cfgret.Clear();
104 int magic = PINMAPPER_MAGIC;
105 WDL_Queue__AddToLE(&m_cfgret, &magic);
106 WDL_Queue__AddToLE(&m_cfgret, &m_nCh);
107 WDL_Queue__AddToLE(&m_cfgret, &m_nPins);
108 WDL_Queue__AddDataToLE(&m_cfgret, m_mapping, m_nPins*sizeof(WDL_UINT64), sizeof(WDL_UINT64));
109 *pLen = m_cfgret.GetSize();
110 return (char*)m_cfgret.Get();
113 bool ChannelPinMapper::LoadState(const char* buf, int len)
115 WDL_Queue chunk;
116 chunk.Add(buf, len);
117 int* pMagic = WDL_Queue__GetTFromLE(&chunk, (int*)0);
118 if (!pMagic || *pMagic != PINMAPPER_MAGIC) return false;
119 int* pNCh = WDL_Queue__GetTFromLE(&chunk, (int*) 0);
120 int* pNPins = WDL_Queue__GetTFromLE(&chunk, (int*) 0);
121 if (!pNCh || !pNPins) return false;
122 SetNPins(*pNCh);
123 SetNChannels(*pNCh);
124 int maplen = *pNPins*sizeof(WDL_UINT64);
125 if (chunk.Available() < maplen) return false;
126 void* pMap = WDL_Queue__GetDataFromLE(&chunk, maplen, sizeof(WDL_UINT64));
128 int sz= m_nPins*sizeof(WDL_UINT64);
129 if (sz>maplen) sz=maplen;
130 memcpy(m_mapping, pMap, sz);
132 return true;
135 template <class TDEST, class TSRC> void BufConvertT(TDEST* dest, const TSRC* src, int nFrames, int destStride, int srcStride)
137 int i;
138 for (i = 0; i < nFrames; ++i)
140 dest[i*destStride] = (TDEST)src[i*srcStride];
144 template <class T> void BufMixT(T* dest, const T* src, int nFrames, bool addToDest, double wt_start, double wt_end)
146 int i;
148 if (wt_start == 1.0 && wt_end == 1.0)
150 if (addToDest)
152 for (i = 0; i < nFrames; ++i)
154 dest[i] += src[i];
157 else
159 memcpy(dest, src, nFrames*sizeof(T));
162 else
164 double dw = (wt_end-wt_start)/(double)nFrames;
165 double cw = wt_start;
167 if (addToDest)
169 for (i = 0; i < nFrames; ++i)
171 dest[i] += (T)(1.0-cw)*dest[i]+(T)cw*src[i];
172 cw += dw;
175 else
177 for (i = 0; i < nFrames; ++i)
179 dest[i] = (T)(1.0-cw)*dest[i]+(T)cw*src[i];
180 cw += dw;
186 // static
187 bool AudioBufferContainer::BufConvert(void* dest, const void* src, int destFmt, int srcFmt, int nFrames, int destStride, int srcStride)
189 if (destFmt == FMT_32FP)
191 if (srcFmt == FMT_32FP)
193 BufConvertT((float*)dest, (float*)src, nFrames, destStride, srcStride);
194 return true;
196 else if (srcFmt == FMT_64FP)
198 BufConvertT((float*)dest, (double*)src, nFrames, destStride, srcStride);
199 return true;
202 else if (destFmt == FMT_64FP)
204 if (srcFmt == FMT_32FP)
206 BufConvertT((double*)dest, (float*)src, nFrames, destStride, srcStride);
207 return true;
209 else if (srcFmt == FMT_64FP)
211 BufConvertT((double*)dest, (double*)src, nFrames, destStride, srcStride);
212 return true;
215 return false;
218 AudioBufferContainer::AudioBufferContainer()
220 m_nCh = 0;
221 m_nFrames = 0;
222 m_fmt = FMT_32FP;
223 m_interleaved = true;
224 m_hasData = false;
227 void AudioBufferContainer::Resize(int nCh, int nFrames, bool preserveData)
229 if (!m_hasData)
231 preserveData = false;
234 const int newsz = nCh*nFrames*(int)m_fmt;
236 if (preserveData && (nCh != m_nCh || nFrames != m_nFrames))
238 GetAllChannels(m_fmt, true); // causes m_data to be interleaved
240 if (newsz > m_data.GetSize()) m_data.Resize(newsz);
241 if (nCh != m_nCh && m_data.GetSize() >= newsz)
243 char *out = (char *)m_data.Get();
244 const char *in = out;
245 const int in_adv = m_nCh * m_fmt, out_adv = nCh * m_fmt;
246 const int copysz = wdl_min(in_adv,out_adv);
248 int n = wdl_min(nFrames,m_nFrames);
249 if (out_adv < in_adv) // decreasing channel count, left to right
251 while (n--)
253 if (out!=in) memmove(out,in,copysz);
254 out+=out_adv;
255 in+=in_adv;
258 else // increasing channel count, copy right to left
260 out += n * out_adv;
261 in += n * in_adv;
262 while (n--)
264 out-=out_adv;
265 in-=in_adv;
266 if (out!=in) memmove(out,in,copysz);
269 // adjust interleaving
273 m_data.Resize(newsz);
274 m_hasData = preserveData;
275 m_nCh = nCh;
276 m_nFrames = nFrames;
279 void AudioBufferContainer::Reformat(int fmt, bool preserveData)
281 if (!m_hasData)
283 preserveData = false;
286 int newsz = m_nCh*m_nFrames*(int)fmt;
288 if (preserveData && fmt != m_fmt)
290 int oldsz = m_data.GetSize();
291 void* src = m_data.Resize(oldsz+newsz);
292 void* dest = (unsigned char*)src+oldsz;
293 BufConvert(dest, src, fmt, m_fmt, m_nCh*m_nFrames, 1, 1);
294 memmove(src, dest, newsz);
297 m_data.Resize(newsz);
298 m_hasData = preserveData;
299 m_fmt = fmt;
302 // src=NULL to memset(0)
303 void* AudioBufferContainer::SetAllChannels(int fmt, const void* src, int nCh, int nFrames)
305 Reformat(fmt, false);
306 Resize(nCh, nFrames, false);
308 int sz = nCh*nFrames*(int)fmt;
309 void* dest = GetAllChannels(fmt, false);
310 if (src)
312 memcpy(dest, src, sz);
314 else
316 memset(dest, 0, sz);
319 m_interleaved = true;
320 m_hasData = true;
321 return dest;
324 // src=NULL to memset(0)
325 void* AudioBufferContainer::SetChannel(int fmt, const void* src, int chIdx, int nFrames)
327 Reformat(fmt, true);
328 if (nFrames > m_nFrames || chIdx >= m_nCh)
330 int maxframes = (nFrames > m_nFrames ? nFrames : m_nFrames);
331 Resize(chIdx+1, maxframes, true);
334 int sz = nFrames*(int)fmt;
335 void* dest = GetChannel(fmt, chIdx, true);
336 if (src)
338 memcpy(dest, src, sz);
340 else
342 memset(dest, 0, sz);
345 m_interleaved = false;
346 m_hasData = true;
347 return dest;
350 void* AudioBufferContainer::MixChannel(int fmt, const void* src, int chIdx, int nFrames, bool addToDest, double wt_start, double wt_end)
352 Reformat(fmt, true);
353 if (nFrames > m_nFrames || chIdx >= m_nCh)
355 int maxframes = (nFrames > m_nFrames ? nFrames : m_nFrames);
356 Resize(chIdx+1, maxframes, true);
359 void* dest = GetChannel(fmt, chIdx, true);
361 if (fmt == FMT_32FP)
363 BufMixT((float*)dest, (float*)src, nFrames, addToDest, wt_start, wt_end);
365 else if (fmt == FMT_64FP)
367 BufMixT((double*)dest, (double*)src, nFrames, addToDest, wt_start, wt_end);
370 m_interleaved = false;
371 m_hasData = true;
372 return dest;
376 void* AudioBufferContainer::GetAllChannels(int fmt, bool preserveData)
378 Reformat(fmt, preserveData);
379 ReLeave(true, preserveData);
381 m_hasData = true; // because caller may use the returned pointer to populate the container
383 return m_data.Get();
386 void* AudioBufferContainer::GetChannel(int fmt, int chIdx, bool preserveData)
388 Reformat(fmt, preserveData);
389 if (chIdx >= m_nCh)
391 Resize(chIdx+1, m_nFrames, true);
393 ReLeave(false, preserveData);
395 m_hasData = true; // because caller may use the returned pointer to populate the container
397 int offsz = chIdx*m_nFrames*(int)fmt;
398 return (unsigned char*)m_data.Get()+offsz;
401 void AudioBufferContainer::ReLeave(bool interleave, bool preserveData)
403 if (interleave != m_interleaved && preserveData && m_hasData)
405 int elemsz = (int)m_fmt;
406 int chansz = m_nFrames*elemsz;
407 int bufsz = m_nCh*chansz;
408 int i;
410 unsigned char* src = (unsigned char*)m_data.Resize(bufsz*2);
411 unsigned char* dest = src+bufsz;
413 if (interleave)
415 for (i = 0; i < m_nCh; ++i)
417 BufConvert((void*)(dest+i*elemsz), (void*)(src+i*chansz), m_fmt, m_fmt, m_nFrames, m_nCh, 1);
420 else
422 for (i = 0; i < m_nCh; ++i)
424 BufConvert((void*)(dest+i*chansz), (void*)(src+i*elemsz), m_fmt, m_fmt, m_nFrames, 1, m_nCh);
428 memcpy(src, dest, bufsz); // no overlap
429 m_data.Resize(bufsz);
432 m_hasData = preserveData;
433 m_interleaved = interleave;
436 void AudioBufferContainer::CopyFrom(const AudioBufferContainer* rhs)
438 int sz = rhs->m_data.GetSize();
439 void* dest = m_data.Resize(sz);
441 if (rhs->m_hasData)
443 void* src = rhs->m_data.Get();
444 memcpy(dest, src, sz);
447 m_nCh = rhs->m_nCh;
448 m_nFrames = rhs->m_nFrames;
449 m_fmt = rhs->m_fmt;
450 m_interleaved = rhs->m_interleaved;
451 m_hasData = rhs->m_hasData;
455 void SetPinsFromChannels(AudioBufferContainer* dest, AudioBufferContainer* src, ChannelPinMapper* mapper, int forceMinChanCnt)
457 if (mapper->IsStraightPassthrough())
459 dest->CopyFrom(src);
460 return;
463 const int nch = mapper->GetNChannels();
464 const int npins = mapper->GetNPins();
465 const int nframes = src->GetNFrames();
466 const int fmt = src->GetFormat();
467 const int np = wdl_max(npins,forceMinChanCnt);
469 dest->Resize(np, nframes, false);
471 int c, p;
472 for (p = 0; p < np; ++p)
474 bool pinused = false;
475 if (p < npins) for (c = 0; c < nch; ++c)
477 if (mapper->GetPin(p, c))
479 void* srcbuf = src->GetChannel(fmt, c, true);
480 dest->MixChannel(fmt, srcbuf, p, nframes, pinused, 1.0, 1.0);
481 pinused = true;
483 if (!mapper->PinHasMoreMappings(p, c))
485 break;
490 if (!pinused)
492 dest->SetChannel(fmt, 0, p, nframes); // clear unused pins
497 void SetChannelsFromPins(AudioBufferContainer* dest, AudioBufferContainer* src, const ChannelPinMapper* mapper, double wt_start, double wt_end)
499 if (wt_start == 1.0 && wt_end == 1.0 && mapper->IsStraightPassthrough())
501 dest->CopyFrom(src);
502 return;
505 int nch = mapper->GetNChannels();
506 int npins = mapper->GetNPins();
507 int nframes = src->GetNFrames();
508 int fmt = src->GetFormat();
510 dest->Resize(nch, nframes, true);
512 int c, p;
513 for (c = 0; c < nch; ++c)
515 bool chanused = false;
516 for (p = 0; p < npins; ++p)
518 if (mapper->GetPin(p, c))
520 void* srcbuf = src->GetChannel(fmt, p, true);
521 dest->MixChannel(fmt, srcbuf, c, nframes, chanused, wt_start, wt_end);
522 chanused = true;
525 // don't clear unused channels
533 // converts interleaved buffer to interleaved buffer, using min(len_in,len_out) and zeroing any extra samples
534 // isInput means it reads from track channels and writes to plugin pins
535 // wantZeroExcessOutput=false means that untouched channels will be preserved in buf_out
536 void PinMapperConvertBuffers(const double *buf, int len_in, int nch_in,
537 double *buf_out, int len_out, int nch_out,
538 const ChannelPinMapper *pinmap, bool isInput, bool wantZeroExcessOutput)
541 if (pinmap->IsStraightPassthrough() || !pinmap->GetNPins())
543 int x;
544 char *op = (char *)buf_out;
545 const char *ip = (const char *)buf;
547 const int ip_adv = nch_in * sizeof(double);
549 const int clen = wdl_min(nch_in, nch_out) * sizeof(double);
550 const int zlen = nch_out > nch_in ? (nch_out - nch_in) * sizeof(double) : 0;
552 const int cplen = wdl_min(len_in,len_out);
554 for (x=0;x<cplen;x++)
556 memcpy(op,ip,clen);
557 op += clen;
558 if (zlen)
560 if (wantZeroExcessOutput) memset(op,0,zlen);
561 op += zlen;
563 ip += ip_adv;
565 if (x < len_out && wantZeroExcessOutput) memset(op, 0, (len_out-x)*sizeof(double)*nch_out);
567 else
569 if (wantZeroExcessOutput) memset(buf_out,0,len_out*nch_out*sizeof(double));
571 const int npins = wdl_min(pinmap->GetNPins(),isInput ? nch_out : nch_in);
572 const int nchan = isInput ? nch_in : nch_out;
574 int p;
575 WDL_UINT64 clearmask=0;
576 for (p = 0; p < npins; p ++)
578 WDL_UINT64 map = pinmap->m_mapping[p];
579 int x;
580 for (x = 0; x < nchan && map; x ++)
582 if (map & 1)
584 int i=len_in;
585 const double *ip = buf + (isInput ? x : p);
586 const int out_idx = (isInput ? p : x);
588 bool want_zero=false;
589 if (!wantZeroExcessOutput)
591 WDL_UINT64 m = ((WDL_UINT64)1)<<out_idx;
592 if (!(clearmask & m))
594 clearmask|=m;
595 want_zero=true;
599 double *op = buf_out + out_idx;
601 if (want_zero)
603 while (i-- > 0)
605 *op = *ip;
606 op += nch_out;
607 ip += nch_in;
610 else
612 while (i-- > 0)
614 *op += *ip;
615 op += nch_out;
616 ip += nch_in;
620 map >>= 1;