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  OneDimensionalArray* setChannels(size_t channels) {
764  return this;
765  }
766 
767  inline number getSampleRate() const {
768  return 0.0;
769  }
770 
771  virtual OneDimensionalArray<T, DR>* allocateIfNeeded() override {
772  DataView<T, DR>::allocateIfNeeded();
773  return this;
774  }
775 
776  inline T getSample(const size_t /*channel*/, const size_t index) const {
777  return DataView<T, DR>::operator[](index);
778  }
779 
780  inline T getSampleSafe(const long channel, const long index) const {
781  if (channel == 0 && index < DataView<T, DR>::getSize()) {
782  return DataView<T, DR>::operator[](index);
783  }
784  return 0;
785  }
786 
787  // channel numbers are 0 based
788  inline void setSample(const size_t /*channel*/, const size_t index, const T value) {
789  DataView<T, DR>::operator[](index) = value;
790  }
791 
792  inline void setSampleSafe(const long channel, const long index, const T value) {
793  if (channel == 0 && index < DataView<T, DR>::getSize()) {
794  DataView<T, DR>::operator[](index) = value;
795  }
796  }
797 
798  OneDimensionalArray<T, DR>* setSize(size_t size) override {
799  DataView<T, DR>::setSize(size);
800  return this;
801  }
802  };
803 
807  template<typename T, typename DR> class InterleavedAudioBuffer : public DataView<T, DR>
808  {
809  public:
810  InterleavedAudioBuffer(DR& dataRef, DataType::Type type)
811  : DataView<T, DR>(dataRef)
812  {
813  if (DataView<T, DR>::getType().type == DataType::Untyped) {
814  DataType info;
815  info.type = type;
816  info.audioBufferInfo.channels = 0;
817  info.audioBufferInfo.samplerate = RNBO_DEFAULT_SAMPLERATE;
818  DataView<T, DR>::setType(info);
819  }
820 
821  updateCachedSize();
822  }
823 
824  virtual ~InterleavedAudioBuffer() override {}
825 
826  InterleavedAudioBuffer* operator->() {
827  return this;
828  }
829 
830  inline T getSample(const size_t channel, const size_t index) const {
831  if (!_audioData) return 0;
832  return _audioData[_channels * index + channel];
833  }
834 
835  inline T getSampleSafe(const long channel, const long index) const {
836  if (!_audioData) return 0;
837  const auto ind = _channels * index + channel;
838  if (ind < 0 || static_cast<size_t>(ind) >= DataView<T, DR>::getSize() * _channels) {
839  return static_cast<T>(0);
840  }
841  return _audioData[ind];
842  }
843 
844  // channel numbers are 0 based
845  inline void setSample(const size_t channel, const size_t index, const T value) {
846  if (_audioData)
847  _audioData[_channels * index + channel] = value;
848  }
849 
850  inline void setSampleSafe(const long channel, const long index, const T value) {
851  if (channel < 0 || static_cast<size_t>(channel) >= _channels || index < 0 || static_cast<size_t>(index) >= DataView<T, DR>::getSize()) {
852  return;
853  }
854  _audioData[_channels * index + channel] = value;
855  }
856 
857  inline size_t getChannels() const {
858  return _channels;
859  }
860 
861  inline number getSampleRate() const {
862  DataType info = DataView<T, DR>::getType();
863  return info.audioBufferInfo.samplerate;
864  }
865 
866  void setSampleRate(number sampleRate) {
867  DataType info = DataView<T, DR>::getType();
868  info.audioBufferInfo.samplerate = sampleRate;
869  DataView<T, DR>::setType(info);
870  }
871 
872  bool isInterleaved() {
873  // for now we only support interleaved audio
874  return true;
875  }
876 
877  void requestSize(size_t size, size_t channels) {
878  DataView<T, DR>::requestSize(size * channels);
879  _requestedChannels = channels;
880  }
881 
882  InterleavedAudioBuffer<T, DR>* setSize(size_t size) override {
883  DataView<T, DR>::setSize(size * _channels);
884  return this;
885  }
886 
887  void updateCachedSize() override {
888  DataType info = DataView<T, DR>::getType();
889  _channels = info.audioBufferInfo.channels;
890  _audioData = reinterpret_cast<T*>(DataView<T, DR>::_dataRef->getData());
891  DataView<T, DR>::_size = _channels ? (DataView<T, DR>::getSizeInBytes() / sizeof(T)) / _channels : 0;
892  }
893 
894  virtual InterleavedAudioBuffer<T, DR>* setChannels(size_t channels) {
895  if (channels != _channels) {
896  size_t currentSize = DataView<T, DR>::getSize();
897 
898  DataType info = DataView<T, DR>::getType();
899  info.audioBufferInfo.channels = channels;
900  DataView<T, DR>::setType(info);
901 
902  // update local cache
903  _channels = channels;
904  _audioData = reinterpret_cast<T*>(DataView<T, DR>::_dataRef->getData());
905 
906  // we might want to implement preserving the data in the future
907  DataView<T, DR>::clear();
908 
909  DataView<T, DR>::setSize(currentSize * _channels);
910  }
911 
912  return this;
913  }
914 
915  InterleavedAudioBuffer<T, DR>* allocateIfNeeded() override {
916  if (_requestedChannels > 0) {
917  if (_channels != 0 && _requestedChannels != _channels) {
918  DataView<T, DR>::setZero();
919  }
920 
921  DataType info = DataView<T, DR>::getType();
922  info.audioBufferInfo.channels = _requestedChannels;
923  DataView<T, DR>::setType(info);
924 
925  DataView<T, DR>::allocateIfNeeded();
926  }
927 
928  return this;
929  }
930 
931  DataRefIndex getCurrentIndex() const {
932  return 0;
933  }
934 
935  private:
936  size_t _requestedChannels = 0;
937  size_t _channels = 0;
938  T* _audioData = nullptr;
939 
940  };
941 
947  class Float32Buffer : public InterleavedAudioBuffer<float, DataRef>
948  {
949  public:
950  Float32Buffer(DataRef& dataRef)
951  : InterleavedAudioBuffer<float, DataRef>(dataRef, DataType::Float32AudioBuffer)
952  {}
953 
954  virtual Float32Buffer* allocateIfNeeded() override {
955  InterleavedAudioBuffer<float, DataRef>::allocateIfNeeded();
956  return this;
957  }
958 
959  virtual Float32Buffer* setChannels(size_t channels) override {
960  InterleavedAudioBuffer<float, DataRef>::setChannels(channels);
961  return this;
962  }
963 
964  virtual Float32Buffer* setSize(size_t size) override {
965  InterleavedAudioBuffer<float, DataRef>::setSize(size);
966  return this;
967  }
968  };
969 
970  using Float32BufferRef = DataViewRef<float, Float32Buffer >;
971 
975  class Float64Buffer : public InterleavedAudioBuffer<double, DataRef>
976  {
977  public:
978  Float64Buffer(DataRef& dataRef)
979  : InterleavedAudioBuffer<double, DataRef>(dataRef, DataType::Float64AudioBuffer)
980  {}
981 
982  virtual Float64Buffer* allocateIfNeeded() override {
983  InterleavedAudioBuffer<double, DataRef>::allocateIfNeeded();
984  return this;
985  }
986 
987  virtual Float64Buffer* setChannels(size_t channels) override {
988  InterleavedAudioBuffer<double, DataRef>::setChannels(channels);
989  return this;
990  }
991 
992  virtual Float64Buffer* setSize(size_t size) override {
993  InterleavedAudioBuffer<double, DataRef>::setSize(size);
994  return this;
995  }
996  };
997 
998  using Float64BufferRef = DataViewRef<double, Float64Buffer>;
999 
1000 
1004  class SampleBuffer : public InterleavedAudioBuffer<SampleValue, DataRef>
1005  {
1006  public:
1007  SampleBuffer(DataRef& dataRef)
1008  : InterleavedAudioBuffer<SampleValue, DataRef>(dataRef, DataType::SampleAudioBuffer)
1009  {}
1010 
1011  virtual SampleBuffer* allocateIfNeeded() override {
1012  InterleavedAudioBuffer<SampleValue, DataRef>::allocateIfNeeded();
1013  return this;
1014  }
1015 
1016  virtual SampleBuffer* setChannels(size_t channels) override {
1017  InterleavedAudioBuffer<SampleValue, DataRef>::setChannels(channels);
1018  return this;
1019  }
1020 
1021  virtual SampleBuffer* setSize(size_t size) override {
1022  InterleavedAudioBuffer<SampleValue, DataRef>::setSize(size);
1023  return this;
1024  }
1025  };
1026 
1027  using SampleBufferRef = DataViewRef<SampleValue, SampleBuffer>;
1028 
1040  template <typename T> class MultiBuffer : public InterleavedAudioBuffer<T, DataRef>
1041  {
1042  public:
1043  MultiBuffer(MultiDataRef& multiRef, DataType::Type type)
1044  : InterleavedAudioBuffer<T, DataRef>(multiRef.getCurrent(), type)
1045  , _multiRef(multiRef)
1046  {}
1047 
1048  void setCurrent(DataRefIndex current) {
1049  _multiRef.setCurrent(current);
1050  }
1051 
1052  DataRefIndex getIndex() const {
1053  return _multiRef.getIndex();
1054  }
1055 
1056  void reInit() override {
1057  InterleavedAudioBuffer<T, DataRef>::reInit(_multiRef.getCurrent());
1058  }
1059 
1060  DataRefIndex getCurrentIndex() const {
1061  return _multiRef.getCurrentIndex();
1062  }
1063 
1064  private:
1065  MultiDataRef& _multiRef;
1066  };
1067 
1071  class Float32MultiBuffer : public MultiBuffer<float>
1072  {
1073  public:
1074  Float32MultiBuffer(MultiDataRef& dataRef)
1075  : MultiBuffer<float>(dataRef, DataType::Float32AudioBuffer)
1076  {}
1077  };
1078 
1079  using Float32MultiBufferRef = DataViewRef<float, Float32MultiBuffer >;
1080 
1084  class Float64MultiBuffer : public MultiBuffer<double>
1085  {
1086  public:
1087  Float64MultiBuffer(MultiDataRef& dataRef)
1088  : MultiBuffer<double>(dataRef, DataType::Float64AudioBuffer)
1089  {}
1090  };
1091 
1092  using Float64MultiBufferRef = DataViewRef<double, Float64MultiBuffer>;
1093 
1094 
1095  using Int8Buffer = OneDimensionalArray<int8_t, DataRef>;
1096  using Int8BufferRef = DataViewRef<int8_t, Int8Buffer>;
1097 
1098  using UInt8Buffer = OneDimensionalArray<uint8_t, DataRef>;
1099  using UInt8BufferRef = DataViewRef<uint8_t, UInt8Buffer>;
1100 
1101  using Int32Buffer = OneDimensionalArray<int32_t, DataRef>;
1102  using Int32BufferRef = DataViewRef<int32_t, Int32Buffer>;
1103 
1104  using UInt32Buffer = OneDimensionalArray<uint32_t, DataRef>;
1105  using UInt32BufferRef = DataViewRef<uint32_t, UInt32Buffer>;
1106 
1107  using Int64Buffer = OneDimensionalArray<int64_t, DataRef>;
1108  using Int64BufferRef = DataViewRef<int64_t, Int64Buffer>;
1109 
1110  using UInt64Buffer = OneDimensionalArray<uint64_t, DataRef>;
1111  using UInt64BufferRef = DataViewRef<uint64_t, UInt64Buffer>;
1112 
1113  using IntBuffer = OneDimensionalArray<Int, DataRef>;
1114  using IntBufferRef = DataViewRef<Int, IntBuffer>;
1115 
1116  using UIntBuffer = OneDimensionalArray<UInt, DataRef>;
1117  using UIntBufferRef = DataViewRef<UInt, UIntBuffer>;
1118 
1119 
1123  struct UntypedDataBuffer : public DataType {
1124  UntypedDataBuffer() {
1125  type = DataType::Untyped;
1126  }
1127  };
1128 
1129  static_assert(sizeof(UntypedDataBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1130 
1135  {
1136  Float32AudioBuffer(Index channels, number samplerate) {
1138  audioBufferInfo.channels = channels;
1139  audioBufferInfo.samplerate = samplerate;
1140  }
1141  };
1142 
1143  static_assert(sizeof(Float32AudioBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1144 
1149  {
1150  Float64AudioBuffer(Index channels, number samplerate) {
1152  audioBufferInfo.channels = channels;
1153  audioBufferInfo.samplerate = samplerate;
1154  }
1155  };
1156 
1157  static_assert(sizeof(Float64AudioBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1158 
1162  template<class T, typename U> void updateMultiRef(T patcher, U& ref, DataRefIndex current)
1163  {
1164  ref->setCurrent(current);
1165  patcher->getEngine()->sendDataRefUpdated(ref->getIndex());
1166  }
1167  template<typename T> void updateMultiRef(T, Float32BufferRef&, DataRefIndex) {}
1168  template<typename T> void updateMultiRef(T, Float64BufferRef&, DataRefIndex) {}
1169  template<typename T> void updateMultiRef(T, SampleBufferRef&, DataRefIndex) {}
1170 
1171  template<class T, typename U> void updateDataRef(T patcher, U& ref)
1172  {
1173  patcher->getEngine()->sendDataRefUpdated(ref->getIndex());
1174  }
1175 
1176  ATTRIBUTE_UNUSED
1177  static DataRef& serializeDataRef(DataRef& ref) {
1178  ref.resetRequestedSizeInByte();
1179  return ref;
1180  }
1181 
1182  template<typename T, typename U> T& reInitDataView(T& bufferRef, U&) {
1183  bufferRef->reInit();
1184  return bufferRef;
1185  }
1186 
1188  SerializedBuffer() {}
1189 
1190  SerializedBuffer(const DataRef& ref) {
1191  type = ref.getType();
1192  if (type.type == DataType::SampleAudioBuffer) {
1193  if (sizeof(SampleValue) == sizeof(float)) {
1194  type.type = DataType::Float32AudioBuffer;
1195  }
1196  else {
1197  type.type = DataType::Float64AudioBuffer;
1198  }
1199  }
1200  sizeInBytes = ref.getSizeInBytes();
1201  data = (uint8_t *)Platform::malloc(sizeInBytes);
1202  Platform::memcpy(data, ref.getData(), sizeInBytes);
1203  }
1204 
1205  ~SerializedBuffer() {
1206  if (data) {
1207  free(data);
1208  data = nullptr;
1209  }
1210  }
1211 
1213  {
1214  type = other.type;
1215  sizeInBytes = other.sizeInBytes;
1216  data = other.data;
1217 
1218  other.data = nullptr;
1219  other.sizeInBytes = 0;
1220  other.type = DataType();
1221  }
1222 
1223  // disable copy constructors for development purposes
1224  SerializedBuffer (const SerializedBuffer& other) {
1225  type = other.type;
1226  sizeInBytes = other.sizeInBytes;
1227  data = (uint8_t*)Platform::malloc(sizeInBytes);
1228  Platform::memcpy(data, other.data, sizeInBytes);
1229  }
1230 
1231  SerializedBuffer& operator= (const SerializedBuffer&) = delete;
1232 
1233  DataType type;
1234  size_t sizeInBytes = 0;
1235  uint8_t* data = nullptr;
1236  };
1237 
1238  ATTRIBUTE_UNUSED
1239  static SerializedBuffer serializeBuffer(const DataRef& ref) {
1240  return SerializedBuffer(ref);
1241  }
1242 
1243  template<class T> void deserializeBuffer(T patcher, DataRef& dst, const SerializedBuffer& src) {
1244  char* data = (char *)Platform::malloc(src.sizeInBytes);
1245  Platform::memcpy(data, src.data, src.sizeInBytes);
1246  dst.setData(data, src.sizeInBytes, true);
1247  dst.setType(src.type);
1248  patcher->getEngine()->sendDataRefUpdated(dst->getIndex());
1249  }
1250 
1251 } // namespace RNBO
1252 
1253 #endif // #ifndef _RNBO_DATAREF_H_