| 48 | |
| 49 | template <typename T> |
| 50 | void DecodeAudio(TensorView<StorageCPU, T, DynamicDimensions> audio, AudioDecoderBase &decoder, |
| 51 | const AudioMetadata &meta, kernels::signal::resampling::ResamplerCPU &resampler, |
| 52 | span<float> decode_scratch_mem, |
| 53 | span<float> resample_scratch_mem, |
| 54 | float target_sample_rate, bool downmix, |
| 55 | const char *audio_filepath) { // audio_filepath for debug purposes |
| 56 | assert(meta.sample_rate > 0 && "Invalid sampling rate"); |
| 57 | bool should_resample = target_sample_rate > 0 && meta.sample_rate != target_sample_rate; |
| 58 | bool should_downmix = meta.channels > 1 && downmix; |
| 59 | assert(audio.data != nullptr); |
| 60 | if (volume(audio.shape) <= 0) |
| 61 | return; |
| 62 | |
| 63 | if (!should_resample && !should_downmix) { |
| 64 | assert(audio.shape[0] <= meta.length && "Requested to decode more data than available."); |
| 65 | assert(meta.channels == (audio.shape.size() == 1 ? 1 : audio.shape[1]) && |
| 66 | "Number of channels should match the metadata."); |
| 67 | int64_t ret = decoder.DecodeFrames(audio.data, audio.shape[0]); |
| 68 | DALI_ENFORCE(ret == audio.shape[0], |
| 69 | make_string("Error decoding audio file ", audio_filepath, ". Requested ", |
| 70 | audio.shape[0], " samples but got ", ret, " samples.")); |
| 71 | return; |
| 72 | } |
| 73 | |
| 74 | assert(decode_scratch_mem.size() > 0 && |
| 75 | "Dowmixing or resampling is required but decoder scratch memory is empty."); |
| 76 | assert(decode_scratch_mem.size() % meta.channels == 0 && |
| 77 | "Expected to decode full audio frames only."); |
| 78 | assert(decode_scratch_mem.size() <= meta.length * meta.channels && |
| 79 | "Requested to decode more data than available."); |
| 80 | int64_t decoded_audio_len = decode_scratch_mem.size() / meta.channels; |
| 81 | if (should_resample && should_downmix) { |
| 82 | // When downmixing, we need an extra buffer for the input of resampling |
| 83 | assert(resample_scratch_mem.size() == decoded_audio_len && |
| 84 | "Downmixing and resampling is required but resampler scratch is either empty or doesn't " |
| 85 | "have the expected size"); |
| 86 | } |
| 87 | |
| 88 | int64_t ret = decoder.DecodeFrames(decode_scratch_mem.data(), decoded_audio_len); |
| 89 | DALI_ENFORCE(ret == decoded_audio_len, make_string("Error decoding audio file ", audio_filepath)); |
| 90 | |
| 91 | if (should_resample && should_downmix) { |
| 92 | kernels::signal::Downmix(resample_scratch_mem.data(), decode_scratch_mem.data(), |
| 93 | decoded_audio_len, meta.channels); |
| 94 | resampler.Resample(audio.data, 0, audio.shape[0], target_sample_rate, |
| 95 | resample_scratch_mem.data(), decoded_audio_len, meta.sample_rate, 1); |
| 96 | } else if (should_resample) { // No downmix |
| 97 | resampler.Resample(audio.data, 0, audio.shape[0], target_sample_rate, decode_scratch_mem.data(), |
| 98 | decoded_audio_len, meta.sample_rate, meta.channels); |
| 99 | } else if (should_downmix) { // downmix only |
| 100 | kernels::signal::Downmix(audio.data, decode_scratch_mem.data(), decoded_audio_len, |
| 101 | meta.channels); |
| 102 | } else { |
| 103 | assert(false && "Logic error. This should never happen."); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | #define DECLARE_IMPL(OutType) \ |
nothing calls this directly
no test coverage detected