C++ API Reference RNBO: common/RNBO_DataRef.h Source File

RNBO: common/RNBO_DataRef.h Source File

1 //
2 // RNBO_DataRef.h
3 //
4 //
5 
6 #ifndef _RNBO_DATAREF_H_
7 #define _RNBO_DATAREF_H_
8 
9 #include "RNBO_Types.h"
10 
11 #ifndef RNBO_NOSTDLIB
12 #include <atomic>
13 #endif
14 
15 namespace RNBO {
16 
17  // it is hard coded for now
18  #define RNBO_DEFAULT_SAMPLERATE 44100
19 
26 
27  };
28 
32  struct AudioBufferInfo {
33  size_t channels;
34  number samplerate;
35  };
36 
45  struct DataType {
47  enum Type {
52  TypedArray
53  } type = Untyped;
54 
55 
56  union {
57  UntypedBufferInfo untypedBufferInfo;
58  AudioBufferInfo audioBufferInfo;
59  };
60 
61  bool operator==(const DataType& rhs) const
62  {
63  if (type != rhs.type) return false;
64  switch (type) {
65  case Untyped: return true;
66  case TypedArray: return true;
67  case Float32AudioBuffer:
68  case Float64AudioBuffer:
69  case SampleAudioBuffer:
70  return (audioBufferInfo.channels == rhs.audioBufferInfo.channels
71  && audioBufferInfo.samplerate == rhs.audioBufferInfo.samplerate);
72  }
73 
74  return false;
75  }
76 
77  bool operator!=(const DataType& rhs) const
78  {
79  return !operator==(rhs);
80  }
81 
82  bool matches(const DataType& rhs) const
83  {
84  if (type == Untyped) return false;
85  return type == rhs.type;
86  }
87  };
88 
92  class DataRef {
93  public:
94 
95  DataRef()
96  : _name(nullptr)
97  , _file(nullptr)
98  , _tag(nullptr)
99  , _sizeInBytes(0)
100  , _data(nullptr)
101  , _touched(false)
102  {}
103 
104  DataRef(DataRef&& other)
105  {
106  _name = other._name;
107  _file = other._file;
108  _sizeInBytes = other._sizeInBytes;
109  _data = other._data;
110  _type = other._type;
111  _touched = other._touched;
112  _tag = other._tag;
113  _internal = other._internal;
114  _index = other._index;
115  _requestedSizeInBytes = other._requestedSizeInBytes;
116  _allocatedSizeInBytes = other._allocatedSizeInBytes;
117  _deAlloc = other._deAlloc;
118 
119  // now reset the other one
120  other._data = nullptr;
121  other._sizeInBytes = 0;
122  other._deAlloc = false;
123  other._name = nullptr;
124  other._file = nullptr;
125  other._requestedSizeInBytes = 0;
126  other._index = -1;
127  other._tag = nullptr;
128  }
129 
130  void operator=(const DataRef& ref ) = delete;
131 
138  DataRef& operator=(DataRef&& other)
139  {
140  if (this != &other) {
141  _name = other._name;
142  _file = other._file;
143  _sizeInBytes = other._sizeInBytes;
144  _data = other._data;
145  _type = other._type;
146  _touched = other._touched;
147  _deAlloc = other._deAlloc;
148  _tag = other._tag;
149  _internal = other._internal;
150  _index = other._index;
151  _requestedSizeInBytes = other._requestedSizeInBytes;
152  _allocatedSizeInBytes = other._allocatedSizeInBytes;
153 
154  // now reset the other one
155  other._data = nullptr;
156  other._sizeInBytes = 0;
157  other._deAlloc = false;
158  other._name = nullptr;
159  other._file = nullptr;
160  other._requestedSizeInBytes = 0;
161  other._allocatedSizeInBytes = 0;
162  other._index = -1;
163  other._tag = nullptr;
164  }
165 
166  return *this;
167  }
168 
169  void operator=(DataRef& other)
170  {
171  if (this != &other) {
172  _name = other._name;
173  _file = other._file;
174  _sizeInBytes = other._sizeInBytes;
175  _data = other._data;
176  _type = other._type;
177  _touched = other._touched;
178  _deAlloc = other._deAlloc;
179  _tag = other._tag;
180  _internal = other._internal;
181  _index = other._index;
182  _requestedSizeInBytes = other._requestedSizeInBytes;
183  _allocatedSizeInBytes = other._allocatedSizeInBytes;
184 
185  // now reset the other one
186  other._data = nullptr;
187  other._sizeInBytes = 0;
188  other._deAlloc = false;
189  other._name = nullptr;
190  other._file = nullptr;
191  other._requestedSizeInBytes = 0;
192  other._allocatedSizeInBytes = 0;
193  other._index = -1;
194  other._tag = nullptr;
195  }
196  }
197 
198  DataRef* operator->() {
199  return this;
200  }
201 
202  ~DataRef() {
203  freeIfNeeded();
204  }
205 
206  inline DataType getType() const {
207  return _type;
208  }
209 
210  void setType(DataType type) {
211  _type = type;
212  }
213 
214  inline const char *getName() const {
215  return _name;
216  }
217 
218  void setName(const char *name) {
219  if (name && Platform::strlen(name)) _name = name;
220  else _name = nullptr;
221  }
222 
223  inline const char *getFile() const {
224  return _file;
225  }
226 
227  void setFile(const char *file) {
228  if (file && Platform::strlen(file)) _file = file;
229  else _file = nullptr;
230  }
231 
232  inline char *getData() {
233  return _data;
234  }
235 
236  const char *getData() const {
237  return _data;
238  }
239 
240  void setData(char *data, size_t sizeInBytes, bool deAlloc = false) {
241  freeIfNeeded();
242 
243  _data = data;
244  _sizeInBytes = _allocatedSizeInBytes = sizeInBytes;
245  // normally we now hold external data, but in the WASM case
246  // we want to de-allocate
247  _deAlloc = deAlloc;
248  }
249 
250  inline size_t getSizeInBytes() const {
251  return _sizeInBytes;
252  }
253 
254  void requestSizeInBytes(size_t size, bool force) {
255  if (size > _requestedSizeInBytes || force) _requestedSizeInBytes = size;
256  }
257 
258  bool hasRequestedSize() const {
259  return _requestedSizeInBytes > 0;
260  }
261 
262  void resetRequestedSizeInByte() {
263  _requestedSizeInBytes = 0;
264  }
265 
266  inline bool getTouched() const {
267  return _touched;
268  }
269 
270  void setTouched(bool value) {
271  _touched = value;
272  }
273 
274  void allocateIfNeeded() {
275  if (_requestedSizeInBytes) {
276  if (_requestedSizeInBytes > _allocatedSizeInBytes || !_deAlloc) {
277  auto oldData = _data;
278  _data = static_cast<char *>(Platform::calloc(_requestedSizeInBytes, 1));
279  if (_deAlloc && oldData) {
280  // we own the old data, so copy and free it
281  Platform::memcpy(_data, oldData, _sizeInBytes);
282  Platform::free(oldData);
283  _wantsFill = false;
284  }
285  else {
286  _wantsFill = true;
287  }
288  _deAlloc = true;
289 
290  _sizeInBytes = _allocatedSizeInBytes = _requestedSizeInBytes;
291  }
292  else {
293  // zero out padding if we grow
294  if (_requestedSizeInBytes > _sizeInBytes) {
295  Platform::memset(_data + _sizeInBytes, 0, _requestedSizeInBytes - _sizeInBytes);
296  }
297  // if we didn't need to allocate, we just reset our size to the requested value
298  _sizeInBytes = _requestedSizeInBytes;
299  }
300  }
301  }
302 
303  void freeIfNeeded() {
304  if (_deAlloc && _data != nullptr) {
305  Platform::free(_data);
306  _data = nullptr;
307  _deAlloc = false;
308  }
309  }
310 
311  inline bool wantsFill() const {
312  return _wantsFill;
313  }
314 
315  void setWantsFill(bool value) {
316  _wantsFill = value;
317  }
318 
319  inline const char *getTag() const {
320  return _tag;
321  }
322 
323  void setTag(const char *tag) {
324  if (tag && Platform::strlen(tag)) _tag = tag;
325  else _tag = nullptr;
326  }
327 
328  void setInternal(bool value) {
329  _internal = value;
330  }
331 
332  inline bool isInternal() const {
333  return _internal;
334  }
335 
336  void setZero() {
337  Platform::memset(_data, 0, _sizeInBytes);
338  }
339 
340  void setIndex(DataRefIndex index) {
341  _index = index;
342  }
343 
344  DataRefIndex getIndex() {
345  return _index;
346  }
347 
348  private:
349  const char* _name = nullptr;
350  const char* _file = nullptr;
351  const char* _tag = nullptr;
352 
353  size_t _sizeInBytes = 0;
354  size_t _requestedSizeInBytes = 0;
355  size_t _allocatedSizeInBytes = 0;
356  char *_data = nullptr;
357  bool _touched = false;
358  bool _deAlloc = false;
359  bool _wantsFill = false;
360  bool _internal = false;
361  DataRefIndex _index = -1;
362 
363  DataType _type;
364  };
365 
366  // set the name of the DataRef, this is needed for Javascript and C to be similar
367  // might go away in the future
368  ATTRIBUTE_UNUSED
369  static inline DataRef& initDataRef(DataRef& ref, const char *name, bool internal, const char* file, const char* tag) {
370  ref.setName(name);
371  ref.setInternal(internal);
372  ref.setFile(file);
373  ref.setTag(tag);
374  return ref;
375  }
376 
380  class MultiDataRef
381  {
382  public:
383  template<typename... Ts> MultiDataRef(Ts & ... args)
384  : _count(sizeof ... (args))
385  {
386  _refs = static_cast<DataRef**>(Platform::malloc(_count * sizeof(DataRef *)));
387  DataRef* refs[sizeof...(args)] = {static_cast<DataRef*>(&args)...};
388  for (size_t i = 0; i < _count; i++) {
389  _refs[i] = refs[i];
390  }
391  }
392 
393  MultiDataRef() = default;
394 
395  MultiDataRef(MultiDataRef&& other)
396  {
397  _count = other._count;
398  _current = other._current;
399  if (!_refs) {
400  _refs = other._refs;
401  other._refs = nullptr;
402  }
403  _index = other._index;
404 
405  }
406 
407  void operator=(const MultiDataRef& ref ) = delete;
408 
409  MultiDataRef& operator=(MultiDataRef&& other)
410  {
411  if (this != &other) {
412  _count = other._count;
413  _current = other._current;
414  if (!_refs) {
415  _refs = other._refs;
416  other._refs = nullptr;
417  }
418  _index = other._index;
419  }
420 
421  return *this;
422  }
423 
424  void operator=(MultiDataRef& other)
425  {
426  if (this != &other) {
427  _count = other._count;
428  _current = other._current;
429  if (!_refs) {
430  _refs = other._refs;
431  other._refs = nullptr;
432  }
433  _index = other._index;
434  }
435  }
436 
437 
438  ~MultiDataRef() {
439  if (_refs) {
440  Platform::free(_refs);
441  }
442  }
443 
444  MultiDataRef* operator->() {
445  return this;
446  }
447 
448  void setCurrent(DataRefIndex current) {
449  if (current >= 0 && current < static_cast<DataRefIndex>(_count)) {
450  _current = current;
451  }
452  }
453 
454  DataRef& getCurrent() const {
455  return *_refs[_current];
456  }
457 
458  DataRefIndex getCurrentIndex() const {
459  return _current;
460  }
461 
462  void setIndex(DataRefIndex index) {
463  _index = index;
464  }
465 
466  DataRefIndex getIndex() const {
467  return _index;
468  }
469 
470  private:
471  Index _count = 0;
472  DataRefIndex _current = 0;
473  DataRef** _refs = nullptr;
474  DataRefIndex _index = 0;
475  };
476 
477  template<typename ... Ts> MultiDataRef initMultiRef(Ts & ... args)
478  {
479  MultiDataRef ref(args...);
480  return ref;
481  }
482 
486  template<typename T, typename DR> class DataView {
487  public:
488  DataView(DR& dataRef)
489  : _usage(0)
490  , _dataRef(&dataRef)
491  {
492  updateCachedSize();
493  }
494 
495  virtual ~DataView() {}
496 
497  inline T& operator[](size_t i) {
498  T *values = reinterpret_cast<T*>(_dataRef->getData());
499  return values[i];
500  }
501 
502  inline T operator[](size_t i) const {
503  T *values = reinterpret_cast<T*>(_dataRef->getData());
504  return values[i];
505  }
506 
507  inline bool typeislockfree() const {
508 #if defined(_MSC_VER)
509  //TODO
510 #elif defined(__clang__) || defined(__GNUC__)
511  T dummy = 0;
512  return __atomic_is_lock_free(sizeof(T), &dummy);
513 #endif
514 #ifndef RNBO_NOSTDLIB
515  return std::atomic<T>{}.is_lock_free();
516 #else
517  return false; //unknown
518 #endif
519  }
520 
521  inline T atomicload(const Index index, int order = 5) const { //order = 5 -> memory_order_seq_cst
522  if (index < getSize()) {
523  T *loc = reinterpret_cast<T*>(_dataRef->getData()) + index;
524 #if defined(__clang__) || defined(__GNUC__)
525  //https://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary
526  T ret;
527  int order = 5;
528  //llvm's docs show a size arg as first arg but also says they use gcc's format which doesn't have the size
529  __atomic_load(loc, &ret, order);
530  return ret;
531 #elif defined(_MSC_VER)
532  switch (sizeof(T)) {
533  case 8:
534  return InterlockedOr64(loc, 0);
535  case 4:
536  return InterlockedOr(loc, 0);
537  case 2:
538  return InterlockedOr16(loc, 0);
539  case 1:
540  return InterlockedOr8(loc, 0);
541  default:
542  return 0; //error
543  }
544 #else
545  //TODO?
546  return *loc;
547 #endif
548  }
549  return 0;
550  }
551 
552  inline void atomicstore(const Index index, T value, int order = 5) { //order = 5 -> memory_order_seq_cst
553  if (index < DataView<T, DR>::getSize()) {
554  T *loc = reinterpret_cast<T*>(_dataRef->getData()) + index;
555 #if defined(__clang__) || defined(__GNUC__)
556  //https://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary
557  //llvm's docs show a size arg as first arg but also says they use gcc's format which doesn't have the size
558  __atomic_store(loc, &value, order);
559 #elif defined(_MSC_VER)
560  switch (sizeof(T)) {
561  case 8:
562  InterlockedExchange64(loc, value);
563  break;
564  case 4:
565  InterlockedExchange(loc, value);
566  break;
567  case 2:
568  InterlockedExchange16(loc, value);
569  break;
570  case 1:
571  InterlockedExchange8(loc, value);
572  break;
573  default:
574  return; //error
575  }
576 #else
577  //TODO?
578  *loc = value;
579 #endif
580  }
581  }
582 
583  DataView* operator->() {
584  return this;
585  }
586 
587  const DataView* operator->() const {
588  return this;
589  }
590 
591  inline size_t getSize() const {
592  return _size;
593  }
594 
595  virtual void updateCachedSize() {
596  _size = _dataRef->getSizeInBytes() / sizeof(T);
597  }
598 
599  inline DataType getType() const {
600  return _dataRef->getType();
601  }
602 
603  void setType(DataType type) {
604  _dataRef->setType(type);
605  updateCachedSize();
606  }
607 
608  inline size_t getSizeInBytes() const {
609  return _dataRef->getSizeInBytes();
610  }
611 
612  void setTouched(bool value) {
613  _dataRef->setTouched(value);
614  }
615 
616  bool getTouched() {
617  return _dataRef->getTouched();
618  }
619 
620  virtual DataView<T, DR>* allocateIfNeeded() {
621  _dataRef->allocateIfNeeded();
622  updateCachedSize();
623  return this;
624  }
625 
626  void setWantsFill(bool value) {
627  _dataRef->setWantsFill(value);
628  }
629 
630  void clear() {
631  _dataRef->setData(nullptr, 0);
632  }
633 
634  void setZero() {
635  _dataRef->setZero();
636  }
637 
638  DataRefIndex getIndex() const {
639  return _dataRef->getIndex();
640  }
641 
642  int _usage;
643 
644  virtual void reInit() {
645  reInit(*_dataRef);
646  }
647 
648  protected:
649  // the derived view class has to implement the correct version for its data format
650  void requestSize(size_t size) {
651  size_t sizeInBytes = size * sizeof(T);
652  _dataRef->requestSizeInBytes(sizeInBytes, false);
653  }
654 
655  // the derive view class has to implement the correct version for its data format
656  virtual DataView<T, DR>* setSize(size_t size) {
657  size_t sizeInBytes = size * sizeof(T);
658  _dataRef->requestSizeInBytes(sizeInBytes, true);
659  _dataRef->allocateIfNeeded();
660  updateCachedSize();
661  return this;
662  }
663 
664  void reInit(DR& dataRef) {
665  _dataRef = &dataRef;
666  updateCachedSize();
667  }
668 
669  size_t _size;
670  DR* _dataRef;
671  };
672 
677  template<typename T, typename U> class DataViewRef {
678  public:
679  DataViewRef()
680  {}
681 
682  virtual ~DataViewRef()
683  {
684  freeView();
685  }
686 
687  DataViewRef(const DataViewRef<T, U>& other)
688  {
689  other._view->_usage++;
690  freeView();
691  _view = other._view;
692  }
693 
694  DataViewRef(U* view)
695  {
696  view->_usage++;
697  freeView();
698  _view = view;
699  }
700 
701  void operator=(U* view )
702  {
703  view->_usage++;
704  freeView();
705  _view = view;
706  }
707 
708  void operator=(const DataViewRef<T, U>& other)
709  {
710  if (&other != this) {
711  other._view->_usage++;
712  freeView();
713  _view = other._view;
714  }
715  }
716 
717  inline T& operator[](size_t i) {
718  return (*_view)[i];
719  }
720 
721  inline T operator[](size_t i) const {
722  return (*_view)[i];
723  }
724 
725  U* operator->() {
726  return _view;
727  }
728 
729  void freeView() {
730  if (_view) {
731  _view->_usage--;
732  if (!_view->_usage) delete _view;
733  _view = nullptr;
734  }
735  }
736 
737  private:
738  U* _view = nullptr;
739  };
740 
744  template<typename T, typename DR> class OneDimensionalArray : public DataView<T, DR>
745  {
746  public:
747  OneDimensionalArray(DR& dataRef)
748  : DataView<T, DR>(dataRef)
749  {
750  DataType info;
751  info.type = DataType::TypedArray;
752  DataView<T, DR>::setType(info);
753  }
754 
755  void requestSize(size_t size) {
756  DataView<T, DR>::requestSize(size);
757  }
758 
759  inline size_t getChannels() const {
760  return 1;
761  }
762 
763  inline number getSampleRate() const {
764  return 0.0;
765  }
766 
767  virtual OneDimensionalArray<T, DR>* allocateIfNeeded() override {
768  DataView<T, DR>::allocateIfNeeded();
769  return this;
770  }
771 
772  inline T getSample(const size_t /*channel*/, const size_t index) const {
773  return DataView<T, DR>::operator[](index);
774  }
775 
776  inline T getSampleSafe(const long channel, const long index) const {
777  if (channel == 0 && index < DataView<T, DR>::getSize()) {
778  return DataView<T, DR>::operator[](index);
779  }
780  return 0;
781  }
782 
783  // channel numbers are 0 based
784  inline void setSample(const size_t /*channel*/, const size_t index, const T value) {
785  DataView<T, DR>::operator[](index) = value;
786  }
787 
788  inline void setSampleSafe(const long channel, const long index, const T value) {
789  if (channel == 0 && index < DataView<T, DR>::getSize()) {
790  DataView<T, DR>::operator[](index) = value;
791  }
792  }
793 
794  OneDimensionalArray<T, DR>* setSize(size_t size) override {
795  DataView<T, DR>::setSize(size);
796  return this;
797  }
798  };
799 
803  template<typename T, typename DR> class InterleavedAudioBuffer : public DataView<T, DR>
804  {
805  public:
806  InterleavedAudioBuffer(DR& dataRef, DataType::Type type)
807  : DataView<T, DR>(dataRef)
808  {
809  if (DataView<T, DR>::getType().type == DataType::Untyped) {
810  DataType info;
811  info.type = type;
812  info.audioBufferInfo.channels = 0;
813  info.audioBufferInfo.samplerate = RNBO_DEFAULT_SAMPLERATE;
814  DataView<T, DR>::setType(info);
815  }
816 
817  updateCachedSize();
818  }
819 
820  virtual ~InterleavedAudioBuffer() override {}
821 
822  InterleavedAudioBuffer* operator->() {
823  return this;
824  }
825 
826  inline T getSample(const size_t channel, const size_t index) const {
827  if (!_audioData) return 0;
828  return _audioData[_channels * index + channel];
829  }
830 
831  inline T getSampleSafe(const long channel, const long index) const {
832  if (!_audioData) return 0;
833  const auto ind = _channels * index + channel;
834  if (ind < 0 || static_cast<size_t>(ind) >= DataView<T, DR>::getSize() * _channels) {
835  return static_cast<T>(0);
836  }
837  return _audioData[ind];
838  }
839 
840  // channel numbers are 0 based
841  inline void setSample(const size_t channel, const size_t index, const T value) {
842  if (_audioData)
843  _audioData[_channels * index + channel] = value;
844  }
845 
846  inline void setSampleSafe(const long channel, const long index, const T value) {
847  if (channel < 0 || static_cast<size_t>(channel) >= _channels || index < 0 || static_cast<size_t>(index) >= DataView<T, DR>::getSize()) {
848  return;
849  }
850  _audioData[_channels * index + channel] = value;
851  }
852 
853  inline size_t getChannels() const {
854  return _channels;
855  }
856 
857  inline number getSampleRate() const {
858  DataType info = DataView<T, DR>::getType();
859  return info.audioBufferInfo.samplerate;
860  }
861 
862  void setSampleRate(number sampleRate) {
863  DataType info = DataView<T, DR>::getType();
864  info.audioBufferInfo.samplerate = sampleRate;
865  DataView<T, DR>::setType(info);
866  }
867 
868  bool isInterleaved() {
869  // for now we only support interleaved audio
870  return true;
871  }
872 
873  void requestSize(size_t size, size_t channels) {
874  DataView<T, DR>::requestSize(size * channels);
875  _requestedChannels = channels;
876  }
877 
878  InterleavedAudioBuffer<T, DR>* setSize(size_t size) override {
879  DataView<T, DR>::setSize(size * _channels);
880  return this;
881  }
882 
883  void updateCachedSize() override {
884  DataType info = DataView<T, DR>::getType();
885  _channels = info.audioBufferInfo.channels;
886  _audioData = reinterpret_cast<T*>(DataView<T, DR>::_dataRef->getData());
887  DataView<T, DR>::_size = _channels ? (DataView<T, DR>::getSizeInBytes() / sizeof(T)) / _channels : 0;
888  }
889 
890  virtual InterleavedAudioBuffer<T, DR>* setChannels(size_t channels) {
891  if (channels != _channels) {
892  size_t currentSize = DataView<T, DR>::getSize();
893 
894  DataType info = DataView<T, DR>::getType();
895  info.audioBufferInfo.channels = channels;
896  DataView<T, DR>::setType(info);
897 
898  // update local cache
899  _channels = channels;
900  _audioData = reinterpret_cast<T*>(DataView<T, DR>::_dataRef->getData());
901 
902  // we might want to implement preserving the data in the future
903  DataView<T, DR>::clear();
904 
905  DataView<T, DR>::setSize(currentSize * _channels);
906  }
907 
908  return this;
909  }
910 
911  InterleavedAudioBuffer<T, DR>* allocateIfNeeded() override {
912  if (_requestedChannels > 0) {
913  if (_channels != 0 && _requestedChannels != _channels) {
914  DataView<T, DR>::setZero();
915  }
916 
917  DataType info = DataView<T, DR>::getType();
918  info.audioBufferInfo.channels = _requestedChannels;
919  DataView<T, DR>::setType(info);
920 
921  DataView<T, DR>::allocateIfNeeded();
922  }
923 
924  return this;
925  }
926 
927  DataRefIndex getCurrentIndex() const {
928  return 0;
929  }
930 
931  private:
932  size_t _requestedChannels = 0;
933  size_t _channels = 0;
934  T* _audioData = nullptr;
935 
936  };
937 
943  class Float32Buffer : public InterleavedAudioBuffer<float, DataRef>
944  {
945  public:
946  Float32Buffer(DataRef& dataRef)
947  : InterleavedAudioBuffer<float, DataRef>(dataRef, DataType::Float32AudioBuffer)
948  {}
949 
950  virtual Float32Buffer* allocateIfNeeded() override {
951  InterleavedAudioBuffer<float, DataRef>::allocateIfNeeded();
952  return this;
953  }
954 
955  virtual Float32Buffer* setChannels(size_t channels) override {
956  InterleavedAudioBuffer<float, DataRef>::setChannels(channels);
957  return this;
958  }
959 
960  virtual Float32Buffer* setSize(size_t size) override {
961  InterleavedAudioBuffer<float, DataRef>::setSize(size);
962  return this;
963  }
964  };
965 
966  using Float32BufferRef = DataViewRef<float, Float32Buffer >;
967 
971  class Float64Buffer : public InterleavedAudioBuffer<double, DataRef>
972  {
973  public:
974  Float64Buffer(DataRef& dataRef)
975  : InterleavedAudioBuffer<double, DataRef>(dataRef, DataType::Float64AudioBuffer)
976  {}
977 
978  virtual Float64Buffer* allocateIfNeeded() override {
979  InterleavedAudioBuffer<double, DataRef>::allocateIfNeeded();
980  return this;
981  }
982 
983  virtual Float64Buffer* setChannels(size_t channels) override {
984  InterleavedAudioBuffer<double, DataRef>::setChannels(channels);
985  return this;
986  }
987 
988  virtual Float64Buffer* setSize(size_t size) override {
989  InterleavedAudioBuffer<double, DataRef>::setSize(size);
990  return this;
991  }
992  };
993 
994  using Float64BufferRef = DataViewRef<double, Float64Buffer>;
995 
996 
1000  class SampleBuffer : public InterleavedAudioBuffer<SampleValue, DataRef>
1001  {
1002  public:
1003  SampleBuffer(DataRef& dataRef)
1004  : InterleavedAudioBuffer<SampleValue, DataRef>(dataRef, DataType::SampleAudioBuffer)
1005  {}
1006 
1007  virtual SampleBuffer* allocateIfNeeded() override {
1008  InterleavedAudioBuffer<SampleValue, DataRef>::allocateIfNeeded();
1009  return this;
1010  }
1011 
1012  virtual SampleBuffer* setChannels(size_t channels) override {
1013  InterleavedAudioBuffer<SampleValue, DataRef>::setChannels(channels);
1014  return this;
1015  }
1016 
1017  virtual SampleBuffer* setSize(size_t size) override {
1018  InterleavedAudioBuffer<SampleValue, DataRef>::setSize(size);
1019  return this;
1020  }
1021  };
1022 
1023  using SampleBufferRef = DataViewRef<SampleValue, SampleBuffer>;
1024 
1036  template <typename T> class MultiBuffer : public InterleavedAudioBuffer<T, DataRef>
1037  {
1038  public:
1039  MultiBuffer(MultiDataRef& multiRef, DataType::Type type)
1040  : InterleavedAudioBuffer<T, DataRef>(multiRef.getCurrent(), type)
1041  , _multiRef(multiRef)
1042  {}
1043 
1044  void setCurrent(DataRefIndex current) {
1045  _multiRef.setCurrent(current);
1046  }
1047 
1048  DataRefIndex getIndex() const {
1049  return _multiRef.getIndex();
1050  }
1051 
1052  void reInit() override {
1053  InterleavedAudioBuffer<T, DataRef>::reInit(_multiRef.getCurrent());
1054  }
1055 
1056  DataRefIndex getCurrentIndex() const {
1057  return _multiRef.getCurrentIndex();
1058  }
1059 
1060  private:
1061  MultiDataRef& _multiRef;
1062  };
1063 
1067  class Float32MultiBuffer : public MultiBuffer<float>
1068  {
1069  public:
1070  Float32MultiBuffer(MultiDataRef& dataRef)
1071  : MultiBuffer<float>(dataRef, DataType::Float32AudioBuffer)
1072  {}
1073  };
1074 
1075  using Float32MultiBufferRef = DataViewRef<float, Float32MultiBuffer >;
1076 
1080  class Float64MultiBuffer : public MultiBuffer<double>
1081  {
1082  public:
1083  Float64MultiBuffer(MultiDataRef& dataRef)
1084  : MultiBuffer<double>(dataRef, DataType::Float64AudioBuffer)
1085  {}
1086  };
1087 
1088  using Float64MultiBufferRef = DataViewRef<double, Float64MultiBuffer>;
1089 
1090 
1091  using Int8Buffer = OneDimensionalArray<int8_t, DataRef>;
1092  using Int8BufferRef = DataViewRef<int8_t, Int8Buffer>;
1093 
1094  using UInt8Buffer = OneDimensionalArray<uint8_t, DataRef>;
1095  using UInt8BufferRef = DataViewRef<uint8_t, UInt8Buffer>;
1096 
1097  using Int32Buffer = OneDimensionalArray<int32_t, DataRef>;
1098  using Int32BufferRef = DataViewRef<int32_t, Int32Buffer>;
1099 
1100  using UInt32Buffer = OneDimensionalArray<uint32_t, DataRef>;
1101  using UInt32BufferRef = DataViewRef<uint32_t, UInt32Buffer>;
1102 
1103  using Int64Buffer = OneDimensionalArray<int64_t, DataRef>;
1104  using Int64BufferRef = DataViewRef<int64_t, Int64Buffer>;
1105 
1106  using UInt64Buffer = OneDimensionalArray<uint64_t, DataRef>;
1107  using UInt64BufferRef = DataViewRef<uint64_t, UInt64Buffer>;
1108 
1109  using IntBuffer = OneDimensionalArray<Int, DataRef>;
1110  using IntBufferRef = DataViewRef<Int, IntBuffer>;
1111 
1112  using UIntBuffer = OneDimensionalArray<UInt, DataRef>;
1113  using UIntBufferRef = DataViewRef<UInt, UIntBuffer>;
1114 
1115 
1119  struct UntypedDataBuffer : public DataType {
1120  UntypedDataBuffer() {
1121  type = DataType::Untyped;
1122  }
1123  };
1124 
1125  static_assert(sizeof(UntypedDataBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1126 
1131  {
1132  Float32AudioBuffer(Index channels, number samplerate) {
1134  audioBufferInfo.channels = channels;
1135  audioBufferInfo.samplerate = samplerate;
1136  }
1137  };
1138 
1139  static_assert(sizeof(Float32AudioBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1140 
1145  {
1146  Float64AudioBuffer(Index channels, number samplerate) {
1148  audioBufferInfo.channels = channels;
1149  audioBufferInfo.samplerate = samplerate;
1150  }
1151  };
1152 
1153  static_assert(sizeof(Float64AudioBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1154 
1158  template<class T, typename U> void updateMultiRef(T patcher, U& ref, DataRefIndex current)
1159  {
1160  ref->setCurrent(current);
1161  patcher->getEngine()->sendDataRefUpdated(ref->getIndex());
1162  }
1163  template<typename T> void updateMultiRef(T, Float32BufferRef&, DataRefIndex) {}
1164  template<typename T> void updateMultiRef(T, Float64BufferRef&, DataRefIndex) {}
1165  template<typename T> void updateMultiRef(T, SampleBufferRef&, DataRefIndex) {}
1166 
1167  template<class T, typename U> void updateDataRef(T patcher, U& ref)
1168  {
1169  patcher->getEngine()->sendDataRefUpdated(ref->getIndex());
1170  }
1171 
1172  ATTRIBUTE_UNUSED
1173  static DataRef& serializeDataRef(DataRef& ref) {
1174  ref.resetRequestedSizeInByte();
1175  return ref;
1176  }
1177 
1178  template<typename T, typename U> T& reInitDataView(T& bufferRef, U&) {
1179  bufferRef->reInit();
1180  return bufferRef;
1181  }
1182 
1184  SerializedBuffer() {}
1185 
1186  SerializedBuffer(const DataRef& ref) {
1187  type = ref.getType();
1188  if (type.type == DataType::SampleAudioBuffer) {
1189  if (sizeof(SampleValue) == sizeof(float)) {
1190  type.type = DataType::Float32AudioBuffer;
1191  }
1192  else {
1193  type.type = DataType::Float64AudioBuffer;
1194  }
1195  }
1196  sizeInBytes = ref.getSizeInBytes();
1197  data = (uint8_t *)Platform::malloc(sizeInBytes);
1198  Platform::memcpy(data, ref.getData(), sizeInBytes);
1199  }
1200 
1201  ~SerializedBuffer() {
1202  if (data) {
1203  free(data);
1204  data = nullptr;
1205  }
1206  }
1207 
1209  {
1210  type = other.type;
1211  sizeInBytes = other.sizeInBytes;
1212  data = other.data;
1213 
1214  other.data = nullptr;
1215  other.sizeInBytes = 0;
1216  other.type = DataType();
1217  }
1218 
1219  // disable copy constructors for development purposes
1220  SerializedBuffer (const SerializedBuffer& other) {
1221  type = other.type;
1222  sizeInBytes = other.sizeInBytes;
1223  data = (uint8_t*)Platform::malloc(sizeInBytes);
1224  Platform::memcpy(data, other.data, sizeInBytes);
1225  }
1226 
1227  SerializedBuffer& operator= (const SerializedBuffer&) = delete;
1228 
1229  DataType type;
1230  size_t sizeInBytes = 0;
1231  uint8_t* data = nullptr;
1232  };
1233 
1234  ATTRIBUTE_UNUSED
1235  static SerializedBuffer serializeBuffer(const DataRef& ref) {
1236  return SerializedBuffer(ref);
1237  }
1238 
1239  template<class T> void deserializeBuffer(T patcher, DataRef& dst, const SerializedBuffer& src) {
1240  char* data = (char *)Platform::malloc(src.sizeInBytes);
1241  Platform::memcpy(data, src.data, src.sizeInBytes);
1242  dst.setData(data, src.sizeInBytes, true);
1243  dst.setType(src.type);
1244  patcher->getEngine()->sendDataRefUpdated(dst->getIndex());
1245  }
1246 
1247 } // namespace RNBO
1248 
1249 #endif // #ifndef _RNBO_DATAREF_H_