1 #include "audiobuffercontainer.h"
5 void ChannelPinMapper::SetNPins(int nPins
)
8 else if (nPins
>CHANNELPINMAPPER_MAXPINS
) nPins
=CHANNELPINMAPPER_MAXPINS
;
10 for (i
= m_nPins
; i
< nPins
; ++i
) {
19 void ChannelPinMapper::SetNChannels(int nCh
)
22 for (i
= m_nCh
; i
< nCh
&& i
< m_nPins
; ++i
) {
28 void ChannelPinMapper::Init(const WDL_UINT64
* pMapping
, int nPins
)
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
)
50 m_mapping
[pinIdx
] |= BITMASK64(chIdx
);
54 m_mapping
[pinIdx
] &= ~BITMASK64(chIdx
);
59 bool ChannelPinMapper::TogglePin(int pinIdx
, int chIdx
)
61 bool on
= GetPin(pinIdx
, chIdx
);
63 SetPin(pinIdx
, chIdx
, 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
));
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));
87 bool ChannelPinMapper::IsStraightPassthrough() const
89 if (m_nCh
!= m_nPins
) return false;
90 const WDL_UINT64
* pMap
= m_mapping
;
92 for (i
= 0; i
< m_nPins
; ++i
, ++pMap
) {
93 if (*pMap
!= BITMASK64(i
)) return false;
98 #define PINMAPPER_MAGIC 1000
100 // return is on the heap
101 char* ChannelPinMapper::SaveStateNew(int* pLen
)
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
)
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;
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
);
135 template <class TDEST
, class TSRC
> void BufConvertT(TDEST
* dest
, const TSRC
* src
, int nFrames
, int destStride
, int srcStride
)
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
)
148 if (wt_start
== 1.0 && wt_end
== 1.0)
152 for (i
= 0; i
< nFrames
; ++i
)
159 memcpy(dest
, src
, nFrames
*sizeof(T
));
164 double dw
= (wt_end
-wt_start
)/(double)nFrames
;
165 double cw
= wt_start
;
169 for (i
= 0; i
< nFrames
; ++i
)
171 dest
[i
] += (T
)(1.0-cw
)*dest
[i
]+(T
)cw
*src
[i
];
177 for (i
= 0; i
< nFrames
; ++i
)
179 dest
[i
] = (T
)(1.0-cw
)*dest
[i
]+(T
)cw
*src
[i
];
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
);
196 else if (srcFmt
== FMT_64FP
)
198 BufConvertT((float*)dest
, (double*)src
, nFrames
, destStride
, srcStride
);
202 else if (destFmt
== FMT_64FP
)
204 if (srcFmt
== FMT_32FP
)
206 BufConvertT((double*)dest
, (float*)src
, nFrames
, destStride
, srcStride
);
209 else if (srcFmt
== FMT_64FP
)
211 BufConvertT((double*)dest
, (double*)src
, nFrames
, destStride
, srcStride
);
218 AudioBufferContainer::AudioBufferContainer()
223 m_interleaved
= true;
227 void AudioBufferContainer::Resize(int nCh
, int nFrames
, bool preserveData
)
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
253 if (out
!=in
) memmove(out
,in
,copysz
);
258 else // increasing channel count, copy right to left
266 if (out
!=in
) memmove(out
,in
,copysz
);
269 // adjust interleaving
273 m_data
.Resize(newsz
);
274 m_hasData
= preserveData
;
279 void AudioBufferContainer::Reformat(int fmt
, bool preserveData
)
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
;
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);
312 memcpy(dest
, src
, sz
);
319 m_interleaved
= true;
324 // src=NULL to memset(0)
325 void* AudioBufferContainer::SetChannel(int fmt
, const void* src
, int chIdx
, int nFrames
)
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);
338 memcpy(dest
, src
, sz
);
345 m_interleaved
= false;
350 void* AudioBufferContainer::MixChannel(int fmt
, const void* src
, int chIdx
, int nFrames
, bool addToDest
, double wt_start
, double wt_end
)
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);
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;
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
386 void* AudioBufferContainer::GetChannel(int fmt
, int chIdx
, bool preserveData
)
388 Reformat(fmt
, preserveData
);
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
;
410 unsigned char* src
= (unsigned char*)m_data
.Resize(bufsz
*2);
411 unsigned char* dest
= src
+bufsz
;
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);
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
);
443 void* src
= rhs
->m_data
.Get();
444 memcpy(dest
, src
, sz
);
448 m_nFrames
= rhs
->m_nFrames
;
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())
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);
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);
483 if (!mapper
->PinHasMoreMappings(p
, c
))
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())
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);
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
);
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())
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
++)
560 if (wantZeroExcessOutput
) memset(op
,0,zlen
);
565 if (x
< len_out
&& wantZeroExcessOutput
) memset(op
, 0, (len_out
-x
)*sizeof(double)*nch_out
);
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
;
575 WDL_UINT64 clearmask
=0;
576 for (p
= 0; p
< npins
; p
++)
578 WDL_UINT64 map
= pinmap
->m_mapping
[p
];
580 for (x
= 0; x
< nchan
&& map
; x
++)
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
))
599 double *op
= buf_out
+ out_idx
;