// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "audio/resampler.hpp" #include "util/plugin.hpp" #include "libvideostitch/audio.hpp" #include #include #include #include using namespace VideoStitch::Plugin; namespace VideoStitch { namespace Audio { Samples::Samples() : samples{}, nbSamples(0), timestamp(-1), delete_([](data_buffer_t&) {}), depth(SamplingDepth::SD_NONE), rate(SamplingRate::SR_NONE), layout(UNKNOWN) {} Samples::Samples(const SamplingRate r, const SamplingDepth d, const ChannelLayout l, mtime_t timestamp, data_buffer_t& data, size_t nbSamples, deleter del) : Samples(r, d, l, timestamp, data.data(), nbSamples, del) {} Samples::Samples(const SamplingRate r, const SamplingDepth d, const ChannelLayout l, mtime_t timestamp, data_buffer_t& data, size_t nbSamples) : Samples(r, d, l, timestamp, data.data(), nbSamples) {} Samples::Samples(const SamplingRate r, const SamplingDepth d, const ChannelLayout l, mtime_t timestamp, uint8_t** data, size_t nbSamples, deleter del) : nbSamples(nbSamples), timestamp(timestamp), delete_(del), depth(d), rate(r), layout(l) { alloc(data); } Samples::Samples(const SamplingRate r, const SamplingDepth d, const ChannelLayout l, mtime_t timestamp, uint8_t** data, size_t nbSamples) : nbSamples(nbSamples), timestamp(timestamp), depth(d), rate(r), layout(l) { delete_ = [](data_buffer_t& samples) { for (uint8_t*& ptr : samples) { delete[] ptr; ptr = nullptr; } }; alloc(data); } Samples::~Samples() { delete_(samples); } Samples::Samples(Samples&& o) : depth(o.depth), rate(o.rate), layout(o.layout) { // steal that music nbSamples = o.nbSamples; timestamp = o.timestamp; delete_ = o.delete_; samples = o.samples; o.clear(); } Samples& Samples::operator=(Samples&& o) { rate = o.rate; depth = o.depth; layout = o.layout; // delete current audio signal delete_(samples); // steal that music nbSamples = o.nbSamples; timestamp = o.timestamp; delete_ = o.delete_; samples = o.samples; o.clear(); return *this; } Samples Samples::clone() const { data_buffer_t newdata{}; if (isInterleaved(depth)) { const size_t dataSize = nbSamples * getSampleSizeFromSamplingDepth(depth) * getNbChannelsFromChannelLayout(layout); newdata[0] = new uint8_t[dataSize]; memcpy(newdata[0], samples[0], dataSize); } else { ChannelMap mask = SPEAKER_FRONT_LEFT; const size_t dataSize = nbSamples * getSampleSizeFromSamplingDepth(depth); for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (mask & layout) { newdata[i] = new uint8_t[dataSize]; memcpy(newdata[i], samples[i], dataSize); } mask = (ChannelMap)(mask << 1); } } return Samples(rate, depth, layout, timestamp, newdata, nbSamples); } void Samples::alloc(uint8_t** data) { samples = {}; if (depth == SamplingDepth::UINT8 || depth == SamplingDepth::INT16 || depth == SamplingDepth::INT24 || depth == SamplingDepth::INT32 || depth == SamplingDepth::FLT || depth == SamplingDepth::DBL) { // For interleaved data allocate first channel only samples[0] = data[0]; } else { ChannelMap mask = SPEAKER_FRONT_LEFT; for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (mask & layout) { samples[i] = data[i]; } mask = (ChannelMap)(mask << 1); } } } void Samples::clear() { samples = {}; nbSamples = 0; timestamp = -1; delete_ = [](data_buffer_t& samples) { for (uint8_t* ptr : samples) { delete[] ptr; } }; } Status Samples::drop(size_t n) { if (n > nbSamples) { std::stringstream errmsg; errmsg << "nb of samples to drop " << n << " larger than nbSamples available " << nbSamples; return {Origin::AudioPipeline, ErrType::RuntimeError, errmsg.str()}; } auto _drop = [this, n](int chan, int nbChannels) { uint8_t* newSamples = new uint8_t[getSampleSizeFromSamplingDepth(depth) * (nbSamples - n) * nbChannels]; memcpy(newSamples, samples[chan] + getSampleSizeFromSamplingDepth(depth) * n * nbChannels, getSampleSizeFromSamplingDepth(depth) * (nbSamples - n) * nbChannels); delete[] samples[chan]; samples[chan] = newSamples; }; mapSamples(_drop); nbSamples -= n; assert(rate != SamplingRate::SR_NONE); timestamp += (mtime_t)std::round(n * 1000000. / getIntFromSamplingRate(rate)); return Status::OK(); } Status Samples::append(const Samples& other) { if (other.nbSamples == 0) { // Nothing to append in fact return Status::OK(); } if (other.depth != depth || other.layout != layout || other.rate != rate) { std::stringstream errmsg; errmsg << "Unexpected sample format to append : depth " << getStringFromSamplingDepth(other.depth) << " layout " << getStringFromChannelLayout(other.layout) << " rate " << getIntFromSamplingRate(other.rate) << " instead of depth " << getStringFromSamplingDepth(depth) << " layout " << getStringFromChannelLayout(layout) << " rate " << getIntFromSamplingRate(rate); return {Origin::AudioPipeline, ErrType::RuntimeError, errmsg.str()}; } auto _append = [&](int chan, int nbChannels) { uint8_t* newSamples = new uint8_t[getSampleSizeFromSamplingDepth(depth) * (nbSamples + other.nbSamples) * nbChannels]; memcpy(newSamples, samples[chan], getSampleSizeFromSamplingDepth(depth) * nbSamples * nbChannels); delete[] samples[chan]; memcpy(newSamples + getSampleSizeFromSamplingDepth(depth) * nbSamples * nbChannels, other.samples[chan], getSampleSizeFromSamplingDepth(depth) * other.nbSamples * nbChannels); samples[chan] = newSamples; }; mapSamples(_append); nbSamples += other.nbSamples; return Status::OK(); } int getChannelIndexFromChannelMap(ChannelMap speaker) { switch (speaker) { case SPEAKER_FRONT_LEFT: return 0; case SPEAKER_FRONT_RIGHT: return 1; case SPEAKER_SIDE_LEFT: return 2; case SPEAKER_SIDE_RIGHT: return 3; case SPEAKER_FRONT_CENTER: return 4; case SPEAKER_BACK_CENTER: return 5; case SPEAKER_LOW_FREQUENCY: return 6; case SPEAKER_BACK_LEFT: return 7; case SPEAKER_BACK_RIGHT: return 8; case SPEAKER_FRONT_LEFT_OF_CENTER: return 9; case SPEAKER_FRONT_RIGHT_OF_CENTER: return 10; case SPEAKER_TOP_CENTER: return 11; case SPEAKER_TOP_FRONT_LEFT: return 12; case SPEAKER_TOP_FRONT_CENTER: return 13; case SPEAKER_TOP_FRONT_RIGHT: return 14; case SPEAKER_TOP_BACK_LEFT: return 15; case SPEAKER_TOP_BACK_CENTER: return 16; case SPEAKER_TOP_BACK_RIGHT: return 17; // By default we support the ACN-ordering for the ambisonic ie (WYZX) case SPEAKER_AMB_W: return 18; case SPEAKER_AMB_X: return 19; case SPEAKER_AMB_Y: return 20; case SPEAKER_AMB_Z: return 21; case SPEAKER_AMB_V: return 22; case SPEAKER_AMB_T: return 23; case SPEAKER_AMB_R: return 24; case SPEAKER_AMB_S: return 25; case SPEAKER_AMB_U: return 26; case SPEAKER_AMB_Q: return 27; case SPEAKER_AMB_O: return 28; case SPEAKER_AMB_M: return 29; case SPEAKER_AMB_K: return 30; case SPEAKER_AMB_L: return 31; case SPEAKER_AMB_N: return 32; case SPEAKER_AMB_P: return 33; case NO_SPEAKER: return 34; default: return -1; } } ChannelMap getChannelMapFromChannelIndex(int i) { if (getChannelIndexFromChannelMap(SPEAKER_FRONT_LEFT) == i) { return SPEAKER_FRONT_LEFT; } else if (getChannelIndexFromChannelMap(SPEAKER_FRONT_RIGHT) == i) { return SPEAKER_FRONT_RIGHT; } else if (getChannelIndexFromChannelMap(SPEAKER_FRONT_CENTER) == i) { return SPEAKER_FRONT_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_LOW_FREQUENCY) == i) { return SPEAKER_LOW_FREQUENCY; } else if (getChannelIndexFromChannelMap(SPEAKER_BACK_LEFT) == i) { return SPEAKER_BACK_LEFT; } else if (getChannelIndexFromChannelMap(SPEAKER_BACK_RIGHT) == i) { return SPEAKER_BACK_RIGHT; } else if (getChannelIndexFromChannelMap(SPEAKER_FRONT_LEFT_OF_CENTER) == i) { return SPEAKER_FRONT_LEFT_OF_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_FRONT_RIGHT_OF_CENTER) == i) { return SPEAKER_FRONT_RIGHT_OF_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_BACK_CENTER) == i) { return SPEAKER_BACK_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_SIDE_LEFT) == i) { return SPEAKER_SIDE_LEFT; } else if (getChannelIndexFromChannelMap(SPEAKER_SIDE_RIGHT) == i) { return SPEAKER_SIDE_RIGHT; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_CENTER) == i) { return SPEAKER_TOP_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_FRONT_LEFT) == i) { return SPEAKER_TOP_FRONT_LEFT; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_FRONT_CENTER) == i) { return SPEAKER_TOP_FRONT_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_FRONT_RIGHT) == i) { return SPEAKER_TOP_FRONT_RIGHT; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_BACK_LEFT) == i) { return SPEAKER_TOP_BACK_LEFT; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_BACK_CENTER) == i) { return SPEAKER_TOP_BACK_CENTER; } else if (getChannelIndexFromChannelMap(SPEAKER_TOP_BACK_RIGHT) == i) { return SPEAKER_TOP_BACK_RIGHT; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_W) == i) { return SPEAKER_AMB_W; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_X) == i) { return SPEAKER_AMB_X; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_Y) == i) { return SPEAKER_AMB_Y; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_Z) == i) { return SPEAKER_AMB_Z; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_R) == i) { return SPEAKER_AMB_R; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_S) == i) { return SPEAKER_AMB_S; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_T) == i) { return SPEAKER_AMB_T; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_U) == i) { return SPEAKER_AMB_U; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_V) == i) { return SPEAKER_AMB_V; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_K) == i) { return SPEAKER_AMB_K; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_L) == i) { return SPEAKER_AMB_L; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_M) == i) { return SPEAKER_AMB_M; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_N) == i) { return SPEAKER_AMB_N; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_O) == i) { return SPEAKER_AMB_O; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_P) == i) { return SPEAKER_AMB_P; } else if (getChannelIndexFromChannelMap(SPEAKER_AMB_Q) == i) { return SPEAKER_AMB_Q; } else { return NO_SPEAKER; } } int getIntFromBlockSize(BlockSize bs) { switch (bs) { case BlockSize::BS_32: return 32; case BlockSize::BS_64: return 64; case BlockSize::BS_128: return 128; case BlockSize::BS_256: return 256; case BlockSize::BS_512: return 512; case BlockSize::BS_1024: return 1024; case BlockSize::BS_2048: return 2048; case BlockSize::BS_4096: return 4096; case BlockSize::BS_NONE: return 0; } return 0; } double getDblFromBlockSize(BlockSize bs) { return static_cast(getIntFromBlockSize(bs)); } int getIntFromSamplingRate(SamplingRate samplingRate) { switch (samplingRate) { case SamplingRate::SR_NONE: return 0; case SamplingRate::SR_22050: return 22050; case SamplingRate::SR_32000: return 32000; case SamplingRate::SR_44100: return 44100; case SamplingRate::SR_48000: return 48000; case SamplingRate::SR_88200: return 88200; case SamplingRate::SR_96000: return 96000; case SamplingRate::SR_176400: return 176400; case SamplingRate::SR_192000: return 192000; default: return 0; } } double getDblFromSamplingRate(SamplingRate samplingRate) { return static_cast(getIntFromSamplingRate(samplingRate)); } BlockSize getBlockSizeFromInt(const int bs) { if (getIntFromBlockSize(BlockSize::BS_32) == bs) { return BlockSize::BS_32; } else if (getIntFromBlockSize(BlockSize::BS_64) == bs) { return BlockSize::BS_64; } else if (getIntFromBlockSize(BlockSize::BS_128) == bs) { return BlockSize::BS_128; } else if (getIntFromBlockSize(BlockSize::BS_256) == bs) { return BlockSize::BS_256; } else if (getIntFromBlockSize(BlockSize::BS_512) == bs) { return BlockSize::BS_512; } else if (getIntFromBlockSize(BlockSize::BS_1024) == bs) { return BlockSize::BS_1024; } else if (getIntFromBlockSize(BlockSize::BS_2048) == bs) { return BlockSize::BS_2048; } else if (getIntFromBlockSize(BlockSize::BS_4096) == bs) { return BlockSize::BS_4096; } else { return BlockSize::BS_NONE; } } SamplingRate getSamplingRateFromInt(const int samplingRateInt) { if (getIntFromSamplingRate(SamplingRate::SR_22050) == samplingRateInt) { return SamplingRate::SR_22050; } else if (getIntFromSamplingRate(SamplingRate::SR_32000) == samplingRateInt) { return SamplingRate::SR_32000; } else if (getIntFromSamplingRate(SamplingRate::SR_44100) == samplingRateInt) { return SamplingRate::SR_44100; } else if (getIntFromSamplingRate(SamplingRate::SR_48000) == samplingRateInt) { return SamplingRate::SR_48000; } else if (getIntFromSamplingRate(SamplingRate::SR_88200) == samplingRateInt) { return SamplingRate::SR_88200; } else if (getIntFromSamplingRate(SamplingRate::SR_96000) == samplingRateInt) { return SamplingRate::SR_96000; } else if (getIntFromSamplingRate(SamplingRate::SR_176400) == samplingRateInt) { return SamplingRate::SR_176400; } else if (getIntFromSamplingRate(SamplingRate::SR_192000) == samplingRateInt) { return SamplingRate::SR_192000; } else { return SamplingRate::SR_NONE; } } SamplingFormat getSamplingFormatFromSamplingDepth(SamplingDepth samplingDepth) { switch (samplingDepth) { case SamplingDepth::UINT8: case SamplingDepth::INT16: case SamplingDepth::INT24: case SamplingDepth::INT32: case SamplingDepth::FLT: case SamplingDepth::DBL: return SamplingFormat::INTERLEAVED; case SamplingDepth::UINT8_P: case SamplingDepth::INT16_P: case SamplingDepth::INT24_P: case SamplingDepth::INT32_P: case SamplingDepth::FLT_P: case SamplingDepth::DBL_P: return SamplingFormat::PLANAR; default: // Logger::get(Logger::Warning) << "getSamplingFormatFromSamplingDepth: unknown samplingDepth value: " << // samplingDepth << std::endl; return SamplingFormat::FORMAT_UNKNOWN; } } std::size_t getSampleSizeFromSamplingDepth(SamplingDepth samplingDepth) { switch (samplingDepth) { case SamplingDepth::UINT8: case SamplingDepth::UINT8_P: return sizeof(uint8_t); case SamplingDepth::INT16: case SamplingDepth::INT16_P: return sizeof(int16_t); case SamplingDepth::INT24: case SamplingDepth::INT24_P: return 3 * sizeof(uint8_t); case SamplingDepth::INT32: case SamplingDepth::INT32_P: return sizeof(int32_t); case SamplingDepth::FLT: case SamplingDepth::FLT_P: return sizeof(float); case SamplingDepth::DBL: case SamplingDepth::DBL_P: return sizeof(double); default: // Logger::get(Logger::Warning) << "getSampleSizeFromSamplingDepth: unknown samplingDepth value: " << // samplingDepth << std::endl; return 0; } } const char* getStringFromSamplingDepth(SamplingDepth samplingDepth) { switch (samplingDepth) { case SamplingDepth::SD_NONE: return "No sampling depth"; case SamplingDepth::UINT8: return "s8"; case SamplingDepth::INT16: return "s16"; case SamplingDepth::INT32: return "s32"; case SamplingDepth::FLT: return "flt"; case SamplingDepth::DBL: return "dbl"; case SamplingDepth::UINT8_P: return "s8p"; case SamplingDepth::INT16_P: return "s16p"; case SamplingDepth::INT32_P: return "s32p"; case SamplingDepth::FLT_P: return "fltp"; case SamplingDepth::DBL_P: return "dblp"; default: return ""; } } SamplingDepth getSamplingDepthFromString(const char* samplingDepthStr) { if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::UINT8), samplingDepthStr) == 0) { return SamplingDepth::UINT8; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::INT16), samplingDepthStr) == 0) { return SamplingDepth::INT16; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::INT32), samplingDepthStr) == 0) { return SamplingDepth::INT32; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::FLT), samplingDepthStr) == 0) { return SamplingDepth::FLT; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::DBL), samplingDepthStr) == 0) { return SamplingDepth::DBL; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::UINT8_P), samplingDepthStr) == 0) { return SamplingDepth::UINT8_P; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::INT16_P), samplingDepthStr) == 0) { return SamplingDepth::INT16_P; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::INT32_P), samplingDepthStr) == 0) { return SamplingDepth::INT32_P; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::FLT_P), samplingDepthStr) == 0) { return SamplingDepth::FLT_P; } else if (std::strcmp(getStringFromSamplingDepth(SamplingDepth::DBL_P), samplingDepthStr) == 0) { return SamplingDepth::DBL_P; } else { return SamplingDepth::SD_NONE; } } const char* getStringFromChannelType(ChannelMap map) { switch (map) { case SPEAKER_FRONT_LEFT: return "front left"; case SPEAKER_FRONT_RIGHT: return "front right"; case SPEAKER_FRONT_CENTER: return "front center"; case SPEAKER_LOW_FREQUENCY: return "front low frequency"; case SPEAKER_BACK_LEFT: return "back left"; case SPEAKER_BACK_RIGHT: return "back right"; case SPEAKER_FRONT_LEFT_OF_CENTER: return "front left of center"; case SPEAKER_FRONT_RIGHT_OF_CENTER: return "front right of center"; case SPEAKER_BACK_CENTER: return "back center"; case SPEAKER_SIDE_LEFT: return "side left"; case SPEAKER_SIDE_RIGHT: return "side right"; case SPEAKER_TOP_CENTER: return "top center"; case SPEAKER_TOP_FRONT_LEFT: return "top front left"; case SPEAKER_TOP_FRONT_CENTER: return "top front center"; case SPEAKER_TOP_FRONT_RIGHT: return "top front right"; case SPEAKER_TOP_BACK_LEFT: return "top back left"; case SPEAKER_TOP_BACK_CENTER: return "top back center"; case SPEAKER_TOP_BACK_RIGHT: return "top back right"; case SPEAKER_AMB_W: return "amb w"; case SPEAKER_AMB_X: return "amb x"; case SPEAKER_AMB_Y: return "amb y"; case SPEAKER_AMB_Z: return "amb z"; case SPEAKER_AMB_R: return "amb r"; case SPEAKER_AMB_S: return "amb s"; case SPEAKER_AMB_T: return "amb t"; case SPEAKER_AMB_U: return "amb u"; case SPEAKER_AMB_V: return "amb v"; case SPEAKER_AMB_K: return "amb k"; case SPEAKER_AMB_L: return "amb l"; case SPEAKER_AMB_M: return "amb m"; case SPEAKER_AMB_N: return "amb n"; case SPEAKER_AMB_O: return "amb o"; case SPEAKER_AMB_P: return "amb p"; case SPEAKER_AMB_Q: return "amb q"; case NO_SPEAKER: return "no speaker"; } return "no speaker"; } const char* getStringFromChannelLayout(ChannelLayout channelLayout) { switch (channelLayout) { case MONO: return "mono"; case STEREO: return "stereo"; case _2POINT1: return "2.1"; case _3DUMMY: return "3(dummy)"; case _2_1: return "3.0(back)"; case SURROUND: return "3.0"; case _3POINT1: return "3.1"; case _4POINT0: return "4.0"; case _4POINT1: return "4.1"; case _2_2: return "quad(side)"; case QUAD: return "quad"; case _5POINT0: return "5.0(side)"; case _5POINT1: return "5.1(side)"; case _5POINT0_BACK: return "5.0"; case _5POINT1_BACK: return "5.1"; case _6POINT0: return "6.0"; case _6POINT0_FRONT: return "6.0(front)"; case HEXAGONAL: return "hexagonal"; case _6POINT1: return "6.1"; case _6POINT1_BACK: return "6.1"; case _6POINT1_FRONT: return "6.1(side)"; case _7POINT0: return "7.0"; case _7POINT0_FRONT: return "7.0(front)"; case _7POINT1: return "7.1"; case _7POINT1_WIDE: return "7.1(wide-side)"; case _7POINT1_WIDE_BACK: return "7.1(wide)"; case OCTAGONAL: return "octagonal"; case _8DUMMY: return "8(dummy)"; case AMBISONICS_WXY: return "amb_wxy"; case AMBISONICS_WXYZ: return "amb_wxyz"; case AMBISONICS_2ND: return "amb_2nd"; case AMBISONICS_3RD: return "amb_3rd"; case UNKNOWN: return "unknown"; } return "unknown"; } int getNbChannelsFromChannelLayout(ChannelLayout channelLayout) { switch (channelLayout) { case MONO: return 1; case STEREO: return 2; case _3DUMMY: case _2POINT1: case _2_1: case SURROUND: case AMBISONICS_WXY: return 3; case _3POINT1: case _4POINT0: case _2_2: case QUAD: case AMBISONICS_WXYZ: return 4; case _4POINT1: case _5POINT0: case _5POINT0_BACK: return 5; case _5POINT1: case _5POINT1_BACK: case _6POINT0: case _6POINT0_FRONT: case HEXAGONAL: return 6; case _6POINT1: case _6POINT1_BACK: case _6POINT1_FRONT: case _7POINT0: case _7POINT0_FRONT: return 7; case _7POINT1: case _7POINT1_WIDE: case _7POINT1_WIDE_BACK: case OCTAGONAL: case _8DUMMY: return 8; case AMBISONICS_2ND: return 9; case AMBISONICS_3RD: return 16; case UNKNOWN: return 0; } return 0; } ChannelLayout getAChannelLayoutFromNbChannels(size_t nbChannels) { if (nbChannels == 1) { return MONO; } else if (nbChannels == 2) { return STEREO; } else if (nbChannels == 3) { return _3DUMMY; } else if (nbChannels == 4) { return _2_2; } else if (nbChannels == 5) { return _5POINT0; } else if (nbChannels == 6) { return _6POINT0; } else if (nbChannels == 7) { return _6POINT1; } else if (nbChannels == 8) { return _8DUMMY; } else { return UNKNOWN; } } ChannelLayout getChannelLayoutFromString(const char* channelLayout) { if (std::strcmp(getStringFromChannelLayout(MONO), channelLayout) == 0) { return MONO; } else if (std::strcmp(getStringFromChannelLayout(STEREO), channelLayout) == 0) { return STEREO; } else if (std::strcmp(getStringFromChannelLayout(_2POINT1), channelLayout) == 0) { return _2POINT1; } else if (std::strcmp(getStringFromChannelLayout(_2_1), channelLayout) == 0) { return _2_1; } else if (std::strcmp(getStringFromChannelLayout(SURROUND), channelLayout) == 0) { return SURROUND; } else if (std::strcmp(getStringFromChannelLayout(_3POINT1), channelLayout) == 0) { return _3POINT1; } else if (std::strcmp(getStringFromChannelLayout(_4POINT0), channelLayout) == 0) { return _4POINT0; } else if (std::strcmp(getStringFromChannelLayout(_4POINT1), channelLayout) == 0) { return _4POINT1; } else if (std::strcmp(getStringFromChannelLayout(_2_2), channelLayout) == 0) { return _2_2; } else if (std::strcmp(getStringFromChannelLayout(QUAD), channelLayout) == 0) { return QUAD; } else if (std::strcmp(getStringFromChannelLayout(_5POINT0), channelLayout) == 0) { return _5POINT0; } else if (std::strcmp(getStringFromChannelLayout(_5POINT1), channelLayout) == 0) { return _5POINT1; } else if (std::strcmp(getStringFromChannelLayout(_5POINT0_BACK), channelLayout) == 0) { return _5POINT0_BACK; } else if (std::strcmp(getStringFromChannelLayout(_5POINT1_BACK), channelLayout) == 0) { return _5POINT1_BACK; } else if (std::strcmp(getStringFromChannelLayout(_6POINT0), channelLayout) == 0) { return _6POINT0; } else if (std::strcmp(getStringFromChannelLayout(_6POINT0_FRONT), channelLayout) == 0) { return _6POINT0_FRONT; } else if (std::strcmp(getStringFromChannelLayout(HEXAGONAL), channelLayout) == 0) { return HEXAGONAL; } else if (std::strcmp(getStringFromChannelLayout(_6POINT1), channelLayout) == 0) { return _6POINT1; } else if (std::strcmp(getStringFromChannelLayout(_6POINT1_BACK), channelLayout) == 0) { return _6POINT1_BACK; } else if (std::strcmp(getStringFromChannelLayout(_6POINT1_FRONT), channelLayout) == 0) { return _6POINT1_FRONT; } else if (std::strcmp(getStringFromChannelLayout(_7POINT0), channelLayout) == 0) { return _7POINT0; } else if (std::strcmp(getStringFromChannelLayout(_7POINT0_FRONT), channelLayout) == 0) { return _7POINT0_FRONT; } else if (std::strcmp(getStringFromChannelLayout(_7POINT1), channelLayout) == 0) { return _7POINT1; } else if (std::strcmp(getStringFromChannelLayout(_7POINT1_WIDE), channelLayout) == 0) { return _7POINT1_WIDE; } else if (std::strcmp(getStringFromChannelLayout(_7POINT1_WIDE_BACK), channelLayout) == 0) { return _7POINT1_WIDE_BACK; } else if (std::strcmp(getStringFromChannelLayout(OCTAGONAL), channelLayout) == 0) { return OCTAGONAL; } else if (std::strcmp(getStringFromChannelLayout(AMBISONICS_WXY), channelLayout) == 0) { return AMBISONICS_WXY; } else if (std::strcmp(getStringFromChannelLayout(AMBISONICS_WXYZ), channelLayout) == 0) { return AMBISONICS_WXYZ; } else if (std::strcmp(getStringFromChannelLayout(AMBISONICS_2ND), channelLayout) == 0) { return AMBISONICS_2ND; } else if (std::strcmp(getStringFromChannelLayout(AMBISONICS_3RD), channelLayout) == 0) { return AMBISONICS_3RD; } return UNKNOWN; } void convertSamplesToMonoDouble(const Audio::Samples& samples, Audio::AudioTrack& snd, const int nChannels, const Audio::SamplingDepth sampleDepth) { switch (sampleDepth) { case Audio::SamplingDepth::UINT8_P: { uint8_t* s = samples.getSamples()[0]; for (size_t i = 0; i < samples.getNbOfSamples(); i++) { if (*s > 0) { snd.push_back(((double)*s++ - 128.0) / 127.0); } else { snd.push_back(((double)*s++ - 128.0) / 128.0); } } break; } case Audio::SamplingDepth::INT16_P: { int16_t* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { if (*s > 0) { snd.push_back(((double)*s++) / 32767.0); } else { snd.push_back(((double)*s++) / 32768.0); } } break; } case Audio::SamplingDepth::INT24_P: { uint8_t* s = samples.getSamples()[0]; uint32_t sh; for (size_t i = 0; i < samples.getNbOfSamples(); i++) { sh = 0; memcpy(&sh, s, 3); int32_t shi = static_cast(sh << 8); if (shi > 0) { snd.push_back(((double)shi) / 2147483392.0); } else { snd.push_back(((double)shi) / 2147483648.0); } s += 3; } break; } case Audio::SamplingDepth::INT32_P: { int32_t* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { if (*s > 0) { snd.push_back(((double)*s++) / 2147483647.0); } else { snd.push_back(((double)*s++) / 2147483648.0); } } break; } case Audio::SamplingDepth::FLT_P: { float* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { snd.push_back((double)*s++); } break; } case Audio::SamplingDepth::DBL_P: { double* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { snd.push_back(*s++); } break; } case Audio::SamplingDepth::UINT8: { uint8_t* s = samples.getSamples()[0]; for (size_t i = 0; i < samples.getNbOfSamples(); i++) { if (*s > 128) { snd.push_back(((double)*s - 128.0) / 127.0); } else { snd.push_back(((double)*s - 128.0) / 128.0); } s += nChannels; } break; } case Audio::SamplingDepth::INT16: { int16_t* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { if (*s > 0) { snd.push_back(((double)*s) / 32767.0); } else { snd.push_back(((double)*s) / 32768.0); } s += nChannels; } break; } case Audio::SamplingDepth::INT24: { uint8_t* s = samples.getSamples()[0]; uint32_t sh; for (size_t i = 0; i < samples.getNbOfSamples(); i++) { sh = 0; memcpy(&sh, s, 3); int32_t shi = static_cast(sh << 8); if (shi > 0) { snd.push_back(((double)shi) / 2147483392.0); } else { snd.push_back(((double)shi) / 2147483648.0); } s += nChannels * 3; } break; } case Audio::SamplingDepth::INT32: { int32_t* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { if (*s > 0) { snd.push_back(((double)*s) / 2147483647.0); } else { snd.push_back(((double)*s) / 2147483648.0); } s += nChannels; } break; } case Audio::SamplingDepth::FLT: { float* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { snd.push_back((double)*s); s += nChannels; } break; } case Audio::SamplingDepth::DBL: { double* s = reinterpret_cast(samples.getSamples()[0]); for (size_t i = 0; i < samples.getNbOfSamples(); i++) { snd.push_back(*s); s += nChannels; } break; } default: break; } } template void Samples::mapSamples(const Functor& execFunctor) { switch (getSamplingFormatFromSamplingDepth(depth)) { case SamplingFormat::INTERLEAVED: { execFunctor(0, getNbChannelsFromChannelLayout(layout)); break; } case SamplingFormat::PLANAR: { int64_t mask = 0x1; for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (layout & mask) execFunctor(i, 1); mask <<= 1; } break; } default: assert(false && "Sampling format is unknown"); } } } // namespace Audio } // namespace VideoStitch