nlsCppSdk/encoder/oggopusAudioIn.cpp (144 lines of code) (raw):

/* * Copyright 2021 Alibaba Group Holding Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "oggopusAudioIn.h" #include <limits.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #ifdef WIN32 #include <io.h> /*_get_osfhandle()*/ #include <windows.h> /*GetFileType()*/ #endif #include "lpc.h" #include "ogg/ogg.h" #include "oggopusHeader.h" namespace AlibabaNls { // return: sample number actually read int ReadBuffer(char *requested_buffer, int requested_len, char **src_buffer, int *length) { if (*length == 0 || NULL == *src_buffer) return 0; // input length is smaller than the length requested if (*length < requested_len) { memcpy(requested_buffer, *src_buffer, *length); requested_len = *length; *length = 0; free(*src_buffer); *src_buffer = NULL; return requested_len / 2; } memcpy(requested_buffer, *src_buffer, requested_len); // save the left data to tmp buffer *length = *length - requested_len; if (*length > 0) { char *tmp_buffer = (char *)malloc(*length); memcpy(tmp_buffer, *src_buffer + requested_len, *length); free(*src_buffer); *src_buffer = tmp_buffer; } else { *length = 0; free(*src_buffer); *src_buffer = NULL; } return requested_len / 2; } int64_t WavRead(void *read_info, float *buffer, int samples, char **inbuf, int *length) { WavInfo *wav_info = reinterpret_cast<WavInfo *>(read_info); int sample_bytes = wav_info->sample_bits / 8; int requested_sample_num = samples; int requested_len = requested_sample_num * sample_bytes * wav_info->channels; // Obsolete function 'alloca' called. In C++11 and later it is recommended to // use std::array<> instead. signed char *requested_buf = (signed char *)alloca(requested_len); int *ch_permute = wav_info->channel_permute; requested_sample_num = ReadBuffer((char *)requested_buf, requested_len, inbuf, length); wav_info->samplesread += requested_sample_num; for (int i = 0; i < requested_sample_num; i++) { for (int j = 0; j < wav_info->channels; j++) { buffer[i * wav_info->channels + j] = ((requested_buf[i * 2 * wav_info->channels + 2 * ch_permute[j] + 1] << 8) | (requested_buf[i * 2 * wav_info->channels + 2 * ch_permute[j]] & 0xff)) / 32768.0f; } } return requested_sample_num; } void WavClose(void *info) { WavInfo *wav_info = reinterpret_cast<WavInfo *>(info); free(wav_info->channel_permute); delete wav_info; } void RawOpen(OggEncodeOpt *ogg_encode_opt) { WavInfo *wav_info = new WavInfo(); wav_info->samplesread = 0; wav_info->bigendian = ogg_encode_opt->endianness; wav_info->unsigned8bit = (ogg_encode_opt->sample_bits == 8); wav_info->channels = ogg_encode_opt->channels; wav_info->sample_bits = ogg_encode_opt->sample_bits; wav_info->channel_permute = (int *)malloc(wav_info->channels * sizeof(int)); for (int i = 0; i < wav_info->channels; i++) wav_info->channel_permute[i] = i; ogg_encode_opt->read_func = WavRead; ogg_encode_opt->read_info = (void *)wav_info; ogg_encode_opt->total_samples_per_channel = 0; /* raw mode, don't bother */ } /* Read audio data, appending padding to make up any gap between the available * and requested number of samples with LPC-predicted data to minimize the * pertubation of the valid data that falls in the same frame. */ static int64_t ReadPadder(void *read_info, float *buffer, int samples, char **inbuf, int *length) { Padder *padder = reinterpret_cast<Padder *>(read_info); // use WavRead Func here int64_t in_samples = padder->read_func(padder->read_info, buffer, samples, inbuf, length); if (in_samples <= 0) { return in_samples; // no sample fetched } int extra = 0; const int lpc_order = 32; if (padder->original_sample_number) *padder->original_sample_number += in_samples; if (in_samples < samples) { if (padder->lpc_ptr < 0) { padder->lpc_out = reinterpret_cast<float *>( calloc(padder->channels * (*padder->extra_samples), sizeof(*padder->lpc_out))); if (in_samples > lpc_order * 2) { float *lpc = reinterpret_cast<float *>(alloca(lpc_order * sizeof(*lpc))); for (int i = 0; i < padder->channels; i++) { vorbis_lpc_from_data(buffer + i, lpc, in_samples, lpc_order, padder->channels); vorbis_lpc_predict( lpc, buffer + i + (in_samples - lpc_order) * padder->channels, lpc_order, padder->lpc_out + i, *padder->extra_samples, padder->channels); } } padder->lpc_ptr = 0; } extra = samples - in_samples; if (extra > *padder->extra_samples) extra = *padder->extra_samples; *padder->extra_samples -= extra; } memcpy(buffer + in_samples * padder->channels, padder->lpc_out + padder->lpc_ptr * padder->channels, extra * padder->channels * sizeof(*buffer)); padder->lpc_ptr += extra; return in_samples + extra; } void SetupPadder(OggEncodeOpt *ogg_encode_opt, ogg_int64_t *original_sample_number) { Padder *padder = new Padder(); padder->read_func = ogg_encode_opt->read_func; padder->read_info = ogg_encode_opt->read_info; padder->channels = ogg_encode_opt->channels; padder->extra_samples = &ogg_encode_opt->extraout; padder->original_sample_number = original_sample_number; padder->lpc_ptr = -1; padder->lpc_out = NULL; ogg_encode_opt->read_func = ReadPadder; ogg_encode_opt->read_info = static_cast<Padder *>(padder); // use the padder's read data } void ClearPadder(OggEncodeOpt *ogg_encode_opt) { Padder *padder = static_cast<Padder *>(ogg_encode_opt->read_info); ogg_encode_opt->read_func = padder->read_func; ogg_encode_opt->read_info = padder->read_info; if (padder->lpc_out) free(padder->lpc_out); delete padder; } } // namespace AlibabaNls