Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.xiph.org/xiph/opus.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/harmony_encoder.c')
-rw-r--r--src/harmony_encoder.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/harmony_encoder.c b/src/harmony_encoder.c
new file mode 100644
index 00000000..569eb7a3
--- /dev/null
+++ b/src/harmony_encoder.c
@@ -0,0 +1,270 @@
+/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "harmony_encoder.h"
+#include "entenc.h"
+#include "modes.h"
+#include "SKP_Silk_SDK_API.h"
+
+HarmonyEncoder *harmony_encoder_create(int Fs)
+{
+ char *raw_state;
+ CELTMode *celtMode;
+ HarmonyEncoder *st;
+ int ret, silkEncSizeBytes, celtEncSizeBytes;
+ SKP_SILK_SDK_EncControlStruct encControl;
+
+ /* We should not have to create a CELT mode for each encoder state */
+ celtMode = celt_mode_create(Fs, Fs/50, NULL);
+
+ /* Create SILK encoder */
+ ret = SKP_Silk_SDK_Get_Encoder_Size( &silkEncSizeBytes );
+ if( ret ) {
+ /* Handle error */
+ }
+ celtEncSizeBytes = celt_encoder_get_size(celtMode, 1);
+ raw_state = calloc(sizeof(HarmonyEncoder)+silkEncSizeBytes+celtEncSizeBytes, 1);
+ st = (HarmonyEncoder*)raw_state;
+ st->silk_enc = (void*)(raw_state+sizeof(HarmonyEncoder));
+ st->celt_enc = (CELTEncoder*)(raw_state+sizeof(HarmonyEncoder)+silkEncSizeBytes);
+
+ st->Fs = Fs;
+ st->celt_mode = celtMode;
+
+ /*encControl.API_sampleRate = st->Fs;
+ encControl.packetLossPercentage = 0;
+ encControl.useInBandFEC = 0;
+ encControl.useDTX = 0;
+ encControl.complexity = 2;*/
+ ret = SKP_Silk_SDK_InitEncoder( st->silk_enc, &encControl );
+ if( ret ) {
+ /* Handle error */
+ }
+
+ /* Create CELT encoder */
+ /* Initialize CELT encoder */
+ st->celt_enc = celt_encoder_init(st->celt_enc, st->celt_mode, 1, NULL);
+
+ st->mode = MODE_HYBRID;
+ st->bandwidth = BANDWIDTH_FULLBAND;
+ st->vbr_rate = 0;
+
+ return st;
+}
+
+int harmony_encode(HarmonyEncoder *st, const short *pcm, int frame_size,
+ unsigned char *data, int bytes_per_packet)
+{
+ int i;
+ int ret=0;
+ SKP_int16 nBytes;
+ ec_enc enc;
+ ec_byte_buffer buf;
+ SKP_SILK_SDK_EncControlStruct encControl;
+ int framerate, period;
+
+ bytes_per_packet -= 1;
+ data += 1;
+ ec_byte_writeinit_buffer(&buf, data, bytes_per_packet);
+ ec_enc_init(&enc,&buf);
+
+ if (st->mode != MODE_CELT_ONLY)
+ {
+ /* Set Encoder parameters */
+ encControl.API_sampleRate = st->Fs;
+ encControl.packetLossPercentage = 2;
+ encControl.useInBandFEC = 0;
+ encControl.useDTX = 0;
+ encControl.complexity = 2;
+
+ if (st->vbr_rate != 0)
+ encControl.bitRate = (st->vbr_rate+6000)/2;
+ else {
+ encControl.bitRate = (bytes_per_packet*8*(celt_int32)st->Fs/frame_size+6000)/2;
+ if (st->Fs == 100 * frame_size)
+ encControl.bitRate -= 5000;
+ }
+ encControl.packetSize = frame_size;
+
+ if (st->bandwidth == BANDWIDTH_NARROWBAND)
+ encControl.maxInternalSampleRate = 8000;
+ else if (st->bandwidth == BANDWIDTH_MEDIUMBAND)
+ encControl.maxInternalSampleRate = 12000;
+ else
+ encControl.maxInternalSampleRate = 16000;
+
+ /* Call SILK encoder for the low band */
+ nBytes = bytes_per_packet;
+ ret = SKP_Silk_SDK_Encode( st->silk_enc, &encControl, pcm, frame_size, &enc, &nBytes );
+ if( ret ) {
+ fprintf (stderr, "SILK encode error\n");
+ /* Handle error */
+ }
+ ret = (ec_enc_tell(&enc, 0)+7)>>3;
+ }
+
+ if (st->mode == MODE_HYBRID)
+ {
+ /* This should be adjusted based on the SILK bandwidth */
+ celt_encoder_ctl(st->celt_enc, CELT_SET_START_BAND(17));
+ } else {
+ celt_encoder_ctl(st->celt_enc, CELT_SET_START_BAND(0));
+ }
+
+ if (st->mode != MODE_SILK_ONLY && st->bandwidth > BANDWIDTH_WIDEBAND)
+ {
+ short pcm_buf[960];
+
+ if (st->bandwidth == BANDWIDTH_SUPERWIDEBAND)
+ celt_encoder_ctl(st->celt_enc, CELT_SET_END_BAND(20));
+ else
+ celt_encoder_ctl(st->celt_enc, CELT_SET_END_BAND(21));
+
+ for (i=0;i<ENCODER_DELAY_COMPENSATION;i++)
+ pcm_buf[i] = st->delay_buffer[i];
+ for (;i<frame_size;i++)
+ pcm_buf[i] = pcm[i-ENCODER_DELAY_COMPENSATION];
+
+ celt_encoder_ctl(st->celt_enc, CELT_SET_PREDICTION(1));
+
+ if (st->vbr_rate != 0)
+ {
+ int tmp = (st->vbr_rate-6000)/2;
+ tmp = ((ec_enc_tell(&enc, 0)+4)>>3) + tmp * frame_size/(8*st->Fs);
+ if (tmp <= bytes_per_packet)
+ bytes_per_packet = tmp;
+ ec_byte_shrink(&buf, bytes_per_packet);
+ }
+ /* Encode high band with CELT */
+ ret = celt_encode_with_ec(st->celt_enc, pcm_buf, NULL, frame_size, NULL, bytes_per_packet, &enc);
+ for (i=0;i<ENCODER_DELAY_COMPENSATION;i++)
+ st->delay_buffer[i] = pcm[frame_size-ENCODER_DELAY_COMPENSATION+i];
+ } else {
+ ec_enc_done(&enc);
+ }
+
+ /* Signalling the mode in the first byte */
+ data--;
+ framerate = st->Fs/frame_size;
+ period = 0;
+ while (framerate < 400)
+ {
+ framerate <<= 1;
+ period++;
+ }
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ data[0] = (st->bandwidth-BANDWIDTH_NARROWBAND)<<5;
+ data[0] |= (period-2)<<3;
+ } else if (st->mode == MODE_CELT_ONLY)
+ {
+ int tmp = st->bandwidth-BANDWIDTH_MEDIUMBAND;
+ if (tmp < 0)
+ tmp = 0;
+ data[0] = 0x80;
+ data[0] |= tmp << 5;
+ data[0] |= period<<3;
+ } else /* Harmony */
+ {
+ data[0] = 0x60;
+ data[0] |= (st->bandwidth-BANDWIDTH_SUPERWIDEBAND)<<4;
+ data[0] |= (period-2)<<3;
+ }
+ /*printf ("%x\n", (int)data[0]);*/
+
+ return ret+1;
+}
+
+void harmony_encoder_ctl(HarmonyEncoder *st, int request, ...)
+{
+ va_list ap;
+
+ va_start(ap, request);
+
+ switch (request)
+ {
+ case HARMONY_SET_MODE_REQUEST:
+ {
+ int value = va_arg(ap, int);
+ st->mode = value;
+ }
+ break;
+ case HARMONY_GET_MODE_REQUEST:
+ {
+ int *value = va_arg(ap, int*);
+ *value = st->mode;
+ }
+ break;
+ case HARMONY_SET_BANDWIDTH_REQUEST:
+ {
+ int value = va_arg(ap, int);
+ st->bandwidth = value;
+ }
+ break;
+ case HARMONY_GET_BANDWIDTH_REQUEST:
+ {
+ int *value = va_arg(ap, int*);
+ *value = st->bandwidth;
+ }
+ break;
+ case HARMONY_SET_VBR_RATE_REQUEST:
+ {
+ int value = va_arg(ap, int);
+ st->vbr_rate = value;
+ }
+ break;
+ case HARMONY_GET_VBR_RATE_REQUEST:
+ {
+ int *value = va_arg(ap, int*);
+ *value = st->vbr_rate;
+ }
+ break;
+ default:
+ fprintf(stderr, "unknown harmony_encoder_ctl() request: %d", request);
+ break;
+ }
+
+ va_end(ap);
+}
+
+void harmony_encoder_destroy(HarmonyEncoder *st)
+{
+ celt_mode_destroy(st->celt_mode);
+ free(st);
+}
+