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 namespace RNBO {
12 
13  // it is hard coded for now
14  #define RNBO_DEFAULT_SAMPLERATE 44100
15 
22 
23  };
24 
28  struct AudioBufferInfo {
29  size_t channels;
30  number samplerate;
31  };
32 
41  struct DataType {
43  enum Type {
48  TypedArray
49  } type = Untyped;
50 
51 
52  union {
53  UntypedBufferInfo untypedBufferInfo;
54  AudioBufferInfo audioBufferInfo;
55  };
56 
57  bool operator==(const DataType& rhs) const
58  {
59  if (type != rhs.type) return false;
60  switch (type) {
61  case Untyped: return true;
62  case TypedArray: return true;
63  case Float32AudioBuffer:
64  case Float64AudioBuffer:
65  case SampleAudioBuffer:
66  return (audioBufferInfo.channels == rhs.audioBufferInfo.channels
67  && audioBufferInfo.samplerate == rhs.audioBufferInfo.samplerate);
68  }
69 
70  return false;
71  }
72 
73  bool operator!=(const DataType& rhs) const
74  {
75  return !operator==(rhs);
76  }
77 
78  bool matches(const DataType& rhs) const
79  {
80  if (type == Untyped) return false;
81  return type == rhs.type;
82  }
83  };
84 
88  class DataRef {
89  public:
90 
91  DataRef()
92  : _name(nullptr)
93  , _file(nullptr)
94  , _tag(nullptr)
95  , _sizeInBytes(0)
96  , _data(nullptr)
97  , _touched(false)
98  {}
99 
100  DataRef(DataRef&& other)
101  {
102  _name = other._name;
103  _file = other._file;
104  _sizeInBytes = other._sizeInBytes;
105  _data = other._data;
106  _type = other._type;
107  _touched = other._touched;
108  _tag = other._tag;
109  _internal = other._internal;
110  _index = other._index;
111  _requestedSizeInBytes = other._requestedSizeInBytes;
112  _allocatedSizeInBytes = other._allocatedSizeInBytes;
113  _deAlloc = other._deAlloc;
114 
115  // now reset the other one
116  other._data = nullptr;
117  other._sizeInBytes = 0;
118  other._deAlloc = false;
119  other._name = nullptr;
120  other._file = nullptr;
121  other._requestedSizeInBytes = 0;
122  other._index = -1;
123  other._tag = nullptr;
124  }
125 
126  void operator=(const DataRef& ref ) = delete;
127 
134  DataRef& operator=(DataRef&& other)
135  {
136  if (this != &other) {
137  _name = other._name;
138  _file = other._file;
139  _sizeInBytes = other._sizeInBytes;
140  _data = other._data;
141  _type = other._type;
142  _touched = other._touched;
143  _deAlloc = other._deAlloc;
144  _tag = other._tag;
145  _internal = other._internal;
146  _index = other._index;
147  _requestedSizeInBytes = other._requestedSizeInBytes;
148  _allocatedSizeInBytes = other._allocatedSizeInBytes;
149 
150  // now reset the other one
151  other._data = nullptr;
152  other._sizeInBytes = 0;
153  other._deAlloc = false;
154  other._name = nullptr;
155  other._file = nullptr;
156  other._requestedSizeInBytes = 0;
157  other._allocatedSizeInBytes = 0;
158  other._index = -1;
159  other._tag = nullptr;
160  }
161 
162  return *this;
163  }
164 
165  void operator=(DataRef& other)
166  {
167  if (this != &other) {
168  _name = other._name;
169  _file = other._file;
170  _sizeInBytes = other._sizeInBytes;
171  _data = other._data;
172  _type = other._type;
173  _touched = other._touched;
174  _deAlloc = other._deAlloc;
175  _tag = other._tag;
176  _internal = other._internal;
177  _index = other._index;
178  _requestedSizeInBytes = other._requestedSizeInBytes;
179  _allocatedSizeInBytes = other._allocatedSizeInBytes;
180 
181  // now reset the other one
182  other._data = nullptr;
183  other._sizeInBytes = 0;
184  other._deAlloc = false;
185  other._name = nullptr;
186  other._file = nullptr;
187  other._requestedSizeInBytes = 0;
188  other._allocatedSizeInBytes = 0;
189  other._index = -1;
190  other._tag = nullptr;
191  }
192  }
193 
194  DataRef* operator->() {
195  return this;
196  }
197 
198  ~DataRef() {
199  freeIfNeeded();
200  }
201 
202  inline DataType getType() const {
203  return _type;
204  }
205 
206  void setType(DataType type) {
207  _type = type;
208  }
209 
210  inline const char *getName() const {
211  return _name;
212  }
213 
214  void setName(const char *name) {
215  if (name && Platform::strlen(name)) _name = name;
216  else _name = nullptr;
217  }
218 
219  inline const char *getFile() const {
220  return _file;
221  }
222 
223  void setFile(const char *file) {
224  if (file && Platform::strlen(file)) _file = file;
225  else _file = nullptr;
226  }
227 
228  inline char *getData() {
229  return _data;
230  }
231 
232  const char *getData() const {
233  return _data;
234  }
235 
236  void setData(char *data, size_t sizeInBytes, bool deAlloc = false) {
237  freeIfNeeded();
238 
239  _data = data;
240  _sizeInBytes = _allocatedSizeInBytes = sizeInBytes;
241  // normally we now hold external data, but in the WASM case
242  // we want to de-allocate
243  _deAlloc = deAlloc;
244  }
245 
246  inline size_t getSizeInBytes() const {
247  return _sizeInBytes;
248  }
249 
250  void requestSizeInBytes(size_t size, bool force) {
251  if (size > _requestedSizeInBytes || force) _requestedSizeInBytes = size;
252  }
253 
254  bool hasRequestedSize() const {
255  return _requestedSizeInBytes > 0;
256  }
257 
258  void resetRequestedSizeInByte() {
259  _requestedSizeInBytes = 0;
260  }
261 
262  inline bool getTouched() const {
263  return _touched;
264  }
265 
266  void setTouched(bool value) {
267  _touched = value;
268  }
269 
270  void allocateIfNeeded() {
271  if (_requestedSizeInBytes) {
272  if (_requestedSizeInBytes > _allocatedSizeInBytes || !_deAlloc) {
273  auto oldData = _data;
274  _data = static_cast<char *>(Platform::calloc(_requestedSizeInBytes, 1));
275  if (_deAlloc && oldData) {
276  // we own the old data, so copy and free it
277  Platform::memcpy(_data, oldData, _sizeInBytes);
278  Platform::free(oldData);
279  _wantsFill = false;
280  }
281  else {
282  _wantsFill = true;
283  }
284  _deAlloc = true;
285 
286  _sizeInBytes = _allocatedSizeInBytes = _requestedSizeInBytes;
287  }
288  else {
289  // zero out padding if we grow
290  if (_requestedSizeInBytes > _sizeInBytes) {
291  Platform::memset(_data + _sizeInBytes, 0, _requestedSizeInBytes - _sizeInBytes);
292  }
293  // if we didn't need to allocate, we just reset our size to the requested value
294  _sizeInBytes = _requestedSizeInBytes;
295  }
296  }
297  }
298 
299  void freeIfNeeded() {
300  if (_deAlloc && _data != nullptr) {
301  Platform::free(_data);
302  _data = nullptr;
303  _deAlloc = false;
304  }
305  }
306 
307  inline bool wantsFill() const {
308  return _wantsFill;
309  }
310 
311  void setWantsFill(bool value) {
312  _wantsFill = value;
313  }
314 
315  inline const char *getTag() const {
316  return _tag;
317  }
318 
319  void setTag(const char *tag) {
320  if (tag && Platform::strlen(tag)) _tag = tag;
321  else _tag = nullptr;
322  }
323 
324  void setInternal(bool value) {
325  _internal = value;
326  }
327 
328  inline bool isInternal() const {
329  return _internal;
330  }
331 
332  void setZero() {
333  Platform::memset(_data, 0, _sizeInBytes);
334  }
335 
336  void setIndex(DataRefIndex index) {
337  _index = index;
338  }
339 
340  DataRefIndex getIndex() {
341  return _index;
342  }
343 
344  private:
345  const char* _name = nullptr;
346  const char* _file = nullptr;
347  const char* _tag = nullptr;
348 
349  size_t _sizeInBytes = 0;
350  size_t _requestedSizeInBytes = 0;
351  size_t _allocatedSizeInBytes = 0;
352  char *_data = nullptr;
353  bool _touched = false;
354  bool _deAlloc = false;
355  bool _wantsFill = false;
356  bool _internal = false;
357  DataRefIndex _index = -1;
358 
359  DataType _type;
360  };
361 
362  // set the name of the DataRef, this is needed for Javascript and C to be similar
363  // might go away in the future
364  ATTRIBUTE_UNUSED
365  static inline DataRef& initDataRef(DataRef& ref, const char *name, bool internal, const char* file, const char* tag) {
366  ref.setName(name);
367  ref.setInternal(internal);
368  ref.setFile(file);
369  ref.setTag(tag);
370  return ref;
371  }
372 
376  class MultiDataRef
377  {
378  public:
379  template<typename... Ts> MultiDataRef(Ts & ... args)
380  : _count(sizeof ... (args))
381  {
382  _refs = static_cast<DataRef**>(Platform::malloc(_count * sizeof(DataRef *)));
383  DataRef* refs[sizeof...(args)] = {static_cast<DataRef*>(&args)...};
384  for (size_t i = 0; i < _count; i++) {
385  _refs[i] = refs[i];
386  }
387  }
388 
389  MultiDataRef() = default;
390 
391  MultiDataRef(MultiDataRef&& other)
392  {
393  _count = other._count;
394  _current = other._current;
395  if (!_refs) {
396  _refs = other._refs;
397  other._refs = nullptr;
398  }
399  _index = other._index;
400 
401  }
402 
403  void operator=(const MultiDataRef& ref ) = delete;
404 
405  MultiDataRef& operator=(MultiDataRef&& other)
406  {
407  if (this != &other) {
408  _count = other._count;
409  _current = other._current;
410  if (!_refs) {
411  _refs = other._refs;
412  other._refs = nullptr;
413  }
414  _index = other._index;
415  }
416 
417  return *this;
418  }
419 
420  void operator=(MultiDataRef& other)
421  {
422  if (this != &other) {
423  _count = other._count;
424  _current = other._current;
425  if (!_refs) {
426  _refs = other._refs;
427  other._refs = nullptr;
428  }
429  _index = other._index;
430  }
431  }
432 
433 
434  ~MultiDataRef() {
435  if (_refs) {
436  Platform::free(_refs);
437  }
438  }
439 
440  MultiDataRef* operator->() {
441  return this;
442  }
443 
444  void setCurrent(DataRefIndex current) {
445  if (current >= 0 && current < static_cast<DataRefIndex>(_count)) {
446  _current = current;
447  }
448  }
449 
450  DataRef& getCurrent() const {
451  return *_refs[_current];
452  }
453 
454  DataRefIndex getCurrentIndex() const {
455  return _current;
456  }
457 
458  void setIndex(DataRefIndex index) {
459  _index = index;
460  }
461 
462  DataRefIndex getIndex() const {
463  return _index;
464  }
465 
466  private:
467  Index _count = 0;
468  DataRefIndex _current = 0;
469  DataRef** _refs = nullptr;
470  DataRefIndex _index = 0;
471  };
472 
473  template<typename ... Ts> MultiDataRef initMultiRef(Ts & ... args)
474  {
475  MultiDataRef ref(args...);
476  return ref;
477  }
478 
482  template<typename T, typename DR> class DataView {
483  public:
484  DataView(DR& dataRef)
485  : _usage(0)
486  , _dataRef(&dataRef)
487  {
488  updateCachedSize();
489  }
490 
491  virtual ~DataView() {}
492 
493  inline T& operator[](size_t i) {
494  T *values = reinterpret_cast<T*>(_dataRef->getData());
495  return values[i];
496  }
497 
498  inline T operator[](size_t i) const {
499  T *values = reinterpret_cast<T*>(_dataRef->getData());
500  return values[i];
501  }
502 
503  DataView* operator->() {
504  return this;
505  }
506 
507  const DataView* operator->() const {
508  return this;
509  }
510 
511  inline size_t getSize() const {
512  return _size;
513  }
514 
515  virtual void updateCachedSize() {
516  _size = _dataRef->getSizeInBytes() / sizeof(T);
517  }
518 
519  inline DataType getType() const {
520  return _dataRef->getType();
521  }
522 
523  void setType(DataType type) {
524  _dataRef->setType(type);
525  updateCachedSize();
526  }
527 
528  inline size_t getSizeInBytes() const {
529  return _dataRef->getSizeInBytes();
530  }
531 
532  void setTouched(bool value) {
533  _dataRef->setTouched(value);
534  }
535 
536  bool getTouched() {
537  return _dataRef->getTouched();
538  }
539 
540  virtual DataView<T, DR>* allocateIfNeeded() {
541  _dataRef->allocateIfNeeded();
542  updateCachedSize();
543  return this;
544  }
545 
546  void setWantsFill(bool value) {
547  _dataRef->setWantsFill(value);
548  }
549 
550  void clear() {
551  _dataRef->setData(nullptr, 0);
552  }
553 
554  void setZero() {
555  _dataRef->setZero();
556  }
557 
558  DataRefIndex getIndex() const {
559  return _dataRef->getIndex();
560  }
561 
562  int _usage;
563 
564  virtual void reInit() {
565  reInit(*_dataRef);
566  }
567 
568  protected:
569  // the derived view class has to implement the correct version for its data format
570  void requestSize(size_t size) {
571  size_t sizeInBytes = size * sizeof(T);
572  _dataRef->requestSizeInBytes(sizeInBytes, false);
573  }
574 
575  // the derive view class has to implement the correct version for its data format
576  virtual DataView<T, DR>* setSize(size_t size) {
577  size_t sizeInBytes = size * sizeof(T);
578  _dataRef->requestSizeInBytes(sizeInBytes, true);
579  _dataRef->allocateIfNeeded();
580  updateCachedSize();
581  return this;
582  }
583 
584  void reInit(DR& dataRef) {
585  _dataRef = &dataRef;
586  updateCachedSize();
587  }
588 
589  size_t _size;
590  DR* _dataRef;
591  };
592 
597  template<typename T, typename U> class DataViewRef {
598  public:
599  DataViewRef()
600  {}
601 
602  virtual ~DataViewRef()
603  {
604  freeView();
605  }
606 
607  DataViewRef(const DataViewRef<T, U>& other)
608  {
609  other._view->_usage++;
610  freeView();
611  _view = other._view;
612  }
613 
614  DataViewRef(U* view)
615  {
616  view->_usage++;
617  freeView();
618  _view = view;
619  }
620 
621  void operator=(U* view )
622  {
623  view->_usage++;
624  freeView();
625  _view = view;
626  }
627 
628  void operator=(const DataViewRef<T, U>& other)
629  {
630  if (&other != this) {
631  other._view->_usage++;
632  freeView();
633  _view = other._view;
634  }
635  }
636 
637  inline T& operator[](size_t i) {
638  return (*_view)[i];
639  }
640 
641  inline T operator[](size_t i) const {
642  return (*_view)[i];
643  }
644 
645  U* operator->() {
646  return _view;
647  }
648 
649  void freeView() {
650  if (_view) {
651  _view->_usage--;
652  if (!_view->_usage) delete _view;
653  _view = nullptr;
654  }
655  }
656 
657  private:
658  U* _view = nullptr;
659  };
660 
664  template<typename T, typename DR> class OneDimensionalArray : public DataView<T, DR>
665  {
666  public:
667  OneDimensionalArray(DR& dataRef)
668  : DataView<T, DR>(dataRef)
669  {
670  DataType info;
671  info.type = DataType::TypedArray;
672  DataView<T, DR>::setType(info);
673  }
674 
675  void requestSize(size_t size) {
676  DataView<T, DR>::requestSize(size);
677  }
678  };
679 
683  template<typename T, typename DR> class InterleavedAudioBuffer : public DataView<T, DR>
684  {
685  public:
686  InterleavedAudioBuffer(DR& dataRef, DataType::Type type)
687  : DataView<T, DR>(dataRef)
688  {
689  if (DataView<T, DR>::getType().type == DataType::Untyped) {
690  DataType info;
691  info.type = type;
692  info.audioBufferInfo.channels = 0;
693  info.audioBufferInfo.samplerate = RNBO_DEFAULT_SAMPLERATE;
694  DataView<T, DR>::setType(info);
695  }
696 
697  updateCachedSize();
698  }
699 
700  virtual ~InterleavedAudioBuffer() override {}
701 
702  InterleavedAudioBuffer* operator->() {
703  return this;
704  }
705 
706  inline T getSample(const size_t channel, const size_t index) const {
707  if (!_audioData) return 0;
708  return _audioData[_channels * index + channel];
709  }
710 
711  inline T getSampleSafe(const long channel, const long index) const {
712  if (!_audioData) return 0;
713  const auto ind = _channels * index + channel;
714  if (ind < 0 || static_cast<size_t>(ind) >= DataView<T, DR>::getSize() * _channels) {
715  return static_cast<T>(0);
716  }
717  return _audioData[ind];
718  }
719 
720  // channel numbers are 0 based
721  inline void setSample(const size_t channel, const size_t index, const T value) {
722  if (_audioData)
723  _audioData[_channels * index + channel] = value;
724  }
725 
726  inline void setSampleSafe(const long channel, const long index, const T value) {
727  if (channel < 0 || static_cast<size_t>(channel) >= _channels || index < 0 || static_cast<size_t>(index) >= DataView<T, DR>::getSize()) {
728  return;
729  }
730  _audioData[_channels * index + channel] = value;
731  }
732 
733  inline size_t getChannels() const {
734  return _channels;
735  }
736 
737  inline number getSampleRate() const {
738  DataType info = DataView<T, DR>::getType();
739  return info.audioBufferInfo.samplerate;
740  }
741 
742  void setSampleRate(number sampleRate) {
743  DataType info = DataView<T, DR>::getType();
744  info.audioBufferInfo.samplerate = sampleRate;
745  DataView<T, DR>::setType(info);
746  }
747 
748  bool isInterleaved() {
749  // for now we only support interleaved audio
750  return true;
751  }
752 
753  void requestSize(size_t size, size_t channels) {
754  DataView<T, DR>::requestSize(size * channels);
755  _requestedChannels = channels;
756  }
757 
758  InterleavedAudioBuffer<T, DR>* setSize(size_t size) override {
759  DataView<T, DR>::setSize(size * _channels);
760  return this;
761  }
762 
763  void updateCachedSize() override {
764  DataType info = DataView<T, DR>::getType();
765  _channels = info.audioBufferInfo.channels;
766  _audioData = reinterpret_cast<T*>(DataView<T, DR>::_dataRef->getData());
767  DataView<T, DR>::_size = _channels ? (DataView<T, DR>::getSizeInBytes() / sizeof(T)) / _channels : 0;
768  }
769 
770  virtual InterleavedAudioBuffer<T, DR>* setChannels(size_t channels) {
771  if (channels != _channels) {
772  size_t currentSize = DataView<T, DR>::getSize();
773 
774  DataType info = DataView<T, DR>::getType();
775  info.audioBufferInfo.channels = channels;
776  DataView<T, DR>::setType(info);
777 
778  // update local cache
779  _channels = channels;
780  _audioData = reinterpret_cast<T*>(DataView<T, DR>::_dataRef->getData());
781 
782  // we might want to implement preserving the data in the future
783  DataView<T, DR>::clear();
784 
785  DataView<T, DR>::setSize(currentSize * _channels);
786  }
787 
788  return this;
789  }
790 
791  InterleavedAudioBuffer<T, DR>* allocateIfNeeded() override {
792  if (_requestedChannels > 0) {
793  if (_channels != 0 && _requestedChannels != _channels) {
794  DataView<T, DR>::setZero();
795  }
796 
797  DataType info = DataView<T, DR>::getType();
798  info.audioBufferInfo.channels = _requestedChannels;
799  DataView<T, DR>::setType(info);
800 
801  DataView<T, DR>::allocateIfNeeded();
802  }
803 
804  return this;
805  }
806 
807  DataRefIndex getCurrentIndex() const {
808  return 0;
809  }
810 
811  private:
812  size_t _requestedChannels = 0;
813  size_t _channels = 0;
814  T* _audioData = nullptr;
815 
816  };
817 
823  class Float32Buffer : public InterleavedAudioBuffer<float, DataRef>
824  {
825  public:
826  Float32Buffer(DataRef& dataRef)
827  : InterleavedAudioBuffer<float, DataRef>(dataRef, DataType::Float32AudioBuffer)
828  {}
829 
830  virtual Float32Buffer* allocateIfNeeded() {
831  InterleavedAudioBuffer<float, DataRef>::allocateIfNeeded();
832  return this;
833  }
834 
835  virtual Float32Buffer* setChannels(size_t channels) {
836  InterleavedAudioBuffer<float, DataRef>::setChannels(channels);
837  return this;
838  }
839 
840  virtual Float32Buffer* setSize(size_t size) {
841  InterleavedAudioBuffer<float, DataRef>::setSize(size);
842  return this;
843  }
844  };
845 
846  using Float32BufferRef = DataViewRef<float, Float32Buffer >;
847 
851  class Float64Buffer : public InterleavedAudioBuffer<double, DataRef>
852  {
853  public:
854  Float64Buffer(DataRef& dataRef)
855  : InterleavedAudioBuffer<double, DataRef>(dataRef, DataType::Float64AudioBuffer)
856  {}
857 
858  virtual Float64Buffer* allocateIfNeeded() {
859  InterleavedAudioBuffer<double, DataRef>::allocateIfNeeded();
860  return this;
861  }
862 
863  virtual Float64Buffer* setChannels(size_t channels) {
864  InterleavedAudioBuffer<double, DataRef>::setChannels(channels);
865  return this;
866  }
867 
868  virtual Float64Buffer* setSize(size_t size) {
869  InterleavedAudioBuffer<double, DataRef>::setSize(size);
870  return this;
871  }
872  };
873 
874  using Float64BufferRef = DataViewRef<double, Float64Buffer>;
875 
876 
880  class SampleBuffer : public InterleavedAudioBuffer<SampleValue, DataRef>
881  {
882  public:
883  SampleBuffer(DataRef& dataRef)
884  : InterleavedAudioBuffer<SampleValue, DataRef>(dataRef, DataType::SampleAudioBuffer)
885  {}
886 
887  virtual SampleBuffer* allocateIfNeeded() {
888  InterleavedAudioBuffer<SampleValue, DataRef>::allocateIfNeeded();
889  return this;
890  }
891 
892  virtual SampleBuffer* setChannels(size_t channels) {
893  InterleavedAudioBuffer<SampleValue, DataRef>::setChannels(channels);
894  return this;
895  }
896 
897  virtual SampleBuffer* setSize(size_t size) {
898  InterleavedAudioBuffer<SampleValue, DataRef>::setSize(size);
899  return this;
900  }
901  };
902 
903  using SampleBufferRef = DataViewRef<SampleValue, SampleBuffer>;
904 
916  template <typename T> class MultiBuffer : public InterleavedAudioBuffer<T, DataRef>
917  {
918  public:
919  MultiBuffer(MultiDataRef& multiRef, DataType::Type type)
920  : InterleavedAudioBuffer<T, DataRef>(multiRef.getCurrent(), type)
921  , _multiRef(multiRef)
922  {}
923 
924  void setCurrent(DataRefIndex current) {
925  _multiRef.setCurrent(current);
926  }
927 
928  DataRefIndex getIndex() const {
929  return _multiRef.getIndex();
930  }
931 
932  void reInit() override {
933  InterleavedAudioBuffer<T, DataRef>::reInit(_multiRef.getCurrent());
934  }
935 
936  DataRefIndex getCurrentIndex() const {
937  return _multiRef.getCurrentIndex();
938  }
939 
940  private:
941  MultiDataRef& _multiRef;
942  };
943 
947  class Float32MultiBuffer : public MultiBuffer<float>
948  {
949  public:
950  Float32MultiBuffer(MultiDataRef& dataRef)
951  : MultiBuffer<float>(dataRef, DataType::Float32AudioBuffer)
952  {}
953  };
954 
955  using Float32MultiBufferRef = DataViewRef<float, Float32MultiBuffer >;
956 
960  class Float64MultiBuffer : public MultiBuffer<double>
961  {
962  public:
963  Float64MultiBuffer(MultiDataRef& dataRef)
964  : MultiBuffer<double>(dataRef, DataType::Float64AudioBuffer)
965  {}
966  };
967 
968  using Float64MultiBufferRef = DataViewRef<double, Float64MultiBuffer>;
969 
973  class IntBuffer : public OneDimensionalArray<uint32_t, DataRef>
974  {
975  public:
976  IntBuffer(DataRef& dataRef)
977  : OneDimensionalArray<uint32_t, DataRef>(dataRef)
978  {}
979 
980  virtual IntBuffer* allocateIfNeeded() {
981  OneDimensionalArray<uint32_t, DataRef>::allocateIfNeeded();
982  return this;
983  }
984  };
985 
986  using IntBufferRef = DataViewRef<uint32_t, IntBuffer>;
987 
991  class UInt8Buffer : public OneDimensionalArray<uint8_t, DataRef>
992  {
993  public:
994  UInt8Buffer(DataRef& dataRef)
995  : OneDimensionalArray<uint8_t, DataRef>(dataRef)
996  {}
997 
998  virtual UInt8Buffer* allocateIfNeeded() {
999  OneDimensionalArray<uint8_t, DataRef>::allocateIfNeeded();
1000  return this;
1001  }
1002  };
1003 
1004  using UInt8BufferRef = DataViewRef<uint8_t, UInt8Buffer>;
1005 
1009  struct UntypedDataBuffer : public DataType {
1010  UntypedDataBuffer() {
1011  type = DataType::Untyped;
1012  }
1013  };
1014 
1015  static_assert(sizeof(UntypedDataBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1016 
1021  {
1022  Float32AudioBuffer(Index channels, number samplerate) {
1024  audioBufferInfo.channels = channels;
1025  audioBufferInfo.samplerate = samplerate;
1026  }
1027  };
1028 
1029  static_assert(sizeof(Float32AudioBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1030 
1035  {
1036  Float64AudioBuffer(Index channels, number samplerate) {
1038  audioBufferInfo.channels = channels;
1039  audioBufferInfo.samplerate = samplerate;
1040  }
1041  };
1042 
1043  static_assert(sizeof(Float64AudioBuffer) == sizeof(DataType), "Do not add any members to the derived class.");
1044 
1048  template<class T, typename U> void updateMultiRef(T patcher, U& ref, DataRefIndex current)
1049  {
1050  ref->setCurrent(current);
1051  patcher->getEngine()->sendDataRefUpdated(ref->getIndex());
1052  }
1053  template<typename T> void updateMultiRef(T, Float32BufferRef&, DataRefIndex) {}
1054  template<typename T> void updateMultiRef(T, Float64BufferRef&, DataRefIndex) {}
1055  template<typename T> void updateMultiRef(T, SampleBufferRef&, DataRefIndex) {}
1056 
1057  template<class T, typename U> void updateDataRef(T patcher, U& ref)
1058  {
1059  patcher->getEngine()->sendDataRefUpdated(ref->getIndex());
1060  }
1061 
1062  ATTRIBUTE_UNUSED
1063  static DataRef& serializeDataRef(DataRef& ref) {
1064  ref.resetRequestedSizeInByte();
1065  return ref;
1066  }
1067 
1068  template<typename T, typename U> T& reInitDataView(T& bufferRef, U&) {
1069  bufferRef->reInit();
1070  return bufferRef;
1071  }
1072 
1074  SerializedBuffer() {}
1075 
1076  SerializedBuffer(const DataRef& ref) {
1077  type = ref.getType();
1078  if (type.type == DataType::SampleAudioBuffer) {
1079  if (sizeof(SampleValue) == sizeof(float)) {
1080  type.type = DataType::Float32AudioBuffer;
1081  }
1082  else {
1083  type.type = DataType::Float64AudioBuffer;
1084  }
1085  }
1086  sizeInBytes = ref.getSizeInBytes();
1087  data = (uint8_t *)Platform::malloc(sizeInBytes);
1088  Platform::memcpy(data, ref.getData(), sizeInBytes);
1089  }
1090 
1091  ~SerializedBuffer() {
1092  if (data) {
1093  free(data);
1094  data = nullptr;
1095  }
1096  }
1097 
1099  {
1100  type = other.type;
1101  sizeInBytes = other.sizeInBytes;
1102  data = other.data;
1103 
1104  other.data = nullptr;
1105  other.sizeInBytes = 0;
1106  other.type = DataType();
1107  }
1108 
1109  // disable copy constructors for development purposes
1110  SerializedBuffer (const SerializedBuffer& other) {
1111  type = other.type;
1112  sizeInBytes = other.sizeInBytes;
1113  data = (uint8_t*)Platform::malloc(sizeInBytes);
1114  Platform::memcpy(data, other.data, sizeInBytes);
1115  }
1116 
1117  SerializedBuffer& operator= (const SerializedBuffer&) = delete;
1118 
1119  DataType type;
1120  size_t sizeInBytes = 0;
1121  uint8_t* data = nullptr;
1122  };
1123 
1124  ATTRIBUTE_UNUSED
1125  static SerializedBuffer serializeBuffer(const DataRef& ref) {
1126  return SerializedBuffer(ref);
1127  }
1128 
1129  template<class T> void deserializeBuffer(T patcher, DataRef& dst, const SerializedBuffer& src) {
1130  char* data = (char *)Platform::malloc(src.sizeInBytes);
1131  Platform::memcpy(data, src.data, src.sizeInBytes);
1132  dst.setData(data, src.sizeInBytes, true);
1133  dst.setType(src.type);
1134  patcher->getEngine()->sendDataRefUpdated(dst->getIndex());
1135  }
1136 
1137 } // namespace RNBO
1138 
1139 #endif // #ifndef _RNBO_DATAREF_H_