mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-15 14:28:24 +00:00
Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio ConfBridge, and other stuff
-Functional changes 1. Dynamic global format list build by codecs defined in codecs.conf 2. SILK 8khz, 12khz, 16khz, and 24khz with custom attributes defined in codecs.conf 3. Negotiation of SILK attributes in chan_sip. 4. SPEEX 32khz with translation 5. SLINEAR 8khz, 12khz, 24khz, 32khz, 44.1khz, 48khz, 96khz, 192khz with translation using codec_resample.c 6. Various changes to RTP code required to properly handle the dynamic format list and formats with attributes. 7. ConfBridge now dynamically jumps to the best possible sample rate. This allows for conferences to take advantage of HD audio (Which sounds awesome) 8. Audiohooks are no longer limited to 8khz audio, and most effects have been updated to take advantage of this such as Volume, DENOISE, PITCH_SHIFT. 9. codec_resample now uses its own code rather than depending on libresample. -Organizational changes Global format list is moved from frame.c to format.c Various format specific functions moved from frame.c to format.c Review: https://reviewboard.asterisk.org/r/1104/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@308582 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -29,11 +29,13 @@ GSM_INCLUDE:=-Igsm/inc
|
||||
$(if $(filter codec_gsm,$(EMBEDDED_MODS)),modules.link,codec_gsm.so): gsm/lib/libgsm.a
|
||||
endif
|
||||
|
||||
|
||||
clean::
|
||||
$(MAKE) -C gsm clean
|
||||
$(MAKE) -C lpc10 clean
|
||||
$(MAKE) -C ilbc clean
|
||||
rm -f g722/*.[oa]
|
||||
rm -f speex/*.[oa]
|
||||
|
||||
gsm/lib/libgsm.a:
|
||||
@mkdir -p gsm/lib
|
||||
@@ -47,7 +49,17 @@ $(if $(filter codec_lpc10,$(EMBEDDED_MODS)),modules.link,codec_lpc10.so): $(LIBL
|
||||
$(LIBILBC):
|
||||
@$(MAKE) -C ilbc all _ASTCFLAGS="$(filter-out -Wmissing-prototypes -Wmissing-declarations -Wshadow,$(_ASTCFLAGS)) $(AST_NO_STRICT_OVERFLOW)"
|
||||
|
||||
|
||||
$(if $(filter codec_ilbc,$(EMBEDDED_MODS)),modules.link,codec_ilbc.so): $(LIBILBC)
|
||||
|
||||
$(if $(filter codec_g722,$(EMBEDDED_MODS)),modules.link,codec_g722.so): g722/g722_encode.o g722/g722_decode.o
|
||||
g722/g722_encode.o g722/g722_decode.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,codec_g722)
|
||||
|
||||
ifeq ($(BUILD_CPU),x86_64)
|
||||
SPEEX_RESAMPLE_CFLAGS:=-fPIC
|
||||
else
|
||||
SPEEX_RESAMPLE_CFLAGS:=
|
||||
endif
|
||||
|
||||
$(if $(filter codec_resample,$(EMBEDDED_MODS)),modules.link,codec_resample.so): speex/resample.o
|
||||
speex/resample.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,codec_resample) $(SPEEX_RESAMPLE_CFLAGS)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2007, Digium, Inc.
|
||||
* Copyright (C) 2011, Digium, Inc.
|
||||
*
|
||||
* Russell Bryant <russell@digium.com>
|
||||
* David Vossel <dvossel@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
@@ -21,9 +22,6 @@
|
||||
*
|
||||
* \brief Resample slinear audio
|
||||
*
|
||||
* \note To install libresample, check it out of the following repository:
|
||||
* <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
|
||||
*
|
||||
* \ingroup codecs
|
||||
*/
|
||||
|
||||
@@ -32,170 +30,75 @@
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
#include "speex/speex_resampler.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
/* These are for SHRT_MAX and FLT_MAX -- { */
|
||||
#if defined(__Darwin__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
|
||||
#include <float.h>
|
||||
#else
|
||||
#include <values.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
/* } */
|
||||
|
||||
#include <libresample.h>
|
||||
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
|
||||
#include "asterisk/slin.h"
|
||||
|
||||
#define RESAMPLER_QUALITY 1
|
||||
|
||||
#define OUTBUF_SIZE 8096
|
||||
|
||||
struct slin16_to_slin8_pvt {
|
||||
void *resampler;
|
||||
float resample_factor;
|
||||
static struct ast_translator *translators;
|
||||
static int trans_size;
|
||||
static int id_list[] = {
|
||||
AST_FORMAT_SLINEAR,
|
||||
AST_FORMAT_SLINEAR12,
|
||||
AST_FORMAT_SLINEAR16,
|
||||
AST_FORMAT_SLINEAR24,
|
||||
AST_FORMAT_SLINEAR32,
|
||||
AST_FORMAT_SLINEAR44,
|
||||
AST_FORMAT_SLINEAR48,
|
||||
AST_FORMAT_SLINEAR96,
|
||||
AST_FORMAT_SLINEAR192,
|
||||
};
|
||||
|
||||
struct slin8_to_slin16_pvt {
|
||||
void *resampler;
|
||||
float resample_factor;
|
||||
};
|
||||
|
||||
static int slin16_to_slin8_new(struct ast_trans_pvt *pvt)
|
||||
static int resamp_new(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
|
||||
int err;
|
||||
|
||||
resamp_pvt->resample_factor = 8000.0 / 16000.0;
|
||||
|
||||
if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
|
||||
if (!(pvt->pvt = speex_resampler_init(1, ast_format_rate(&pvt->t->src_format), ast_format_rate(&pvt->t->dst_format), 5, &err))) {
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slin8_to_slin16_new(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
|
||||
|
||||
resamp_pvt->resample_factor = 16000.0 / 8000.0;
|
||||
|
||||
if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void slin16_to_slin8_destroy(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
|
||||
|
||||
if (resamp_pvt->resampler)
|
||||
resample_close(resamp_pvt->resampler);
|
||||
}
|
||||
|
||||
static void slin8_to_slin16_destroy(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
|
||||
|
||||
if (resamp_pvt->resampler)
|
||||
resample_close(resamp_pvt->resampler);
|
||||
}
|
||||
|
||||
static int resample_frame(struct ast_trans_pvt *pvt,
|
||||
void *resampler, float resample_factor, struct ast_frame *f)
|
||||
{
|
||||
int total_in_buf_used = 0;
|
||||
int total_out_buf_used = 0;
|
||||
int16_t *in_buf = (int16_t *) f->data.ptr;
|
||||
int16_t *out_buf = pvt->outbuf.i16 + pvt->samples;
|
||||
float in_buf_f[f->samples];
|
||||
float out_buf_f[2048];
|
||||
int res = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < f->samples; i++)
|
||||
in_buf_f[i] = in_buf[i] * (FLT_MAX / SHRT_MAX);
|
||||
|
||||
while (total_in_buf_used < f->samples) {
|
||||
int in_buf_used, out_buf_used;
|
||||
|
||||
out_buf_used = resample_process(resampler, resample_factor,
|
||||
&in_buf_f[total_in_buf_used], f->samples - total_in_buf_used,
|
||||
0, &in_buf_used,
|
||||
&out_buf_f[total_out_buf_used], ARRAY_LEN(out_buf_f) - total_out_buf_used);
|
||||
|
||||
if (out_buf_used < 0)
|
||||
break;
|
||||
|
||||
total_out_buf_used += out_buf_used;
|
||||
total_in_buf_used += in_buf_used;
|
||||
|
||||
if (total_out_buf_used == ARRAY_LEN(out_buf_f)) {
|
||||
ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < total_out_buf_used; i++)
|
||||
out_buf[i] = out_buf_f[i] * (SHRT_MAX / FLT_MAX);
|
||||
|
||||
pvt->samples += total_out_buf_used;
|
||||
pvt->datalen += (total_out_buf_used * sizeof(int16_t));
|
||||
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slin16_to_slin8_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
||||
static void resamp_destroy(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
|
||||
void *resampler = resamp_pvt->resampler;
|
||||
float resample_factor = resamp_pvt->resample_factor;
|
||||
|
||||
return resample_frame(pvt, resampler, resample_factor, f);
|
||||
SpeexResamplerState *resamp_pvt = pvt->pvt;
|
||||
speex_resampler_destroy(resamp_pvt);
|
||||
}
|
||||
|
||||
static int slin8_to_slin16_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
||||
static int resamp_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
||||
{
|
||||
struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
|
||||
void *resampler = resamp_pvt->resampler;
|
||||
float resample_factor = resamp_pvt->resample_factor;
|
||||
SpeexResamplerState *resamp_pvt = pvt->pvt;
|
||||
unsigned int out_samples = (OUTBUF_SIZE / sizeof(int16_t)) - pvt->samples;
|
||||
unsigned int in_samples = f->samples;
|
||||
|
||||
return resample_frame(pvt, resampler, resample_factor, f);
|
||||
speex_resampler_process_int(resamp_pvt,
|
||||
0,
|
||||
f->data.ptr,
|
||||
&in_samples,
|
||||
pvt->outbuf.i16 + pvt->samples,
|
||||
&out_samples);
|
||||
|
||||
pvt->samples += out_samples;
|
||||
pvt->datalen += out_samples * 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_translator slin16_to_slin8 = {
|
||||
.name = "slin16_to_slin8",
|
||||
.newpvt = slin16_to_slin8_new,
|
||||
.destroy = slin16_to_slin8_destroy,
|
||||
.framein = slin16_to_slin8_framein,
|
||||
.sample = slin16_sample,
|
||||
.desc_size = sizeof(struct slin16_to_slin8_pvt),
|
||||
.buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
|
||||
.buf_size = OUTBUF_SIZE,
|
||||
};
|
||||
|
||||
static struct ast_translator slin8_to_slin16 = {
|
||||
.name = "slin8_to_slin16",
|
||||
.newpvt = slin8_to_slin16_new,
|
||||
.destroy = slin8_to_slin16_destroy,
|
||||
.framein = slin8_to_slin16_framein,
|
||||
.sample = slin8_sample,
|
||||
.desc_size = sizeof(struct slin8_to_slin16_pvt),
|
||||
.buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
|
||||
.buf_size = OUTBUF_SIZE,
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
int idx;
|
||||
|
||||
res |= ast_unregister_translator(&slin16_to_slin8);
|
||||
res |= ast_unregister_translator(&slin8_to_slin16);
|
||||
for (idx = 0; idx < trans_size; idx++) {
|
||||
res |= ast_unregister_translator(&translators[idx]);
|
||||
}
|
||||
ast_free(translators);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -203,15 +106,33 @@ static int unload_module(void)
|
||||
static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
int x, y, idx = 0;
|
||||
|
||||
ast_format_set(&slin16_to_slin8.src_format, AST_FORMAT_SLINEAR16, 0);
|
||||
ast_format_set(&slin16_to_slin8.dst_format, AST_FORMAT_SLINEAR, 0);
|
||||
trans_size = ARRAY_LEN(id_list) * ARRAY_LEN(id_list);
|
||||
if (!(translators = ast_calloc(1, sizeof(struct ast_translator) * trans_size))) {
|
||||
return AST_MODULE_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
ast_format_set(&slin8_to_slin16.src_format, AST_FORMAT_SLINEAR, 0);
|
||||
ast_format_set(&slin8_to_slin16.dst_format, AST_FORMAT_SLINEAR16, 0);
|
||||
for (x = 0; x < ARRAY_LEN(id_list); x++) {
|
||||
for (y = 0; y < ARRAY_LEN(id_list); y++) {
|
||||
if (x == y) {
|
||||
continue;
|
||||
}
|
||||
translators[idx].newpvt = resamp_new;
|
||||
translators[idx].destroy = resamp_destroy;
|
||||
translators[idx].framein = resamp_framein;
|
||||
translators[idx].desc_size = 0;
|
||||
translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t));
|
||||
translators[idx].buf_size = OUTBUF_SIZE;
|
||||
ast_format_set(&translators[idx].src_format, id_list[x], 0);
|
||||
ast_format_set(&translators[idx].dst_format, id_list[y], 0);
|
||||
snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %dkhz -> %dkhz",
|
||||
ast_format_rate(&translators[idx].src_format), ast_format_rate(&translators[idx].dst_format));
|
||||
res |= ast_register_translator(&translators[idx]);
|
||||
idx++;
|
||||
}
|
||||
|
||||
res |= ast_register_translator(&slin16_to_slin8);
|
||||
res |= ast_register_translator(&slin8_to_slin16);
|
||||
}
|
||||
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -148,6 +148,11 @@ static int lin16tospeexwb_new(struct ast_trans_pvt *pvt)
|
||||
return speex_encoder_construct(pvt, &speex_wb_mode, 16000);
|
||||
}
|
||||
|
||||
static int lin32tospeexuwb_new(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
return speex_encoder_construct(pvt, &speex_uwb_mode, 32000);
|
||||
}
|
||||
|
||||
static int speex_decoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile)
|
||||
{
|
||||
struct speex_coder_pvt *tmp = pvt->pvt;
|
||||
@@ -173,6 +178,11 @@ static int speexwbtolin16_new(struct ast_trans_pvt *pvt)
|
||||
return speex_decoder_construct(pvt, &speex_wb_mode);
|
||||
}
|
||||
|
||||
static int speexuwbtolin32_new(struct ast_trans_pvt *pvt)
|
||||
{
|
||||
return speex_decoder_construct(pvt, &speex_uwb_mode);
|
||||
}
|
||||
|
||||
/*! \brief convert and store into outbuf */
|
||||
static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
||||
{
|
||||
@@ -376,6 +386,28 @@ static struct ast_translator lin16tospeexwb = {
|
||||
.buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
|
||||
};
|
||||
|
||||
static struct ast_translator speexuwbtolin32 = {
|
||||
.name = "speexuwbtolin32",
|
||||
.newpvt = speexuwbtolin32_new,
|
||||
.framein = speextolin_framein,
|
||||
.destroy = speextolin_destroy,
|
||||
.desc_size = sizeof(struct speex_coder_pvt),
|
||||
.buffer_samples = BUFFER_SAMPLES,
|
||||
.buf_size = BUFFER_SAMPLES * 2,
|
||||
.native_plc = 1,
|
||||
};
|
||||
|
||||
static struct ast_translator lin32tospeexuwb = {
|
||||
.name = "lin32tospeexuwb",
|
||||
.newpvt = lin32tospeexuwb_new,
|
||||
.framein = lintospeex_framein,
|
||||
.frameout = lintospeex_frameout,
|
||||
.destroy = lintospeex_destroy,
|
||||
.desc_size = sizeof(struct speex_coder_pvt),
|
||||
.buffer_samples = BUFFER_SAMPLES,
|
||||
.buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
|
||||
};
|
||||
|
||||
static int parse_config(int reload)
|
||||
{
|
||||
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
||||
@@ -486,6 +518,9 @@ static int unload_module(void)
|
||||
res |= ast_unregister_translator(&lintospeex);
|
||||
res |= ast_unregister_translator(&speexwbtolin16);
|
||||
res |= ast_unregister_translator(&lin16tospeexwb);
|
||||
res |= ast_unregister_translator(&speexuwbtolin32);
|
||||
res |= ast_unregister_translator(&lin32tospeexuwb);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -510,10 +545,19 @@ static int load_module(void)
|
||||
ast_format_set(&lin16tospeexwb.src_format, AST_FORMAT_SLINEAR16, 0);
|
||||
ast_format_set(&lin16tospeexwb.dst_format, AST_FORMAT_SPEEX16, 0);
|
||||
|
||||
ast_format_set(&speexuwbtolin32.src_format, AST_FORMAT_SPEEX32, 0);
|
||||
ast_format_set(&speexuwbtolin32.dst_format, AST_FORMAT_SLINEAR32, 0);
|
||||
|
||||
ast_format_set(&lin32tospeexuwb.src_format, AST_FORMAT_SLINEAR32, 0);
|
||||
ast_format_set(&lin32tospeexuwb.dst_format, AST_FORMAT_SPEEX32, 0);
|
||||
|
||||
res |= ast_register_translator(&speextolin);
|
||||
res |= ast_register_translator(&lintospeex);
|
||||
res |= ast_register_translator(&speexwbtolin16);
|
||||
res |= ast_register_translator(&lin16tospeexwb);
|
||||
res |= ast_register_translator(&speexuwbtolin32);
|
||||
res |= ast_register_translator(&lin32tospeexuwb);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
241
codecs/speex/arch.h
Normal file
241
codecs/speex/arch.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/* Copyright (C) 2003 Jean-Marc Valin */
|
||||
/**
|
||||
@file arch.h
|
||||
@brief Various architecture definitions Speex
|
||||
*/
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ARCH_H
|
||||
#define ARCH_H
|
||||
|
||||
#ifndef SPEEX_VERSION
|
||||
#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
|
||||
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
|
||||
#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
|
||||
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
|
||||
#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
|
||||
#endif
|
||||
|
||||
#define FIXED_POINT
|
||||
|
||||
/* A couple test to catch stupid option combinations */
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
#error You cannot compile as floating point and fixed point at the same time
|
||||
#endif
|
||||
#ifdef _USE_SSE
|
||||
#error SSE is only for floating-point
|
||||
#endif
|
||||
#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))
|
||||
#error Make up your mind. What CPU do you have?
|
||||
#endif
|
||||
#ifdef VORBIS_PSYCHO
|
||||
#error Vorbis-psy model currently not implemented in fixed-point
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef FLOATING_POINT
|
||||
#error You now need to define either FIXED_POINT or FLOATING_POINT
|
||||
#endif
|
||||
#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)
|
||||
#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
|
||||
#endif
|
||||
#ifdef FIXED_POINT_DEBUG
|
||||
#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef OUTSIDE_SPEEX
|
||||
#include "speex/speex_types.h"
|
||||
#endif
|
||||
|
||||
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
|
||||
#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
|
||||
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
|
||||
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
typedef spx_int16_t spx_word16_t;
|
||||
typedef spx_int32_t spx_word32_t;
|
||||
typedef spx_word32_t spx_mem_t;
|
||||
typedef spx_word16_t spx_coef_t;
|
||||
typedef spx_word16_t spx_lsp_t;
|
||||
typedef spx_word32_t spx_sig_t;
|
||||
|
||||
#define Q15ONE 32767
|
||||
|
||||
#define LPC_SCALING 8192
|
||||
#define SIG_SCALING 16384
|
||||
#define LSP_SCALING 8192.
|
||||
#define GAMMA_SCALING 32768.
|
||||
#define GAIN_SCALING 64
|
||||
#define GAIN_SCALING_1 0.015625
|
||||
|
||||
#define LPC_SHIFT 13
|
||||
#define LSP_SHIFT 13
|
||||
#define SIG_SHIFT 14
|
||||
#define GAIN_SHIFT 6
|
||||
|
||||
#define VERY_SMALL 0
|
||||
#define VERY_LARGE32 ((spx_word32_t)2147483647)
|
||||
#define VERY_LARGE16 ((spx_word16_t)32767)
|
||||
#define Q15_ONE ((spx_word16_t)32767)
|
||||
|
||||
|
||||
#ifdef FIXED_DEBUG
|
||||
#include "fixed_debug.h"
|
||||
#else
|
||||
|
||||
#include "fixed_generic.h"
|
||||
|
||||
#ifdef ARM5E_ASM
|
||||
#include "fixed_arm5e.h"
|
||||
#elif defined (ARM4_ASM)
|
||||
#include "fixed_arm4.h"
|
||||
#elif defined (BFIN_ASM)
|
||||
#include "fixed_bfin.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
|
||||
typedef float spx_mem_t;
|
||||
typedef float spx_coef_t;
|
||||
typedef float spx_lsp_t;
|
||||
typedef float spx_sig_t;
|
||||
typedef float spx_word16_t;
|
||||
typedef float spx_word32_t;
|
||||
|
||||
#define Q15ONE 1.0f
|
||||
#define LPC_SCALING 1.f
|
||||
#define SIG_SCALING 1.f
|
||||
#define LSP_SCALING 1.f
|
||||
#define GAMMA_SCALING 1.f
|
||||
#define GAIN_SCALING 1.f
|
||||
#define GAIN_SCALING_1 1.f
|
||||
|
||||
|
||||
#define VERY_SMALL 1e-15f
|
||||
#define VERY_LARGE32 1e15f
|
||||
#define VERY_LARGE16 1e15f
|
||||
#define Q15_ONE ((spx_word16_t)1.f)
|
||||
|
||||
#define QCONST16(x,bits) (x)
|
||||
#define QCONST32(x,bits) (x)
|
||||
|
||||
#define NEG16(x) (-(x))
|
||||
#define NEG32(x) (-(x))
|
||||
#define EXTRACT16(x) (x)
|
||||
#define EXTEND32(x) (x)
|
||||
#define SHR16(a,shift) (a)
|
||||
#define SHL16(a,shift) (a)
|
||||
#define SHR32(a,shift) (a)
|
||||
#define SHL32(a,shift) (a)
|
||||
#define PSHR16(a,shift) (a)
|
||||
#define PSHR32(a,shift) (a)
|
||||
#define VSHR32(a,shift) (a)
|
||||
#define SATURATE16(x,a) (x)
|
||||
#define SATURATE32(x,a) (x)
|
||||
|
||||
#define PSHR(a,shift) (a)
|
||||
#define SHR(a,shift) (a)
|
||||
#define SHL(a,shift) (a)
|
||||
#define SATURATE(x,a) (x)
|
||||
|
||||
#define ADD16(a,b) ((a)+(b))
|
||||
#define SUB16(a,b) ((a)-(b))
|
||||
#define ADD32(a,b) ((a)+(b))
|
||||
#define SUB32(a,b) ((a)-(b))
|
||||
#define MULT16_16_16(a,b) ((a)*(b))
|
||||
#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b))
|
||||
#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
|
||||
|
||||
#define MULT16_32_Q11(a,b) ((a)*(b))
|
||||
#define MULT16_32_Q13(a,b) ((a)*(b))
|
||||
#define MULT16_32_Q14(a,b) ((a)*(b))
|
||||
#define MULT16_32_Q15(a,b) ((a)*(b))
|
||||
#define MULT16_32_P15(a,b) ((a)*(b))
|
||||
|
||||
#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
|
||||
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
|
||||
|
||||
#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b))
|
||||
#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b))
|
||||
#define MAC16_16_P13(c,a,b) ((c)+(a)*(b))
|
||||
#define MULT16_16_Q11_32(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q13(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q14(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q15(a,b) ((a)*(b))
|
||||
#define MULT16_16_P15(a,b) ((a)*(b))
|
||||
#define MULT16_16_P13(a,b) ((a)*(b))
|
||||
#define MULT16_16_P14(a,b) ((a)*(b))
|
||||
|
||||
#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
|
||||
#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
|
||||
#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
|
||||
#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
|
||||
|
||||
/* 2 on TI C5x DSP */
|
||||
#define BYTES_PER_CHAR 2
|
||||
#define BITS_PER_CHAR 16
|
||||
#define LOG2_BITS_PER_CHAR 4
|
||||
|
||||
#else
|
||||
|
||||
#define BYTES_PER_CHAR 1
|
||||
#define BITS_PER_CHAR 8
|
||||
#define LOG2_BITS_PER_CHAR 3
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef FIXED_DEBUG
|
||||
extern long long spx_mips;
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
106
codecs/speex/fixed_generic.h
Normal file
106
codecs/speex/fixed_generic.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* Copyright (C) 2003 Jean-Marc Valin */
|
||||
/**
|
||||
@file fixed_generic.h
|
||||
@brief Generic fixed-point operations
|
||||
*/
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_GENERIC_H
|
||||
#define FIXED_GENERIC_H
|
||||
|
||||
#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
|
||||
#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
|
||||
|
||||
#define NEG16(x) (-(x))
|
||||
#define NEG32(x) (-(x))
|
||||
#define EXTRACT16(x) ((spx_word16_t)(x))
|
||||
#define EXTEND32(x) ((spx_word32_t)(x))
|
||||
#define SHR16(a,shift) ((a) >> (shift))
|
||||
#define SHL16(a,shift) ((a) << (shift))
|
||||
#define SHR32(a,shift) ((a) >> (shift))
|
||||
#define SHL32(a,shift) ((a) << (shift))
|
||||
#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift))
|
||||
#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
|
||||
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
|
||||
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||
#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||
|
||||
#define SHR(a,shift) ((a) >> (shift))
|
||||
#define SHL(a,shift) ((spx_word32_t)(a) << (shift))
|
||||
#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
|
||||
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||
|
||||
|
||||
#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
|
||||
#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
|
||||
#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
|
||||
#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
|
||||
|
||||
|
||||
/* result fits in 16 bits */
|
||||
#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b))))
|
||||
|
||||
/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
|
||||
#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
|
||||
|
||||
#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
|
||||
#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
|
||||
#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
|
||||
#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
|
||||
|
||||
#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
|
||||
#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
|
||||
|
||||
#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
|
||||
#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
|
||||
#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
|
||||
|
||||
|
||||
#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11)))
|
||||
#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13)))
|
||||
#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
|
||||
|
||||
#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
|
||||
#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
|
||||
#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
|
||||
#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
|
||||
|
||||
#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
|
||||
#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
|
||||
#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
|
||||
|
||||
#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15))
|
||||
|
||||
#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b))))
|
||||
#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b))))
|
||||
#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b)))
|
||||
#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b)))
|
||||
|
||||
#endif
|
||||
1124
codecs/speex/resample.c
Normal file
1124
codecs/speex/resample.c
Normal file
File diff suppressed because it is too large
Load Diff
128
codecs/speex/resample_sse.h
Normal file
128
codecs/speex/resample_sse.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* Copyright (C) 2007-2008 Jean-Marc Valin
|
||||
* Copyright (C) 2008 Thorvald Natvig
|
||||
*/
|
||||
/**
|
||||
@file resample_sse.h
|
||||
@brief Resampler functions (SSE version)
|
||||
*/
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#define OVERRIDE_INNER_PRODUCT_SINGLE
|
||||
static inline float inner_product_single(const float *a, const float *b, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
float ret;
|
||||
__m128 sum = _mm_setzero_ps();
|
||||
for (i=0;i<len;i+=8)
|
||||
{
|
||||
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i)));
|
||||
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4)));
|
||||
}
|
||||
sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
|
||||
sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
|
||||
_mm_store_ss(&ret, sum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
|
||||
static inline float interpolate_product_single(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
|
||||
int i;
|
||||
float ret;
|
||||
__m128 sum = _mm_setzero_ps();
|
||||
__m128 f = _mm_loadu_ps(frac);
|
||||
for(i=0;i<len;i+=2)
|
||||
{
|
||||
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample)));
|
||||
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample)));
|
||||
}
|
||||
sum = _mm_mul_ps(f, sum);
|
||||
sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
|
||||
sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
|
||||
_mm_store_ss(&ret, sum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef _USE_SSE2
|
||||
#include <emmintrin.h>
|
||||
#define OVERRIDE_INNER_PRODUCT_DOUBLE
|
||||
|
||||
static inline double inner_product_double(const float *a, const float *b, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
double ret;
|
||||
__m128d sum = _mm_setzero_pd();
|
||||
__m128 t;
|
||||
for (i=0;i<len;i+=8)
|
||||
{
|
||||
t = _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i));
|
||||
sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
|
||||
sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
|
||||
|
||||
t = _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4));
|
||||
sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
|
||||
sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
|
||||
}
|
||||
sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
|
||||
_mm_store_sd(&ret, sum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
|
||||
static inline double interpolate_product_double(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
|
||||
int i;
|
||||
double ret;
|
||||
__m128d sum;
|
||||
__m128d sum1 = _mm_setzero_pd();
|
||||
__m128d sum2 = _mm_setzero_pd();
|
||||
__m128 f = _mm_loadu_ps(frac);
|
||||
__m128d f1 = _mm_cvtps_pd(f);
|
||||
__m128d f2 = _mm_cvtps_pd(_mm_movehl_ps(f,f));
|
||||
__m128 t;
|
||||
for(i=0;i<len;i+=2)
|
||||
{
|
||||
t = _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample));
|
||||
sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
|
||||
sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
|
||||
|
||||
t = _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample));
|
||||
sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
|
||||
sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
|
||||
}
|
||||
sum1 = _mm_mul_pd(f1, sum1);
|
||||
sum2 = _mm_mul_pd(f2, sum2);
|
||||
sum = _mm_add_pd(sum1, sum2);
|
||||
sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
|
||||
_mm_store_sd(&ret, sum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
342
codecs/speex/speex_resampler.h
Normal file
342
codecs/speex/speex_resampler.h
Normal file
@@ -0,0 +1,342 @@
|
||||
/* Copyright (C) 2007 Jean-Marc Valin
|
||||
|
||||
File: speex_resampler.h
|
||||
Resampling code
|
||||
|
||||
The design goals of this code are:
|
||||
- Very fast algorithm
|
||||
- Low memory requirement
|
||||
- Good *perceptual* quality (and not best SNR)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SPEEX_RESAMPLER_H
|
||||
#define SPEEX_RESAMPLER_H
|
||||
|
||||
#define OUTSIDE_SPEEX
|
||||
|
||||
#ifdef OUTSIDE_SPEEX
|
||||
|
||||
/********* WARNING: MENTAL SANITY ENDS HERE *************/
|
||||
|
||||
/* If the resampler is defined outside of Speex, we change the symbol names so that
|
||||
there won't be any clash if linking with Speex later on. */
|
||||
|
||||
#define RANDOM_PREFIX ast
|
||||
#ifndef RANDOM_PREFIX
|
||||
#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes"
|
||||
#endif
|
||||
|
||||
#define CAT_PREFIX2(a,b) a ## b
|
||||
#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
|
||||
|
||||
#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
|
||||
#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
|
||||
#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
|
||||
#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)
|
||||
#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)
|
||||
#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)
|
||||
#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)
|
||||
#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)
|
||||
#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)
|
||||
#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)
|
||||
#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)
|
||||
#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)
|
||||
#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
|
||||
#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
|
||||
#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
|
||||
#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
|
||||
#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
|
||||
#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
|
||||
#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
|
||||
#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
|
||||
#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
|
||||
#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
|
||||
|
||||
#define spx_int16_t short
|
||||
#define spx_int32_t int
|
||||
#define spx_uint16_t unsigned short
|
||||
#define spx_uint32_t unsigned int
|
||||
|
||||
#else /* OUTSIDE_SPEEX */
|
||||
|
||||
#include "speex/speex_types.h"
|
||||
|
||||
#endif /* OUTSIDE_SPEEX */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SPEEX_RESAMPLER_QUALITY_MAX 10
|
||||
#define SPEEX_RESAMPLER_QUALITY_MIN 0
|
||||
#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
|
||||
#define SPEEX_RESAMPLER_QUALITY_VOIP 3
|
||||
#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
|
||||
|
||||
enum {
|
||||
RESAMPLER_ERR_SUCCESS = 0,
|
||||
RESAMPLER_ERR_ALLOC_FAILED = 1,
|
||||
RESAMPLER_ERR_BAD_STATE = 2,
|
||||
RESAMPLER_ERR_INVALID_ARG = 3,
|
||||
RESAMPLER_ERR_PTR_OVERLAP = 4,
|
||||
|
||||
RESAMPLER_ERR_MAX_ERROR
|
||||
};
|
||||
|
||||
struct SpeexResamplerState_;
|
||||
typedef struct SpeexResamplerState_ SpeexResamplerState;
|
||||
|
||||
/** Create a new resampler with integer input and output rates.
|
||||
* @param nb_channels Number of channels to be processed
|
||||
* @param in_rate Input sampling rate (integer number of Hz).
|
||||
* @param out_rate Output sampling rate (integer number of Hz).
|
||||
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
|
||||
* and 10 has very high quality.
|
||||
* @return Newly created resampler state
|
||||
* @retval NULL Error: not enough memory
|
||||
*/
|
||||
SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
|
||||
spx_uint32_t in_rate,
|
||||
spx_uint32_t out_rate,
|
||||
int quality,
|
||||
int *err);
|
||||
|
||||
/** Create a new resampler with fractional input/output rates. The sampling
|
||||
* rate ratio is an arbitrary rational number with both the numerator and
|
||||
* denominator being 32-bit integers.
|
||||
* @param nb_channels Number of channels to be processed
|
||||
* @param ratio_num Numerator of the sampling rate ratio
|
||||
* @param ratio_den Denominator of the sampling rate ratio
|
||||
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
|
||||
* @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
|
||||
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
|
||||
* and 10 has very high quality.
|
||||
* @return Newly created resampler state
|
||||
* @retval NULL Error: not enough memory
|
||||
*/
|
||||
SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
|
||||
spx_uint32_t ratio_num,
|
||||
spx_uint32_t ratio_den,
|
||||
spx_uint32_t in_rate,
|
||||
spx_uint32_t out_rate,
|
||||
int quality,
|
||||
int *err);
|
||||
|
||||
/** Destroy a resampler state.
|
||||
* @param st Resampler state
|
||||
*/
|
||||
void speex_resampler_destroy(SpeexResamplerState *st);
|
||||
|
||||
/** Resample a float array. The input and output buffers must *not* overlap.
|
||||
* @param st Resampler state
|
||||
* @param channel_index Index of the channel to process for the multi-channel
|
||||
* base (0 otherwise)
|
||||
* @param in Input buffer
|
||||
* @param in_len Number of input samples in the input buffer. Returns the
|
||||
* number of samples processed
|
||||
* @param out Output buffer
|
||||
* @param out_len Size of the output buffer. Returns the number of samples written
|
||||
*/
|
||||
int speex_resampler_process_float(SpeexResamplerState *st,
|
||||
spx_uint32_t channel_index,
|
||||
const float *in,
|
||||
spx_uint32_t *in_len,
|
||||
float *out,
|
||||
spx_uint32_t *out_len);
|
||||
|
||||
/** Resample an int array. The input and output buffers must *not* overlap.
|
||||
* @param st Resampler state
|
||||
* @param channel_index Index of the channel to process for the multi-channel
|
||||
* base (0 otherwise)
|
||||
* @param in Input buffer
|
||||
* @param in_len Number of input samples in the input buffer. Returns the number
|
||||
* of samples processed
|
||||
* @param out Output buffer
|
||||
* @param out_len Size of the output buffer. Returns the number of samples written
|
||||
*/
|
||||
int speex_resampler_process_int(SpeexResamplerState *st,
|
||||
spx_uint32_t channel_index,
|
||||
const spx_int16_t *in,
|
||||
spx_uint32_t *in_len,
|
||||
spx_int16_t *out,
|
||||
spx_uint32_t *out_len);
|
||||
|
||||
/** Resample an interleaved float array. The input and output buffers must *not* overlap.
|
||||
* @param st Resampler state
|
||||
* @param in Input buffer
|
||||
* @param in_len Number of input samples in the input buffer. Returns the number
|
||||
* of samples processed. This is all per-channel.
|
||||
* @param out Output buffer
|
||||
* @param out_len Size of the output buffer. Returns the number of samples written.
|
||||
* This is all per-channel.
|
||||
*/
|
||||
int speex_resampler_process_interleaved_float(SpeexResamplerState *st,
|
||||
const float *in,
|
||||
spx_uint32_t *in_len,
|
||||
float *out,
|
||||
spx_uint32_t *out_len);
|
||||
|
||||
/** Resample an interleaved int array. The input and output buffers must *not* overlap.
|
||||
* @param st Resampler state
|
||||
* @param in Input buffer
|
||||
* @param in_len Number of input samples in the input buffer. Returns the number
|
||||
* of samples processed. This is all per-channel.
|
||||
* @param out Output buffer
|
||||
* @param out_len Size of the output buffer. Returns the number of samples written.
|
||||
* This is all per-channel.
|
||||
*/
|
||||
int speex_resampler_process_interleaved_int(SpeexResamplerState *st,
|
||||
const spx_int16_t *in,
|
||||
spx_uint32_t *in_len,
|
||||
spx_int16_t *out,
|
||||
spx_uint32_t *out_len);
|
||||
|
||||
/** Set (change) the input/output sampling rates (integer value).
|
||||
* @param st Resampler state
|
||||
* @param in_rate Input sampling rate (integer number of Hz).
|
||||
* @param out_rate Output sampling rate (integer number of Hz).
|
||||
*/
|
||||
int speex_resampler_set_rate(SpeexResamplerState *st,
|
||||
spx_uint32_t in_rate,
|
||||
spx_uint32_t out_rate);
|
||||
|
||||
/** Get the current input/output sampling rates (integer value).
|
||||
* @param st Resampler state
|
||||
* @param in_rate Input sampling rate (integer number of Hz) copied.
|
||||
* @param out_rate Output sampling rate (integer number of Hz) copied.
|
||||
*/
|
||||
void speex_resampler_get_rate(SpeexResamplerState *st,
|
||||
spx_uint32_t *in_rate,
|
||||
spx_uint32_t *out_rate);
|
||||
|
||||
/** Set (change) the input/output sampling rates and resampling ratio
|
||||
* (fractional values in Hz supported).
|
||||
* @param st Resampler state
|
||||
* @param ratio_num Numerator of the sampling rate ratio
|
||||
* @param ratio_den Denominator of the sampling rate ratio
|
||||
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
|
||||
* @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
|
||||
*/
|
||||
int speex_resampler_set_rate_frac(SpeexResamplerState *st,
|
||||
spx_uint32_t ratio_num,
|
||||
spx_uint32_t ratio_den,
|
||||
spx_uint32_t in_rate,
|
||||
spx_uint32_t out_rate);
|
||||
|
||||
/** Get the current resampling ratio. This will be reduced to the least
|
||||
* common denominator.
|
||||
* @param st Resampler state
|
||||
* @param ratio_num Numerator of the sampling rate ratio copied
|
||||
* @param ratio_den Denominator of the sampling rate ratio copied
|
||||
*/
|
||||
void speex_resampler_get_ratio(SpeexResamplerState *st,
|
||||
spx_uint32_t *ratio_num,
|
||||
spx_uint32_t *ratio_den);
|
||||
|
||||
/** Set (change) the conversion quality.
|
||||
* @param st Resampler state
|
||||
* @param quality Resampling quality between 0 and 10, where 0 has poor
|
||||
* quality and 10 has very high quality.
|
||||
*/
|
||||
int speex_resampler_set_quality(SpeexResamplerState *st,
|
||||
int quality);
|
||||
|
||||
/** Get the conversion quality.
|
||||
* @param st Resampler state
|
||||
* @param quality Resampling quality between 0 and 10, where 0 has poor
|
||||
* quality and 10 has very high quality.
|
||||
*/
|
||||
void speex_resampler_get_quality(SpeexResamplerState *st,
|
||||
int *quality);
|
||||
|
||||
/** Set (change) the input stride.
|
||||
* @param st Resampler state
|
||||
* @param stride Input stride
|
||||
*/
|
||||
void speex_resampler_set_input_stride(SpeexResamplerState *st,
|
||||
spx_uint32_t stride);
|
||||
|
||||
/** Get the input stride.
|
||||
* @param st Resampler state
|
||||
* @param stride Input stride copied
|
||||
*/
|
||||
void speex_resampler_get_input_stride(SpeexResamplerState *st,
|
||||
spx_uint32_t *stride);
|
||||
|
||||
/** Set (change) the output stride.
|
||||
* @param st Resampler state
|
||||
* @param stride Output stride
|
||||
*/
|
||||
void speex_resampler_set_output_stride(SpeexResamplerState *st,
|
||||
spx_uint32_t stride);
|
||||
|
||||
/** Get the output stride.
|
||||
* @param st Resampler state copied
|
||||
* @param stride Output stride
|
||||
*/
|
||||
void speex_resampler_get_output_stride(SpeexResamplerState *st,
|
||||
spx_uint32_t *stride);
|
||||
|
||||
/** Get the latency in input samples introduced by the resampler.
|
||||
* @param st Resampler state
|
||||
*/
|
||||
int speex_resampler_get_input_latency(SpeexResamplerState *st);
|
||||
|
||||
/** Get the latency in output samples introduced by the resampler.
|
||||
* @param st Resampler state
|
||||
*/
|
||||
int speex_resampler_get_output_latency(SpeexResamplerState *st);
|
||||
|
||||
/** Make sure that the first samples to go out of the resamplers don't have
|
||||
* leading zeros. This is only useful before starting to use a newly created
|
||||
* resampler. It is recommended to use that when resampling an audio file, as
|
||||
* it will generate a file with the same length. For real-time processing,
|
||||
* it is probably easier not to use this call (so that the output duration
|
||||
* is the same for the first frame).
|
||||
* @param st Resampler state
|
||||
*/
|
||||
int speex_resampler_skip_zeros(SpeexResamplerState *st);
|
||||
|
||||
/** Reset a resampler so a new (unrelated) stream can be processed.
|
||||
* @param st Resampler state
|
||||
*/
|
||||
int speex_resampler_reset_mem(SpeexResamplerState *st);
|
||||
|
||||
/** Returns the English meaning for an error code
|
||||
* @param err Error code
|
||||
* @return English string
|
||||
*/
|
||||
const char *speex_resampler_strerror(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
115
codecs/speex/stack_alloc.h
Normal file
115
codecs/speex/stack_alloc.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* Copyright (C) 2002 Jean-Marc Valin */
|
||||
/**
|
||||
@file stack_alloc.h
|
||||
@brief Temporary memory allocation on stack
|
||||
*/
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef STACK_ALLOC_H
|
||||
#define STACK_ALLOC_H
|
||||
|
||||
#ifdef USE_ALLOCA
|
||||
# ifdef WIN32
|
||||
# include <malloc.h>
|
||||
# else
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def ALIGN(stack, size)
|
||||
*
|
||||
* Aligns the stack to a 'size' boundary
|
||||
*
|
||||
* @param stack Stack
|
||||
* @param size New size boundary
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def PUSH(stack, size, type)
|
||||
*
|
||||
* Allocates 'size' elements of type 'type' on the stack
|
||||
*
|
||||
* @param stack Stack
|
||||
* @param size Number of elements
|
||||
* @param type Type of element
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def VARDECL(var)
|
||||
*
|
||||
* Declare variable on stack
|
||||
*
|
||||
* @param var Variable to declare
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def ALLOC(var, size, type)
|
||||
*
|
||||
* Allocate 'size' elements of 'type' on stack
|
||||
*
|
||||
* @param var Name of variable to allocate
|
||||
* @param size Number of elements
|
||||
* @param type Type of element
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_VALGRIND
|
||||
|
||||
#include <valgrind/memcheck.h>
|
||||
|
||||
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
|
||||
|
||||
#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
|
||||
|
||||
#else
|
||||
|
||||
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
|
||||
|
||||
#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(VAR_ARRAYS)
|
||||
#define VARDECL(var)
|
||||
#define ALLOC(var, size, type) type var[size]
|
||||
#elif defined(USE_ALLOCA)
|
||||
#define VARDECL(var) var
|
||||
#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))
|
||||
#else
|
||||
#define VARDECL(var) var
|
||||
#define ALLOC(var, size, type) var = PUSH(stack, size, type)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user