// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm // // An object to hold and pass around audio samples internally. #include "libvideostitch/audioBlock.hpp" #include namespace VideoStitch { namespace Audio { AudioTrack::~AudioTrack() {} AudioTrack::AudioTrack(AudioTrack&& o) : std::vector(std::move(o)), channel_(o.channel_) {} AudioTrack& AudioTrack::operator=(AudioTrack&& o) { std::vector::operator=(std::move(o)); channel_ = o.channel_; return *this; } AudioTrack::AudioTrack(ChannelMap c) : channel_(c) {} ChannelMap AudioTrack::channel() const { return channel_; } void AudioTrack::setChannel(ChannelMap c) { channel_ = c; } /// ----------- #define INIT_DATA_BUFFER \ { \ { \ AudioTrack(NO_SPEAKER), AudioTrack(SPEAKER_FRONT_LEFT), AudioTrack(SPEAKER_FRONT_RIGHT), \ AudioTrack(SPEAKER_SIDE_LEFT), AudioTrack(SPEAKER_SIDE_RIGHT), AudioTrack(SPEAKER_FRONT_CENTER), \ AudioTrack(SPEAKER_BACK_CENTER), AudioTrack(SPEAKER_LOW_FREQUENCY), AudioTrack(SPEAKER_BACK_LEFT), \ AudioTrack(SPEAKER_BACK_RIGHT), AudioTrack(SPEAKER_FRONT_LEFT_OF_CENTER), \ AudioTrack(SPEAKER_FRONT_RIGHT_OF_CENTER), AudioTrack(SPEAKER_TOP_CENTER), \ AudioTrack(SPEAKER_TOP_FRONT_LEFT), AudioTrack(SPEAKER_TOP_FRONT_CENTER), \ AudioTrack(SPEAKER_TOP_FRONT_RIGHT), AudioTrack(SPEAKER_TOP_BACK_LEFT), AudioTrack(SPEAKER_TOP_BACK_CENTER), \ AudioTrack(SPEAKER_TOP_BACK_RIGHT), AudioTrack(SPEAKER_AMB_W), AudioTrack(SPEAKER_AMB_X), \ AudioTrack(SPEAKER_AMB_Y), AudioTrack(SPEAKER_AMB_Z), AudioTrack(SPEAKER_AMB_R), AudioTrack(SPEAKER_AMB_S), \ AudioTrack(SPEAKER_AMB_T), AudioTrack(SPEAKER_AMB_U), AudioTrack(SPEAKER_AMB_V), AudioTrack(SPEAKER_AMB_K), \ AudioTrack(SPEAKER_AMB_L), AudioTrack(SPEAKER_AMB_M), AudioTrack(SPEAKER_AMB_N), AudioTrack(SPEAKER_AMB_O), \ AudioTrack(SPEAKER_AMB_P), AudioTrack(SPEAKER_AMB_Q), \ } \ } namespace { AudioBlock::data_buffer_t initDataBuffer = INIT_DATA_BUFFER; } AudioBlock::AudioBlock(ChannelLayout layout, mtime_t timestamp) : layout_(layout), timestamp_(timestamp) { for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { data_[i] = initDataBuffer[i]; } } AudioBlock::AudioBlock(unsigned char nbTracks, mtime_t timestamp) : timestamp_(timestamp) { int layout = 0; for (unsigned char i = 0; i < nbTracks; ++i) { layout <<= layout; layout &= 1; } layout_ = static_cast(layout); for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { data_[i] = initDataBuffer[i]; } } AudioBlock::AudioBlock(const AudioBlock& o) : layout_(o.layout_), timestamp_(o.timestamp_) { for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { data_[i] = o.data_[i]; } } AudioBlock::AudioBlock(AudioBlock&& o) : layout_(o.layout_), timestamp_(o.timestamp_) { // for some reason, MVSC tries to generate a copy ctor // for the std::array when invoking its move ctor ¯\_(ツ)_/¯ for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { data_[i] = std::move(o.data_[i]); } } AudioBlock& AudioBlock::operator=(AudioBlock&& o) { layout_ = o.layout_; timestamp_ = o.timestamp_; // for some reason, MVSC tries to generate a copy ctor // for the std::array when invoking its move ctor ¯\_(ツ)_/¯ for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) { data_[i] = std::move(o.data_[i]); } return *this; } AudioBlock::~AudioBlock() {} void AudioBlock::setChannelLayout(const ChannelLayout layout) { layout_ = layout; } void AudioBlock::setTimestamp(mtime_t time) { timestamp_ = time; } mtime_t AudioBlock::getTimestamp() const { return timestamp_; } ChannelLayout AudioBlock::getLayout() const { return layout_; } void AudioBlock::clear() { for (auto& track : *this) { track.resize(0); } } AudioBlock::iterator AudioBlock::begin() { return (iterator(layout_, data_.begin() + 1)); } AudioBlock::const_iterator AudioBlock::begin() const { return (const_iterator(layout_, const_cast(this)->data_.begin() + 1)); } AudioBlock::const_iterator AudioBlock::cbegin() const { return this->begin(); } AudioBlock::iterator AudioBlock::end() { return iterator(); } AudioBlock::const_iterator AudioBlock::end() const { return const_iterator(); } AudioBlock::const_iterator AudioBlock::cend() const { return this->end(); } #define GETAUDIOTRACK(i) \ { \ switch (i) { \ case SPEAKER_FRONT_LEFT: \ return data_[1]; \ case SPEAKER_FRONT_RIGHT: \ return data_[2]; \ case SPEAKER_SIDE_LEFT: \ return data_[3]; \ case SPEAKER_SIDE_RIGHT: \ return data_[4]; \ case SPEAKER_FRONT_CENTER: \ return data_[5]; \ case SPEAKER_BACK_CENTER: \ return data_[6]; \ case SPEAKER_LOW_FREQUENCY: \ return data_[7]; \ case SPEAKER_BACK_LEFT: \ return data_[8]; \ case SPEAKER_BACK_RIGHT: \ return data_[9]; \ case SPEAKER_FRONT_LEFT_OF_CENTER: \ return data_[10]; \ case SPEAKER_FRONT_RIGHT_OF_CENTER: \ return data_[11]; \ case SPEAKER_TOP_CENTER: \ return data_[12]; \ case SPEAKER_TOP_FRONT_LEFT: \ return data_[13]; \ case SPEAKER_TOP_FRONT_CENTER: \ return data_[14]; \ case SPEAKER_TOP_FRONT_RIGHT: \ return data_[15]; \ case SPEAKER_TOP_BACK_LEFT: \ return data_[16]; \ case SPEAKER_TOP_BACK_CENTER: \ return data_[17]; \ case SPEAKER_TOP_BACK_RIGHT: \ return data_[18]; \ case SPEAKER_AMB_W: \ return data_[19]; \ case SPEAKER_AMB_X: \ return data_[20]; \ case SPEAKER_AMB_Y: \ return data_[21]; \ case SPEAKER_AMB_Z: \ return data_[22]; \ case SPEAKER_AMB_R: \ return data_[23]; \ case SPEAKER_AMB_S: \ return data_[24]; \ case SPEAKER_AMB_T: \ return data_[25]; \ case SPEAKER_AMB_U: \ return data_[26]; \ case SPEAKER_AMB_V: \ return data_[27]; \ case SPEAKER_AMB_K: \ return data_[28]; \ case SPEAKER_AMB_L: \ return data_[29]; \ case SPEAKER_AMB_M: \ return data_[30]; \ case SPEAKER_AMB_N: \ return data_[31]; \ case SPEAKER_AMB_O: \ return data_[32]; \ case SPEAKER_AMB_P: \ return data_[33]; \ case SPEAKER_AMB_Q: \ return data_[34]; \ } \ return data_[0]; \ } AudioBlock::reference AudioBlock::operator[](size_type i) { GETAUDIOTRACK(i); } AudioBlock::const_reference AudioBlock::operator[](size_type i) const { GETAUDIOTRACK(i); } AudioBlock::reference AudioBlock::at(size_type i) { return (*this)[i]; } AudioBlock::const_reference AudioBlock::at(size_type i) const { return (*this)[i]; } AudioBlock& AudioBlock::operator+=(const AudioBlock& rhs) { assert(rhs.layout_ == this->layout_); assert(rhs.numSamples() == this->numSamples()); size_t nbSamples = this->numSamples(); for (AudioTrack& track : *this) { for (size_t i = 0; i < nbSamples; ++i) { track[i] += rhs[track.channel()][i]; } } return *this; } void AudioBlock::swap(AudioBlock& o) { std::swap(timestamp_, o.timestamp_); std::swap(layout_, o.layout_); std::swap(data_, o.data_); } AudioBlock::size_type AudioBlock::size() { // SWAR algorithm uint32_t i = (uint32_t)layout_; i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; } AudioBlock::size_type AudioBlock::max_size() { return MAX_AUDIO_CHANNELS; } bool AudioBlock::empty() const { for (const auto& track : data_) { if (!track.empty()) { return false; } } return true; } void AudioBlock::resize(size_t nSamples) { if (layout_ == UNKNOWN) { return; } for (auto& track : *this) { track.resize(nSamples); } } void AudioBlock::assign(size_t nSamples, audioSample_t val) { if (layout_ == UNKNOWN) { return; } for (auto& track : *this) { track.assign(nSamples, val); } } size_t AudioBlock::numSamples() const { return begin()->size(); } /// const_iterator AudioBlock::const_iterator::const_iterator() : mask_(NO_SPEAKER) {} AudioBlock::const_iterator::const_iterator(ChannelLayout l, data_buffer_t::iterator ptr) : mask_(1), layout_(l), ptr_(ptr) { if (!(layout_ & mask_)) { advance(); } } AudioBlock::const_iterator::const_iterator(const const_iterator& o) : mask_(o.mask_), layout_(o.layout_), ptr_(o.ptr_) {} AudioBlock::const_iterator::const_iterator(const iterator& o) : mask_(o.mask_), layout_(o.layout_), ptr_(o.ptr_) {} AudioBlock::const_iterator::~const_iterator() {} channel_t AudioBlock::const_iterator::channel() const { return (channel_t)mask_; } AudioBlock::const_iterator& AudioBlock::const_iterator::operator=(const const_iterator& o) { mask_ = o.mask_; layout_ = o.layout_; ptr_ = o.ptr_; return *this; } bool AudioBlock::const_iterator::operator==(const const_iterator& o) const { return mask_ == o.mask_; } bool AudioBlock::const_iterator::operator!=(const const_iterator& o) const { return mask_ != o.mask_; } AudioBlock::const_iterator& AudioBlock::const_iterator::operator++() { advance(); return *this; } void AudioBlock::const_iterator::advance() { do { ++ptr_; mask_ <<= 1; } while (!(layout_ & mask_) && mask_ != NO_SPEAKER); } AudioBlock::const_iterator::const_reference AudioBlock::const_iterator::operator*() const { return *ptr_; } AudioBlock::const_iterator::const_pointer AudioBlock::const_iterator::operator->() const { return ptr_; } /// iterator AudioBlock::iterator::iterator() {} AudioBlock::iterator::iterator(ChannelLayout l, data_buffer_t::iterator ptr) : const_iterator(l, ptr) {} AudioBlock::iterator::iterator(const iterator& o) : const_iterator(o) {} AudioBlock::iterator::~iterator() {} AudioBlock::iterator& AudioBlock::iterator::operator=(const iterator& o) { mask_ = o.mask_; layout_ = o.layout_; ptr_ = o.ptr_; return *this; } bool AudioBlock::iterator::operator==(const iterator& o) const { return mask_ == o.mask_; } bool AudioBlock::iterator::operator!=(const iterator& o) const { return mask_ != o.mask_; } AudioBlock::iterator& AudioBlock::iterator::operator++() { advance(); return *this; } AudioBlock::iterator::reference AudioBlock::iterator::operator*() const { return *ptr_; } AudioBlock::iterator::pointer AudioBlock::iterator::operator->() const { return ptr_; } } // namespace Audio } // namespace VideoStitch