Update common_audio
Corresponds to upstream commit 524e9b043e7e86fd72353b987c9d5f6a1ebf83e1 Update notes: * Moved src/ to webrtc/ to easily diff against the third_party/webrtc in the chromium tree * ARM/NEON/MIPS support is not yet hooked up * Tests have not been copied
This commit is contained in:
1
webrtc/Makefile.am
Normal file
1
webrtc/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = common_audio system_wrappers modules
|
227
webrtc/base/checks.h
Normal file
227
webrtc/base/checks.h
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2006 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_CHECKS_H_
|
||||
#define WEBRTC_BASE_CHECKS_H_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// The macros here print a message to stderr and abort under various
|
||||
// conditions. All will accept additional stream messages. For example:
|
||||
// RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar.";
|
||||
//
|
||||
// - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't,
|
||||
// it's better to terminate the process than to continue. During development,
|
||||
// the reason that it's better to terminate might simply be that the error
|
||||
// handling code isn't in place yet; in production, the reason might be that
|
||||
// the author of the code truly believes that x will always be true, but that
|
||||
// she recognizes that if she is wrong, abrupt and unpleasant process
|
||||
// termination is still better than carrying on with the assumption violated.
|
||||
//
|
||||
// RTC_CHECK always evaluates its argument, so it's OK for x to have side
|
||||
// effects.
|
||||
//
|
||||
// - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always
|
||||
// true---except that x will only be evaluated in debug builds; in production
|
||||
// builds, x is simply assumed to be true. This is useful if evaluating x is
|
||||
// expensive and the expected cost of failing to detect the violated
|
||||
// assumption is acceptable. You should not handle cases where a production
|
||||
// build fails to spot a violated condition, even those that would result in
|
||||
// crashes. If the code needs to cope with the error, make it cope, but don't
|
||||
// call RTC_DCHECK; if the condition really can't occur, but you'd sleep
|
||||
// better at night knowing that the process will suicide instead of carrying
|
||||
// on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK.
|
||||
//
|
||||
// RTC_DCHECK only evaluates its argument in debug builds, so if x has visible
|
||||
// side effects, you need to write e.g.
|
||||
// bool w = x; RTC_DCHECK(w);
|
||||
//
|
||||
// - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are
|
||||
// specialized variants of RTC_CHECK and RTC_DCHECK that print prettier
|
||||
// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and
|
||||
// RTC_DCHECK.
|
||||
//
|
||||
// - FATAL() aborts unconditionally.
|
||||
//
|
||||
// TODO(ajm): Ideally, checks.h would be combined with logging.h, but
|
||||
// consolidation with system_wrappers/logging.h should happen first.
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Helper macro which avoids evaluating the arguments to a stream if
|
||||
// the condition doesn't hold.
|
||||
#define RTC_LAZY_STREAM(stream, condition) \
|
||||
!(condition) ? static_cast<void>(0) : rtc::FatalMessageVoidify() & (stream)
|
||||
|
||||
// The actual stream used isn't important. We reference condition in the code
|
||||
// but don't evaluate it; this is to avoid "unused variable" warnings (we do so
|
||||
// in a particularly convoluted way with an extra ?: because that appears to be
|
||||
// the simplest construct that keeps Visual Studio from complaining about
|
||||
// condition being unused).
|
||||
#define RTC_EAT_STREAM_PARAMETERS(condition) \
|
||||
(true ? true : !(condition)) \
|
||||
? static_cast<void>(0) \
|
||||
: rtc::FatalMessageVoidify() & rtc::FatalMessage("", 0).stream()
|
||||
|
||||
// RTC_CHECK dies with a fatal error if condition is not true. It is *not*
|
||||
// controlled by NDEBUG, so the check will be executed regardless of
|
||||
// compilation mode.
|
||||
//
|
||||
// We make sure RTC_CHECK et al. always evaluates their arguments, as
|
||||
// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
|
||||
#define RTC_CHECK(condition) \
|
||||
RTC_LAZY_STREAM(rtc::FatalMessage(__FILE__, __LINE__).stream(), \
|
||||
!(condition)) \
|
||||
<< "Check failed: " #condition << std::endl << "# "
|
||||
|
||||
// Helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use RTC_CHECK_EQ et al below.
|
||||
//
|
||||
// TODO(akalin): Rewrite this so that constructs like if (...)
|
||||
// RTC_CHECK_EQ(...) else { ... } work properly.
|
||||
#define RTC_CHECK_OP(name, op, val1, val2) \
|
||||
if (std::string* _result = \
|
||||
rtc::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \
|
||||
rtc::FatalMessage(__FILE__, __LINE__, _result).stream()
|
||||
|
||||
// Build the error message string. This is separate from the "Impl"
|
||||
// function template because it is not performance critical and so can
|
||||
// be out of line, while the "Impl" code should be inline. Caller
|
||||
// takes ownership of the returned string.
|
||||
template<class t1, class t2>
|
||||
std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
|
||||
std::ostringstream ss;
|
||||
ss << names << " (" << v1 << " vs. " << v2 << ")";
|
||||
std::string* msg = new std::string(ss.str());
|
||||
return msg;
|
||||
}
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
|
||||
// in logging.cc.
|
||||
extern template std::string* MakeCheckOpString<int, int>(
|
||||
const int&, const int&, const char* names);
|
||||
extern template
|
||||
std::string* MakeCheckOpString<unsigned long, unsigned long>(
|
||||
const unsigned long&, const unsigned long&, const char* names);
|
||||
extern template
|
||||
std::string* MakeCheckOpString<unsigned long, unsigned int>(
|
||||
const unsigned long&, const unsigned int&, const char* names);
|
||||
extern template
|
||||
std::string* MakeCheckOpString<unsigned int, unsigned long>(
|
||||
const unsigned int&, const unsigned long&, const char* names);
|
||||
extern template
|
||||
std::string* MakeCheckOpString<std::string, std::string>(
|
||||
const std::string&, const std::string&, const char* name);
|
||||
#endif
|
||||
|
||||
// Helper functions for RTC_CHECK_OP macro.
|
||||
// The (int, int) specialization works around the issue that the compiler
|
||||
// will not instantiate the template version of the function on values of
|
||||
// unnamed enum type - see comment below.
|
||||
#define DEFINE_RTC_CHECK_OP_IMPL(name, op) \
|
||||
template <class t1, class t2> \
|
||||
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
|
||||
const char* names) { \
|
||||
if (v1 op v2) \
|
||||
return NULL; \
|
||||
else \
|
||||
return rtc::MakeCheckOpString(v1, v2, names); \
|
||||
} \
|
||||
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
|
||||
if (v1 op v2) \
|
||||
return NULL; \
|
||||
else \
|
||||
return rtc::MakeCheckOpString(v1, v2, names); \
|
||||
}
|
||||
DEFINE_RTC_CHECK_OP_IMPL(EQ, ==)
|
||||
DEFINE_RTC_CHECK_OP_IMPL(NE, !=)
|
||||
DEFINE_RTC_CHECK_OP_IMPL(LE, <=)
|
||||
DEFINE_RTC_CHECK_OP_IMPL(LT, < )
|
||||
DEFINE_RTC_CHECK_OP_IMPL(GE, >=)
|
||||
DEFINE_RTC_CHECK_OP_IMPL(GT, > )
|
||||
#undef DEFINE_RTC_CHECK_OP_IMPL
|
||||
|
||||
#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(EQ, ==, val1, val2)
|
||||
#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(NE, !=, val1, val2)
|
||||
#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(LE, <=, val1, val2)
|
||||
#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(LT, < , val1, val2)
|
||||
#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(GE, >=, val1, val2)
|
||||
#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(GT, > , val1, val2)
|
||||
|
||||
// The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates
|
||||
// code in debug builds. It does reference the condition parameter in all cases,
|
||||
// though, so callers won't risk getting warnings about unused variables.
|
||||
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
|
||||
#define RTC_DCHECK(condition) RTC_CHECK(condition)
|
||||
#define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2)
|
||||
#define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2)
|
||||
#define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2)
|
||||
#define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2)
|
||||
#define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2)
|
||||
#define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2)
|
||||
#else
|
||||
#define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition)
|
||||
#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) == (v2))
|
||||
#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) != (v2))
|
||||
#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) <= (v2))
|
||||
#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) < (v2))
|
||||
#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) >= (v2))
|
||||
#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) > (v2))
|
||||
#endif
|
||||
|
||||
// This is identical to LogMessageVoidify but in name.
|
||||
class FatalMessageVoidify {
|
||||
public:
|
||||
FatalMessageVoidify() { }
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(std::ostream&) { }
|
||||
};
|
||||
|
||||
#define RTC_UNREACHABLE_CODE_HIT false
|
||||
#define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
|
||||
|
||||
#define FATAL() rtc::FatalMessage(__FILE__, __LINE__).stream()
|
||||
// TODO(ajm): Consider adding RTC_NOTIMPLEMENTED macro when
|
||||
// base/logging.h and system_wrappers/logging.h are consolidated such that we
|
||||
// can match the Chromium behavior.
|
||||
|
||||
// Like a stripped-down LogMessage from logging.h, except that it aborts.
|
||||
class FatalMessage {
|
||||
public:
|
||||
FatalMessage(const char* file, int line);
|
||||
// Used for RTC_CHECK_EQ(), etc. Takes ownership of the given string.
|
||||
FatalMessage(const char* file, int line, std::string* result);
|
||||
NO_RETURN ~FatalMessage();
|
||||
|
||||
std::ostream& stream() { return stream_; }
|
||||
|
||||
private:
|
||||
void Init(const char* file, int line);
|
||||
|
||||
std::ostringstream stream_;
|
||||
};
|
||||
|
||||
// Performs the integer division a/b and returns the result. CHECKs that the
|
||||
// remainder is zero.
|
||||
template <typename T>
|
||||
inline T CheckedDivExact(T a, T b) {
|
||||
RTC_CHECK_EQ(a % b, static_cast<T>(0));
|
||||
return a / b;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_CHECKS_H_
|
34
webrtc/base/constructormagic.h
Normal file
34
webrtc/base/constructormagic.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_CONSTRUCTORMAGIC_H_
|
||||
#define WEBRTC_BASE_CONSTRUCTORMAGIC_H_
|
||||
|
||||
// Put this in the declarations for a class to be unassignable.
|
||||
#define RTC_DISALLOW_ASSIGN(TypeName) \
|
||||
void operator=(const TypeName&) = delete
|
||||
|
||||
// A macro to disallow the copy constructor and operator= functions. This should
|
||||
// be used in the declarations for a class.
|
||||
#define RTC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&) = delete; \
|
||||
RTC_DISALLOW_ASSIGN(TypeName)
|
||||
|
||||
// A macro to disallow all the implicit constructors, namely the default
|
||||
// constructor, copy constructor and operator= functions.
|
||||
//
|
||||
// This should be used in the declarations for a class that wants to prevent
|
||||
// anyone from instantiating it. This is especially useful for classes
|
||||
// containing only static methods.
|
||||
#define RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||
TypeName() = delete; \
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
|
||||
#endif // WEBRTC_BASE_CONSTRUCTORMAGIC_H_
|
636
webrtc/base/scoped_ptr.h
Normal file
636
webrtc/base/scoped_ptr.h
Normal file
@ -0,0 +1,636 @@
|
||||
/*
|
||||
* Copyright 2012 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Borrowed from Chromium's src/base/memory/scoped_ptr.h.
|
||||
|
||||
// Scopers help you manage ownership of a pointer, helping you easily manage a
|
||||
// pointer within a scope, and automatically destroying the pointer at the end
|
||||
// of a scope. There are two main classes you will use, which correspond to the
|
||||
// operators new/delete and new[]/delete[].
|
||||
//
|
||||
// Example usage (scoped_ptr<T>):
|
||||
// {
|
||||
// scoped_ptr<Foo> foo(new Foo("wee"));
|
||||
// } // foo goes out of scope, releasing the pointer with it.
|
||||
//
|
||||
// {
|
||||
// scoped_ptr<Foo> foo; // No pointer managed.
|
||||
// foo.reset(new Foo("wee")); // Now a pointer is managed.
|
||||
// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed.
|
||||
// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
|
||||
// foo->Method(); // Foo::Method() called.
|
||||
// foo.get()->Method(); // Foo::Method() called.
|
||||
// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
|
||||
// // manages a pointer.
|
||||
// foo.reset(new Foo("wee4")); // foo manages a pointer again.
|
||||
// foo.reset(); // Foo("wee4") destroyed, foo no longer
|
||||
// // manages a pointer.
|
||||
// } // foo wasn't managing a pointer, so nothing was destroyed.
|
||||
//
|
||||
// Example usage (scoped_ptr<T[]>):
|
||||
// {
|
||||
// scoped_ptr<Foo[]> foo(new Foo[100]);
|
||||
// foo.get()->Method(); // Foo::Method on the 0th element.
|
||||
// foo[10].Method(); // Foo::Method on the 10th element.
|
||||
// }
|
||||
//
|
||||
// These scopers also implement part of the functionality of C++11 unique_ptr
|
||||
// in that they are "movable but not copyable." You can use the scopers in
|
||||
// the parameter and return types of functions to signify ownership transfer
|
||||
// in to and out of a function. When calling a function that has a scoper
|
||||
// as the argument type, it must be called with the result of an analogous
|
||||
// scoper's Pass() function or another function that generates a temporary;
|
||||
// passing by copy will NOT work. Here is an example using scoped_ptr:
|
||||
//
|
||||
// void TakesOwnership(scoped_ptr<Foo> arg) {
|
||||
// // Do something with arg
|
||||
// }
|
||||
// scoped_ptr<Foo> CreateFoo() {
|
||||
// // No need for calling Pass() because we are constructing a temporary
|
||||
// // for the return value.
|
||||
// return scoped_ptr<Foo>(new Foo("new"));
|
||||
// }
|
||||
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
|
||||
// return arg.Pass();
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
|
||||
// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
|
||||
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
|
||||
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
|
||||
// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr.
|
||||
// }
|
||||
//
|
||||
// Notice that if you do not call Pass() when returning from PassThru(), or
|
||||
// when invoking TakesOwnership(), the code will not compile because scopers
|
||||
// are not copyable; they only implement move semantics which require calling
|
||||
// the Pass() function to signify a destructive transfer of state. CreateFoo()
|
||||
// is different though because we are constructing a temporary on the return
|
||||
// line and thus can avoid needing to call Pass().
|
||||
//
|
||||
// Pass() properly handles upcast in initialization, i.e. you can use a
|
||||
// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
|
||||
//
|
||||
// scoped_ptr<Foo> foo(new Foo());
|
||||
// scoped_ptr<FooParent> parent(foo.Pass());
|
||||
//
|
||||
// PassAs<>() should be used to upcast return value in return statement:
|
||||
//
|
||||
// scoped_ptr<Foo> CreateFoo() {
|
||||
// scoped_ptr<FooChild> result(new FooChild());
|
||||
// return result.PassAs<Foo>();
|
||||
// }
|
||||
//
|
||||
// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
|
||||
// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
|
||||
|
||||
#ifndef WEBRTC_BASE_SCOPED_PTR_H__
|
||||
#define WEBRTC_BASE_SCOPED_PTR_H__
|
||||
|
||||
// This is an implementation designed to match the anticipated future TR2
|
||||
// implementation of the scoped_ptr class.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm> // For std::swap().
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/base/template_util.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Function object which deletes its parameter, which must be a pointer.
|
||||
// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
|
||||
// invokes 'delete'. The default deleter for scoped_ptr<T>.
|
||||
template <class T>
|
||||
struct DefaultDeleter {
|
||||
DefaultDeleter() {}
|
||||
template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
|
||||
// IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
|
||||
// if U* is implicitly convertible to T* and U is not an array type.
|
||||
//
|
||||
// Correct implementation should use SFINAE to disable this
|
||||
// constructor. However, since there are no other 1-argument constructors,
|
||||
// using a static_assert based on is_convertible<> and requiring
|
||||
// complete types is simpler and will cause compile failures for equivalent
|
||||
// misuses.
|
||||
//
|
||||
// Note, the is_convertible<U*, T*> check also ensures that U is not an
|
||||
// array. T is guaranteed to be a non-array, so any U* where U is an array
|
||||
// cannot convert to T*.
|
||||
enum { T_must_be_complete = sizeof(T) };
|
||||
enum { U_must_be_complete = sizeof(U) };
|
||||
static_assert(rtc::is_convertible<U*, T*>::value,
|
||||
"U* must implicitly convert to T*");
|
||||
}
|
||||
inline void operator()(T* ptr) const {
|
||||
enum { type_must_be_complete = sizeof(T) };
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of DefaultDeleter for array types.
|
||||
template <class T>
|
||||
struct DefaultDeleter<T[]> {
|
||||
inline void operator()(T* ptr) const {
|
||||
enum { type_must_be_complete = sizeof(T) };
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Disable this operator for any U != T because it is undefined to execute
|
||||
// an array delete when the static type of the array mismatches the dynamic
|
||||
// type.
|
||||
//
|
||||
// References:
|
||||
// C++98 [expr.delete]p3
|
||||
// http://cplusplus.github.com/LWG/lwg-defects.html#938
|
||||
template <typename U> void operator()(U* array) const;
|
||||
};
|
||||
|
||||
template <class T, int n>
|
||||
struct DefaultDeleter<T[n]> {
|
||||
// Never allow someone to declare something like scoped_ptr<int[10]>.
|
||||
static_assert(sizeof(T) == -1, "do not use array with size as type");
|
||||
};
|
||||
|
||||
// Function object which invokes 'free' on its parameter, which must be
|
||||
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
|
||||
//
|
||||
// scoped_ptr<int, rtc::FreeDeleter> foo_ptr(
|
||||
// static_cast<int*>(malloc(sizeof(int))));
|
||||
struct FreeDeleter {
|
||||
inline void operator()(void* ptr) const {
|
||||
free(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
struct ShouldAbortOnSelfReset {
|
||||
template <typename U>
|
||||
static rtc::internal::NoType Test(const typename U::AllowSelfReset*);
|
||||
|
||||
template <typename U>
|
||||
static rtc::internal::YesType Test(...);
|
||||
|
||||
static const bool value =
|
||||
sizeof(Test<T>(0)) == sizeof(rtc::internal::YesType);
|
||||
};
|
||||
|
||||
// Minimal implementation of the core logic of scoped_ptr, suitable for
|
||||
// reuse in both scoped_ptr and its specializations.
|
||||
template <class T, class D>
|
||||
class scoped_ptr_impl {
|
||||
public:
|
||||
explicit scoped_ptr_impl(T* p) : data_(p) {}
|
||||
|
||||
// Initializer for deleters that have data parameters.
|
||||
scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
|
||||
|
||||
// Templated constructor that destructively takes the value from another
|
||||
// scoped_ptr_impl.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
|
||||
: data_(other->release(), other->get_deleter()) {
|
||||
// We do not support move-only deleters. We could modify our move
|
||||
// emulation to have rtc::subtle::move() and rtc::subtle::forward()
|
||||
// functions that are imperfect emulations of their C++11 equivalents,
|
||||
// but until there's a requirement, just assume deleters are copyable.
|
||||
}
|
||||
|
||||
template <typename U, typename V>
|
||||
void TakeState(scoped_ptr_impl<U, V>* other) {
|
||||
// See comment in templated constructor above regarding lack of support
|
||||
// for move-only deleters.
|
||||
reset(other->release());
|
||||
get_deleter() = other->get_deleter();
|
||||
}
|
||||
|
||||
~scoped_ptr_impl() {
|
||||
if (data_.ptr != nullptr) {
|
||||
// Not using get_deleter() saves one function call in non-optimized
|
||||
// builds.
|
||||
static_cast<D&>(data_)(data_.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void reset(T* p) {
|
||||
// This is a self-reset, which is no longer allowed for default deleters:
|
||||
// https://crbug.com/162971
|
||||
assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
|
||||
|
||||
// Note that running data_.ptr = p can lead to undefined behavior if
|
||||
// get_deleter()(get()) deletes this. In order to prevent this, reset()
|
||||
// should update the stored pointer before deleting its old value.
|
||||
//
|
||||
// However, changing reset() to use that behavior may cause current code to
|
||||
// break in unexpected ways. If the destruction of the owned object
|
||||
// dereferences the scoped_ptr when it is destroyed by a call to reset(),
|
||||
// then it will incorrectly dispatch calls to |p| rather than the original
|
||||
// value of |data_.ptr|.
|
||||
//
|
||||
// During the transition period, set the stored pointer to nullptr while
|
||||
// deleting the object. Eventually, this safety check will be removed to
|
||||
// prevent the scenario initially described from occurring and
|
||||
// http://crbug.com/176091 can be closed.
|
||||
T* old = data_.ptr;
|
||||
data_.ptr = nullptr;
|
||||
if (old != nullptr)
|
||||
static_cast<D&>(data_)(old);
|
||||
data_.ptr = p;
|
||||
}
|
||||
|
||||
T* get() const { return data_.ptr; }
|
||||
|
||||
D& get_deleter() { return data_; }
|
||||
const D& get_deleter() const { return data_; }
|
||||
|
||||
void swap(scoped_ptr_impl& p2) {
|
||||
// Standard swap idiom: 'using std::swap' ensures that std::swap is
|
||||
// present in the overload set, but we call swap unqualified so that
|
||||
// any more-specific overloads can be used, if available.
|
||||
using std::swap;
|
||||
swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
|
||||
swap(data_.ptr, p2.data_.ptr);
|
||||
}
|
||||
|
||||
T* release() {
|
||||
T* old_ptr = data_.ptr;
|
||||
data_.ptr = nullptr;
|
||||
return old_ptr;
|
||||
}
|
||||
|
||||
T** accept() {
|
||||
reset(nullptr);
|
||||
return &(data_.ptr);
|
||||
}
|
||||
|
||||
T** use() {
|
||||
return &(data_.ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
// Needed to allow type-converting constructor.
|
||||
template <typename U, typename V> friend class scoped_ptr_impl;
|
||||
|
||||
// Use the empty base class optimization to allow us to have a D
|
||||
// member, while avoiding any space overhead for it when D is an
|
||||
// empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
|
||||
// discussion of this technique.
|
||||
struct Data : public D {
|
||||
explicit Data(T* ptr_in) : ptr(ptr_in) {}
|
||||
Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
|
||||
T* ptr;
|
||||
};
|
||||
|
||||
Data data_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
|
||||
// automatically deletes the pointer it holds (if any).
|
||||
// That is, scoped_ptr<T> owns the T object that it points to.
|
||||
// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
|
||||
// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
|
||||
// dereference it, you get the thread safety guarantees of T.
|
||||
//
|
||||
// The size of scoped_ptr is small. On most compilers, when using the
|
||||
// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
|
||||
// increase the size proportional to whatever state they need to have. See
|
||||
// comments inside scoped_ptr_impl<> for details.
|
||||
//
|
||||
// Current implementation targets having a strict subset of C++11's
|
||||
// unique_ptr<> features. Known deficiencies include not supporting move-only
|
||||
// deleters, function pointers as deleters, and deleters with reference
|
||||
// types.
|
||||
template <class T, class D = rtc::DefaultDeleter<T> >
|
||||
class scoped_ptr {
|
||||
|
||||
// TODO(ajm): If we ever import RefCountedBase, this check needs to be
|
||||
// enabled.
|
||||
//static_assert(rtc::internal::IsNotRefCounted<T>::value,
|
||||
// "T is refcounted type and needs scoped refptr");
|
||||
|
||||
public:
|
||||
// The element and deleter types.
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
// Constructor. Defaults to initializing with nullptr.
|
||||
scoped_ptr() : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Takes ownership of p.
|
||||
explicit scoped_ptr(element_type* p) : impl_(p) {}
|
||||
|
||||
// Constructor. Allows initialization of a stateful deleter.
|
||||
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
|
||||
|
||||
// Constructor. Allows construction from a nullptr.
|
||||
scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Allows construction from a scoped_ptr rvalue for a
|
||||
// convertible type and deleter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
|
||||
// from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
|
||||
// has different post-conditions if D is a reference type. Since this
|
||||
// implementation does not support deleters with reference type,
|
||||
// we do not need a separate move constructor allowing us to avoid one
|
||||
// use of SFINAE. You only need to care about this if you modify the
|
||||
// implementation of scoped_ptr.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr(scoped_ptr<U, V>&& other)
|
||||
: impl_(&other.impl_) {
|
||||
static_assert(!rtc::is_array<U>::value, "U cannot be an array");
|
||||
}
|
||||
|
||||
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
|
||||
// type and deleter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
|
||||
// the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
|
||||
// form has different requirements on for move-only Deleters. Since this
|
||||
// implementation does not support move-only Deleters, we do not need a
|
||||
// separate move assignment operator allowing us to avoid one use of SFINAE.
|
||||
// You only need to care about this if you modify the implementation of
|
||||
// scoped_ptr.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
|
||||
static_assert(!rtc::is_array<U>::value, "U cannot be an array");
|
||||
impl_.TakeState(&rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator=. Allows assignment from a nullptr. Deletes the currently owned
|
||||
// object, if any.
|
||||
scoped_ptr& operator=(decltype(nullptr)) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Deleted copy constructor and copy assignment, to make the type move-only.
|
||||
scoped_ptr(const scoped_ptr& other) = delete;
|
||||
scoped_ptr& operator=(const scoped_ptr& other) = delete;
|
||||
|
||||
// Get an rvalue reference. (sp.Pass() does the same thing as std::move(sp).)
|
||||
scoped_ptr&& Pass() { return static_cast<scoped_ptr&&>(*this); }
|
||||
|
||||
// Reset. Deletes the currently owned object, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
void reset(element_type* p = nullptr) { impl_.reset(p); }
|
||||
|
||||
// Accessors to get the owned object.
|
||||
// operator* and operator-> will assert() if there is no current object.
|
||||
element_type& operator*() const {
|
||||
assert(impl_.get() != nullptr);
|
||||
return *impl_.get();
|
||||
}
|
||||
element_type* operator->() const {
|
||||
assert(impl_.get() != nullptr);
|
||||
return impl_.get();
|
||||
}
|
||||
element_type* get() const { return impl_.get(); }
|
||||
|
||||
// Access to the deleter.
|
||||
deleter_type& get_deleter() { return impl_.get_deleter(); }
|
||||
const deleter_type& get_deleter() const { return impl_.get_deleter(); }
|
||||
|
||||
// Allow scoped_ptr<element_type> to be used in boolean expressions, but not
|
||||
// implicitly convertible to a real bool (which is dangerous).
|
||||
//
|
||||
// Note that this trick is only safe when the == and != operators
|
||||
// are declared explicitly, as otherwise "scoped_ptr1 ==
|
||||
// scoped_ptr2" will compile but do the wrong thing (i.e., convert
|
||||
// to Testable and then do the comparison).
|
||||
private:
|
||||
typedef rtc::internal::scoped_ptr_impl<element_type, deleter_type>
|
||||
scoped_ptr::*Testable;
|
||||
|
||||
public:
|
||||
operator Testable() const {
|
||||
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether two scoped_ptr refer to the same object, not just to
|
||||
// two different but equal objects.
|
||||
bool operator==(const element_type* p) const { return impl_.get() == p; }
|
||||
bool operator!=(const element_type* p) const { return impl_.get() != p; }
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object. If this object
|
||||
// holds a nullptr, the return value is nullptr. After this operation, this
|
||||
// object will hold a nullptr, and will not own the object any more.
|
||||
element_type* release() WARN_UNUSED_RESULT {
|
||||
return impl_.release();
|
||||
}
|
||||
|
||||
// Delete the currently held pointer and return a pointer
|
||||
// to allow overwriting of the current pointer address.
|
||||
element_type** accept() WARN_UNUSED_RESULT {
|
||||
return impl_.accept();
|
||||
}
|
||||
|
||||
// Return a pointer to the current pointer address.
|
||||
element_type** use() WARN_UNUSED_RESULT {
|
||||
return impl_.use();
|
||||
}
|
||||
|
||||
private:
|
||||
// Needed to reach into |impl_| in the constructor.
|
||||
template <typename U, typename V> friend class scoped_ptr;
|
||||
rtc::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
|
||||
|
||||
// Forbidden for API compatibility with std::unique_ptr.
|
||||
explicit scoped_ptr(int disallow_construction_from_null);
|
||||
|
||||
// Forbid comparison of scoped_ptr types. If U != T, it totally
|
||||
// doesn't make sense, and if U == T, it still doesn't make sense
|
||||
// because you should never have the same object owned by two different
|
||||
// scoped_ptrs.
|
||||
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
|
||||
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
class scoped_ptr<T[], D> {
|
||||
public:
|
||||
// The element and deleter types.
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
// Constructor. Defaults to initializing with nullptr.
|
||||
scoped_ptr() : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Stores the given array. Note that the argument's type
|
||||
// must exactly match T*. In particular:
|
||||
// - it cannot be a pointer to a type derived from T, because it is
|
||||
// inherently unsafe in the general case to access an array through a
|
||||
// pointer whose dynamic type does not match its static type (eg., if
|
||||
// T and the derived types had different sizes access would be
|
||||
// incorrectly calculated). Deletion is also always undefined
|
||||
// (C++98 [expr.delete]p3). If you're doing this, fix your code.
|
||||
// - it cannot be const-qualified differently from T per unique_ptr spec
|
||||
// (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
|
||||
// to work around this may use implicit_cast<const T*>().
|
||||
// However, because of the first bullet in this comment, users MUST
|
||||
// NOT use implicit_cast<Base*>() to upcast the static type of the array.
|
||||
explicit scoped_ptr(element_type* array) : impl_(array) {}
|
||||
|
||||
// Constructor. Allows construction from a nullptr.
|
||||
scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Allows construction from a scoped_ptr rvalue.
|
||||
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
|
||||
|
||||
// operator=. Allows assignment from a scoped_ptr rvalue.
|
||||
scoped_ptr& operator=(scoped_ptr&& rhs) {
|
||||
impl_.TakeState(&rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator=. Allows assignment from a nullptr. Deletes the currently owned
|
||||
// array, if any.
|
||||
scoped_ptr& operator=(decltype(nullptr)) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Deleted copy constructor and copy assignment, to make the type move-only.
|
||||
scoped_ptr(const scoped_ptr& other) = delete;
|
||||
scoped_ptr& operator=(const scoped_ptr& other) = delete;
|
||||
|
||||
// Get an rvalue reference. (sp.Pass() does the same thing as std::move(sp).)
|
||||
scoped_ptr&& Pass() { return static_cast<scoped_ptr&&>(*this); }
|
||||
|
||||
// Reset. Deletes the currently owned array, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
void reset(element_type* array = nullptr) { impl_.reset(array); }
|
||||
|
||||
// Accessors to get the owned array.
|
||||
element_type& operator[](size_t i) const {
|
||||
assert(impl_.get() != nullptr);
|
||||
return impl_.get()[i];
|
||||
}
|
||||
element_type* get() const { return impl_.get(); }
|
||||
|
||||
// Access to the deleter.
|
||||
deleter_type& get_deleter() { return impl_.get_deleter(); }
|
||||
const deleter_type& get_deleter() const { return impl_.get_deleter(); }
|
||||
|
||||
// Allow scoped_ptr<element_type> to be used in boolean expressions, but not
|
||||
// implicitly convertible to a real bool (which is dangerous).
|
||||
private:
|
||||
typedef rtc::internal::scoped_ptr_impl<element_type, deleter_type>
|
||||
scoped_ptr::*Testable;
|
||||
|
||||
public:
|
||||
operator Testable() const {
|
||||
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether two scoped_ptr refer to the same object, not just to
|
||||
// two different but equal objects.
|
||||
bool operator==(element_type* array) const { return impl_.get() == array; }
|
||||
bool operator!=(element_type* array) const { return impl_.get() != array; }
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object. If this object
|
||||
// holds a nullptr, the return value is nullptr. After this operation, this
|
||||
// object will hold a nullptr, and will not own the object any more.
|
||||
element_type* release() WARN_UNUSED_RESULT {
|
||||
return impl_.release();
|
||||
}
|
||||
|
||||
// Delete the currently held pointer and return a pointer
|
||||
// to allow overwriting of the current pointer address.
|
||||
element_type** accept() WARN_UNUSED_RESULT {
|
||||
return impl_.accept();
|
||||
}
|
||||
|
||||
// Return a pointer to the current pointer address.
|
||||
element_type** use() WARN_UNUSED_RESULT {
|
||||
return impl_.use();
|
||||
}
|
||||
|
||||
private:
|
||||
// Force element_type to be a complete type.
|
||||
enum { type_must_be_complete = sizeof(element_type) };
|
||||
|
||||
// Actually hold the data.
|
||||
rtc::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
|
||||
|
||||
// Disable initialization from any type other than element_type*, by
|
||||
// providing a constructor that matches such an initialization, but is
|
||||
// private and has no definition. This is disabled because it is not safe to
|
||||
// call delete[] on an array whose static type does not match its dynamic
|
||||
// type.
|
||||
template <typename U> explicit scoped_ptr(U* array);
|
||||
explicit scoped_ptr(int disallow_construction_from_null);
|
||||
|
||||
// Disable reset() from any type other than element_type*, for the same
|
||||
// reasons as the constructor above.
|
||||
template <typename U> void reset(U* array);
|
||||
void reset(int disallow_reset_from_null);
|
||||
|
||||
// Forbid comparison of scoped_ptr types. If U != T, it totally
|
||||
// doesn't make sense, and if U == T, it still doesn't make sense
|
||||
// because you should never have the same object owned by two different
|
||||
// scoped_ptrs.
|
||||
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
|
||||
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
void swap(rtc::scoped_ptr<T, D>& p1, rtc::scoped_ptr<T, D>& p2) {
|
||||
p1.swap(p2);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
template <class T, class D>
|
||||
bool operator==(T* p1, const rtc::scoped_ptr<T, D>& p2) {
|
||||
return p1 == p2.get();
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator!=(T* p1, const rtc::scoped_ptr<T, D>& p2) {
|
||||
return p1 != p2.get();
|
||||
}
|
||||
|
||||
// A function to convert T* into scoped_ptr<T>
|
||||
// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
|
||||
// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
|
||||
template <typename T>
|
||||
rtc::scoped_ptr<T> rtc_make_scoped_ptr(T* ptr) {
|
||||
return rtc::scoped_ptr<T>(ptr);
|
||||
}
|
||||
|
||||
#endif // #ifndef WEBRTC_BASE_SCOPED_PTR_H__
|
114
webrtc/base/template_util.h
Normal file
114
webrtc/base/template_util.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Borrowed from Chromium's src/base/template_util.h.
|
||||
|
||||
#ifndef WEBRTC_BASE_TEMPLATE_UTIL_H_
|
||||
#define WEBRTC_BASE_TEMPLATE_UTIL_H_
|
||||
|
||||
#include <stddef.h> // For size_t.
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Template definitions from tr1.
|
||||
|
||||
template<class T, T v>
|
||||
struct integral_constant {
|
||||
static const T value = v;
|
||||
typedef T value_type;
|
||||
typedef integral_constant<T, v> type;
|
||||
};
|
||||
|
||||
template <class T, T v> const T integral_constant<T, v>::value;
|
||||
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
|
||||
template <class T> struct is_pointer : false_type {};
|
||||
template <class T> struct is_pointer<T*> : true_type {};
|
||||
|
||||
template <class T, class U> struct is_same : public false_type {};
|
||||
template <class T> struct is_same<T, T> : true_type {};
|
||||
|
||||
template<class> struct is_array : public false_type {};
|
||||
template<class T, size_t n> struct is_array<T[n]> : public true_type {};
|
||||
template<class T> struct is_array<T[]> : public true_type {};
|
||||
|
||||
template <class T> struct is_non_const_reference : false_type {};
|
||||
template <class T> struct is_non_const_reference<T&> : true_type {};
|
||||
template <class T> struct is_non_const_reference<const T&> : false_type {};
|
||||
|
||||
template <class T> struct is_void : false_type {};
|
||||
template <> struct is_void<void> : true_type {};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Types YesType and NoType are guaranteed such that sizeof(YesType) <
|
||||
// sizeof(NoType).
|
||||
typedef char YesType;
|
||||
|
||||
struct NoType {
|
||||
YesType dummy[2];
|
||||
};
|
||||
|
||||
// This class is an implementation detail for is_convertible, and you
|
||||
// don't need to know how it works to use is_convertible. For those
|
||||
// who care: we declare two different functions, one whose argument is
|
||||
// of type To and one with a variadic argument list. We give them
|
||||
// return types of different size, so we can use sizeof to trick the
|
||||
// compiler into telling us which function it would have chosen if we
|
||||
// had called it with an argument of type From. See Alexandrescu's
|
||||
// _Modern C++ Design_ for more details on this sort of trick.
|
||||
|
||||
struct ConvertHelper {
|
||||
template <typename To>
|
||||
static YesType Test(To);
|
||||
|
||||
template <typename To>
|
||||
static NoType Test(...);
|
||||
|
||||
template <typename From>
|
||||
static From& Create();
|
||||
};
|
||||
|
||||
// Used to determine if a type is a struct/union/class. Inspired by Boost's
|
||||
// is_class type_trait implementation.
|
||||
struct IsClassHelper {
|
||||
template <typename C>
|
||||
static YesType Test(void(C::*)(void));
|
||||
|
||||
template <typename C>
|
||||
static NoType Test(...);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Inherits from true_type if From is convertible to To, false_type otherwise.
|
||||
//
|
||||
// Note that if the type is convertible, this will be a true_type REGARDLESS
|
||||
// of whether or not the conversion would emit a warning.
|
||||
template <typename From, typename To>
|
||||
struct is_convertible
|
||||
: integral_constant<bool,
|
||||
sizeof(internal::ConvertHelper::Test<To>(
|
||||
internal::ConvertHelper::Create<From>())) ==
|
||||
sizeof(internal::YesType)> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_class
|
||||
: integral_constant<bool,
|
||||
sizeof(internal::IsClassHelper::Test<T>(0)) ==
|
||||
sizeof(internal::YesType)> {
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_TEMPLATE_UTIL_H_
|
243
webrtc/common_audio/BUILD.gn
Normal file
243
webrtc/common_audio/BUILD.gn
Normal file
@ -0,0 +1,243 @@
|
||||
# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("//build/config/arm.gni")
|
||||
import("../build/webrtc.gni")
|
||||
|
||||
config("common_audio_config") {
|
||||
include_dirs = [
|
||||
"resampler/include",
|
||||
"signal_processing/include",
|
||||
"vad/include",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("common_audio") {
|
||||
sources = [
|
||||
"audio_converter.cc",
|
||||
"audio_converter.h",
|
||||
"audio_ring_buffer.cc",
|
||||
"audio_ring_buffer.h",
|
||||
"audio_util.cc",
|
||||
"blocker.cc",
|
||||
"blocker.h",
|
||||
"channel_buffer.cc",
|
||||
"channel_buffer.h",
|
||||
"fft4g.c",
|
||||
"fft4g.h",
|
||||
"fir_filter.cc",
|
||||
"fir_filter.h",
|
||||
"fir_filter_neon.h",
|
||||
"fir_filter_sse.h",
|
||||
"include/audio_util.h",
|
||||
"lapped_transform.cc",
|
||||
"lapped_transform.h",
|
||||
"real_fourier.cc",
|
||||
"real_fourier.h",
|
||||
"real_fourier_ooura.cc",
|
||||
"real_fourier_ooura.h",
|
||||
"resampler/include/push_resampler.h",
|
||||
"resampler/include/resampler.h",
|
||||
"resampler/push_resampler.cc",
|
||||
"resampler/push_sinc_resampler.cc",
|
||||
"resampler/push_sinc_resampler.h",
|
||||
"resampler/resampler.cc",
|
||||
"resampler/sinc_resampler.cc",
|
||||
"resampler/sinc_resampler.h",
|
||||
"ring_buffer.c",
|
||||
"ring_buffer.h",
|
||||
"signal_processing/auto_corr_to_refl_coef.c",
|
||||
"signal_processing/auto_correlation.c",
|
||||
"signal_processing/complex_fft_tables.h",
|
||||
"signal_processing/copy_set_operations.c",
|
||||
"signal_processing/cross_correlation.c",
|
||||
"signal_processing/division_operations.c",
|
||||
"signal_processing/dot_product_with_scale.c",
|
||||
"signal_processing/downsample_fast.c",
|
||||
"signal_processing/energy.c",
|
||||
"signal_processing/filter_ar.c",
|
||||
"signal_processing/filter_ma_fast_q12.c",
|
||||
"signal_processing/get_hanning_window.c",
|
||||
"signal_processing/get_scaling_square.c",
|
||||
"signal_processing/ilbc_specific_functions.c",
|
||||
"signal_processing/include/real_fft.h",
|
||||
"signal_processing/include/signal_processing_library.h",
|
||||
"signal_processing/include/spl_inl.h",
|
||||
"signal_processing/levinson_durbin.c",
|
||||
"signal_processing/lpc_to_refl_coef.c",
|
||||
"signal_processing/min_max_operations.c",
|
||||
"signal_processing/randomization_functions.c",
|
||||
"signal_processing/real_fft.c",
|
||||
"signal_processing/refl_coef_to_lpc.c",
|
||||
"signal_processing/resample.c",
|
||||
"signal_processing/resample_48khz.c",
|
||||
"signal_processing/resample_by_2.c",
|
||||
"signal_processing/resample_by_2_internal.c",
|
||||
"signal_processing/resample_by_2_internal.h",
|
||||
"signal_processing/resample_fractional.c",
|
||||
"signal_processing/spl_init.c",
|
||||
"signal_processing/spl_sqrt.c",
|
||||
"signal_processing/splitting_filter.c",
|
||||
"signal_processing/sqrt_of_one_minus_x_squared.c",
|
||||
"signal_processing/vector_scaling_operations.c",
|
||||
"sparse_fir_filter.cc",
|
||||
"sparse_fir_filter.h",
|
||||
"vad/include/vad.h",
|
||||
"vad/include/webrtc_vad.h",
|
||||
"vad/vad.cc",
|
||||
"vad/vad_core.c",
|
||||
"vad/vad_core.h",
|
||||
"vad/vad_filterbank.c",
|
||||
"vad/vad_filterbank.h",
|
||||
"vad/vad_gmm.c",
|
||||
"vad/vad_gmm.h",
|
||||
"vad/vad_sp.c",
|
||||
"vad/vad_sp.h",
|
||||
"vad/webrtc_vad.c",
|
||||
"wav_file.cc",
|
||||
"wav_file.h",
|
||||
"wav_header.cc",
|
||||
"wav_header.h",
|
||||
"window_generator.cc",
|
||||
"window_generator.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../system_wrappers",
|
||||
]
|
||||
|
||||
defines = []
|
||||
if (rtc_use_openmax_dl) {
|
||||
sources += [
|
||||
"real_fourier_openmax.cc",
|
||||
"real_fourier_openmax.h",
|
||||
]
|
||||
defines += [ "RTC_USE_OPENMAX_DL" ]
|
||||
if (rtc_build_openmax_dl) {
|
||||
deps += [ "//third_party/openmax_dl/dl" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (current_cpu == "arm") {
|
||||
sources += [
|
||||
"signal_processing/complex_bit_reverse_arm.S",
|
||||
"signal_processing/spl_sqrt_floor_arm.S",
|
||||
]
|
||||
|
||||
if (arm_version >= 7) {
|
||||
sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ]
|
||||
} else {
|
||||
sources += [ "signal_processing/filter_ar_fast_q12.c" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_build_with_neon) {
|
||||
deps += [ ":common_audio_neon" ]
|
||||
}
|
||||
|
||||
if (current_cpu == "mipsel") {
|
||||
sources += [
|
||||
"signal_processing/complex_bit_reverse_mips.c",
|
||||
"signal_processing/complex_fft_mips.c",
|
||||
"signal_processing/cross_correlation_mips.c",
|
||||
"signal_processing/downsample_fast_mips.c",
|
||||
"signal_processing/filter_ar_fast_q12_mips.c",
|
||||
"signal_processing/include/spl_inl_mips.h",
|
||||
"signal_processing/min_max_operations_mips.c",
|
||||
"signal_processing/resample_by_2_mips.c",
|
||||
"signal_processing/spl_sqrt_floor_mips.c",
|
||||
]
|
||||
if (mips_dsp_rev > 0) {
|
||||
sources += [ "signal_processing/vector_scaling_operations_mips.c" ]
|
||||
}
|
||||
} else {
|
||||
sources += [ "signal_processing/complex_fft.c" ]
|
||||
}
|
||||
|
||||
if (current_cpu != "arm" && current_cpu != "mipsel") {
|
||||
sources += [
|
||||
"signal_processing/complex_bit_reverse.c",
|
||||
"signal_processing/filter_ar_fast_q12.c",
|
||||
"signal_processing/spl_sqrt_floor.c",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
cflags = [ "/wd4334" ] # Ignore warning on shift operator promotion.
|
||||
}
|
||||
|
||||
configs += [ "..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"..:common_inherited_config",
|
||||
":common_audio_config",
|
||||
]
|
||||
|
||||
if (is_clang) {
|
||||
# Suppress warnings from Chrome's Clang plugins.
|
||||
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
|
||||
configs -= [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
|
||||
if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
deps += [ ":common_audio_sse2" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
source_set("common_audio_sse2") {
|
||||
sources = [
|
||||
"fir_filter_sse.cc",
|
||||
"resampler/sinc_resampler_sse.cc",
|
||||
]
|
||||
|
||||
if (is_posix) {
|
||||
cflags = [ "-msse2" ]
|
||||
}
|
||||
|
||||
configs += [ "..:common_inherited_config" ]
|
||||
|
||||
if (is_clang) {
|
||||
# Suppress warnings from Chrome's Clang plugins.
|
||||
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
|
||||
configs -= [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_build_with_neon) {
|
||||
source_set("common_audio_neon") {
|
||||
sources = [
|
||||
"fir_filter_neon.cc",
|
||||
"resampler/sinc_resampler_neon.cc",
|
||||
"signal_processing/cross_correlation_neon.c",
|
||||
"signal_processing/downsample_fast_neon.c",
|
||||
"signal_processing/min_max_operations_neon.c",
|
||||
]
|
||||
|
||||
if (current_cpu != "arm64") {
|
||||
# Enable compilation for the NEON instruction set. This is needed
|
||||
# since //build/config/arm.gni only enables NEON for iOS, not Android.
|
||||
# This provides the same functionality as webrtc/build/arm_neon.gypi.
|
||||
configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
|
||||
cflags = [ "-mfpu=neon" ]
|
||||
}
|
||||
|
||||
# Disable LTO on NEON targets due to compiler bug.
|
||||
# TODO(fdegans): Enable this. See crbug.com/408997.
|
||||
if (rtc_use_lto) {
|
||||
cflags -= [
|
||||
"-flto",
|
||||
"-ffat-lto-objects",
|
||||
]
|
||||
}
|
||||
|
||||
configs += [ "..:common_config" ]
|
||||
public_configs = [ "..:common_inherited_config" ]
|
||||
}
|
||||
}
|
74
webrtc/common_audio/Makefile.am
Normal file
74
webrtc/common_audio/Makefile.am
Normal file
@ -0,0 +1,74 @@
|
||||
noinst_LTLIBRARIES = libcommon_audio.la
|
||||
|
||||
libcommon_audio_la_SOURCES = signal_processing/include/real_fft.h \
|
||||
signal_processing/include/signal_processing_library.h \
|
||||
signal_processing/include/spl_inl.h \
|
||||
signal_processing/include/spl_inl_armv7.h \
|
||||
signal_processing/include/spl_inl_mips.h \
|
||||
signal_processing/auto_corr_to_refl_coef.c \
|
||||
signal_processing/auto_correlation.c \
|
||||
signal_processing/complex_bit_reverse.c \
|
||||
signal_processing/complex_fft.c \
|
||||
signal_processing/complex_fft_tables.h \
|
||||
signal_processing/copy_set_operations.c \
|
||||
signal_processing/cross_correlation.c \
|
||||
signal_processing/division_operations.c \
|
||||
signal_processing/dot_product_with_scale.c \
|
||||
signal_processing/downsample_fast.c \
|
||||
signal_processing/energy.c \
|
||||
signal_processing/filter_ar.c \
|
||||
signal_processing/filter_ar_fast_q12.c \
|
||||
signal_processing/filter_ma_fast_q12.c \
|
||||
signal_processing/get_hanning_window.c \
|
||||
signal_processing/get_scaling_square.c \
|
||||
signal_processing/ilbc_specific_functions.c \
|
||||
signal_processing/levinson_durbin.c \
|
||||
signal_processing/lpc_to_refl_coef.c \
|
||||
signal_processing/min_max_operations.c \
|
||||
signal_processing/randomization_functions.c \
|
||||
signal_processing/real_fft.c \
|
||||
signal_processing/refl_coef_to_lpc.c \
|
||||
signal_processing/resample.c \
|
||||
signal_processing/resample_48khz.c \
|
||||
signal_processing/resample_by_2.c \
|
||||
signal_processing/resample_by_2_internal.c \
|
||||
signal_processing/resample_by_2_internal.h \
|
||||
signal_processing/resample_fractional.c \
|
||||
signal_processing/spl_init.c \
|
||||
signal_processing/spl_sqrt.c \
|
||||
signal_processing/spl_sqrt_floor.c \
|
||||
signal_processing/splitting_filter.c \
|
||||
signal_processing/sqrt_of_one_minus_x_squared.c \
|
||||
signal_processing/vector_scaling_operations.c \
|
||||
vad/include/vad.h \
|
||||
vad/include/webrtc_vad.h \
|
||||
vad/vad.cc \
|
||||
vad/vad_core.c \
|
||||
vad/vad_core.h \
|
||||
vad/vad_filterbank.c \
|
||||
vad/vad_filterbank.h \
|
||||
vad/vad_gmm.c \
|
||||
vad/vad_gmm.h \
|
||||
vad/vad_sp.c \
|
||||
vad/vad_sp.h \
|
||||
vad/webrtc_vad.c
|
||||
|
||||
libcommon_audio_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS)
|
||||
libcommon_audio_la_CXXFLAGS = $(AM_CXXFLAGS) $(COMMON_CXXFLAGS)
|
||||
|
||||
# FIXME:
|
||||
# if ARM - signal_processing/complex_bit_reverse_arm.S
|
||||
# signal_processing/spl_sqrt_floor_arm.S
|
||||
# ARM7 - signal_processing/filter_ar_fast_q12_armv7.S
|
||||
# NEON - signal_processing/cross_correlation_neon.c
|
||||
# signal_processing/downsample_fast_neon.c
|
||||
# signal_processing/min_max_operations_neon.c
|
||||
# if MIPS - signal_processing/complex_bit_reverse_mips.c
|
||||
# signal_processing/complex_fft_mips.c
|
||||
# signal_processing/cross_correlation_mips.c
|
||||
# signal_processing/downsample_fast_mips.c
|
||||
# signal_processing/filter_ar_fast_q12_mips.c
|
||||
# signal_processing/min_max_operations_mips.c
|
||||
# signal_processing/resample_by_2_mips.c
|
||||
# signal_processing/spl_sqrt_floor_mips.c
|
||||
# signal_processing/vector_scaling_operations_mips.c
|
103
webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
Normal file
103
webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_AutoCorrToReflCoef().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_AutoCorrToReflCoef(const int32_t *R, int use_order, int16_t *K)
|
||||
{
|
||||
int i, n;
|
||||
int16_t tmp;
|
||||
const int32_t *rptr;
|
||||
int32_t L_num, L_den;
|
||||
int16_t *acfptr, *pptr, *wptr, *p1ptr, *w1ptr, ACF[WEBRTC_SPL_MAX_LPC_ORDER],
|
||||
P[WEBRTC_SPL_MAX_LPC_ORDER], W[WEBRTC_SPL_MAX_LPC_ORDER];
|
||||
|
||||
// Initialize loop and pointers.
|
||||
acfptr = ACF;
|
||||
rptr = R;
|
||||
pptr = P;
|
||||
p1ptr = &P[1];
|
||||
w1ptr = &W[1];
|
||||
wptr = w1ptr;
|
||||
|
||||
// First loop; n=0. Determine shifting.
|
||||
tmp = WebRtcSpl_NormW32(*R);
|
||||
*acfptr = (int16_t)((*rptr++ << tmp) >> 16);
|
||||
*pptr++ = *acfptr++;
|
||||
|
||||
// Initialize ACF, P and W.
|
||||
for (i = 1; i <= use_order; i++)
|
||||
{
|
||||
*acfptr = (int16_t)((*rptr++ << tmp) >> 16);
|
||||
*wptr++ = *acfptr;
|
||||
*pptr++ = *acfptr++;
|
||||
}
|
||||
|
||||
// Compute reflection coefficients.
|
||||
for (n = 1; n <= use_order; n++, K++)
|
||||
{
|
||||
tmp = WEBRTC_SPL_ABS_W16(*p1ptr);
|
||||
if (*P < tmp)
|
||||
{
|
||||
for (i = n; i <= use_order; i++)
|
||||
*K++ = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Division: WebRtcSpl_div(tmp, *P)
|
||||
*K = 0;
|
||||
if (tmp != 0)
|
||||
{
|
||||
L_num = tmp;
|
||||
L_den = *P;
|
||||
i = 15;
|
||||
while (i--)
|
||||
{
|
||||
(*K) <<= 1;
|
||||
L_num <<= 1;
|
||||
if (L_num >= L_den)
|
||||
{
|
||||
L_num -= L_den;
|
||||
(*K)++;
|
||||
}
|
||||
}
|
||||
if (*p1ptr > 0)
|
||||
*K = -*K;
|
||||
}
|
||||
|
||||
// Last iteration; don't do Schur recursion.
|
||||
if (n == use_order)
|
||||
return;
|
||||
|
||||
// Schur recursion.
|
||||
pptr = P;
|
||||
wptr = w1ptr;
|
||||
tmp = (int16_t)(((int32_t)*p1ptr * (int32_t)*K + 16384) >> 15);
|
||||
*pptr = WebRtcSpl_AddSatW16(*pptr, tmp);
|
||||
pptr++;
|
||||
for (i = 1; i <= use_order - n; i++)
|
||||
{
|
||||
tmp = (int16_t)(((int32_t)*wptr * (int32_t)*K + 16384) >> 15);
|
||||
*pptr = WebRtcSpl_AddSatW16(*(pptr + 1), tmp);
|
||||
pptr++;
|
||||
tmp = (int16_t)(((int32_t)*pptr * (int32_t)*K + 16384) >> 15);
|
||||
*wptr = WebRtcSpl_AddSatW16(*wptr, tmp);
|
||||
wptr++;
|
||||
}
|
||||
}
|
||||
}
|
65
webrtc/common_audio/signal_processing/auto_correlation.c
Normal file
65
webrtc/common_audio/signal_processing/auto_correlation.c
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector,
|
||||
size_t in_vector_length,
|
||||
size_t order,
|
||||
int32_t* result,
|
||||
int* scale) {
|
||||
int32_t sum = 0;
|
||||
size_t i = 0, j = 0;
|
||||
int16_t smax = 0;
|
||||
int scaling = 0;
|
||||
|
||||
assert(order <= in_vector_length);
|
||||
|
||||
// Find the maximum absolute value of the samples.
|
||||
smax = WebRtcSpl_MaxAbsValueW16(in_vector, in_vector_length);
|
||||
|
||||
// In order to avoid overflow when computing the sum we should scale the
|
||||
// samples so that (in_vector_length * smax * smax) will not overflow.
|
||||
if (smax == 0) {
|
||||
scaling = 0;
|
||||
} else {
|
||||
// Number of bits in the sum loop.
|
||||
int nbits = WebRtcSpl_GetSizeInBits((uint32_t)in_vector_length);
|
||||
// Number of bits to normalize smax.
|
||||
int t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax));
|
||||
|
||||
if (t > nbits) {
|
||||
scaling = 0;
|
||||
} else {
|
||||
scaling = nbits - t;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the actual correlation calculation.
|
||||
for (i = 0; i < order + 1; i++) {
|
||||
sum = 0;
|
||||
/* Unroll the loop to improve performance. */
|
||||
for (j = 0; i + j + 3 < in_vector_length; j += 4) {
|
||||
sum += (in_vector[j + 0] * in_vector[i + j + 0]) >> scaling;
|
||||
sum += (in_vector[j + 1] * in_vector[i + j + 1]) >> scaling;
|
||||
sum += (in_vector[j + 2] * in_vector[i + j + 2]) >> scaling;
|
||||
sum += (in_vector[j + 3] * in_vector[i + j + 3]) >> scaling;
|
||||
}
|
||||
for (; j < in_vector_length - i; j++) {
|
||||
sum += (in_vector[j] * in_vector[i + j]) >> scaling;
|
||||
}
|
||||
*result++ = sum;
|
||||
}
|
||||
|
||||
*scale = scaling;
|
||||
return order + 1;
|
||||
}
|
108
webrtc/common_audio/signal_processing/complex_bit_reverse.c
Normal file
108
webrtc/common_audio/signal_processing/complex_bit_reverse.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
/* Tables for data buffer indexes that are bit reversed and thus need to be
|
||||
* swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap
|
||||
* operations, while index_7[{1, 3, 5, ...}] are for the right side of the
|
||||
* operation. Same for index_8.
|
||||
*/
|
||||
|
||||
/* Indexes for the case of stages == 7. */
|
||||
static const int16_t index_7[112] = {
|
||||
1, 64, 2, 32, 3, 96, 4, 16, 5, 80, 6, 48, 7, 112, 9, 72, 10, 40, 11, 104,
|
||||
12, 24, 13, 88, 14, 56, 15, 120, 17, 68, 18, 36, 19, 100, 21, 84, 22, 52,
|
||||
23, 116, 25, 76, 26, 44, 27, 108, 29, 92, 30, 60, 31, 124, 33, 66, 35, 98,
|
||||
37, 82, 38, 50, 39, 114, 41, 74, 43, 106, 45, 90, 46, 58, 47, 122, 49, 70,
|
||||
51, 102, 53, 86, 55, 118, 57, 78, 59, 110, 61, 94, 63, 126, 67, 97, 69,
|
||||
81, 71, 113, 75, 105, 77, 89, 79, 121, 83, 101, 87, 117, 91, 109, 95, 125,
|
||||
103, 115, 111, 123
|
||||
};
|
||||
|
||||
/* Indexes for the case of stages == 8. */
|
||||
static const int16_t index_8[240] = {
|
||||
1, 128, 2, 64, 3, 192, 4, 32, 5, 160, 6, 96, 7, 224, 8, 16, 9, 144, 10, 80,
|
||||
11, 208, 12, 48, 13, 176, 14, 112, 15, 240, 17, 136, 18, 72, 19, 200, 20,
|
||||
40, 21, 168, 22, 104, 23, 232, 25, 152, 26, 88, 27, 216, 28, 56, 29, 184,
|
||||
30, 120, 31, 248, 33, 132, 34, 68, 35, 196, 37, 164, 38, 100, 39, 228, 41,
|
||||
148, 42, 84, 43, 212, 44, 52, 45, 180, 46, 116, 47, 244, 49, 140, 50, 76,
|
||||
51, 204, 53, 172, 54, 108, 55, 236, 57, 156, 58, 92, 59, 220, 61, 188, 62,
|
||||
124, 63, 252, 65, 130, 67, 194, 69, 162, 70, 98, 71, 226, 73, 146, 74, 82,
|
||||
75, 210, 77, 178, 78, 114, 79, 242, 81, 138, 83, 202, 85, 170, 86, 106, 87,
|
||||
234, 89, 154, 91, 218, 93, 186, 94, 122, 95, 250, 97, 134, 99, 198, 101,
|
||||
166, 103, 230, 105, 150, 107, 214, 109, 182, 110, 118, 111, 246, 113, 142,
|
||||
115, 206, 117, 174, 119, 238, 121, 158, 123, 222, 125, 190, 127, 254, 131,
|
||||
193, 133, 161, 135, 225, 137, 145, 139, 209, 141, 177, 143, 241, 147, 201,
|
||||
149, 169, 151, 233, 155, 217, 157, 185, 159, 249, 163, 197, 167, 229, 171,
|
||||
213, 173, 181, 175, 245, 179, 205, 183, 237, 187, 221, 191, 253, 199, 227,
|
||||
203, 211, 207, 243, 215, 235, 223, 251, 239, 247
|
||||
};
|
||||
|
||||
void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages) {
|
||||
/* For any specific value of stages, we know exactly the indexes that are
|
||||
* bit reversed. Currently (Feb. 2012) in WebRTC the only possible values of
|
||||
* stages are 7 and 8, so we use tables to save unnecessary iterations and
|
||||
* calculations for these two cases.
|
||||
*/
|
||||
if (stages == 7 || stages == 8) {
|
||||
int m = 0;
|
||||
int length = 112;
|
||||
const int16_t* index = index_7;
|
||||
|
||||
if (stages == 8) {
|
||||
length = 240;
|
||||
index = index_8;
|
||||
}
|
||||
|
||||
/* Decimation in time. Swap the elements with bit-reversed indexes. */
|
||||
for (m = 0; m < length; m += 2) {
|
||||
/* We declare a int32_t* type pointer, to load both the 16-bit real
|
||||
* and imaginary elements from complex_data in one instruction, reducing
|
||||
* complexity.
|
||||
*/
|
||||
int32_t* complex_data_ptr = (int32_t*)complex_data;
|
||||
int32_t temp = 0;
|
||||
|
||||
temp = complex_data_ptr[index[m]]; /* Real and imaginary */
|
||||
complex_data_ptr[index[m]] = complex_data_ptr[index[m + 1]];
|
||||
complex_data_ptr[index[m + 1]] = temp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int m = 0, mr = 0, l = 0;
|
||||
int n = 1 << stages;
|
||||
int nn = n - 1;
|
||||
|
||||
/* Decimation in time - re-order data */
|
||||
for (m = 1; m <= nn; ++m) {
|
||||
int32_t* complex_data_ptr = (int32_t*)complex_data;
|
||||
int32_t temp = 0;
|
||||
|
||||
/* Find out indexes that are bit-reversed. */
|
||||
l = n;
|
||||
do {
|
||||
l >>= 1;
|
||||
} while (l > nn - mr);
|
||||
mr = (mr & (l - 1)) + l;
|
||||
|
||||
if (mr <= m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Swap the elements with bit-reversed indexes.
|
||||
* This is similar to the loop in the stages == 7 or 8 cases.
|
||||
*/
|
||||
temp = complex_data_ptr[m]; /* Real and imaginary */
|
||||
complex_data_ptr[m] = complex_data_ptr[mr];
|
||||
complex_data_ptr[mr] = temp;
|
||||
}
|
||||
}
|
||||
}
|
119
webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
Normal file
119
webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
Normal file
@ -0,0 +1,119 @@
|
||||
@
|
||||
@ Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
@
|
||||
@ Use of this source code is governed by a BSD-style license
|
||||
@ that can be found in the LICENSE file in the root of the source
|
||||
@ tree. An additional intellectual property rights grant can be found
|
||||
@ in the file PATENTS. All contributing project authors may
|
||||
@ be found in the AUTHORS file in the root of the source tree.
|
||||
@
|
||||
|
||||
@ This file contains the function WebRtcSpl_ComplexBitReverse(), optimized
|
||||
@ for ARMv5 platforms.
|
||||
@ Reference C code is in file complex_bit_reverse.c. Bit-exact.
|
||||
|
||||
#include "webrtc/system_wrappers/interface/asm_defines.h"
|
||||
|
||||
GLOBAL_FUNCTION WebRtcSpl_ComplexBitReverse
|
||||
.align 2
|
||||
DEFINE_FUNCTION WebRtcSpl_ComplexBitReverse
|
||||
push {r4-r7}
|
||||
|
||||
cmp r1, #7
|
||||
adr r3, index_7 @ Table pointer.
|
||||
mov r4, #112 @ Number of interations.
|
||||
beq PRE_LOOP_STAGES_7_OR_8
|
||||
|
||||
cmp r1, #8
|
||||
adr r3, index_8 @ Table pointer.
|
||||
mov r4, #240 @ Number of interations.
|
||||
beq PRE_LOOP_STAGES_7_OR_8
|
||||
|
||||
mov r3, #1 @ Initialize m.
|
||||
mov r1, r3, asl r1 @ n = 1 << stages;
|
||||
subs r6, r1, #1 @ nn = n - 1;
|
||||
ble END
|
||||
|
||||
mov r5, r0 @ &complex_data
|
||||
mov r4, #0 @ ml
|
||||
|
||||
LOOP_GENERIC:
|
||||
rsb r12, r4, r6 @ l > nn - mr
|
||||
mov r2, r1 @ n
|
||||
|
||||
LOOP_SHIFT:
|
||||
asr r2, #1 @ l >>= 1;
|
||||
cmp r2, r12
|
||||
bgt LOOP_SHIFT
|
||||
|
||||
sub r12, r2, #1
|
||||
and r4, r12, r4
|
||||
add r4, r2 @ mr = (mr & (l - 1)) + l;
|
||||
cmp r4, r3 @ mr <= m ?
|
||||
ble UPDATE_REGISTERS
|
||||
|
||||
mov r12, r4, asl #2
|
||||
ldr r7, [r5, #4] @ complex_data[2 * m, 2 * m + 1].
|
||||
@ Offset 4 due to m incrementing from 1.
|
||||
ldr r2, [r0, r12] @ complex_data[2 * mr, 2 * mr + 1].
|
||||
str r7, [r0, r12]
|
||||
str r2, [r5, #4]
|
||||
|
||||
UPDATE_REGISTERS:
|
||||
add r3, r3, #1
|
||||
add r5, #4
|
||||
cmp r3, r1
|
||||
bne LOOP_GENERIC
|
||||
|
||||
b END
|
||||
|
||||
PRE_LOOP_STAGES_7_OR_8:
|
||||
add r4, r3, r4, asl #1
|
||||
|
||||
LOOP_STAGES_7_OR_8:
|
||||
ldrsh r2, [r3], #2 @ index[m]
|
||||
ldrsh r5, [r3], #2 @ index[m + 1]
|
||||
ldr r1, [r0, r2] @ complex_data[index[m], index[m] + 1]
|
||||
ldr r12, [r0, r5] @ complex_data[index[m + 1], index[m + 1] + 1]
|
||||
cmp r3, r4
|
||||
str r1, [r0, r5]
|
||||
str r12, [r0, r2]
|
||||
bne LOOP_STAGES_7_OR_8
|
||||
|
||||
END:
|
||||
pop {r4-r7}
|
||||
bx lr
|
||||
|
||||
@ The index tables. Note the values are doubles of the actual indexes for 16-bit
|
||||
@ elements, different from the generic C code. It actually provides byte offsets
|
||||
@ for the indexes.
|
||||
|
||||
.align 2
|
||||
index_7: @ Indexes for stages == 7.
|
||||
.short 4, 256, 8, 128, 12, 384, 16, 64, 20, 320, 24, 192, 28, 448, 36, 288
|
||||
.short 40, 160, 44, 416, 48, 96, 52, 352, 56, 224, 60, 480, 68, 272, 72, 144
|
||||
.short 76, 400, 84, 336, 88, 208, 92, 464, 100, 304, 104, 176, 108, 432, 116
|
||||
.short 368, 120, 240, 124, 496, 132, 264, 140, 392, 148, 328, 152, 200, 156
|
||||
.short 456, 164, 296, 172, 424, 180, 360, 184, 232, 188, 488, 196, 280, 204
|
||||
.short 408, 212, 344, 220, 472, 228, 312, 236, 440, 244, 376, 252, 504, 268
|
||||
.short 388, 276, 324, 284, 452, 300, 420, 308, 356, 316, 484, 332, 404, 348
|
||||
.short 468, 364, 436, 380, 500, 412, 460, 444, 492
|
||||
|
||||
index_8: @ Indexes for stages == 8.
|
||||
.short 4, 512, 8, 256, 12, 768, 16, 128, 20, 640, 24, 384, 28, 896, 32, 64
|
||||
.short 36, 576, 40, 320, 44, 832, 48, 192, 52, 704, 56, 448, 60, 960, 68, 544
|
||||
.short 72, 288, 76, 800, 80, 160, 84, 672, 88, 416, 92, 928, 100, 608, 104
|
||||
.short 352, 108, 864, 112, 224, 116, 736, 120, 480, 124, 992, 132, 528, 136
|
||||
.short 272, 140, 784, 148, 656, 152, 400, 156, 912, 164, 592, 168, 336, 172
|
||||
.short 848, 176, 208, 180, 720, 184, 464, 188, 976, 196, 560, 200, 304, 204
|
||||
.short 816, 212, 688, 216, 432, 220, 944, 228, 624, 232, 368, 236, 880, 244
|
||||
.short 752, 248, 496, 252, 1008, 260, 520, 268, 776, 276, 648, 280, 392, 284
|
||||
.short 904, 292, 584, 296, 328, 300, 840, 308, 712, 312, 456, 316, 968, 324
|
||||
.short 552, 332, 808, 340, 680, 344, 424, 348, 936, 356, 616, 364, 872, 372
|
||||
.short 744, 376, 488, 380, 1000, 388, 536, 396, 792, 404, 664, 412, 920, 420
|
||||
.short 600, 428, 856, 436, 728, 440, 472, 444, 984, 452, 568, 460, 824, 468
|
||||
.short 696, 476, 952, 484, 632, 492, 888, 500, 760, 508, 1016, 524, 772, 532
|
||||
.short 644, 540, 900, 548, 580, 556, 836, 564, 708, 572, 964, 588, 804, 596
|
||||
.short 676, 604, 932, 620, 868, 628, 740, 636, 996, 652, 788, 668, 916, 684
|
||||
.short 852, 692, 724, 700, 980, 716, 820, 732, 948, 748, 884, 764, 1012, 796
|
||||
.short 908, 812, 844, 828, 972, 860, 940, 892, 1004, 956, 988
|
176
webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
Normal file
176
webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
static int16_t coefTable_7[] = {
|
||||
4, 256, 8, 128, 12, 384, 16, 64,
|
||||
20, 320, 24, 192, 28, 448, 36, 288,
|
||||
40, 160, 44, 416, 48, 96, 52, 352,
|
||||
56, 224, 60, 480, 68, 272, 72, 144,
|
||||
76, 400, 84, 336, 88, 208, 92, 464,
|
||||
100, 304, 104, 176, 108, 432, 116, 368,
|
||||
120, 240, 124, 496, 132, 264, 140, 392,
|
||||
148, 328, 152, 200, 156, 456, 164, 296,
|
||||
172, 424, 180, 360, 184, 232, 188, 488,
|
||||
196, 280, 204, 408, 212, 344, 220, 472,
|
||||
228, 312, 236, 440, 244, 376, 252, 504,
|
||||
268, 388, 276, 324, 284, 452, 300, 420,
|
||||
308, 356, 316, 484, 332, 404, 348, 468,
|
||||
364, 436, 380, 500, 412, 460, 444, 492
|
||||
};
|
||||
|
||||
static int16_t coefTable_8[] = {
|
||||
4, 512, 8, 256, 12, 768, 16, 128,
|
||||
20, 640, 24, 384, 28, 896, 32, 64,
|
||||
36, 576, 40, 320, 44, 832, 48, 192,
|
||||
52, 704, 56, 448, 60, 960, 68, 544,
|
||||
72, 288, 76, 800, 80, 160, 84, 672,
|
||||
88, 416, 92, 928, 100, 608, 104, 352,
|
||||
108, 864, 112, 224, 116, 736, 120, 480,
|
||||
124, 992, 132, 528, 136, 272, 140, 784,
|
||||
148, 656, 152, 400, 156, 912, 164, 592,
|
||||
168, 336, 172, 848, 176, 208, 180, 720,
|
||||
184, 464, 188, 976, 196, 560, 200, 304,
|
||||
204, 816, 212, 688, 216, 432, 220, 944,
|
||||
228, 624, 232, 368, 236, 880, 244, 752,
|
||||
248, 496, 252, 1008, 260, 520, 268, 776,
|
||||
276, 648, 280, 392, 284, 904, 292, 584,
|
||||
296, 328, 300, 840, 308, 712, 312, 456,
|
||||
316, 968, 324, 552, 332, 808, 340, 680,
|
||||
344, 424, 348, 936, 356, 616, 364, 872,
|
||||
372, 744, 376, 488, 380, 1000, 388, 536,
|
||||
396, 792, 404, 664, 412, 920, 420, 600,
|
||||
428, 856, 436, 728, 440, 472, 444, 984,
|
||||
452, 568, 460, 824, 468, 696, 476, 952,
|
||||
484, 632, 492, 888, 500, 760, 508, 1016,
|
||||
524, 772, 532, 644, 540, 900, 548, 580,
|
||||
556, 836, 564, 708, 572, 964, 588, 804,
|
||||
596, 676, 604, 932, 620, 868, 628, 740,
|
||||
636, 996, 652, 788, 668, 916, 684, 852,
|
||||
692, 724, 700, 980, 716, 820, 732, 948,
|
||||
748, 884, 764, 1012, 796, 908, 812, 844,
|
||||
828, 972, 860, 940, 892, 1004, 956, 988
|
||||
};
|
||||
|
||||
void WebRtcSpl_ComplexBitReverse(int16_t frfi[], int stages) {
|
||||
int l;
|
||||
int16_t tr, ti;
|
||||
int32_t tmp1, tmp2, tmp3, tmp4;
|
||||
int32_t* ptr_i;
|
||||
int32_t* ptr_j;
|
||||
|
||||
if (stages == 8) {
|
||||
int16_t* pcoeftable_8 = coefTable_8;
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"addiu %[l], $zero, 120 \n\t"
|
||||
"1: \n\t"
|
||||
"addiu %[l], %[l], -4 \n\t"
|
||||
"lh %[tr], 0(%[pcoeftable_8]) \n\t"
|
||||
"lh %[ti], 2(%[pcoeftable_8]) \n\t"
|
||||
"lh %[tmp3], 4(%[pcoeftable_8]) \n\t"
|
||||
"lh %[tmp4], 6(%[pcoeftable_8]) \n\t"
|
||||
"addu %[ptr_i], %[frfi], %[tr] \n\t"
|
||||
"addu %[ptr_j], %[frfi], %[ti] \n\t"
|
||||
"addu %[tr], %[frfi], %[tmp3] \n\t"
|
||||
"addu %[ti], %[frfi], %[tmp4] \n\t"
|
||||
"ulw %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"ulw %[tmp2], 0(%[ptr_j]) \n\t"
|
||||
"ulw %[tmp3], 0(%[tr]) \n\t"
|
||||
"ulw %[tmp4], 0(%[ti]) \n\t"
|
||||
"usw %[tmp1], 0(%[ptr_j]) \n\t"
|
||||
"usw %[tmp2], 0(%[ptr_i]) \n\t"
|
||||
"usw %[tmp4], 0(%[tr]) \n\t"
|
||||
"usw %[tmp3], 0(%[ti]) \n\t"
|
||||
"lh %[tmp1], 8(%[pcoeftable_8]) \n\t"
|
||||
"lh %[tmp2], 10(%[pcoeftable_8]) \n\t"
|
||||
"lh %[tr], 12(%[pcoeftable_8]) \n\t"
|
||||
"lh %[ti], 14(%[pcoeftable_8]) \n\t"
|
||||
"addu %[ptr_i], %[frfi], %[tmp1] \n\t"
|
||||
"addu %[ptr_j], %[frfi], %[tmp2] \n\t"
|
||||
"addu %[tr], %[frfi], %[tr] \n\t"
|
||||
"addu %[ti], %[frfi], %[ti] \n\t"
|
||||
"ulw %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"ulw %[tmp2], 0(%[ptr_j]) \n\t"
|
||||
"ulw %[tmp3], 0(%[tr]) \n\t"
|
||||
"ulw %[tmp4], 0(%[ti]) \n\t"
|
||||
"usw %[tmp1], 0(%[ptr_j]) \n\t"
|
||||
"usw %[tmp2], 0(%[ptr_i]) \n\t"
|
||||
"usw %[tmp4], 0(%[tr]) \n\t"
|
||||
"usw %[tmp3], 0(%[ti]) \n\t"
|
||||
"bgtz %[l], 1b \n\t"
|
||||
" addiu %[pcoeftable_8], %[pcoeftable_8], 16 \n\t"
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [ptr_i] "=&r" (ptr_i),
|
||||
[ptr_j] "=&r" (ptr_j), [tr] "=&r" (tr), [l] "=&r" (l),
|
||||
[tmp3] "=&r" (tmp3), [pcoeftable_8] "+r" (pcoeftable_8),
|
||||
[ti] "=&r" (ti), [tmp4] "=&r" (tmp4)
|
||||
: [frfi] "r" (frfi)
|
||||
: "memory"
|
||||
);
|
||||
} else if (stages == 7) {
|
||||
int16_t* pcoeftable_7 = coefTable_7;
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"addiu %[l], $zero, 56 \n\t"
|
||||
"1: \n\t"
|
||||
"addiu %[l], %[l], -4 \n\t"
|
||||
"lh %[tr], 0(%[pcoeftable_7]) \n\t"
|
||||
"lh %[ti], 2(%[pcoeftable_7]) \n\t"
|
||||
"lh %[tmp3], 4(%[pcoeftable_7]) \n\t"
|
||||
"lh %[tmp4], 6(%[pcoeftable_7]) \n\t"
|
||||
"addu %[ptr_i], %[frfi], %[tr] \n\t"
|
||||
"addu %[ptr_j], %[frfi], %[ti] \n\t"
|
||||
"addu %[tr], %[frfi], %[tmp3] \n\t"
|
||||
"addu %[ti], %[frfi], %[tmp4] \n\t"
|
||||
"ulw %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"ulw %[tmp2], 0(%[ptr_j]) \n\t"
|
||||
"ulw %[tmp3], 0(%[tr]) \n\t"
|
||||
"ulw %[tmp4], 0(%[ti]) \n\t"
|
||||
"usw %[tmp1], 0(%[ptr_j]) \n\t"
|
||||
"usw %[tmp2], 0(%[ptr_i]) \n\t"
|
||||
"usw %[tmp4], 0(%[tr]) \n\t"
|
||||
"usw %[tmp3], 0(%[ti]) \n\t"
|
||||
"lh %[tmp1], 8(%[pcoeftable_7]) \n\t"
|
||||
"lh %[tmp2], 10(%[pcoeftable_7]) \n\t"
|
||||
"lh %[tr], 12(%[pcoeftable_7]) \n\t"
|
||||
"lh %[ti], 14(%[pcoeftable_7]) \n\t"
|
||||
"addu %[ptr_i], %[frfi], %[tmp1] \n\t"
|
||||
"addu %[ptr_j], %[frfi], %[tmp2] \n\t"
|
||||
"addu %[tr], %[frfi], %[tr] \n\t"
|
||||
"addu %[ti], %[frfi], %[ti] \n\t"
|
||||
"ulw %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"ulw %[tmp2], 0(%[ptr_j]) \n\t"
|
||||
"ulw %[tmp3], 0(%[tr]) \n\t"
|
||||
"ulw %[tmp4], 0(%[ti]) \n\t"
|
||||
"usw %[tmp1], 0(%[ptr_j]) \n\t"
|
||||
"usw %[tmp2], 0(%[ptr_i]) \n\t"
|
||||
"usw %[tmp4], 0(%[tr]) \n\t"
|
||||
"usw %[tmp3], 0(%[ti]) \n\t"
|
||||
"bgtz %[l], 1b \n\t"
|
||||
" addiu %[pcoeftable_7], %[pcoeftable_7], 16 \n\t"
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [ptr_i] "=&r" (ptr_i),
|
||||
[ptr_j] "=&r" (ptr_j), [ti] "=&r" (ti), [tr] "=&r" (tr),
|
||||
[l] "=&r" (l), [pcoeftable_7] "+r" (pcoeftable_7),
|
||||
[tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4)
|
||||
: [frfi] "r" (frfi)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
}
|
298
webrtc/common_audio/signal_processing/complex_fft.c
Normal file
298
webrtc/common_audio/signal_processing/complex_fft.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_ComplexFFT().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#define CFFTSFT 14
|
||||
#define CFFTRND 1
|
||||
#define CFFTRND2 16384
|
||||
|
||||
#define CIFFTSFT 14
|
||||
#define CIFFTRND 1
|
||||
|
||||
|
||||
int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
|
||||
{
|
||||
int i, j, l, k, istep, n, m;
|
||||
int16_t wr, wi;
|
||||
int32_t tr32, ti32, qr32, qi32;
|
||||
|
||||
/* The 1024-value is a constant given from the size of kSinTable1024[],
|
||||
* and should not be changed depending on the input parameter 'stages'
|
||||
*/
|
||||
n = 1 << stages;
|
||||
if (n > 1024)
|
||||
return -1;
|
||||
|
||||
l = 1;
|
||||
k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
|
||||
depending on the input parameter 'stages' */
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
// mode==0: Low-complexity and Low-accuracy mode
|
||||
while (l < n)
|
||||
{
|
||||
istep = l << 1;
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = -kSinTable1024[j];
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
|
||||
|
||||
ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
|
||||
|
||||
qr32 = (int32_t)frfi[2 * i];
|
||||
qi32 = (int32_t)frfi[2 * i + 1];
|
||||
frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1);
|
||||
frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1);
|
||||
frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1);
|
||||
frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
--k;
|
||||
l = istep;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
// mode==1: High-complexity and High-accuracy mode
|
||||
while (l < n)
|
||||
{
|
||||
istep = l << 1;
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = -kSinTable1024[j];
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
int32_t wri = 0;
|
||||
__asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
|
||||
"r"((int32_t)wr), "r"((int32_t)wi));
|
||||
#endif
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
register int32_t frfi_r;
|
||||
__asm __volatile(
|
||||
"pkhbt %[frfi_r], %[frfi_even], %[frfi_odd],"
|
||||
" lsl #16\n\t"
|
||||
"smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
|
||||
"smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
|
||||
:[frfi_r]"=&r"(frfi_r),
|
||||
[tr32]"=&r"(tr32),
|
||||
[ti32]"=r"(ti32)
|
||||
:[frfi_even]"r"((int32_t)frfi[2*j]),
|
||||
[frfi_odd]"r"((int32_t)frfi[2*j +1]),
|
||||
[wri]"r"(wri),
|
||||
[cfftrnd]"r"(CFFTRND));
|
||||
#else
|
||||
tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CFFTRND;
|
||||
|
||||
ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CFFTRND;
|
||||
#endif
|
||||
|
||||
tr32 >>= 15 - CFFTSFT;
|
||||
ti32 >>= 15 - CFFTSFT;
|
||||
|
||||
qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
|
||||
qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
|
||||
|
||||
frfi[2 * j] = (int16_t)(
|
||||
(qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT));
|
||||
frfi[2 * j + 1] = (int16_t)(
|
||||
(qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT));
|
||||
frfi[2 * i] = (int16_t)(
|
||||
(qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT));
|
||||
frfi[2 * i + 1] = (int16_t)(
|
||||
(qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT));
|
||||
}
|
||||
}
|
||||
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
|
||||
{
|
||||
size_t i, j, l, istep, n, m;
|
||||
int k, scale, shift;
|
||||
int16_t wr, wi;
|
||||
int32_t tr32, ti32, qr32, qi32;
|
||||
int32_t tmp32, round2;
|
||||
|
||||
/* The 1024-value is a constant given from the size of kSinTable1024[],
|
||||
* and should not be changed depending on the input parameter 'stages'
|
||||
*/
|
||||
n = 1 << stages;
|
||||
if (n > 1024)
|
||||
return -1;
|
||||
|
||||
scale = 0;
|
||||
|
||||
l = 1;
|
||||
k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
|
||||
depending on the input parameter 'stages' */
|
||||
|
||||
while (l < n)
|
||||
{
|
||||
// variable scaling, depending upon data
|
||||
shift = 0;
|
||||
round2 = 8192;
|
||||
|
||||
tmp32 = WebRtcSpl_MaxAbsValueW16(frfi, 2 * n);
|
||||
if (tmp32 > 13573)
|
||||
{
|
||||
shift++;
|
||||
scale++;
|
||||
round2 <<= 1;
|
||||
}
|
||||
if (tmp32 > 27146)
|
||||
{
|
||||
shift++;
|
||||
scale++;
|
||||
round2 <<= 1;
|
||||
}
|
||||
|
||||
istep = l << 1;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
// mode==0: Low-complexity and Low-accuracy mode
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = kSinTable1024[j];
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
|
||||
|
||||
ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
|
||||
|
||||
qr32 = (int32_t)frfi[2 * i];
|
||||
qi32 = (int32_t)frfi[2 * i + 1];
|
||||
frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift);
|
||||
frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift);
|
||||
frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift);
|
||||
frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift);
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
// mode==1: High-complexity and High-accuracy mode
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = kSinTable1024[j];
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
int32_t wri = 0;
|
||||
__asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
|
||||
"r"((int32_t)wr), "r"((int32_t)wi));
|
||||
#endif
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
register int32_t frfi_r;
|
||||
__asm __volatile(
|
||||
"pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
|
||||
"smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
|
||||
"smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
|
||||
:[frfi_r]"=&r"(frfi_r),
|
||||
[tr32]"=&r"(tr32),
|
||||
[ti32]"=r"(ti32)
|
||||
:[frfi_even]"r"((int32_t)frfi[2*j]),
|
||||
[frfi_odd]"r"((int32_t)frfi[2*j +1]),
|
||||
[wri]"r"(wri),
|
||||
[cifftrnd]"r"(CIFFTRND)
|
||||
);
|
||||
#else
|
||||
|
||||
tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CIFFTRND;
|
||||
|
||||
ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CIFFTRND;
|
||||
#endif
|
||||
tr32 >>= 15 - CIFFTSFT;
|
||||
ti32 >>= 15 - CIFFTSFT;
|
||||
|
||||
qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
|
||||
qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
|
||||
|
||||
frfi[2 * j] = (int16_t)(
|
||||
(qr32 - tr32 + round2) >> (shift + CIFFTSFT));
|
||||
frfi[2 * j + 1] = (int16_t)(
|
||||
(qi32 - ti32 + round2) >> (shift + CIFFTSFT));
|
||||
frfi[2 * i] = (int16_t)(
|
||||
(qr32 + tr32 + round2) >> (shift + CIFFTSFT));
|
||||
frfi[2 * i + 1] = (int16_t)(
|
||||
(qi32 + ti32 + round2) >> (shift + CIFFTSFT));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
return scale;
|
||||
}
|
328
webrtc/common_audio/signal_processing/complex_fft_mips.c
Normal file
328
webrtc/common_audio/signal_processing/complex_fft_mips.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#define CFFTSFT 14
|
||||
#define CFFTRND 1
|
||||
#define CFFTRND2 16384
|
||||
|
||||
#define CIFFTSFT 14
|
||||
#define CIFFTRND 1
|
||||
|
||||
int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) {
|
||||
int i = 0;
|
||||
int l = 0;
|
||||
int k = 0;
|
||||
int istep = 0;
|
||||
int n = 0;
|
||||
int m = 0;
|
||||
int32_t wr = 0, wi = 0;
|
||||
int32_t tmp1 = 0;
|
||||
int32_t tmp2 = 0;
|
||||
int32_t tmp3 = 0;
|
||||
int32_t tmp4 = 0;
|
||||
int32_t tmp5 = 0;
|
||||
int32_t tmp6 = 0;
|
||||
int32_t tmp = 0;
|
||||
int16_t* ptr_j = NULL;
|
||||
int16_t* ptr_i = NULL;
|
||||
|
||||
n = 1 << stages;
|
||||
if (n > 1024) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"addiu %[k], $zero, 10 \n\t"
|
||||
"addiu %[l], $zero, 1 \n\t"
|
||||
"3: \n\t"
|
||||
"sll %[istep], %[l], 1 \n\t"
|
||||
"move %[m], $zero \n\t"
|
||||
"sll %[tmp], %[l], 2 \n\t"
|
||||
"move %[i], $zero \n\t"
|
||||
"2: \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"sllv %[tmp3], %[m], %[k] \n\t"
|
||||
"addiu %[tmp2], %[tmp3], 512 \n\t"
|
||||
"addiu %[m], %[m], 1 \n\t"
|
||||
"lhx %[wi], %[tmp3](%[kSinTable1024]) \n\t"
|
||||
"lhx %[wr], %[tmp2](%[kSinTable1024]) \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"sllv %[tmp3], %[m], %[k] \n\t"
|
||||
"addu %[ptr_j], %[tmp3], %[kSinTable1024] \n\t"
|
||||
"addiu %[ptr_i], %[ptr_j], 512 \n\t"
|
||||
"addiu %[m], %[m], 1 \n\t"
|
||||
"lh %[wi], 0(%[ptr_j]) \n\t"
|
||||
"lh %[wr], 0(%[ptr_i]) \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"1: \n\t"
|
||||
"sll %[tmp1], %[i], 2 \n\t"
|
||||
"addu %[ptr_i], %[frfi], %[tmp1] \n\t"
|
||||
"addu %[ptr_j], %[ptr_i], %[tmp] \n\t"
|
||||
"lh %[tmp6], 0(%[ptr_i]) \n\t"
|
||||
"lh %[tmp5], 2(%[ptr_i]) \n\t"
|
||||
"lh %[tmp3], 0(%[ptr_j]) \n\t"
|
||||
"lh %[tmp4], 2(%[ptr_j]) \n\t"
|
||||
"addu %[i], %[i], %[istep] \n\t"
|
||||
#if defined(MIPS_DSP_R2_LE)
|
||||
"mult %[wr], %[tmp3] \n\t"
|
||||
"madd %[wi], %[tmp4] \n\t"
|
||||
"mult $ac1, %[wr], %[tmp4] \n\t"
|
||||
"msub $ac1, %[wi], %[tmp3] \n\t"
|
||||
"mflo %[tmp1] \n\t"
|
||||
"mflo %[tmp2], $ac1 \n\t"
|
||||
"sll %[tmp6], %[tmp6], 14 \n\t"
|
||||
"sll %[tmp5], %[tmp5], 14 \n\t"
|
||||
"shra_r.w %[tmp1], %[tmp1], 1 \n\t"
|
||||
"shra_r.w %[tmp2], %[tmp2], 1 \n\t"
|
||||
"subu %[tmp4], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp1], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp6], %[tmp5], %[tmp2] \n\t"
|
||||
"subu %[tmp5], %[tmp5], %[tmp2] \n\t"
|
||||
"shra_r.w %[tmp1], %[tmp1], 15 \n\t"
|
||||
"shra_r.w %[tmp6], %[tmp6], 15 \n\t"
|
||||
"shra_r.w %[tmp4], %[tmp4], 15 \n\t"
|
||||
"shra_r.w %[tmp5], %[tmp5], 15 \n\t"
|
||||
#else // #if defined(MIPS_DSP_R2_LE)
|
||||
"mul %[tmp2], %[wr], %[tmp4] \n\t"
|
||||
"mul %[tmp1], %[wr], %[tmp3] \n\t"
|
||||
"mul %[tmp4], %[wi], %[tmp4] \n\t"
|
||||
"mul %[tmp3], %[wi], %[tmp3] \n\t"
|
||||
"sll %[tmp6], %[tmp6], 14 \n\t"
|
||||
"sll %[tmp5], %[tmp5], 14 \n\t"
|
||||
"addiu %[tmp6], %[tmp6], 16384 \n\t"
|
||||
"addiu %[tmp5], %[tmp5], 16384 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[tmp4] \n\t"
|
||||
"subu %[tmp2], %[tmp2], %[tmp3] \n\t"
|
||||
"addiu %[tmp1], %[tmp1], 1 \n\t"
|
||||
"addiu %[tmp2], %[tmp2], 1 \n\t"
|
||||
"sra %[tmp1], %[tmp1], 1 \n\t"
|
||||
"sra %[tmp2], %[tmp2], 1 \n\t"
|
||||
"subu %[tmp4], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp1], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp6], %[tmp5], %[tmp2] \n\t"
|
||||
"subu %[tmp5], %[tmp5], %[tmp2] \n\t"
|
||||
"sra %[tmp4], %[tmp4], 15 \n\t"
|
||||
"sra %[tmp1], %[tmp1], 15 \n\t"
|
||||
"sra %[tmp6], %[tmp6], 15 \n\t"
|
||||
"sra %[tmp5], %[tmp5], 15 \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R2_LE)
|
||||
"sh %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"sh %[tmp6], 2(%[ptr_i]) \n\t"
|
||||
"sh %[tmp4], 0(%[ptr_j]) \n\t"
|
||||
"blt %[i], %[n], 1b \n\t"
|
||||
" sh %[tmp5], 2(%[ptr_j]) \n\t"
|
||||
"blt %[m], %[l], 2b \n\t"
|
||||
" addu %[i], $zero, %[m] \n\t"
|
||||
"move %[l], %[istep] \n\t"
|
||||
"blt %[l], %[n], 3b \n\t"
|
||||
" addiu %[k], %[k], -1 \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
|
||||
[tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6),
|
||||
[ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [wi] "=&r" (wi), [wr] "=&r" (wr),
|
||||
[m] "=&r" (m), [istep] "=&r" (istep), [l] "=&r" (l), [k] "=&r" (k),
|
||||
[ptr_j] "=&r" (ptr_j), [tmp] "=&r" (tmp)
|
||||
: [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024)
|
||||
: "hi", "lo", "memory"
|
||||
#if defined(MIPS_DSP_R2_LE)
|
||||
, "$ac1hi", "$ac1lo"
|
||||
#endif // #if defined(MIPS_DSP_R2_LE)
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) {
|
||||
int i = 0, l = 0, k = 0;
|
||||
int istep = 0, n = 0, m = 0;
|
||||
int scale = 0, shift = 0;
|
||||
int32_t wr = 0, wi = 0;
|
||||
int32_t tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0;
|
||||
int32_t tmp5 = 0, tmp6 = 0, tmp = 0, tempMax = 0, round2 = 0;
|
||||
int16_t* ptr_j = NULL;
|
||||
int16_t* ptr_i = NULL;
|
||||
|
||||
n = 1 << stages;
|
||||
if (n > 1024) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"addiu %[k], $zero, 10 \n\t"
|
||||
"addiu %[l], $zero, 1 \n\t"
|
||||
"move %[scale], $zero \n\t"
|
||||
"3: \n\t"
|
||||
"addiu %[shift], $zero, 14 \n\t"
|
||||
"addiu %[round2], $zero, 8192 \n\t"
|
||||
"move %[ptr_i], %[frfi] \n\t"
|
||||
"move %[tempMax], $zero \n\t"
|
||||
"addu %[i], %[n], %[n] \n\t"
|
||||
"5: \n\t"
|
||||
"lh %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"lh %[tmp2], 2(%[ptr_i]) \n\t"
|
||||
"lh %[tmp3], 4(%[ptr_i]) \n\t"
|
||||
"lh %[tmp4], 6(%[ptr_i]) \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"absq_s.w %[tmp1], %[tmp1] \n\t"
|
||||
"absq_s.w %[tmp2], %[tmp2] \n\t"
|
||||
"absq_s.w %[tmp3], %[tmp3] \n\t"
|
||||
"absq_s.w %[tmp4], %[tmp4] \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"slt %[tmp5], %[tmp1], $zero \n\t"
|
||||
"subu %[tmp6], $zero, %[tmp1] \n\t"
|
||||
"movn %[tmp1], %[tmp6], %[tmp5] \n\t"
|
||||
"slt %[tmp5], %[tmp2], $zero \n\t"
|
||||
"subu %[tmp6], $zero, %[tmp2] \n\t"
|
||||
"movn %[tmp2], %[tmp6], %[tmp5] \n\t"
|
||||
"slt %[tmp5], %[tmp3], $zero \n\t"
|
||||
"subu %[tmp6], $zero, %[tmp3] \n\t"
|
||||
"movn %[tmp3], %[tmp6], %[tmp5] \n\t"
|
||||
"slt %[tmp5], %[tmp4], $zero \n\t"
|
||||
"subu %[tmp6], $zero, %[tmp4] \n\t"
|
||||
"movn %[tmp4], %[tmp6], %[tmp5] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"slt %[tmp5], %[tempMax], %[tmp1] \n\t"
|
||||
"movn %[tempMax], %[tmp1], %[tmp5] \n\t"
|
||||
"addiu %[i], %[i], -4 \n\t"
|
||||
"slt %[tmp5], %[tempMax], %[tmp2] \n\t"
|
||||
"movn %[tempMax], %[tmp2], %[tmp5] \n\t"
|
||||
"slt %[tmp5], %[tempMax], %[tmp3] \n\t"
|
||||
"movn %[tempMax], %[tmp3], %[tmp5] \n\t"
|
||||
"slt %[tmp5], %[tempMax], %[tmp4] \n\t"
|
||||
"movn %[tempMax], %[tmp4], %[tmp5] \n\t"
|
||||
"bgtz %[i], 5b \n\t"
|
||||
" addiu %[ptr_i], %[ptr_i], 8 \n\t"
|
||||
"addiu %[tmp1], $zero, 13573 \n\t"
|
||||
"addiu %[tmp2], $zero, 27146 \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"sll %[tempMax], %[tempMax], 16 \n\t"
|
||||
"sra %[tempMax], %[tempMax], 16 \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"seh %[tempMax] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"slt %[tmp1], %[tmp1], %[tempMax] \n\t"
|
||||
"slt %[tmp2], %[tmp2], %[tempMax] \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[tmp2] \n\t"
|
||||
"addu %[shift], %[shift], %[tmp1] \n\t"
|
||||
"addu %[scale], %[scale], %[tmp1] \n\t"
|
||||
"sllv %[round2], %[round2], %[tmp1] \n\t"
|
||||
"sll %[istep], %[l], 1 \n\t"
|
||||
"move %[m], $zero \n\t"
|
||||
"sll %[tmp], %[l], 2 \n\t"
|
||||
"2: \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"sllv %[tmp3], %[m], %[k] \n\t"
|
||||
"addiu %[tmp2], %[tmp3], 512 \n\t"
|
||||
"addiu %[m], %[m], 1 \n\t"
|
||||
"lhx %[wi], %[tmp3](%[kSinTable1024]) \n\t"
|
||||
"lhx %[wr], %[tmp2](%[kSinTable1024]) \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"sllv %[tmp3], %[m], %[k] \n\t"
|
||||
"addu %[ptr_j], %[tmp3], %[kSinTable1024] \n\t"
|
||||
"addiu %[ptr_i], %[ptr_j], 512 \n\t"
|
||||
"addiu %[m], %[m], 1 \n\t"
|
||||
"lh %[wi], 0(%[ptr_j]) \n\t"
|
||||
"lh %[wr], 0(%[ptr_i]) \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"1: \n\t"
|
||||
"sll %[tmp1], %[i], 2 \n\t"
|
||||
"addu %[ptr_i], %[frfi], %[tmp1] \n\t"
|
||||
"addu %[ptr_j], %[ptr_i], %[tmp] \n\t"
|
||||
"lh %[tmp3], 0(%[ptr_j]) \n\t"
|
||||
"lh %[tmp4], 2(%[ptr_j]) \n\t"
|
||||
"lh %[tmp6], 0(%[ptr_i]) \n\t"
|
||||
"lh %[tmp5], 2(%[ptr_i]) \n\t"
|
||||
"addu %[i], %[i], %[istep] \n\t"
|
||||
#if defined(MIPS_DSP_R2_LE)
|
||||
"mult %[wr], %[tmp3] \n\t"
|
||||
"msub %[wi], %[tmp4] \n\t"
|
||||
"mult $ac1, %[wr], %[tmp4] \n\t"
|
||||
"madd $ac1, %[wi], %[tmp3] \n\t"
|
||||
"mflo %[tmp1] \n\t"
|
||||
"mflo %[tmp2], $ac1 \n\t"
|
||||
"sll %[tmp6], %[tmp6], 14 \n\t"
|
||||
"sll %[tmp5], %[tmp5], 14 \n\t"
|
||||
"shra_r.w %[tmp1], %[tmp1], 1 \n\t"
|
||||
"shra_r.w %[tmp2], %[tmp2], 1 \n\t"
|
||||
"addu %[tmp6], %[tmp6], %[round2] \n\t"
|
||||
"addu %[tmp5], %[tmp5], %[round2] \n\t"
|
||||
"subu %[tmp4], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp1], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp6], %[tmp5], %[tmp2] \n\t"
|
||||
"subu %[tmp5], %[tmp5], %[tmp2] \n\t"
|
||||
"srav %[tmp4], %[tmp4], %[shift] \n\t"
|
||||
"srav %[tmp1], %[tmp1], %[shift] \n\t"
|
||||
"srav %[tmp6], %[tmp6], %[shift] \n\t"
|
||||
"srav %[tmp5], %[tmp5], %[shift] \n\t"
|
||||
#else // #if defined(MIPS_DSP_R2_LE)
|
||||
"mul %[tmp1], %[wr], %[tmp3] \n\t"
|
||||
"mul %[tmp2], %[wr], %[tmp4] \n\t"
|
||||
"mul %[tmp4], %[wi], %[tmp4] \n\t"
|
||||
"mul %[tmp3], %[wi], %[tmp3] \n\t"
|
||||
"sll %[tmp6], %[tmp6], 14 \n\t"
|
||||
"sll %[tmp5], %[tmp5], 14 \n\t"
|
||||
"sub %[tmp1], %[tmp1], %[tmp4] \n\t"
|
||||
"addu %[tmp2], %[tmp2], %[tmp3] \n\t"
|
||||
"addiu %[tmp1], %[tmp1], 1 \n\t"
|
||||
"addiu %[tmp2], %[tmp2], 1 \n\t"
|
||||
"sra %[tmp2], %[tmp2], 1 \n\t"
|
||||
"sra %[tmp1], %[tmp1], 1 \n\t"
|
||||
"addu %[tmp6], %[tmp6], %[round2] \n\t"
|
||||
"addu %[tmp5], %[tmp5], %[round2] \n\t"
|
||||
"subu %[tmp4], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp1], %[tmp6], %[tmp1] \n\t"
|
||||
"addu %[tmp6], %[tmp5], %[tmp2] \n\t"
|
||||
"subu %[tmp5], %[tmp5], %[tmp2] \n\t"
|
||||
"sra %[tmp4], %[tmp4], %[shift] \n\t"
|
||||
"sra %[tmp1], %[tmp1], %[shift] \n\t"
|
||||
"sra %[tmp6], %[tmp6], %[shift] \n\t"
|
||||
"sra %[tmp5], %[tmp5], %[shift] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R2_LE)
|
||||
"sh %[tmp1], 0(%[ptr_i]) \n\t"
|
||||
"sh %[tmp6], 2(%[ptr_i]) \n\t"
|
||||
"sh %[tmp4], 0(%[ptr_j]) \n\t"
|
||||
"blt %[i], %[n], 1b \n\t"
|
||||
" sh %[tmp5], 2(%[ptr_j]) \n\t"
|
||||
"blt %[m], %[l], 2b \n\t"
|
||||
" addu %[i], $zero, %[m] \n\t"
|
||||
"move %[l], %[istep] \n\t"
|
||||
"blt %[l], %[n], 3b \n\t"
|
||||
" addiu %[k], %[k], -1 \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
|
||||
[tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6),
|
||||
[ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [m] "=&r" (m), [tmp] "=&r" (tmp),
|
||||
[istep] "=&r" (istep), [wi] "=&r" (wi), [wr] "=&r" (wr), [l] "=&r" (l),
|
||||
[k] "=&r" (k), [round2] "=&r" (round2), [ptr_j] "=&r" (ptr_j),
|
||||
[shift] "=&r" (shift), [scale] "=&r" (scale), [tempMax] "=&r" (tempMax)
|
||||
: [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024)
|
||||
: "hi", "lo", "memory"
|
||||
#if defined(MIPS_DSP_R2_LE)
|
||||
, "$ac1hi", "$ac1lo"
|
||||
#endif // #if defined(MIPS_DSP_R2_LE)
|
||||
);
|
||||
|
||||
return scale;
|
||||
|
||||
}
|
148
webrtc/common_audio/signal_processing/complex_fft_tables.h
Normal file
148
webrtc/common_audio/signal_processing/complex_fft_tables.h
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
|
||||
#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
static const int16_t kSinTable1024[] = {
|
||||
0, 201, 402, 603, 804, 1005, 1206, 1406,
|
||||
1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
|
||||
3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
|
||||
4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
|
||||
6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766,
|
||||
7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
|
||||
9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849,
|
||||
11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
|
||||
12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
|
||||
14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
|
||||
15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672,
|
||||
16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
|
||||
18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357,
|
||||
19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
|
||||
20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855,
|
||||
22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
|
||||
23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143,
|
||||
24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
|
||||
25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198,
|
||||
26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
|
||||
27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001,
|
||||
28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
|
||||
28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534,
|
||||
29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
|
||||
30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783,
|
||||
30851, 30918, 30984, 31049, 31113, 31175, 31236, 31297,
|
||||
31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
|
||||
31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
|
||||
32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382,
|
||||
32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
|
||||
32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717,
|
||||
32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
|
||||
32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736,
|
||||
32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
|
||||
32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441,
|
||||
32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
|
||||
32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833,
|
||||
31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
|
||||
31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918,
|
||||
30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
|
||||
30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706,
|
||||
29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
|
||||
28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208,
|
||||
28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
|
||||
27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
|
||||
26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
|
||||
25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413,
|
||||
24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
|
||||
23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153,
|
||||
22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
|
||||
20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680,
|
||||
19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
|
||||
18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017,
|
||||
16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
|
||||
15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191,
|
||||
14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
|
||||
12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227,
|
||||
11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
|
||||
9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156,
|
||||
7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
|
||||
6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006,
|
||||
4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
|
||||
3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
|
||||
1607, 1406, 1206, 1005, 804, 603, 402, 201,
|
||||
0, -201, -402, -603, -804, -1005, -1206, -1406,
|
||||
-1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
|
||||
-3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608,
|
||||
-4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
|
||||
-6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766,
|
||||
-7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
|
||||
-9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849,
|
||||
-11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
|
||||
-12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
|
||||
-14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
|
||||
-15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
|
||||
-16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
|
||||
-18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
|
||||
-19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
|
||||
-20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
|
||||
-22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
|
||||
-23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
|
||||
-24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
|
||||
-25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
|
||||
-26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
|
||||
-27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
|
||||
-28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
|
||||
-28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
|
||||
-29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
|
||||
-30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
|
||||
-30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
|
||||
-31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
|
||||
-31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
|
||||
-32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
|
||||
-32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
|
||||
-32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
|
||||
-32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
|
||||
-32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
|
||||
-32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
|
||||
-32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
|
||||
-32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
|
||||
-32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
|
||||
-31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
|
||||
-31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
|
||||
-30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
|
||||
-30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
|
||||
-29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
|
||||
-28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
|
||||
-28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
|
||||
-27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
|
||||
-26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
|
||||
-25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
|
||||
-24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
|
||||
-23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
|
||||
-22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
|
||||
-20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
|
||||
-19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
|
||||
-18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
|
||||
-16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
|
||||
-15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
|
||||
-14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
|
||||
-12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
|
||||
-11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
|
||||
-9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156,
|
||||
-7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
|
||||
-6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
|
||||
-4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
|
||||
-3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
|
||||
-1607, -1406, -1206, -1005, -804, -603, -402, -201
|
||||
};
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
|
82
webrtc/common_audio/signal_processing/copy_set_operations.c
Normal file
82
webrtc/common_audio/signal_processing/copy_set_operations.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the implementation of functions
|
||||
* WebRtcSpl_MemSetW16()
|
||||
* WebRtcSpl_MemSetW32()
|
||||
* WebRtcSpl_MemCpyReversedOrder()
|
||||
* WebRtcSpl_CopyFromEndW16()
|
||||
* WebRtcSpl_ZerosArrayW16()
|
||||
* WebRtcSpl_ZerosArrayW32()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
|
||||
void WebRtcSpl_MemSetW16(int16_t *ptr, int16_t set_value, size_t length)
|
||||
{
|
||||
size_t j;
|
||||
int16_t *arrptr = ptr;
|
||||
|
||||
for (j = length; j > 0; j--)
|
||||
{
|
||||
*arrptr++ = set_value;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_MemSetW32(int32_t *ptr, int32_t set_value, size_t length)
|
||||
{
|
||||
size_t j;
|
||||
int32_t *arrptr = ptr;
|
||||
|
||||
for (j = length; j > 0; j--)
|
||||
{
|
||||
*arrptr++ = set_value;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_MemCpyReversedOrder(int16_t* dest,
|
||||
int16_t* source,
|
||||
size_t length)
|
||||
{
|
||||
size_t j;
|
||||
int16_t* destPtr = dest;
|
||||
int16_t* sourcePtr = source;
|
||||
|
||||
for (j = 0; j < length; j++)
|
||||
{
|
||||
*destPtr-- = *sourcePtr++;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_CopyFromEndW16(const int16_t *vector_in,
|
||||
size_t length,
|
||||
size_t samples,
|
||||
int16_t *vector_out)
|
||||
{
|
||||
// Copy the last <samples> of the input vector to vector_out
|
||||
WEBRTC_SPL_MEMCPY_W16(vector_out, &vector_in[length - samples], samples);
|
||||
}
|
||||
|
||||
void WebRtcSpl_ZerosArrayW16(int16_t *vector, size_t length)
|
||||
{
|
||||
WebRtcSpl_MemSetW16(vector, 0, length);
|
||||
}
|
||||
|
||||
void WebRtcSpl_ZerosArrayW32(int32_t *vector, size_t length)
|
||||
{
|
||||
WebRtcSpl_MemSetW32(vector, 0, length);
|
||||
}
|
30
webrtc/common_audio/signal_processing/cross_correlation.c
Normal file
30
webrtc/common_audio/signal_processing/cross_correlation.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
/* C version of WebRtcSpl_CrossCorrelation() for generic platforms. */
|
||||
void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation,
|
||||
const int16_t* seq1,
|
||||
const int16_t* seq2,
|
||||
size_t dim_seq,
|
||||
size_t dim_cross_correlation,
|
||||
int right_shifts,
|
||||
int step_seq2) {
|
||||
size_t i = 0, j = 0;
|
||||
|
||||
for (i = 0; i < dim_cross_correlation; i++) {
|
||||
int32_t corr = 0;
|
||||
for (j = 0; j < dim_seq; j++)
|
||||
corr += (seq1[j] * seq2[j]) >> right_shifts;
|
||||
seq2 += step_seq2;
|
||||
*cross_correlation++ = corr;
|
||||
}
|
||||
}
|
104
webrtc/common_audio/signal_processing/cross_correlation_mips.c
Normal file
104
webrtc/common_audio/signal_processing/cross_correlation_mips.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation,
|
||||
const int16_t* seq1,
|
||||
const int16_t* seq2,
|
||||
size_t dim_seq,
|
||||
size_t dim_cross_correlation,
|
||||
int right_shifts,
|
||||
int step_seq2) {
|
||||
|
||||
int32_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, sum = 0;
|
||||
int16_t *pseq2 = NULL;
|
||||
int16_t *pseq1 = NULL;
|
||||
int16_t *pseq1_0 = (int16_t*)&seq1[0];
|
||||
int16_t *pseq2_0 = (int16_t*)&seq2[0];
|
||||
int k = 0;
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"sll %[step_seq2], %[step_seq2], 1 \n\t"
|
||||
"andi %[t0], %[dim_seq], 1 \n\t"
|
||||
"bgtz %[t0], 3f \n\t"
|
||||
" nop \n\t"
|
||||
"1: \n\t"
|
||||
"move %[pseq1], %[pseq1_0] \n\t"
|
||||
"move %[pseq2], %[pseq2_0] \n\t"
|
||||
"sra %[k], %[dim_seq], 1 \n\t"
|
||||
"addiu %[dim_cc], %[dim_cc], -1 \n\t"
|
||||
"xor %[sum], %[sum], %[sum] \n\t"
|
||||
"2: \n\t"
|
||||
"lh %[t0], 0(%[pseq1]) \n\t"
|
||||
"lh %[t1], 0(%[pseq2]) \n\t"
|
||||
"lh %[t2], 2(%[pseq1]) \n\t"
|
||||
"lh %[t3], 2(%[pseq2]) \n\t"
|
||||
"mul %[t0], %[t0], %[t1] \n\t"
|
||||
"addiu %[k], %[k], -1 \n\t"
|
||||
"mul %[t2], %[t2], %[t3] \n\t"
|
||||
"addiu %[pseq1], %[pseq1], 4 \n\t"
|
||||
"addiu %[pseq2], %[pseq2], 4 \n\t"
|
||||
"srav %[t0], %[t0], %[right_shifts] \n\t"
|
||||
"addu %[sum], %[sum], %[t0] \n\t"
|
||||
"srav %[t2], %[t2], %[right_shifts] \n\t"
|
||||
"bgtz %[k], 2b \n\t"
|
||||
" addu %[sum], %[sum], %[t2] \n\t"
|
||||
"addu %[pseq2_0], %[pseq2_0], %[step_seq2] \n\t"
|
||||
"sw %[sum], 0(%[cc]) \n\t"
|
||||
"bgtz %[dim_cc], 1b \n\t"
|
||||
" addiu %[cc], %[cc], 4 \n\t"
|
||||
"b 6f \n\t"
|
||||
" nop \n\t"
|
||||
"3: \n\t"
|
||||
"move %[pseq1], %[pseq1_0] \n\t"
|
||||
"move %[pseq2], %[pseq2_0] \n\t"
|
||||
"sra %[k], %[dim_seq], 1 \n\t"
|
||||
"addiu %[dim_cc], %[dim_cc], -1 \n\t"
|
||||
"beqz %[k], 5f \n\t"
|
||||
" xor %[sum], %[sum], %[sum] \n\t"
|
||||
"4: \n\t"
|
||||
"lh %[t0], 0(%[pseq1]) \n\t"
|
||||
"lh %[t1], 0(%[pseq2]) \n\t"
|
||||
"lh %[t2], 2(%[pseq1]) \n\t"
|
||||
"lh %[t3], 2(%[pseq2]) \n\t"
|
||||
"mul %[t0], %[t0], %[t1] \n\t"
|
||||
"addiu %[k], %[k], -1 \n\t"
|
||||
"mul %[t2], %[t2], %[t3] \n\t"
|
||||
"addiu %[pseq1], %[pseq1], 4 \n\t"
|
||||
"addiu %[pseq2], %[pseq2], 4 \n\t"
|
||||
"srav %[t0], %[t0], %[right_shifts] \n\t"
|
||||
"addu %[sum], %[sum], %[t0] \n\t"
|
||||
"srav %[t2], %[t2], %[right_shifts] \n\t"
|
||||
"bgtz %[k], 4b \n\t"
|
||||
" addu %[sum], %[sum], %[t2] \n\t"
|
||||
"5: \n\t"
|
||||
"lh %[t0], 0(%[pseq1]) \n\t"
|
||||
"lh %[t1], 0(%[pseq2]) \n\t"
|
||||
"mul %[t0], %[t0], %[t1] \n\t"
|
||||
"srav %[t0], %[t0], %[right_shifts] \n\t"
|
||||
"addu %[sum], %[sum], %[t0] \n\t"
|
||||
"addu %[pseq2_0], %[pseq2_0], %[step_seq2] \n\t"
|
||||
"sw %[sum], 0(%[cc]) \n\t"
|
||||
"bgtz %[dim_cc], 3b \n\t"
|
||||
" addiu %[cc], %[cc], 4 \n\t"
|
||||
"6: \n\t"
|
||||
".set pop \n\t"
|
||||
: [step_seq2] "+r" (step_seq2), [t0] "=&r" (t0), [t1] "=&r" (t1),
|
||||
[t2] "=&r" (t2), [t3] "=&r" (t3), [pseq1] "=&r" (pseq1),
|
||||
[pseq2] "=&r" (pseq2), [pseq1_0] "+r" (pseq1_0), [pseq2_0] "+r" (pseq2_0),
|
||||
[k] "=&r" (k), [dim_cc] "+r" (dim_cross_correlation), [sum] "=&r" (sum),
|
||||
[cc] "+r" (cross_correlation)
|
||||
: [dim_seq] "r" (dim_seq), [right_shifts] "r" (right_shifts)
|
||||
: "hi", "lo", "memory"
|
||||
);
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
static inline void DotProductWithScaleNeon(int32_t* cross_correlation,
|
||||
const int16_t* vector1,
|
||||
const int16_t* vector2,
|
||||
size_t length,
|
||||
int scaling) {
|
||||
size_t i = 0;
|
||||
size_t len1 = length >> 3;
|
||||
size_t len2 = length & 7;
|
||||
int64x2_t sum0 = vdupq_n_s64(0);
|
||||
int64x2_t sum1 = vdupq_n_s64(0);
|
||||
|
||||
for (i = len1; i > 0; i -= 1) {
|
||||
int16x8_t seq1_16x8 = vld1q_s16(vector1);
|
||||
int16x8_t seq2_16x8 = vld1q_s16(vector2);
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
int32x4_t tmp0 = vmull_s16(vget_low_s16(seq1_16x8),
|
||||
vget_low_s16(seq2_16x8));
|
||||
int32x4_t tmp1 = vmull_high_s16(seq1_16x8, seq2_16x8);
|
||||
#else
|
||||
int32x4_t tmp0 = vmull_s16(vget_low_s16(seq1_16x8),
|
||||
vget_low_s16(seq2_16x8));
|
||||
int32x4_t tmp1 = vmull_s16(vget_high_s16(seq1_16x8),
|
||||
vget_high_s16(seq2_16x8));
|
||||
#endif
|
||||
sum0 = vpadalq_s32(sum0, tmp0);
|
||||
sum1 = vpadalq_s32(sum1, tmp1);
|
||||
vector1 += 8;
|
||||
vector2 += 8;
|
||||
}
|
||||
|
||||
// Calculate the rest of the samples.
|
||||
int64_t sum_res = 0;
|
||||
for (i = len2; i > 0; i -= 1) {
|
||||
sum_res += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
|
||||
vector1++;
|
||||
vector2++;
|
||||
}
|
||||
|
||||
sum0 = vaddq_s64(sum0, sum1);
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
int64_t sum2 = vaddvq_s64(sum0);
|
||||
*cross_correlation = (int32_t)((sum2 + sum_res) >> scaling);
|
||||
#else
|
||||
int64x1_t shift = vdup_n_s64(-scaling);
|
||||
int64x1_t sum2 = vadd_s64(vget_low_s64(sum0), vget_high_s64(sum0));
|
||||
sum2 = vadd_s64(sum2, vdup_n_s64(sum_res));
|
||||
sum2 = vshl_s64(sum2, shift);
|
||||
vst1_lane_s32(cross_correlation, vreinterpret_s32_s64(sum2), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NEON version of WebRtcSpl_CrossCorrelation() for ARM32/64 platforms. */
|
||||
void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation,
|
||||
const int16_t* seq1,
|
||||
const int16_t* seq2,
|
||||
size_t dim_seq,
|
||||
size_t dim_cross_correlation,
|
||||
int right_shifts,
|
||||
int step_seq2) {
|
||||
size_t i = 0;
|
||||
|
||||
for (i = 0; i < dim_cross_correlation; i++) {
|
||||
const int16_t* seq1_ptr = seq1;
|
||||
const int16_t* seq2_ptr = seq2 + (step_seq2 * i);
|
||||
|
||||
DotProductWithScaleNeon(cross_correlation,
|
||||
seq1_ptr,
|
||||
seq2_ptr,
|
||||
dim_seq,
|
||||
right_shifts);
|
||||
cross_correlation++;
|
||||
}
|
||||
}
|
138
webrtc/common_audio/signal_processing/division_operations.c
Normal file
138
webrtc/common_audio/signal_processing/division_operations.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the divisions
|
||||
* WebRtcSpl_DivU32U16()
|
||||
* WebRtcSpl_DivW32W16()
|
||||
* WebRtcSpl_DivW32W16ResW16()
|
||||
* WebRtcSpl_DivResultInQ31()
|
||||
* WebRtcSpl_DivW32HiLow()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (uint32_t)(num / den);
|
||||
} else
|
||||
{
|
||||
return (uint32_t)0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (int32_t)(num / den);
|
||||
} else
|
||||
{
|
||||
return (int32_t)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (int16_t)(num / den);
|
||||
} else
|
||||
{
|
||||
return (int16_t)0x7FFF;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
|
||||
{
|
||||
int32_t L_num = num;
|
||||
int32_t L_den = den;
|
||||
int32_t div = 0;
|
||||
int k = 31;
|
||||
int change_sign = 0;
|
||||
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
change_sign++;
|
||||
L_num = -num;
|
||||
}
|
||||
if (den < 0)
|
||||
{
|
||||
change_sign++;
|
||||
L_den = -den;
|
||||
}
|
||||
while (k--)
|
||||
{
|
||||
div <<= 1;
|
||||
L_num <<= 1;
|
||||
if (L_num >= L_den)
|
||||
{
|
||||
L_num -= L_den;
|
||||
div++;
|
||||
}
|
||||
}
|
||||
if (change_sign == 1)
|
||||
{
|
||||
div = -div;
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
|
||||
{
|
||||
int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
|
||||
int32_t tmpW32;
|
||||
|
||||
approx = (int16_t)WebRtcSpl_DivW32W16((int32_t)0x1FFFFFFF, den_hi);
|
||||
// result in Q14 (Note: 3FFFFFFF = 0.5 in Q30)
|
||||
|
||||
// tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30)
|
||||
tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1);
|
||||
// tmpW32 = den * approx
|
||||
|
||||
tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
|
||||
|
||||
// Store tmpW32 in hi and low format
|
||||
tmp_hi = (int16_t)(tmpW32 >> 16);
|
||||
tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
|
||||
|
||||
// tmpW32 = 1/den in Q29
|
||||
tmpW32 = (tmp_hi * approx + (tmp_low * approx >> 15)) << 1;
|
||||
|
||||
// 1/den in hi and low format
|
||||
tmp_hi = (int16_t)(tmpW32 >> 16);
|
||||
tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
|
||||
|
||||
// Store num in hi and low format
|
||||
num_hi = (int16_t)(num >> 16);
|
||||
num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1);
|
||||
|
||||
// num * (1/den) by 32 bit multiplication (result in Q28)
|
||||
|
||||
tmpW32 = num_hi * tmp_hi + (num_hi * tmp_low >> 15) +
|
||||
(num_low * tmp_hi >> 15);
|
||||
|
||||
// Put result in Q31 (convert from Q28)
|
||||
tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3);
|
||||
|
||||
return tmpW32;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
|
||||
const int16_t* vector2,
|
||||
size_t length,
|
||||
int scaling) {
|
||||
int32_t sum = 0;
|
||||
size_t i = 0;
|
||||
|
||||
/* Unroll the loop to improve performance. */
|
||||
for (i = 0; i + 3 < length; i += 4) {
|
||||
sum += (vector1[i + 0] * vector2[i + 0]) >> scaling;
|
||||
sum += (vector1[i + 1] * vector2[i + 1]) >> scaling;
|
||||
sum += (vector1[i + 2] * vector2[i + 2]) >> scaling;
|
||||
sum += (vector1[i + 3] * vector2[i + 3]) >> scaling;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
sum += (vector1[i] * vector2[i]) >> scaling;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
48
webrtc/common_audio/signal_processing/downsample_fast.c
Normal file
48
webrtc/common_audio/signal_processing/downsample_fast.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// TODO(Bjornv): Change the function parameter order to WebRTC code style.
|
||||
// C version of WebRtcSpl_DownsampleFast() for generic platforms.
|
||||
int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
|
||||
size_t data_in_length,
|
||||
int16_t* data_out,
|
||||
size_t data_out_length,
|
||||
const int16_t* __restrict coefficients,
|
||||
size_t coefficients_length,
|
||||
int factor,
|
||||
size_t delay) {
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
int32_t out_s32 = 0;
|
||||
size_t endpos = delay + factor * (data_out_length - 1) + 1;
|
||||
|
||||
// Return error if any of the running conditions doesn't meet.
|
||||
if (data_out_length == 0 || coefficients_length == 0
|
||||
|| data_in_length < endpos) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = delay; i < endpos; i += factor) {
|
||||
out_s32 = 2048; // Round value, 0.5 in Q12.
|
||||
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
out_s32 += coefficients[j] * data_in[i - j]; // Q12.
|
||||
}
|
||||
|
||||
out_s32 >>= 12; // Q0.
|
||||
|
||||
// Saturate and store the output.
|
||||
*data_out++ = WebRtcSpl_SatW32ToW16(out_s32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
169
webrtc/common_audio/signal_processing/downsample_fast_mips.c
Normal file
169
webrtc/common_audio/signal_processing/downsample_fast_mips.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// Version of WebRtcSpl_DownsampleFast() for MIPS platforms.
|
||||
int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in,
|
||||
size_t data_in_length,
|
||||
int16_t* data_out,
|
||||
size_t data_out_length,
|
||||
const int16_t* __restrict coefficients,
|
||||
size_t coefficients_length,
|
||||
int factor,
|
||||
size_t delay) {
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
int32_t out_s32 = 0;
|
||||
size_t endpos = delay + factor * (data_out_length - 1) + 1;
|
||||
|
||||
int32_t tmp1, tmp2, tmp3, tmp4, factor_2;
|
||||
int16_t* p_coefficients;
|
||||
int16_t* p_data_in;
|
||||
int16_t* p_data_in_0 = (int16_t*)&data_in[delay];
|
||||
int16_t* p_coefficients_0 = (int16_t*)&coefficients[0];
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
int32_t max_16 = 0x7FFF;
|
||||
int32_t min_16 = 0xFFFF8000;
|
||||
#endif // #if !defined(MIPS_DSP_R1_LE)
|
||||
|
||||
// Return error if any of the running conditions doesn't meet.
|
||||
if (data_out_length == 0 || coefficients_length == 0
|
||||
|| data_in_length < endpos) {
|
||||
return -1;
|
||||
}
|
||||
#if defined(MIPS_DSP_R2_LE)
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"subu %[i], %[endpos], %[delay] \n\t"
|
||||
"sll %[factor_2], %[factor], 1 \n\t"
|
||||
"1: \n\t"
|
||||
"move %[p_data_in], %[p_data_in_0] \n\t"
|
||||
"mult $zero, $zero \n\t"
|
||||
"move %[p_coefs], %[p_coefs_0] \n\t"
|
||||
"sra %[j], %[coef_length], 2 \n\t"
|
||||
"beq %[j], $zero, 3f \n\t"
|
||||
" andi %[k], %[coef_length], 3 \n\t"
|
||||
"2: \n\t"
|
||||
"lwl %[tmp1], 1(%[p_data_in]) \n\t"
|
||||
"lwl %[tmp2], 3(%[p_coefs]) \n\t"
|
||||
"lwl %[tmp3], -3(%[p_data_in]) \n\t"
|
||||
"lwl %[tmp4], 7(%[p_coefs]) \n\t"
|
||||
"lwr %[tmp1], -2(%[p_data_in]) \n\t"
|
||||
"lwr %[tmp2], 0(%[p_coefs]) \n\t"
|
||||
"lwr %[tmp3], -6(%[p_data_in]) \n\t"
|
||||
"lwr %[tmp4], 4(%[p_coefs]) \n\t"
|
||||
"packrl.ph %[tmp1], %[tmp1], %[tmp1] \n\t"
|
||||
"packrl.ph %[tmp3], %[tmp3], %[tmp3] \n\t"
|
||||
"dpa.w.ph $ac0, %[tmp1], %[tmp2] \n\t"
|
||||
"dpa.w.ph $ac0, %[tmp3], %[tmp4] \n\t"
|
||||
"addiu %[j], %[j], -1 \n\t"
|
||||
"addiu %[p_data_in], %[p_data_in], -8 \n\t"
|
||||
"bgtz %[j], 2b \n\t"
|
||||
" addiu %[p_coefs], %[p_coefs], 8 \n\t"
|
||||
"3: \n\t"
|
||||
"beq %[k], $zero, 5f \n\t"
|
||||
" nop \n\t"
|
||||
"4: \n\t"
|
||||
"lhu %[tmp1], 0(%[p_data_in]) \n\t"
|
||||
"lhu %[tmp2], 0(%[p_coefs]) \n\t"
|
||||
"addiu %[p_data_in], %[p_data_in], -2 \n\t"
|
||||
"addiu %[k], %[k], -1 \n\t"
|
||||
"dpa.w.ph $ac0, %[tmp1], %[tmp2] \n\t"
|
||||
"bgtz %[k], 4b \n\t"
|
||||
" addiu %[p_coefs], %[p_coefs], 2 \n\t"
|
||||
"5: \n\t"
|
||||
"extr_r.w %[out_s32], $ac0, 12 \n\t"
|
||||
"addu %[p_data_in_0], %[p_data_in_0], %[factor_2] \n\t"
|
||||
"subu %[i], %[i], %[factor] \n\t"
|
||||
"shll_s.w %[out_s32], %[out_s32], 16 \n\t"
|
||||
"sra %[out_s32], %[out_s32], 16 \n\t"
|
||||
"sh %[out_s32], 0(%[data_out]) \n\t"
|
||||
"bgtz %[i], 1b \n\t"
|
||||
" addiu %[data_out], %[data_out], 2 \n\t"
|
||||
".set pop \n\t"
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
|
||||
[tmp4] "=&r" (tmp4), [p_data_in] "=&r" (p_data_in),
|
||||
[p_data_in_0] "+r" (p_data_in_0), [p_coefs] "=&r" (p_coefficients),
|
||||
[j] "=&r" (j), [out_s32] "=&r" (out_s32), [factor_2] "=&r" (factor_2),
|
||||
[i] "=&r" (i), [k] "=&r" (k)
|
||||
: [coef_length] "r" (coefficients_length), [data_out] "r" (data_out),
|
||||
[p_coefs_0] "r" (p_coefficients_0), [endpos] "r" (endpos),
|
||||
[delay] "r" (delay), [factor] "r" (factor)
|
||||
: "memory", "hi", "lo"
|
||||
);
|
||||
#else // #if defined(MIPS_DSP_R2_LE)
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"sll %[factor_2], %[factor], 1 \n\t"
|
||||
"subu %[i], %[endpos], %[delay] \n\t"
|
||||
"1: \n\t"
|
||||
"move %[p_data_in], %[p_data_in_0] \n\t"
|
||||
"addiu %[out_s32], $zero, 2048 \n\t"
|
||||
"move %[p_coefs], %[p_coefs_0] \n\t"
|
||||
"sra %[j], %[coef_length], 1 \n\t"
|
||||
"beq %[j], $zero, 3f \n\t"
|
||||
" andi %[k], %[coef_length], 1 \n\t"
|
||||
"2: \n\t"
|
||||
"lh %[tmp1], 0(%[p_data_in]) \n\t"
|
||||
"lh %[tmp2], 0(%[p_coefs]) \n\t"
|
||||
"lh %[tmp3], -2(%[p_data_in]) \n\t"
|
||||
"lh %[tmp4], 2(%[p_coefs]) \n\t"
|
||||
"mul %[tmp1], %[tmp1], %[tmp2] \n\t"
|
||||
"addiu %[p_coefs], %[p_coefs], 4 \n\t"
|
||||
"mul %[tmp3], %[tmp3], %[tmp4] \n\t"
|
||||
"addiu %[j], %[j], -1 \n\t"
|
||||
"addiu %[p_data_in], %[p_data_in], -4 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[tmp3] \n\t"
|
||||
"bgtz %[j], 2b \n\t"
|
||||
" addu %[out_s32], %[out_s32], %[tmp1] \n\t"
|
||||
"3: \n\t"
|
||||
"beq %[k], $zero, 4f \n\t"
|
||||
" nop \n\t"
|
||||
"lh %[tmp1], 0(%[p_data_in]) \n\t"
|
||||
"lh %[tmp2], 0(%[p_coefs]) \n\t"
|
||||
"mul %[tmp1], %[tmp1], %[tmp2] \n\t"
|
||||
"addu %[out_s32], %[out_s32], %[tmp1] \n\t"
|
||||
"4: \n\t"
|
||||
"sra %[out_s32], %[out_s32], 12 \n\t"
|
||||
"addu %[p_data_in_0], %[p_data_in_0], %[factor_2] \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"shll_s.w %[out_s32], %[out_s32], 16 \n\t"
|
||||
"sra %[out_s32], %[out_s32], 16 \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"slt %[tmp1], %[max_16], %[out_s32] \n\t"
|
||||
"movn %[out_s32], %[max_16], %[tmp1] \n\t"
|
||||
"slt %[tmp1], %[out_s32], %[min_16] \n\t"
|
||||
"movn %[out_s32], %[min_16], %[tmp1] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"subu %[i], %[i], %[factor] \n\t"
|
||||
"sh %[out_s32], 0(%[data_out]) \n\t"
|
||||
"bgtz %[i], 1b \n\t"
|
||||
" addiu %[data_out], %[data_out], 2 \n\t"
|
||||
".set pop \n\t"
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
|
||||
[tmp4] "=&r" (tmp4), [p_data_in] "=&r" (p_data_in), [k] "=&r" (k),
|
||||
[p_data_in_0] "+r" (p_data_in_0), [p_coefs] "=&r" (p_coefficients),
|
||||
[j] "=&r" (j), [out_s32] "=&r" (out_s32), [factor_2] "=&r" (factor_2),
|
||||
[i] "=&r" (i)
|
||||
: [coef_length] "r" (coefficients_length), [data_out] "r" (data_out),
|
||||
[p_coefs_0] "r" (p_coefficients_0), [endpos] "r" (endpos),
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
[max_16] "r" (max_16), [min_16] "r" (min_16),
|
||||
#endif // #if !defined(MIPS_DSP_R1_LE)
|
||||
[delay] "r" (delay), [factor] "r" (factor)
|
||||
: "memory", "hi", "lo"
|
||||
);
|
||||
#endif // #if defined(MIPS_DSP_R2_LE)
|
||||
return 0;
|
||||
}
|
217
webrtc/common_audio/signal_processing/downsample_fast_neon.c
Normal file
217
webrtc/common_audio/signal_processing/downsample_fast_neon.c
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
// NEON intrinsics version of WebRtcSpl_DownsampleFast()
|
||||
// for ARM 32-bit/64-bit platforms.
|
||||
int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
size_t data_in_length,
|
||||
int16_t* data_out,
|
||||
size_t data_out_length,
|
||||
const int16_t* __restrict coefficients,
|
||||
size_t coefficients_length,
|
||||
int factor,
|
||||
size_t delay) {
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
int32_t out_s32 = 0;
|
||||
size_t endpos = delay + factor * (data_out_length - 1) + 1;
|
||||
size_t res = data_out_length & 0x7;
|
||||
size_t endpos1 = endpos - factor * res;
|
||||
|
||||
// Return error if any of the running conditions doesn't meet.
|
||||
if (data_out_length == 0 || coefficients_length == 0
|
||||
|| data_in_length < endpos) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// First part, unroll the loop 8 times, with 3 subcases
|
||||
// (factor == 2, 4, others).
|
||||
switch (factor) {
|
||||
case 2: {
|
||||
for (i = delay; i < endpos1; i += 16) {
|
||||
// Round value, 0.5 in Q12.
|
||||
int32x4_t out32x4_0 = vdupq_n_s32(2048);
|
||||
int32x4_t out32x4_1 = vdupq_n_s32(2048);
|
||||
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
// Unroll the loop 2 times.
|
||||
for (j = 0; j < coefficients_length - 1; j += 2) {
|
||||
int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]);
|
||||
int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32);
|
||||
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]);
|
||||
|
||||
// Mul and accumulate low 64-bit data.
|
||||
int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]);
|
||||
int16x4_t in16x4_1 = vget_low_s16(in16x8x2.val[1]);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 1);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_1, coeff16x4, 0);
|
||||
|
||||
// Mul and accumulate high 64-bit data.
|
||||
// TODO: vget_high_s16 need extra cost on ARM64. This could be
|
||||
// replaced by vmlal_high_lane_s16. But for the interface of
|
||||
// vmlal_high_lane_s16, there is a bug in gcc 4.9.
|
||||
// This issue need to be tracked in the future.
|
||||
int16x4_t in16x4_2 = vget_high_s16(in16x8x2.val[0]);
|
||||
int16x4_t in16x4_3 = vget_high_s16(in16x8x2.val[1]);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_2, coeff16x4, 1);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0);
|
||||
}
|
||||
|
||||
for (; j < coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]);
|
||||
|
||||
// Mul and accumulate low 64-bit data.
|
||||
int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0);
|
||||
|
||||
// Mul and accumulate high 64-bit data.
|
||||
// TODO: vget_high_s16 need extra cost on ARM64. This could be
|
||||
// replaced by vmlal_high_lane_s16. But for the interface of
|
||||
// vmlal_high_lane_s16, there is a bug in gcc 4.9.
|
||||
// This issue need to be tracked in the future.
|
||||
int16x4_t in16x4_1 = vget_high_s16(in16x8x2.val[0]);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0);
|
||||
}
|
||||
#else
|
||||
// On ARMv7, the loop unrolling 2 times results in performance
|
||||
// regression.
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]);
|
||||
|
||||
// Mul and accumulate.
|
||||
int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]);
|
||||
int16x4_t in16x4_1 = vget_high_s16(in16x8x2.val[0]);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Saturate and store the output.
|
||||
int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12);
|
||||
int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12);
|
||||
vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1));
|
||||
data_out += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
for (i = delay; i < endpos1; i += 32) {
|
||||
// Round value, 0.5 in Q12.
|
||||
int32x4_t out32x4_0 = vdupq_n_s32(2048);
|
||||
int32x4_t out32x4_1 = vdupq_n_s32(2048);
|
||||
|
||||
// Unroll the loop 4 times.
|
||||
for (j = 0; j < coefficients_length - 3; j += 4) {
|
||||
int16x4_t coeff16x4 = vld1_s16(&coefficients[j]);
|
||||
int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]);
|
||||
|
||||
// Mul and accumulate low 64-bit data.
|
||||
int16x4_t in16x4_0 = vget_low_s16(in16x8x4.val[0]);
|
||||
int16x4_t in16x4_2 = vget_low_s16(in16x8x4.val[1]);
|
||||
int16x4_t in16x4_4 = vget_low_s16(in16x8x4.val[2]);
|
||||
int16x4_t in16x4_6 = vget_low_s16(in16x8x4.val[3]);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 3);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_2, coeff16x4, 2);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_4, coeff16x4, 1);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_6, coeff16x4, 0);
|
||||
|
||||
// Mul and accumulate high 64-bit data.
|
||||
// TODO: vget_high_s16 need extra cost on ARM64. This could be
|
||||
// replaced by vmlal_high_lane_s16. But for the interface of
|
||||
// vmlal_high_lane_s16, there is a bug in gcc 4.9.
|
||||
// This issue need to be tracked in the future.
|
||||
int16x4_t in16x4_1 = vget_high_s16(in16x8x4.val[0]);
|
||||
int16x4_t in16x4_3 = vget_high_s16(in16x8x4.val[1]);
|
||||
int16x4_t in16x4_5 = vget_high_s16(in16x8x4.val[2]);
|
||||
int16x4_t in16x4_7 = vget_high_s16(in16x8x4.val[3]);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 3);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 2);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_5, coeff16x4, 1);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0);
|
||||
}
|
||||
|
||||
for (; j < coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]);
|
||||
|
||||
// Mul and accumulate low 64-bit data.
|
||||
int16x4_t in16x4_0 = vget_low_s16(in16x8x4.val[0]);
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0);
|
||||
|
||||
// Mul and accumulate high 64-bit data.
|
||||
// TODO: vget_high_s16 need extra cost on ARM64. This could be
|
||||
// replaced by vmlal_high_lane_s16. But for the interface of
|
||||
// vmlal_high_lane_s16, there is a bug in gcc 4.9.
|
||||
// This issue need to be tracked in the future.
|
||||
int16x4_t in16x4_1 = vget_high_s16(in16x8x4.val[0]);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0);
|
||||
}
|
||||
|
||||
// Saturate and store the output.
|
||||
int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12);
|
||||
int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12);
|
||||
vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1));
|
||||
data_out += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
for (i = delay; i < endpos1; i += factor * 8) {
|
||||
// Round value, 0.5 in Q12.
|
||||
int32x4_t out32x4_0 = vdupq_n_s32(2048);
|
||||
int32x4_t out32x4_1 = vdupq_n_s32(2048);
|
||||
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]);
|
||||
in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1);
|
||||
in16x4_0 = vld1_lane_s16(&data_in[i + factor * 2 - j], in16x4_0, 2);
|
||||
in16x4_0 = vld1_lane_s16(&data_in[i + factor * 3 - j], in16x4_0, 3);
|
||||
int16x4_t in16x4_1 = vld1_dup_s16(&data_in[i + factor * 4 - j]);
|
||||
in16x4_1 = vld1_lane_s16(&data_in[i + factor * 5 - j], in16x4_1, 1);
|
||||
in16x4_1 = vld1_lane_s16(&data_in[i + factor * 6 - j], in16x4_1, 2);
|
||||
in16x4_1 = vld1_lane_s16(&data_in[i + factor * 7 - j], in16x4_1, 3);
|
||||
|
||||
// Mul and accumulate.
|
||||
out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0);
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0);
|
||||
}
|
||||
|
||||
// Saturate and store the output.
|
||||
int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12);
|
||||
int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12);
|
||||
vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1));
|
||||
data_out += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Second part, do the rest iterations (if any).
|
||||
for (; i < endpos; i += factor) {
|
||||
out_s32 = 2048; // Round value, 0.5 in Q12.
|
||||
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32);
|
||||
}
|
||||
|
||||
// Saturate and store the output.
|
||||
out_s32 >>= 12;
|
||||
*data_out++ = WebRtcSpl_SatW32ToW16(out_s32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
39
webrtc/common_audio/signal_processing/energy.c
Normal file
39
webrtc/common_audio/signal_processing/energy.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_Energy().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
int32_t WebRtcSpl_Energy(int16_t* vector,
|
||||
size_t vector_length,
|
||||
int* scale_factor)
|
||||
{
|
||||
int32_t en = 0;
|
||||
size_t i;
|
||||
int scaling =
|
||||
WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length);
|
||||
size_t looptimes = vector_length;
|
||||
int16_t *vectorptr = vector;
|
||||
|
||||
for (i = 0; i < looptimes; i++)
|
||||
{
|
||||
en += (*vectorptr * *vectorptr) >> scaling;
|
||||
vectorptr++;
|
||||
}
|
||||
*scale_factor = scaling;
|
||||
|
||||
return en;
|
||||
}
|
89
webrtc/common_audio/signal_processing/filter_ar.c
Normal file
89
webrtc/common_audio/signal_processing/filter_ar.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_FilterAR().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
size_t WebRtcSpl_FilterAR(const int16_t* a,
|
||||
size_t a_length,
|
||||
const int16_t* x,
|
||||
size_t x_length,
|
||||
int16_t* state,
|
||||
size_t state_length,
|
||||
int16_t* state_low,
|
||||
size_t state_low_length,
|
||||
int16_t* filtered,
|
||||
int16_t* filtered_low,
|
||||
size_t filtered_low_length)
|
||||
{
|
||||
int32_t o;
|
||||
int32_t oLOW;
|
||||
size_t i, j, stop;
|
||||
const int16_t* x_ptr = &x[0];
|
||||
int16_t* filteredFINAL_ptr = filtered;
|
||||
int16_t* filteredFINAL_LOW_ptr = filtered_low;
|
||||
|
||||
for (i = 0; i < x_length; i++)
|
||||
{
|
||||
// Calculate filtered[i] and filtered_low[i]
|
||||
const int16_t* a_ptr = &a[1];
|
||||
int16_t* filtered_ptr = &filtered[i - 1];
|
||||
int16_t* filtered_low_ptr = &filtered_low[i - 1];
|
||||
int16_t* state_ptr = &state[state_length - 1];
|
||||
int16_t* state_low_ptr = &state_low[state_length - 1];
|
||||
|
||||
o = (int32_t)(*x_ptr++) << 12;
|
||||
oLOW = (int32_t)0;
|
||||
|
||||
stop = (i < a_length) ? i + 1 : a_length;
|
||||
for (j = 1; j < stop; j++)
|
||||
{
|
||||
o -= *a_ptr * *filtered_ptr--;
|
||||
oLOW -= *a_ptr++ * *filtered_low_ptr--;
|
||||
}
|
||||
for (j = i + 1; j < a_length; j++)
|
||||
{
|
||||
o -= *a_ptr * *state_ptr--;
|
||||
oLOW -= *a_ptr++ * *state_low_ptr--;
|
||||
}
|
||||
|
||||
o += (oLOW >> 12);
|
||||
*filteredFINAL_ptr = (int16_t)((o + (int32_t)2048) >> 12);
|
||||
*filteredFINAL_LOW_ptr++ = (int16_t)(o - ((int32_t)(*filteredFINAL_ptr++)
|
||||
<< 12));
|
||||
}
|
||||
|
||||
// Save the filter state
|
||||
if (x_length >= state_length)
|
||||
{
|
||||
WebRtcSpl_CopyFromEndW16(filtered, x_length, a_length - 1, state);
|
||||
WebRtcSpl_CopyFromEndW16(filtered_low, x_length, a_length - 1, state_low);
|
||||
} else
|
||||
{
|
||||
for (i = 0; i < state_length - x_length; i++)
|
||||
{
|
||||
state[i] = state[i + x_length];
|
||||
state_low[i] = state_low[i + x_length];
|
||||
}
|
||||
for (i = 0; i < x_length; i++)
|
||||
{
|
||||
state[state_length - x_length + i] = filtered[i];
|
||||
state[state_length - x_length + i] = filtered_low[i];
|
||||
}
|
||||
}
|
||||
|
||||
return x_length;
|
||||
}
|
42
webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
Normal file
42
webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// TODO(bjornv): Change the return type to report errors.
|
||||
|
||||
void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
|
||||
int16_t* data_out,
|
||||
const int16_t* __restrict coefficients,
|
||||
size_t coefficients_length,
|
||||
size_t data_length) {
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
|
||||
assert(data_length > 0);
|
||||
assert(coefficients_length > 1);
|
||||
|
||||
for (i = 0; i < data_length; i++) {
|
||||
int32_t output = 0;
|
||||
int32_t sum = 0;
|
||||
|
||||
for (j = coefficients_length - 1; j > 0; j--) {
|
||||
sum += coefficients[j] * data_out[i - j];
|
||||
}
|
||||
|
||||
output = coefficients[0] * data_in[i];
|
||||
output -= sum;
|
||||
|
||||
// Saturate and store the output.
|
||||
output = WEBRTC_SPL_SAT(134215679, output, -134217728);
|
||||
data_out[i] = (int16_t)((output + 2048) >> 12);
|
||||
}
|
||||
}
|
218
webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
Normal file
218
webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
Normal file
@ -0,0 +1,218 @@
|
||||
@
|
||||
@ Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
@
|
||||
@ Use of this source code is governed by a BSD-style license
|
||||
@ that can be found in the LICENSE file in the root of the source
|
||||
@ tree. An additional intellectual property rights grant can be found
|
||||
@ in the file PATENTS. All contributing project authors may
|
||||
@ be found in the AUTHORS file in the root of the source tree.
|
||||
@
|
||||
|
||||
@ This file contains the function WebRtcSpl_FilterARFastQ12(), optimized for
|
||||
@ ARMv7 platform. The description header can be found in
|
||||
@ signal_processing_library.h
|
||||
@
|
||||
@ Output is bit-exact with the generic C code as in filter_ar_fast_q12.c, and
|
||||
@ the reference C code at end of this file.
|
||||
|
||||
@ Assumptions:
|
||||
@ (1) data_length > 0
|
||||
@ (2) coefficients_length > 1
|
||||
|
||||
@ Register usage:
|
||||
@
|
||||
@ r0: &data_in[i]
|
||||
@ r1: &data_out[i], for result ouput
|
||||
@ r2: &coefficients[0]
|
||||
@ r3: coefficients_length
|
||||
@ r4: Iteration counter for the outer loop.
|
||||
@ r5: data_out[j] as multiplication inputs
|
||||
@ r6: Calculated value for output data_out[]; interation counter for inner loop
|
||||
@ r7: Partial sum of a filtering multiplication results
|
||||
@ r8: Partial sum of a filtering multiplication results
|
||||
@ r9: &data_out[], for filtering input; data_in[i]
|
||||
@ r10: coefficients[j]
|
||||
@ r11: Scratch
|
||||
@ r12: &coefficients[j]
|
||||
|
||||
#include "webrtc/system_wrappers/interface/asm_defines.h"
|
||||
|
||||
GLOBAL_FUNCTION WebRtcSpl_FilterARFastQ12
|
||||
.align 2
|
||||
DEFINE_FUNCTION WebRtcSpl_FilterARFastQ12
|
||||
push {r4-r11}
|
||||
|
||||
ldrsh r12, [sp, #32] @ data_length
|
||||
subs r4, r12, #1
|
||||
beq ODD_LENGTH @ jump if data_length == 1
|
||||
|
||||
LOOP_LENGTH:
|
||||
add r12, r2, r3, lsl #1
|
||||
sub r12, #4 @ &coefficients[coefficients_length - 2]
|
||||
sub r9, r1, r3, lsl #1
|
||||
add r9, #2 @ &data_out[i - coefficients_length + 1]
|
||||
ldr r5, [r9], #4 @ data_out[i - coefficients_length + {1,2}]
|
||||
|
||||
mov r7, #0 @ sum1
|
||||
mov r8, #0 @ sum2
|
||||
subs r6, r3, #3 @ Iteration counter for inner loop.
|
||||
beq ODD_A_LENGTH @ branch if coefficients_length == 3
|
||||
blt POST_LOOP_A_LENGTH @ branch if coefficients_length == 2
|
||||
|
||||
LOOP_A_LENGTH:
|
||||
ldr r10, [r12], #-4 @ coefficients[j - 1], coefficients[j]
|
||||
subs r6, #2
|
||||
smlatt r8, r10, r5, r8 @ sum2 += coefficients[j] * data_out[i - j + 1];
|
||||
smlatb r7, r10, r5, r7 @ sum1 += coefficients[j] * data_out[i - j];
|
||||
smlabt r7, r10, r5, r7 @ coefficients[j - 1] * data_out[i - j + 1];
|
||||
ldr r5, [r9], #4 @ data_out[i - j + 2], data_out[i - j + 3]
|
||||
smlabb r8, r10, r5, r8 @ coefficients[j - 1] * data_out[i - j + 2];
|
||||
bgt LOOP_A_LENGTH
|
||||
blt POST_LOOP_A_LENGTH
|
||||
|
||||
ODD_A_LENGTH:
|
||||
ldrsh r10, [r12, #2] @ Filter coefficients coefficients[2]
|
||||
sub r12, #2 @ &coefficients[0]
|
||||
smlabb r7, r10, r5, r7 @ sum1 += coefficients[2] * data_out[i - 2];
|
||||
smlabt r8, r10, r5, r8 @ sum2 += coefficients[2] * data_out[i - 1];
|
||||
ldr r5, [r9, #-2] @ data_out[i - 1], data_out[i]
|
||||
|
||||
POST_LOOP_A_LENGTH:
|
||||
ldr r10, [r12] @ coefficients[0], coefficients[1]
|
||||
smlatb r7, r10, r5, r7 @ sum1 += coefficients[1] * data_out[i - 1];
|
||||
|
||||
ldr r9, [r0], #4 @ data_in[i], data_in[i + 1]
|
||||
smulbb r6, r10, r9 @ output1 = coefficients[0] * data_in[i];
|
||||
sub r6, r7 @ output1 -= sum1;
|
||||
|
||||
sbfx r11, r6, #12, #16
|
||||
ssat r7, #16, r6, asr #12
|
||||
cmp r7, r11
|
||||
addeq r6, r6, #2048
|
||||
ssat r6, #16, r6, asr #12
|
||||
strh r6, [r1], #2 @ Store data_out[i]
|
||||
|
||||
smlatb r8, r10, r6, r8 @ sum2 += coefficients[1] * data_out[i];
|
||||
smulbt r6, r10, r9 @ output2 = coefficients[0] * data_in[i + 1];
|
||||
sub r6, r8 @ output1 -= sum1;
|
||||
|
||||
sbfx r11, r6, #12, #16
|
||||
ssat r7, #16, r6, asr #12
|
||||
cmp r7, r11
|
||||
addeq r6, r6, #2048
|
||||
ssat r6, #16, r6, asr #12
|
||||
strh r6, [r1], #2 @ Store data_out[i + 1]
|
||||
|
||||
subs r4, #2
|
||||
bgt LOOP_LENGTH
|
||||
blt END @ For even data_length, it's done. Jump to END.
|
||||
|
||||
@ Process i = data_length -1, for the case of an odd length.
|
||||
ODD_LENGTH:
|
||||
add r12, r2, r3, lsl #1
|
||||
sub r12, #4 @ &coefficients[coefficients_length - 2]
|
||||
sub r9, r1, r3, lsl #1
|
||||
add r9, #2 @ &data_out[i - coefficients_length + 1]
|
||||
mov r7, #0 @ sum1
|
||||
mov r8, #0 @ sum1
|
||||
subs r6, r3, #2 @ inner loop counter
|
||||
beq EVEN_A_LENGTH @ branch if coefficients_length == 2
|
||||
|
||||
LOOP2_A_LENGTH:
|
||||
ldr r10, [r12], #-4 @ coefficients[j - 1], coefficients[j]
|
||||
ldr r5, [r9], #4 @ data_out[i - j], data_out[i - j + 1]
|
||||
subs r6, #2
|
||||
smlatb r7, r10, r5, r7 @ sum1 += coefficients[j] * data_out[i - j];
|
||||
smlabt r8, r10, r5, r8 @ coefficients[j - 1] * data_out[i - j + 1];
|
||||
bgt LOOP2_A_LENGTH
|
||||
addlt r12, #2
|
||||
blt POST_LOOP2_A_LENGTH
|
||||
|
||||
EVEN_A_LENGTH:
|
||||
ldrsh r10, [r12, #2] @ Filter coefficients coefficients[1]
|
||||
ldrsh r5, [r9] @ data_out[i - 1]
|
||||
smlabb r7, r10, r5, r7 @ sum1 += coefficients[1] * data_out[i - 1];
|
||||
|
||||
POST_LOOP2_A_LENGTH:
|
||||
ldrsh r10, [r12] @ Filter coefficients coefficients[0]
|
||||
ldrsh r9, [r0] @ data_in[i]
|
||||
smulbb r6, r10, r9 @ output1 = coefficients[0] * data_in[i];
|
||||
sub r6, r7 @ output1 -= sum1;
|
||||
sub r6, r8 @ output1 -= sum1;
|
||||
sbfx r8, r6, #12, #16
|
||||
ssat r7, #16, r6, asr #12
|
||||
cmp r7, r8
|
||||
addeq r6, r6, #2048
|
||||
ssat r6, #16, r6, asr #12
|
||||
strh r6, [r1] @ Store the data_out[i]
|
||||
|
||||
END:
|
||||
pop {r4-r11}
|
||||
bx lr
|
||||
|
||||
@Reference C code:
|
||||
@
|
||||
@void WebRtcSpl_FilterARFastQ12(int16_t* data_in,
|
||||
@ int16_t* data_out,
|
||||
@ int16_t* __restrict coefficients,
|
||||
@ size_t coefficients_length,
|
||||
@ size_t data_length) {
|
||||
@ size_t i = 0;
|
||||
@ size_t j = 0;
|
||||
@
|
||||
@ assert(data_length > 0);
|
||||
@ assert(coefficients_length > 1);
|
||||
@
|
||||
@ for (i = 0; i < data_length - 1; i += 2) {
|
||||
@ int32_t output1 = 0;
|
||||
@ int32_t sum1 = 0;
|
||||
@ int32_t output2 = 0;
|
||||
@ int32_t sum2 = 0;
|
||||
@
|
||||
@ for (j = coefficients_length - 1; j > 2; j -= 2) {
|
||||
@ sum1 += coefficients[j] * data_out[i - j];
|
||||
@ sum1 += coefficients[j - 1] * data_out[i - j + 1];
|
||||
@ sum2 += coefficients[j] * data_out[i - j + 1];
|
||||
@ sum2 += coefficients[j - 1] * data_out[i - j + 2];
|
||||
@ }
|
||||
@
|
||||
@ if (j == 2) {
|
||||
@ sum1 += coefficients[2] * data_out[i - 2];
|
||||
@ sum2 += coefficients[2] * data_out[i - 1];
|
||||
@ }
|
||||
@
|
||||
@ sum1 += coefficients[1] * data_out[i - 1];
|
||||
@ output1 = coefficients[0] * data_in[i];
|
||||
@ output1 -= sum1;
|
||||
@ // Saturate and store the output.
|
||||
@ output1 = WEBRTC_SPL_SAT(134215679, output1, -134217728);
|
||||
@ data_out[i] = (int16_t)((output1 + 2048) >> 12);
|
||||
@
|
||||
@ sum2 += coefficients[1] * data_out[i];
|
||||
@ output2 = coefficients[0] * data_in[i + 1];
|
||||
@ output2 -= sum2;
|
||||
@ // Saturate and store the output.
|
||||
@ output2 = WEBRTC_SPL_SAT(134215679, output2, -134217728);
|
||||
@ data_out[i + 1] = (int16_t)((output2 + 2048) >> 12);
|
||||
@ }
|
||||
@
|
||||
@ if (i == data_length - 1) {
|
||||
@ int32_t output1 = 0;
|
||||
@ int32_t sum1 = 0;
|
||||
@
|
||||
@ for (j = coefficients_length - 1; j > 1; j -= 2) {
|
||||
@ sum1 += coefficients[j] * data_out[i - j];
|
||||
@ sum1 += coefficients[j - 1] * data_out[i - j + 1];
|
||||
@ }
|
||||
@
|
||||
@ if (j == 1) {
|
||||
@ sum1 += coefficients[1] * data_out[i - 1];
|
||||
@ }
|
||||
@
|
||||
@ output1 = coefficients[0] * data_in[i];
|
||||
@ output1 -= sum1;
|
||||
@ // Saturate and store the output.
|
||||
@ output1 = WEBRTC_SPL_SAT(134215679, output1, -134217728);
|
||||
@ data_out[i] = (int16_t)((output1 + 2048) >> 12);
|
||||
@ }
|
||||
@}
|
140
webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
Normal file
140
webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
|
||||
int16_t* data_out,
|
||||
const int16_t* __restrict coefficients,
|
||||
size_t coefficients_length,
|
||||
size_t data_length) {
|
||||
int r0, r1, r2, r3;
|
||||
int coef0, offset;
|
||||
int i, j, k;
|
||||
int coefptr, outptr, tmpout, inptr;
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
int max16 = 0x7FFF;
|
||||
int min16 = 0xFFFF8000;
|
||||
#endif // #if !defined(MIPS_DSP_R1_LE)
|
||||
|
||||
assert(data_length > 0);
|
||||
assert(coefficients_length > 1);
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"addiu %[i], %[data_length], 0 \n\t"
|
||||
"lh %[coef0], 0(%[coefficients]) \n\t"
|
||||
"addiu %[j], %[coefficients_length], -1 \n\t"
|
||||
"andi %[k], %[j], 1 \n\t"
|
||||
"sll %[offset], %[j], 1 \n\t"
|
||||
"subu %[outptr], %[data_out], %[offset] \n\t"
|
||||
"addiu %[inptr], %[data_in], 0 \n\t"
|
||||
"bgtz %[k], 3f \n\t"
|
||||
" addu %[coefptr], %[coefficients], %[offset] \n\t"
|
||||
"1: \n\t"
|
||||
"lh %[r0], 0(%[inptr]) \n\t"
|
||||
"addiu %[i], %[i], -1 \n\t"
|
||||
"addiu %[tmpout], %[outptr], 0 \n\t"
|
||||
"mult %[r0], %[coef0] \n\t"
|
||||
"2: \n\t"
|
||||
"lh %[r0], 0(%[tmpout]) \n\t"
|
||||
"lh %[r1], 0(%[coefptr]) \n\t"
|
||||
"lh %[r2], 2(%[tmpout]) \n\t"
|
||||
"lh %[r3], -2(%[coefptr]) \n\t"
|
||||
"addiu %[tmpout], %[tmpout], 4 \n\t"
|
||||
"msub %[r0], %[r1] \n\t"
|
||||
"msub %[r2], %[r3] \n\t"
|
||||
"addiu %[j], %[j], -2 \n\t"
|
||||
"bgtz %[j], 2b \n\t"
|
||||
" addiu %[coefptr], %[coefptr], -4 \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"extr_r.w %[r0], $ac0, 12 \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"mflo %[r0] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"addu %[coefptr], %[coefficients], %[offset] \n\t"
|
||||
"addiu %[inptr], %[inptr], 2 \n\t"
|
||||
"addiu %[j], %[coefficients_length], -1 \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"shll_s.w %[r0], %[r0], 16 \n\t"
|
||||
"sra %[r0], %[r0], 16 \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"addiu %[r0], %[r0], 2048 \n\t"
|
||||
"sra %[r0], %[r0], 12 \n\t"
|
||||
"slt %[r1], %[max16], %[r0] \n\t"
|
||||
"movn %[r0], %[max16], %[r1] \n\t"
|
||||
"slt %[r1], %[r0], %[min16] \n\t"
|
||||
"movn %[r0], %[min16], %[r1] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"sh %[r0], 0(%[tmpout]) \n\t"
|
||||
"bgtz %[i], 1b \n\t"
|
||||
" addiu %[outptr], %[outptr], 2 \n\t"
|
||||
"b 5f \n\t"
|
||||
" nop \n\t"
|
||||
"3: \n\t"
|
||||
"lh %[r0], 0(%[inptr]) \n\t"
|
||||
"addiu %[i], %[i], -1 \n\t"
|
||||
"addiu %[tmpout], %[outptr], 0 \n\t"
|
||||
"mult %[r0], %[coef0] \n\t"
|
||||
"4: \n\t"
|
||||
"lh %[r0], 0(%[tmpout]) \n\t"
|
||||
"lh %[r1], 0(%[coefptr]) \n\t"
|
||||
"lh %[r2], 2(%[tmpout]) \n\t"
|
||||
"lh %[r3], -2(%[coefptr]) \n\t"
|
||||
"addiu %[tmpout], %[tmpout], 4 \n\t"
|
||||
"msub %[r0], %[r1] \n\t"
|
||||
"msub %[r2], %[r3] \n\t"
|
||||
"addiu %[j], %[j], -2 \n\t"
|
||||
"bgtz %[j], 4b \n\t"
|
||||
" addiu %[coefptr], %[coefptr], -4 \n\t"
|
||||
"lh %[r0], 0(%[tmpout]) \n\t"
|
||||
"lh %[r1], 0(%[coefptr]) \n\t"
|
||||
"msub %[r0], %[r1] \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"extr_r.w %[r0], $ac0, 12 \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"mflo %[r0] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"addu %[coefptr], %[coefficients], %[offset] \n\t"
|
||||
"addiu %[inptr], %[inptr], 2 \n\t"
|
||||
"addiu %[j], %[coefficients_length], -1 \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"shll_s.w %[r0], %[r0], 16 \n\t"
|
||||
"sra %[r0], %[r0], 16 \n\t"
|
||||
#else // #if defined(MIPS_DSP_R1_LE)
|
||||
"addiu %[r0], %[r0], 2048 \n\t"
|
||||
"sra %[r0], %[r0], 12 \n\t"
|
||||
"slt %[r1], %[max16], %[r0] \n\t"
|
||||
"movn %[r0], %[max16], %[r1] \n\t"
|
||||
"slt %[r1], %[r0], %[min16] \n\t"
|
||||
"movn %[r0], %[min16], %[r1] \n\t"
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
"sh %[r0], 2(%[tmpout]) \n\t"
|
||||
"bgtz %[i], 3b \n\t"
|
||||
" addiu %[outptr], %[outptr], 2 \n\t"
|
||||
"5: \n\t"
|
||||
".set pop \n\t"
|
||||
: [i] "=&r" (i), [j] "=&r" (j), [k] "=&r" (k), [r0] "=&r" (r0),
|
||||
[r1] "=&r" (r1), [r2] "=&r" (r2), [r3] "=&r" (r3),
|
||||
[coef0] "=&r" (coef0), [offset] "=&r" (offset),
|
||||
[outptr] "=&r" (outptr), [inptr] "=&r" (inptr),
|
||||
[coefptr] "=&r" (coefptr), [tmpout] "=&r" (tmpout)
|
||||
: [coefficients] "r" (coefficients), [data_length] "r" (data_length),
|
||||
[coefficients_length] "r" (coefficients_length),
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
[max16] "r" (max16), [min16] "r" (min16),
|
||||
#endif
|
||||
[data_out] "r" (data_out), [data_in] "r" (data_in)
|
||||
: "hi", "lo", "memory"
|
||||
);
|
||||
}
|
||||
|
45
webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
Normal file
45
webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_FilterMAFastQ12().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_FilterMAFastQ12(const int16_t* in_ptr,
|
||||
int16_t* out_ptr,
|
||||
const int16_t* B,
|
||||
size_t B_length,
|
||||
size_t length)
|
||||
{
|
||||
size_t i, j;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
int32_t o = 0;
|
||||
|
||||
for (j = 0; j < B_length; j++)
|
||||
{
|
||||
o += B[j] * in_ptr[i - j];
|
||||
}
|
||||
|
||||
// If output is higher than 32768, saturate it. Same with negative side
|
||||
// 2^27 = 134217728, which corresponds to 32768 in Q12
|
||||
|
||||
// Saturate the output
|
||||
o = WEBRTC_SPL_SAT((int32_t)134215679, o, (int32_t)-134217728);
|
||||
|
||||
*out_ptr++ = (int16_t)((o + (int32_t)2048) >> 12);
|
||||
}
|
||||
return;
|
||||
}
|
77
webrtc/common_audio/signal_processing/get_hanning_window.c
Normal file
77
webrtc/common_audio/signal_processing/get_hanning_window.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_GetHanningWindow().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// Hanning table with 256 entries
|
||||
static const int16_t kHanningTable[] = {
|
||||
1, 2, 6, 10, 15, 22, 30, 39,
|
||||
50, 62, 75, 89, 104, 121, 138, 157,
|
||||
178, 199, 222, 246, 271, 297, 324, 353,
|
||||
383, 413, 446, 479, 513, 549, 586, 624,
|
||||
663, 703, 744, 787, 830, 875, 920, 967,
|
||||
1015, 1064, 1114, 1165, 1218, 1271, 1325, 1381,
|
||||
1437, 1494, 1553, 1612, 1673, 1734, 1796, 1859,
|
||||
1924, 1989, 2055, 2122, 2190, 2259, 2329, 2399,
|
||||
2471, 2543, 2617, 2691, 2765, 2841, 2918, 2995,
|
||||
3073, 3152, 3232, 3312, 3393, 3475, 3558, 3641,
|
||||
3725, 3809, 3895, 3980, 4067, 4154, 4242, 4330,
|
||||
4419, 4509, 4599, 4689, 4781, 4872, 4964, 5057,
|
||||
5150, 5244, 5338, 5432, 5527, 5622, 5718, 5814,
|
||||
5910, 6007, 6104, 6202, 6299, 6397, 6495, 6594,
|
||||
6693, 6791, 6891, 6990, 7090, 7189, 7289, 7389,
|
||||
7489, 7589, 7690, 7790, 7890, 7991, 8091, 8192,
|
||||
8293, 8393, 8494, 8594, 8694, 8795, 8895, 8995,
|
||||
9095, 9195, 9294, 9394, 9493, 9593, 9691, 9790,
|
||||
9889, 9987, 10085, 10182, 10280, 10377, 10474, 10570,
|
||||
10666, 10762, 10857, 10952, 11046, 11140, 11234, 11327,
|
||||
11420, 11512, 11603, 11695, 11785, 11875, 11965, 12054,
|
||||
12142, 12230, 12317, 12404, 12489, 12575, 12659, 12743,
|
||||
12826, 12909, 12991, 13072, 13152, 13232, 13311, 13389,
|
||||
13466, 13543, 13619, 13693, 13767, 13841, 13913, 13985,
|
||||
14055, 14125, 14194, 14262, 14329, 14395, 14460, 14525,
|
||||
14588, 14650, 14711, 14772, 14831, 14890, 14947, 15003,
|
||||
15059, 15113, 15166, 15219, 15270, 15320, 15369, 15417,
|
||||
15464, 15509, 15554, 15597, 15640, 15681, 15721, 15760,
|
||||
15798, 15835, 15871, 15905, 15938, 15971, 16001, 16031,
|
||||
16060, 16087, 16113, 16138, 16162, 16185, 16206, 16227,
|
||||
16246, 16263, 16280, 16295, 16309, 16322, 16334, 16345,
|
||||
16354, 16362, 16369, 16374, 16378, 16382, 16383, 16384
|
||||
};
|
||||
|
||||
void WebRtcSpl_GetHanningWindow(int16_t *v, size_t size)
|
||||
{
|
||||
size_t jj;
|
||||
int16_t *vptr1;
|
||||
|
||||
int32_t index;
|
||||
int32_t factor = ((int32_t)0x40000000);
|
||||
|
||||
factor = WebRtcSpl_DivW32W16(factor, (int16_t)size);
|
||||
if (size < 513)
|
||||
index = (int32_t)-0x200000;
|
||||
else
|
||||
index = (int32_t)-0x100000;
|
||||
vptr1 = v;
|
||||
|
||||
for (jj = 0; jj < size; jj++)
|
||||
{
|
||||
index += factor;
|
||||
(*vptr1++) = kHanningTable[index >> 22];
|
||||
}
|
||||
|
||||
}
|
46
webrtc/common_audio/signal_processing/get_scaling_square.c
Normal file
46
webrtc/common_audio/signal_processing/get_scaling_square.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_GetScalingSquare().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector,
|
||||
size_t in_vector_length,
|
||||
size_t times)
|
||||
{
|
||||
int16_t nbits = WebRtcSpl_GetSizeInBits((uint32_t)times);
|
||||
size_t i;
|
||||
int16_t smax = -1;
|
||||
int16_t sabs;
|
||||
int16_t *sptr = in_vector;
|
||||
int16_t t;
|
||||
size_t looptimes = in_vector_length;
|
||||
|
||||
for (i = looptimes; i > 0; i--)
|
||||
{
|
||||
sabs = (*sptr > 0 ? *sptr++ : -*sptr++);
|
||||
smax = (sabs > smax ? sabs : smax);
|
||||
}
|
||||
t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax));
|
||||
|
||||
if (smax == 0)
|
||||
{
|
||||
return 0; // Since norm(0) returns 0
|
||||
} else
|
||||
{
|
||||
return (t > nbits) ? 0 : nbits - t;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the iLBC specific functions
|
||||
* WebRtcSpl_ReverseOrderMultArrayElements()
|
||||
* WebRtcSpl_ElementwiseVectorMult()
|
||||
* WebRtcSpl_AddVectorsAndShift()
|
||||
* WebRtcSpl_AddAffineVectorToVector()
|
||||
* WebRtcSpl_AffineTransformVector()
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_ReverseOrderMultArrayElements(int16_t *out, const int16_t *in,
|
||||
const int16_t *win,
|
||||
size_t vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
size_t i;
|
||||
int16_t *outptr = out;
|
||||
const int16_t *inptr = in;
|
||||
const int16_t *winptr = win;
|
||||
for (i = 0; i < vector_length; i++)
|
||||
{
|
||||
*outptr++ = (int16_t)((*inptr++ * *winptr--) >> right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ElementwiseVectorMult(int16_t *out, const int16_t *in,
|
||||
const int16_t *win, size_t vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
size_t i;
|
||||
int16_t *outptr = out;
|
||||
const int16_t *inptr = in;
|
||||
const int16_t *winptr = win;
|
||||
for (i = 0; i < vector_length; i++)
|
||||
{
|
||||
*outptr++ = (int16_t)((*inptr++ * *winptr++) >> right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_AddVectorsAndShift(int16_t *out, const int16_t *in1,
|
||||
const int16_t *in2, size_t vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
size_t i;
|
||||
int16_t *outptr = out;
|
||||
const int16_t *in1ptr = in1;
|
||||
const int16_t *in2ptr = in2;
|
||||
for (i = vector_length; i > 0; i--)
|
||||
{
|
||||
(*outptr++) = (int16_t)(((*in1ptr++) + (*in2ptr++)) >> right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_AddAffineVectorToVector(int16_t *out, int16_t *in,
|
||||
int16_t gain, int32_t add_constant,
|
||||
int16_t right_shifts,
|
||||
size_t vector_length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < vector_length; i++)
|
||||
{
|
||||
out[i] += (int16_t)((in[i] * gain + add_constant) >> right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_AffineTransformVector(int16_t *out, int16_t *in,
|
||||
int16_t gain, int32_t add_constant,
|
||||
int16_t right_shifts, size_t vector_length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < vector_length; i++)
|
||||
{
|
||||
out[i] = (int16_t)((in[i] * gain + add_constant) >> right_shifts);
|
||||
}
|
||||
}
|
97
webrtc/common_audio/signal_processing/include/real_fft.h
Normal file
97
webrtc/common_audio/signal_processing/include/real_fft.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
|
||||
#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// For ComplexFFT(), the maximum fft order is 10;
|
||||
// for OpenMax FFT in ARM, it is 12;
|
||||
// WebRTC APM uses orders of only 7 and 8.
|
||||
enum {kMaxFFTOrder = 10};
|
||||
|
||||
struct RealFFT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct RealFFT* WebRtcSpl_CreateRealFFT(int order);
|
||||
void WebRtcSpl_FreeRealFFT(struct RealFFT* self);
|
||||
|
||||
// Compute an FFT for a real-valued signal of length of 2^order,
|
||||
// where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the
|
||||
// specification structure, which must be initialized prior to calling the FFT
|
||||
// function with WebRtcSpl_CreateRealFFT().
|
||||
// The relationship between the input and output sequences can
|
||||
// be expressed in terms of the DFT, i.e.:
|
||||
// x[n] = (2^(-scalefactor)/N) . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N)
|
||||
// n=0,1,2,...N-1
|
||||
// N=2^order.
|
||||
// The conjugate-symmetric output sequence is represented using a CCS vector,
|
||||
// which is of length N+2, and is organized as follows:
|
||||
// Index: 0 1 2 3 4 5 . . . N-2 N-1 N N+1
|
||||
// Component: R0 0 R1 I1 R2 I2 . . . R[N/2-1] I[N/2-1] R[N/2] 0
|
||||
// where R[n] and I[n], respectively, denote the real and imaginary components
|
||||
// for FFT bin 'n'. Bins are numbered from 0 to N/2, where N is the FFT length.
|
||||
// Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to
|
||||
// the foldover frequency.
|
||||
//
|
||||
// Input Arguments:
|
||||
// self - pointer to preallocated and initialized FFT specification structure.
|
||||
// real_data_in - the input signal. For an ARM Neon platform, it must be
|
||||
// aligned on a 32-byte boundary.
|
||||
//
|
||||
// Output Arguments:
|
||||
// complex_data_out - the output complex signal with (2^order + 2) 16-bit
|
||||
// elements. For an ARM Neon platform, it must be different
|
||||
// from real_data_in, and aligned on a 32-byte boundary.
|
||||
//
|
||||
// Return Value:
|
||||
// 0 - FFT calculation is successful.
|
||||
// -1 - Error with bad arguments (NULL pointers).
|
||||
int WebRtcSpl_RealForwardFFT(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out);
|
||||
|
||||
// Compute the inverse FFT for a conjugate-symmetric input sequence of length of
|
||||
// 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by
|
||||
// the specification structure, which must be initialized prior to calling the
|
||||
// FFT function with WebRtcSpl_CreateRealFFT().
|
||||
// For a transform of length M, the input sequence is represented using a packed
|
||||
// CCS vector of length M+2, which is explained in the comments for
|
||||
// WebRtcSpl_RealForwardFFTC above.
|
||||
//
|
||||
// Input Arguments:
|
||||
// self - pointer to preallocated and initialized FFT specification structure.
|
||||
// complex_data_in - the input complex signal with (2^order + 2) 16-bit
|
||||
// elements. For an ARM Neon platform, it must be aligned on
|
||||
// a 32-byte boundary.
|
||||
//
|
||||
// Output Arguments:
|
||||
// real_data_out - the output real signal. For an ARM Neon platform, it must
|
||||
// be different to complex_data_in, and aligned on a 32-byte
|
||||
// boundary.
|
||||
//
|
||||
// Return Value:
|
||||
// 0 or a positive number - a value that the elements in the |real_data_out|
|
||||
// should be shifted left with in order to get
|
||||
// correct physical values.
|
||||
// -1 - Error with bad arguments (NULL pointers).
|
||||
int WebRtcSpl_RealInverseFFT(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
|
File diff suppressed because it is too large
Load Diff
173
webrtc/common_audio/signal_processing/include/spl_inl.h
Normal file
173
webrtc/common_audio/signal_processing/include/spl_inl.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This header file includes the inline functions in
|
||||
// the fix point signal processing library.
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_H_
|
||||
#define WEBRTC_SPL_SPL_INL_H_
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
#include "webrtc/common_audio/signal_processing/include/spl_inl_armv7.h"
|
||||
#else
|
||||
|
||||
#if defined(MIPS32_LE)
|
||||
#include "webrtc/common_audio/signal_processing/include/spl_inl_mips.h"
|
||||
#endif
|
||||
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
|
||||
int16_t out16 = (int16_t) value32;
|
||||
|
||||
if (value32 > 32767)
|
||||
out16 = 32767;
|
||||
else if (value32 < -32768)
|
||||
out16 = -32768;
|
||||
|
||||
return out16;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sum;
|
||||
|
||||
// Perform long addition
|
||||
l_sum = l_var1 + l_var2;
|
||||
|
||||
if (l_var1 < 0) { // Check for underflow.
|
||||
if ((l_var2 < 0) && (l_sum >= 0)) {
|
||||
l_sum = (int32_t)0x80000000;
|
||||
}
|
||||
} else { // Check for overflow.
|
||||
if ((l_var2 > 0) && (l_sum < 0)) {
|
||||
l_sum = (int32_t)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_diff;
|
||||
|
||||
// Perform subtraction.
|
||||
l_diff = l_var1 - l_var2;
|
||||
|
||||
if (l_var1 < 0) { // Check for underflow.
|
||||
if ((l_var2 > 0) && (l_diff > 0)) {
|
||||
l_diff = (int32_t)0x80000000;
|
||||
}
|
||||
} else { // Check for overflow.
|
||||
if ((l_var2 < 0) && (l_diff < 0)) {
|
||||
l_diff = (int32_t)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return l_diff;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
|
||||
return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b);
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
|
||||
return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2);
|
||||
}
|
||||
#endif // #if !defined(MIPS_DSP_R1_LE)
|
||||
|
||||
#if !defined(MIPS32_LE)
|
||||
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
|
||||
int16_t bits;
|
||||
|
||||
if (0xFFFF0000 & n) {
|
||||
bits = 16;
|
||||
} else {
|
||||
bits = 0;
|
||||
}
|
||||
if (0x0000FF00 & (n >> bits)) bits += 8;
|
||||
if (0x000000F0 & (n >> bits)) bits += 4;
|
||||
if (0x0000000C & (n >> bits)) bits += 2;
|
||||
if (0x00000002 & (n >> bits)) bits += 1;
|
||||
if (0x00000001 & (n >> bits)) bits += 1;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
|
||||
int16_t zeros;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a = ~a;
|
||||
}
|
||||
|
||||
if (!(0xFFFF8000 & a)) {
|
||||
zeros = 16;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xFF800000 & (a << zeros))) zeros += 8;
|
||||
if (!(0xF8000000 & (a << zeros))) zeros += 4;
|
||||
if (!(0xE0000000 & (a << zeros))) zeros += 2;
|
||||
if (!(0xC0000000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
|
||||
int16_t zeros;
|
||||
|
||||
if (a == 0) return 0;
|
||||
|
||||
if (!(0xFFFF0000 & a)) {
|
||||
zeros = 16;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xFF000000 & (a << zeros))) zeros += 8;
|
||||
if (!(0xF0000000 & (a << zeros))) zeros += 4;
|
||||
if (!(0xC0000000 & (a << zeros))) zeros += 2;
|
||||
if (!(0x80000000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
|
||||
int16_t zeros;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a = ~a;
|
||||
}
|
||||
|
||||
if (!(0xFF80 & a)) {
|
||||
zeros = 8;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xF800 & (a << zeros))) zeros += 4;
|
||||
if (!(0xE000 & (a << zeros))) zeros += 2;
|
||||
if (!(0xC000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
|
||||
return (a * b + c);
|
||||
}
|
||||
#endif // #if !defined(MIPS32_LE)
|
||||
|
||||
#endif // WEBRTC_ARCH_ARM_V7
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_H_
|
136
webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
Normal file
136
webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/* This header file includes the inline functions for ARM processors in
|
||||
* the fix point signal processing library.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_ARMV7_H_
|
||||
#define WEBRTC_SPL_SPL_INL_ARMV7_H_
|
||||
|
||||
/* TODO(kma): Replace some assembly code with GCC intrinsics
|
||||
* (e.g. __builtin_clz).
|
||||
*/
|
||||
|
||||
/* This function produces result that is not bit exact with that by the generic
|
||||
* C version in some cases, although the former is at least as accurate as the
|
||||
* later.
|
||||
*/
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile ("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile ("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// TODO(kma): add unit test.
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile ("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
|
||||
int32_t s_sum = 0;
|
||||
|
||||
__asm __volatile ("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b));
|
||||
|
||||
return (int16_t) s_sum;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sum = 0;
|
||||
|
||||
__asm __volatile ("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2));
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sub = 0;
|
||||
|
||||
__asm __volatile ("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2));
|
||||
|
||||
return l_sub;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
|
||||
int32_t s_sub = 0;
|
||||
|
||||
__asm __volatile ("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2));
|
||||
|
||||
return (int16_t)s_sub;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
|
||||
int32_t tmp = 0;
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(n));
|
||||
|
||||
return (int16_t)(32 - tmp);
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
|
||||
int32_t tmp = 0;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a ^= 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return (int16_t)(tmp - 1);
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
|
||||
int tmp = 0;
|
||||
|
||||
if (a == 0) return 0;
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return (int16_t)tmp;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
|
||||
int32_t tmp = 0;
|
||||
int32_t a_32 = a;
|
||||
|
||||
if (a_32 == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a_32 < 0) {
|
||||
a_32 ^= 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a_32));
|
||||
|
||||
return (int16_t)(tmp - 17);
|
||||
}
|
||||
|
||||
// TODO(kma): add unit test.
|
||||
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
|
||||
int32_t out = 0;
|
||||
|
||||
__asm __volatile ("ssat %0, #16, %1" : "=r"(out) : "r"(value32));
|
||||
|
||||
return (int16_t)out;
|
||||
}
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_ARMV7_H_
|
225
webrtc/common_audio/signal_processing/include/spl_inl_mips.h
Normal file
225
webrtc/common_audio/signal_processing/include/spl_inl_mips.h
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This header file includes the inline functions in
|
||||
// the fix point signal processing library.
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_MIPS_H_
|
||||
#define WEBRTC_SPL_SPL_INL_MIPS_H_
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a,
|
||||
int32_t b) {
|
||||
int32_t value32 = 0;
|
||||
int32_t a1 = 0, b1 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a1], %[a] \n\t"
|
||||
"seh %[b1], %[b] \n\t"
|
||||
#else
|
||||
"sll %[a1], %[a], 16 \n\t"
|
||||
"sll %[b1], %[b], 16 \n\t"
|
||||
"sra %[a1], %[a1], 16 \n\t"
|
||||
"sra %[b1], %[b1], 16 \n\t"
|
||||
#endif
|
||||
"mul %[value32], %[a1], %[b1] \n\t"
|
||||
: [value32] "=r" (value32), [a1] "=&r" (a1), [b1] "=&r" (b1)
|
||||
: [a] "r" (a), [b] "r" (b)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a,
|
||||
int32_t b) {
|
||||
int32_t value32 = 0, b1 = 0, b2 = 0;
|
||||
int32_t a1 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a1], %[a] \n\t"
|
||||
#else
|
||||
"sll %[a1], %[a], 16 \n\t"
|
||||
"sra %[a1], %[a1], 16 \n\t"
|
||||
#endif
|
||||
"andi %[b2], %[b], 0xFFFF \n\t"
|
||||
"sra %[b1], %[b], 16 \n\t"
|
||||
"sra %[b2], %[b2], 1 \n\t"
|
||||
"mul %[value32], %[a1], %[b1] \n\t"
|
||||
"mul %[b2], %[a1], %[b2] \n\t"
|
||||
"addiu %[b2], %[b2], 0x4000 \n\t"
|
||||
"sra %[b2], %[b2], 15 \n\t"
|
||||
"addu %[value32], %[value32], %[b2] \n\t"
|
||||
: [value32] "=&r" (value32), [b1] "=&r" (b1), [b2] "=&r" (b2),
|
||||
[a1] "=&r" (a1)
|
||||
: [a] "r" (a), [b] "r" (b)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return value32;
|
||||
}
|
||||
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
|
||||
__asm __volatile(
|
||||
"shll_s.w %[value32], %[value32], 16 \n\t"
|
||||
"sra %[value32], %[value32], 16 \n\t"
|
||||
: [value32] "+r" (value32)
|
||||
:
|
||||
);
|
||||
int16_t out16 = (int16_t)value32;
|
||||
return out16;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
|
||||
int32_t value32 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
"addq_s.ph %[value32], %[a], %[b] \n\t"
|
||||
: [value32] "=r" (value32)
|
||||
: [a] "r" (a), [b] "r" (b)
|
||||
);
|
||||
return (int16_t)value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sum;
|
||||
|
||||
__asm __volatile(
|
||||
"addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t"
|
||||
: [l_sum] "=r" (l_sum)
|
||||
: [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
|
||||
);
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
|
||||
int32_t value32;
|
||||
|
||||
__asm __volatile(
|
||||
"subq_s.ph %[value32], %[var1], %[var2] \n\t"
|
||||
: [value32] "=r" (value32)
|
||||
: [var1] "r" (var1), [var2] "r" (var2)
|
||||
);
|
||||
|
||||
return (int16_t)value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_diff;
|
||||
|
||||
__asm __volatile(
|
||||
"subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t"
|
||||
: [l_diff] "=r" (l_diff)
|
||||
: [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
|
||||
);
|
||||
|
||||
return l_diff;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
|
||||
int bits = 0;
|
||||
int i32 = 32;
|
||||
|
||||
__asm __volatile(
|
||||
"clz %[bits], %[n] \n\t"
|
||||
"subu %[bits], %[i32], %[bits] \n\t"
|
||||
: [bits] "=&r" (bits)
|
||||
: [n] "r" (n), [i32] "r" (i32)
|
||||
);
|
||||
|
||||
return (int16_t)bits;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
|
||||
int zeros = 0;
|
||||
|
||||
__asm __volatile(
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"bnez %[a], 1f \n\t"
|
||||
" sra %[zeros], %[a], 31 \n\t"
|
||||
"b 2f \n\t"
|
||||
" move %[zeros], $zero \n\t"
|
||||
"1: \n\t"
|
||||
"xor %[zeros], %[a], %[zeros] \n\t"
|
||||
"clz %[zeros], %[zeros] \n\t"
|
||||
"addiu %[zeros], %[zeros], -1 \n\t"
|
||||
"2: \n\t"
|
||||
".set pop \n\t"
|
||||
: [zeros]"=&r"(zeros)
|
||||
: [a] "r" (a)
|
||||
);
|
||||
|
||||
return (int16_t)zeros;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
|
||||
int zeros = 0;
|
||||
|
||||
__asm __volatile(
|
||||
"clz %[zeros], %[a] \n\t"
|
||||
: [zeros] "=r" (zeros)
|
||||
: [a] "r" (a)
|
||||
);
|
||||
|
||||
return (int16_t)(zeros & 0x1f);
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
|
||||
int zeros = 0;
|
||||
int a0 = a << 16;
|
||||
|
||||
__asm __volatile(
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"bnez %[a0], 1f \n\t"
|
||||
" sra %[zeros], %[a0], 31 \n\t"
|
||||
"b 2f \n\t"
|
||||
" move %[zeros], $zero \n\t"
|
||||
"1: \n\t"
|
||||
"xor %[zeros], %[a0], %[zeros] \n\t"
|
||||
"clz %[zeros], %[zeros] \n\t"
|
||||
"addiu %[zeros], %[zeros], -1 \n\t"
|
||||
"2: \n\t"
|
||||
".set pop \n\t"
|
||||
: [zeros]"=&r"(zeros)
|
||||
: [a0] "r" (a0)
|
||||
);
|
||||
|
||||
return (int16_t)zeros;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a,
|
||||
int16_t b,
|
||||
int32_t c) {
|
||||
int32_t res = 0, c1 = 0;
|
||||
__asm __volatile(
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a], %[a] \n\t"
|
||||
"seh %[b], %[b] \n\t"
|
||||
#else
|
||||
"sll %[a], %[a], 16 \n\t"
|
||||
"sll %[b], %[b], 16 \n\t"
|
||||
"sra %[a], %[a], 16 \n\t"
|
||||
"sra %[b], %[b], 16 \n\t"
|
||||
#endif
|
||||
"mul %[res], %[a], %[b] \n\t"
|
||||
"addu %[c1], %[c], %[res] \n\t"
|
||||
: [c1] "=r" (c1), [res] "=&r" (res)
|
||||
: [a] "r" (a), [b] "r" (b), [c] "r" (c)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return (c1);
|
||||
}
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_MIPS_H_
|
246
webrtc/common_audio/signal_processing/levinson_durbin.c
Normal file
246
webrtc/common_audio/signal_processing/levinson_durbin.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_LevinsonDurbin().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#define SPL_LEVINSON_MAXORDER 20
|
||||
|
||||
int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
|
||||
size_t order)
|
||||
{
|
||||
size_t i, j;
|
||||
// Auto-correlation coefficients in high precision
|
||||
int16_t R_hi[SPL_LEVINSON_MAXORDER + 1], R_low[SPL_LEVINSON_MAXORDER + 1];
|
||||
// LPC coefficients in high precision
|
||||
int16_t A_hi[SPL_LEVINSON_MAXORDER + 1], A_low[SPL_LEVINSON_MAXORDER + 1];
|
||||
// LPC coefficients for next iteration
|
||||
int16_t A_upd_hi[SPL_LEVINSON_MAXORDER + 1], A_upd_low[SPL_LEVINSON_MAXORDER + 1];
|
||||
// Reflection coefficient in high precision
|
||||
int16_t K_hi, K_low;
|
||||
// Prediction gain Alpha in high precision and with scale factor
|
||||
int16_t Alpha_hi, Alpha_low, Alpha_exp;
|
||||
int16_t tmp_hi, tmp_low;
|
||||
int32_t temp1W32, temp2W32, temp3W32;
|
||||
int16_t norm;
|
||||
|
||||
// Normalize the autocorrelation R[0]...R[order+1]
|
||||
|
||||
norm = WebRtcSpl_NormW32(R[0]);
|
||||
|
||||
for (i = 0; i <= order; ++i)
|
||||
{
|
||||
temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm);
|
||||
// Put R in hi and low format
|
||||
R_hi[i] = (int16_t)(temp1W32 >> 16);
|
||||
R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] << 16)) >> 1);
|
||||
}
|
||||
|
||||
// K = A[1] = -R[1] / R[0]
|
||||
|
||||
temp2W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[1],16)
|
||||
+ WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[1],1); // R[1] in Q31
|
||||
temp3W32 = WEBRTC_SPL_ABS_W32(temp2W32); // abs R[1]
|
||||
temp1W32 = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); // abs(R[1])/R[0] in Q31
|
||||
// Put back the sign on R[1]
|
||||
if (temp2W32 > 0)
|
||||
{
|
||||
temp1W32 = -temp1W32;
|
||||
}
|
||||
|
||||
// Put K in hi and low format
|
||||
K_hi = (int16_t)(temp1W32 >> 16);
|
||||
K_low = (int16_t)((temp1W32 - ((int32_t)K_hi << 16)) >> 1);
|
||||
|
||||
// Store first reflection coefficient
|
||||
K[0] = K_hi;
|
||||
|
||||
temp1W32 >>= 4; // A[1] in Q27.
|
||||
|
||||
// Put A[1] in hi and low format
|
||||
A_hi[1] = (int16_t)(temp1W32 >> 16);
|
||||
A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] << 16)) >> 1);
|
||||
|
||||
// Alpha = R[0] * (1-K^2)
|
||||
|
||||
temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) << 1; // = k^2 in Q31
|
||||
|
||||
temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0
|
||||
temp1W32 = (int32_t)0x7fffffffL - temp1W32; // temp1W32 = (1 - K[0]*K[0]) in Q31
|
||||
|
||||
// Store temp1W32 = 1 - K[0]*K[0] on hi and low format
|
||||
tmp_hi = (int16_t)(temp1W32 >> 16);
|
||||
tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
|
||||
|
||||
// Calculate Alpha in Q31
|
||||
temp1W32 = (R_hi[0] * tmp_hi + (R_hi[0] * tmp_low >> 15) +
|
||||
(R_low[0] * tmp_hi >> 15)) << 1;
|
||||
|
||||
// Normalize Alpha and put it in hi and low format
|
||||
|
||||
Alpha_exp = WebRtcSpl_NormW32(temp1W32);
|
||||
temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp);
|
||||
Alpha_hi = (int16_t)(temp1W32 >> 16);
|
||||
Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
|
||||
|
||||
// Perform the iterative calculations in the Levinson-Durbin algorithm
|
||||
|
||||
for (i = 2; i <= order; i++)
|
||||
{
|
||||
/* ----
|
||||
temp1W32 = R[i] + > R[j]*A[i-j]
|
||||
/
|
||||
----
|
||||
j=1..i-1
|
||||
*/
|
||||
|
||||
temp1W32 = 0;
|
||||
|
||||
for (j = 1; j < i; j++)
|
||||
{
|
||||
// temp1W32 is in Q31
|
||||
temp1W32 += (R_hi[j] * A_hi[i - j] << 1) +
|
||||
(((R_hi[j] * A_low[i - j] >> 15) +
|
||||
(R_low[j] * A_hi[i - j] >> 15)) << 1);
|
||||
}
|
||||
|
||||
temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, 4);
|
||||
temp1W32 += (WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[i], 16)
|
||||
+ WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[i], 1));
|
||||
|
||||
// K = -temp1W32 / Alpha
|
||||
temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32); // abs(temp1W32)
|
||||
temp3W32 = WebRtcSpl_DivW32HiLow(temp2W32, Alpha_hi, Alpha_low); // abs(temp1W32)/Alpha
|
||||
|
||||
// Put the sign of temp1W32 back again
|
||||
if (temp1W32 > 0)
|
||||
{
|
||||
temp3W32 = -temp3W32;
|
||||
}
|
||||
|
||||
// Use the Alpha shifts from earlier to de-normalize
|
||||
norm = WebRtcSpl_NormW32(temp3W32);
|
||||
if ((Alpha_exp <= norm) || (temp3W32 == 0))
|
||||
{
|
||||
temp3W32 = WEBRTC_SPL_LSHIFT_W32(temp3W32, Alpha_exp);
|
||||
} else
|
||||
{
|
||||
if (temp3W32 > 0)
|
||||
{
|
||||
temp3W32 = (int32_t)0x7fffffffL;
|
||||
} else
|
||||
{
|
||||
temp3W32 = (int32_t)0x80000000L;
|
||||
}
|
||||
}
|
||||
|
||||
// Put K on hi and low format
|
||||
K_hi = (int16_t)(temp3W32 >> 16);
|
||||
K_low = (int16_t)((temp3W32 - ((int32_t)K_hi << 16)) >> 1);
|
||||
|
||||
// Store Reflection coefficient in Q15
|
||||
K[i - 1] = K_hi;
|
||||
|
||||
// Test for unstable filter.
|
||||
// If unstable return 0 and let the user decide what to do in that case
|
||||
|
||||
if ((int32_t)WEBRTC_SPL_ABS_W16(K_hi) > (int32_t)32750)
|
||||
{
|
||||
return 0; // Unstable filter
|
||||
}
|
||||
|
||||
/*
|
||||
Compute updated LPC coefficient: Anew[i]
|
||||
Anew[j]= A[j] + K*A[i-j] for j=1..i-1
|
||||
Anew[i]= K
|
||||
*/
|
||||
|
||||
for (j = 1; j < i; j++)
|
||||
{
|
||||
// temp1W32 = A[j] in Q27
|
||||
temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[j],16)
|
||||
+ WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[j],1);
|
||||
|
||||
// temp1W32 += K*A[i-j] in Q27
|
||||
temp1W32 += (K_hi * A_hi[i - j] + (K_hi * A_low[i - j] >> 15) +
|
||||
(K_low * A_hi[i - j] >> 15)) << 1;
|
||||
|
||||
// Put Anew in hi and low format
|
||||
A_upd_hi[j] = (int16_t)(temp1W32 >> 16);
|
||||
A_upd_low[j] = (int16_t)(
|
||||
(temp1W32 - ((int32_t)A_upd_hi[j] << 16)) >> 1);
|
||||
}
|
||||
|
||||
// temp3W32 = K in Q27 (Convert from Q31 to Q27)
|
||||
temp3W32 >>= 4;
|
||||
|
||||
// Store Anew in hi and low format
|
||||
A_upd_hi[i] = (int16_t)(temp3W32 >> 16);
|
||||
A_upd_low[i] = (int16_t)(
|
||||
(temp3W32 - ((int32_t)A_upd_hi[i] << 16)) >> 1);
|
||||
|
||||
// Alpha = Alpha * (1-K^2)
|
||||
|
||||
temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) << 1; // K*K in Q31
|
||||
|
||||
temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0
|
||||
temp1W32 = (int32_t)0x7fffffffL - temp1W32; // 1 - K*K in Q31
|
||||
|
||||
// Convert 1- K^2 in hi and low format
|
||||
tmp_hi = (int16_t)(temp1W32 >> 16);
|
||||
tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
|
||||
|
||||
// Calculate Alpha = Alpha * (1-K^2) in Q31
|
||||
temp1W32 = (Alpha_hi * tmp_hi + (Alpha_hi * tmp_low >> 15) +
|
||||
(Alpha_low * tmp_hi >> 15)) << 1;
|
||||
|
||||
// Normalize Alpha and store it on hi and low format
|
||||
|
||||
norm = WebRtcSpl_NormW32(temp1W32);
|
||||
temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm);
|
||||
|
||||
Alpha_hi = (int16_t)(temp1W32 >> 16);
|
||||
Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
|
||||
|
||||
// Update the total normalization of Alpha
|
||||
Alpha_exp = Alpha_exp + norm;
|
||||
|
||||
// Update A[]
|
||||
|
||||
for (j = 1; j <= i; j++)
|
||||
{
|
||||
A_hi[j] = A_upd_hi[j];
|
||||
A_low[j] = A_upd_low[j];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Set A[0] to 1.0 and store the A[i] i=1...order in Q12
|
||||
(Convert from Q27 and use rounding)
|
||||
*/
|
||||
|
||||
A[0] = 4096;
|
||||
|
||||
for (i = 1; i <= order; i++)
|
||||
{
|
||||
// temp1W32 in Q27
|
||||
temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[i], 16)
|
||||
+ WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1);
|
||||
// Round and store upper word
|
||||
A[i] = (int16_t)(((temp1W32 << 1) + 32768) >> 16);
|
||||
}
|
||||
return 1; // Stable filters
|
||||
}
|
56
webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
Normal file
56
webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_LpcToReflCoef().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#define SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER 50
|
||||
|
||||
void WebRtcSpl_LpcToReflCoef(int16_t* a16, int use_order, int16_t* k16)
|
||||
{
|
||||
int m, k;
|
||||
int32_t tmp32[SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER];
|
||||
int32_t tmp_inv_denom32;
|
||||
int16_t tmp_inv_denom16;
|
||||
|
||||
k16[use_order - 1] = a16[use_order] << 3; // Q12<<3 => Q15
|
||||
for (m = use_order - 1; m > 0; m--)
|
||||
{
|
||||
// (1 - k^2) in Q30
|
||||
tmp_inv_denom32 = 1073741823 - k16[m] * k16[m];
|
||||
// (1 - k^2) in Q15
|
||||
tmp_inv_denom16 = (int16_t)(tmp_inv_denom32 >> 15);
|
||||
|
||||
for (k = 1; k <= m; k++)
|
||||
{
|
||||
// tmp[k] = (a[k] - RC[m] * a[m-k+1]) / (1.0 - RC[m]*RC[m]);
|
||||
|
||||
// [Q12<<16 - (Q15*Q12)<<1] = [Q28 - Q28] = Q28
|
||||
tmp32[k] = (a16[k] << 16) - (k16[m] * a16[m - k + 1] << 1);
|
||||
|
||||
tmp32[k] = WebRtcSpl_DivW32W16(tmp32[k], tmp_inv_denom16); //Q28/Q15 = Q13
|
||||
}
|
||||
|
||||
for (k = 1; k < m; k++)
|
||||
{
|
||||
a16[k] = (int16_t)(tmp32[k] >> 1); // Q13>>1 => Q12
|
||||
}
|
||||
|
||||
tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191);
|
||||
k16[m - 1] = (int16_t)WEBRTC_SPL_LSHIFT_W32(tmp32[m], 2); //Q13<<2 => Q15
|
||||
}
|
||||
return;
|
||||
}
|
224
webrtc/common_audio/signal_processing/min_max_operations.c
Normal file
224
webrtc/common_audio/signal_processing/min_max_operations.c
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the implementation of functions
|
||||
* WebRtcSpl_MaxAbsValueW16C()
|
||||
* WebRtcSpl_MaxAbsValueW32C()
|
||||
* WebRtcSpl_MaxValueW16C()
|
||||
* WebRtcSpl_MaxValueW32C()
|
||||
* WebRtcSpl_MinValueW16C()
|
||||
* WebRtcSpl_MinValueW32C()
|
||||
* WebRtcSpl_MaxAbsIndexW16()
|
||||
* WebRtcSpl_MaxIndexW16()
|
||||
* WebRtcSpl_MaxIndexW32()
|
||||
* WebRtcSpl_MinIndexW16()
|
||||
* WebRtcSpl_MinIndexW32()
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// TODO(bjorn/kma): Consolidate function pairs (e.g. combine
|
||||
// WebRtcSpl_MaxAbsValueW16C and WebRtcSpl_MaxAbsIndexW16 into a single one.)
|
||||
// TODO(kma): Move the next six functions into min_max_operations_c.c.
|
||||
|
||||
// Maximum absolute value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length) {
|
||||
size_t i = 0;
|
||||
int absolute = 0, maximum = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
}
|
||||
|
||||
// Guard the case for abs(-32768).
|
||||
if (maximum > WEBRTC_SPL_WORD16_MAX) {
|
||||
maximum = WEBRTC_SPL_WORD16_MAX;
|
||||
}
|
||||
|
||||
return (int16_t)maximum;
|
||||
}
|
||||
|
||||
// Maximum absolute value of word32 vector. C version for generic platforms.
|
||||
int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length) {
|
||||
// Use uint32_t for the local variables, to accommodate the return value
|
||||
// of abs(0x80000000), which is 0x80000000.
|
||||
|
||||
uint32_t absolute = 0, maximum = 0;
|
||||
size_t i = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
}
|
||||
|
||||
maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX);
|
||||
|
||||
return (int32_t)maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length) {
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
size_t i = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum)
|
||||
maximum = vector[i];
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word32 vector. C version for generic platforms.
|
||||
int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length) {
|
||||
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
|
||||
size_t i = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum)
|
||||
maximum = vector[i];
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Minimum value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length) {
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
size_t i = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum)
|
||||
minimum = vector[i];
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Minimum value of word32 vector. C version for generic platforms.
|
||||
int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length) {
|
||||
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
|
||||
size_t i = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum)
|
||||
minimum = vector[i];
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Index of maximum absolute value in a word16 vector.
|
||||
size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length) {
|
||||
// Use type int for local variables, to accomodate the value of abs(-32768).
|
||||
|
||||
size_t i = 0, index = 0;
|
||||
int absolute = 0, maximum = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of maximum value in a word16 vector.
|
||||
size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length) {
|
||||
size_t i = 0, index = 0;
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum) {
|
||||
maximum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of maximum value in a word32 vector.
|
||||
size_t WebRtcSpl_MaxIndexW32(const int32_t* vector, size_t length) {
|
||||
size_t i = 0, index = 0;
|
||||
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum) {
|
||||
maximum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of minimum value in a word16 vector.
|
||||
size_t WebRtcSpl_MinIndexW16(const int16_t* vector, size_t length) {
|
||||
size_t i = 0, index = 0;
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum) {
|
||||
minimum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of minimum value in a word32 vector.
|
||||
size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length) {
|
||||
size_t i = 0, index = 0;
|
||||
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum) {
|
||||
minimum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
376
webrtc/common_audio/signal_processing/min_max_operations_mips.c
Normal file
376
webrtc/common_audio/signal_processing/min_max_operations_mips.c
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the implementation of function
|
||||
* WebRtcSpl_MaxAbsValueW16()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// Maximum absolute value of word16 vector.
|
||||
int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length) {
|
||||
int32_t totMax = 0;
|
||||
int32_t tmp32_0, tmp32_1, tmp32_2, tmp32_3;
|
||||
size_t i, loop_size;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
#if defined(MIPS_DSP_R1)
|
||||
const int32_t* tmpvec32 = (int32_t*)vector;
|
||||
loop_size = length >> 4;
|
||||
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
__asm__ volatile (
|
||||
"lw %[tmp32_0], 0(%[tmpvec32]) \n\t"
|
||||
"lw %[tmp32_1], 4(%[tmpvec32]) \n\t"
|
||||
"lw %[tmp32_2], 8(%[tmpvec32]) \n\t"
|
||||
"lw %[tmp32_3], 12(%[tmpvec32]) \n\t"
|
||||
|
||||
"absq_s.ph %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"absq_s.ph %[tmp32_1], %[tmp32_1] \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_0] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t"
|
||||
|
||||
"lw %[tmp32_0], 16(%[tmpvec32]) \n\t"
|
||||
"absq_s.ph %[tmp32_2], %[tmp32_2] \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_1] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_1], %[totMax] \n\t"
|
||||
|
||||
"lw %[tmp32_1], 20(%[tmpvec32]) \n\t"
|
||||
"absq_s.ph %[tmp32_3], %[tmp32_3] \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_2] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_2], %[totMax] \n\t"
|
||||
|
||||
"lw %[tmp32_2], 24(%[tmpvec32]) \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_3] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_3], %[totMax] \n\t"
|
||||
|
||||
"lw %[tmp32_3], 28(%[tmpvec32]) \n\t"
|
||||
"absq_s.ph %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"absq_s.ph %[tmp32_1], %[tmp32_1] \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_0] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t"
|
||||
|
||||
"absq_s.ph %[tmp32_2], %[tmp32_2] \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_1] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_1], %[totMax] \n\t"
|
||||
"absq_s.ph %[tmp32_3], %[tmp32_3] \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_2] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_2], %[totMax] \n\t"
|
||||
|
||||
"cmp.lt.ph %[totMax], %[tmp32_3] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_3], %[totMax] \n\t"
|
||||
|
||||
"addiu %[tmpvec32], %[tmpvec32], 32 \n\t"
|
||||
: [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1),
|
||||
[tmp32_2] "=&r" (tmp32_2), [tmp32_3] "=&r" (tmp32_3),
|
||||
[totMax] "+r" (totMax), [tmpvec32] "+r" (tmpvec32)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
__asm__ volatile (
|
||||
"rotr %[tmp32_0], %[totMax], 16 \n\t"
|
||||
"cmp.lt.ph %[totMax], %[tmp32_0] \n\t"
|
||||
"pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t"
|
||||
"packrl.ph %[totMax], $0, %[totMax] \n\t"
|
||||
: [tmp32_0] "=&r" (tmp32_0), [totMax] "+r" (totMax)
|
||||
:
|
||||
);
|
||||
loop_size = length & 0xf;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
__asm__ volatile (
|
||||
"lh %[tmp32_0], 0(%[tmpvec32]) \n\t"
|
||||
"addiu %[tmpvec32], %[tmpvec32], 2 \n\t"
|
||||
"absq_s.w %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"slt %[tmp32_1], %[totMax], %[tmp32_0] \n\t"
|
||||
"movn %[totMax], %[tmp32_0], %[tmp32_1] \n\t"
|
||||
: [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1),
|
||||
[tmpvec32] "+r" (tmpvec32), [totMax] "+r" (totMax)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
#else // #if defined(MIPS_DSP_R1)
|
||||
int32_t v16MaxMax = WEBRTC_SPL_WORD16_MAX;
|
||||
int32_t r, r1, r2, r3;
|
||||
const int16_t* tmpvector = vector;
|
||||
loop_size = length >> 4;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
__asm__ volatile (
|
||||
"lh %[tmp32_0], 0(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_1], 2(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_2], 4(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_3], 6(%[tmpvector]) \n\t"
|
||||
|
||||
"abs %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"abs %[tmp32_1], %[tmp32_1] \n\t"
|
||||
"abs %[tmp32_2], %[tmp32_2] \n\t"
|
||||
"abs %[tmp32_3], %[tmp32_3] \n\t"
|
||||
|
||||
"slt %[r], %[totMax], %[tmp32_0] \n\t"
|
||||
"movn %[totMax], %[tmp32_0], %[r] \n\t"
|
||||
"slt %[r1], %[totMax], %[tmp32_1] \n\t"
|
||||
"movn %[totMax], %[tmp32_1], %[r1] \n\t"
|
||||
"slt %[r2], %[totMax], %[tmp32_2] \n\t"
|
||||
"movn %[totMax], %[tmp32_2], %[r2] \n\t"
|
||||
"slt %[r3], %[totMax], %[tmp32_3] \n\t"
|
||||
"movn %[totMax], %[tmp32_3], %[r3] \n\t"
|
||||
|
||||
"lh %[tmp32_0], 8(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_1], 10(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_2], 12(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_3], 14(%[tmpvector]) \n\t"
|
||||
|
||||
"abs %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"abs %[tmp32_1], %[tmp32_1] \n\t"
|
||||
"abs %[tmp32_2], %[tmp32_2] \n\t"
|
||||
"abs %[tmp32_3], %[tmp32_3] \n\t"
|
||||
|
||||
"slt %[r], %[totMax], %[tmp32_0] \n\t"
|
||||
"movn %[totMax], %[tmp32_0], %[r] \n\t"
|
||||
"slt %[r1], %[totMax], %[tmp32_1] \n\t"
|
||||
"movn %[totMax], %[tmp32_1], %[r1] \n\t"
|
||||
"slt %[r2], %[totMax], %[tmp32_2] \n\t"
|
||||
"movn %[totMax], %[tmp32_2], %[r2] \n\t"
|
||||
"slt %[r3], %[totMax], %[tmp32_3] \n\t"
|
||||
"movn %[totMax], %[tmp32_3], %[r3] \n\t"
|
||||
|
||||
"lh %[tmp32_0], 16(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_1], 18(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_2], 20(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_3], 22(%[tmpvector]) \n\t"
|
||||
|
||||
"abs %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"abs %[tmp32_1], %[tmp32_1] \n\t"
|
||||
"abs %[tmp32_2], %[tmp32_2] \n\t"
|
||||
"abs %[tmp32_3], %[tmp32_3] \n\t"
|
||||
|
||||
"slt %[r], %[totMax], %[tmp32_0] \n\t"
|
||||
"movn %[totMax], %[tmp32_0], %[r] \n\t"
|
||||
"slt %[r1], %[totMax], %[tmp32_1] \n\t"
|
||||
"movn %[totMax], %[tmp32_1], %[r1] \n\t"
|
||||
"slt %[r2], %[totMax], %[tmp32_2] \n\t"
|
||||
"movn %[totMax], %[tmp32_2], %[r2] \n\t"
|
||||
"slt %[r3], %[totMax], %[tmp32_3] \n\t"
|
||||
"movn %[totMax], %[tmp32_3], %[r3] \n\t"
|
||||
|
||||
"lh %[tmp32_0], 24(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_1], 26(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_2], 28(%[tmpvector]) \n\t"
|
||||
"lh %[tmp32_3], 30(%[tmpvector]) \n\t"
|
||||
|
||||
"abs %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"abs %[tmp32_1], %[tmp32_1] \n\t"
|
||||
"abs %[tmp32_2], %[tmp32_2] \n\t"
|
||||
"abs %[tmp32_3], %[tmp32_3] \n\t"
|
||||
|
||||
"slt %[r], %[totMax], %[tmp32_0] \n\t"
|
||||
"movn %[totMax], %[tmp32_0], %[r] \n\t"
|
||||
"slt %[r1], %[totMax], %[tmp32_1] \n\t"
|
||||
"movn %[totMax], %[tmp32_1], %[r1] \n\t"
|
||||
"slt %[r2], %[totMax], %[tmp32_2] \n\t"
|
||||
"movn %[totMax], %[tmp32_2], %[r2] \n\t"
|
||||
"slt %[r3], %[totMax], %[tmp32_3] \n\t"
|
||||
"movn %[totMax], %[tmp32_3], %[r3] \n\t"
|
||||
|
||||
"addiu %[tmpvector], %[tmpvector], 32 \n\t"
|
||||
: [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1),
|
||||
[tmp32_2] "=&r" (tmp32_2), [tmp32_3] "=&r" (tmp32_3),
|
||||
[totMax] "+r" (totMax), [r] "=&r" (r), [tmpvector] "+r" (tmpvector),
|
||||
[r1] "=&r" (r1), [r2] "=&r" (r2), [r3] "=&r" (r3)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
loop_size = length & 0xf;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
__asm__ volatile (
|
||||
"lh %[tmp32_0], 0(%[tmpvector]) \n\t"
|
||||
"addiu %[tmpvector], %[tmpvector], 2 \n\t"
|
||||
"abs %[tmp32_0], %[tmp32_0] \n\t"
|
||||
"slt %[tmp32_1], %[totMax], %[tmp32_0] \n\t"
|
||||
"movn %[totMax], %[tmp32_0], %[tmp32_1] \n\t"
|
||||
: [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1),
|
||||
[tmpvector] "+r" (tmpvector), [totMax] "+r" (totMax)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
__asm__ volatile (
|
||||
"slt %[r], %[v16MaxMax], %[totMax] \n\t"
|
||||
"movn %[totMax], %[v16MaxMax], %[r] \n\t"
|
||||
: [totMax] "+r" (totMax), [r] "=&r" (r)
|
||||
: [v16MaxMax] "r" (v16MaxMax)
|
||||
);
|
||||
#endif // #if defined(MIPS_DSP_R1)
|
||||
return (int16_t)totMax;
|
||||
}
|
||||
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
// Maximum absolute value of word32 vector. Version for MIPS platform.
|
||||
int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length) {
|
||||
// Use uint32_t for the local variables, to accommodate the return value
|
||||
// of abs(0x80000000), which is 0x80000000.
|
||||
|
||||
uint32_t absolute = 0, maximum = 0;
|
||||
int tmp1 = 0, max_value = 0x7fffffff;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
__asm__ volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"1: \n\t"
|
||||
"lw %[absolute], 0(%[vector]) \n\t"
|
||||
"absq_s.w %[absolute], %[absolute] \n\t"
|
||||
"addiu %[length], %[length], -1 \n\t"
|
||||
"slt %[tmp1], %[maximum], %[absolute] \n\t"
|
||||
"movn %[maximum], %[absolute], %[tmp1] \n\t"
|
||||
"bgtz %[length], 1b \n\t"
|
||||
" addiu %[vector], %[vector], 4 \n\t"
|
||||
"slt %[tmp1], %[max_value], %[maximum] \n\t"
|
||||
"movn %[maximum], %[max_value], %[tmp1] \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [absolute] "+r" (absolute)
|
||||
: [vector] "r" (vector), [length] "r" (length), [max_value] "r" (max_value)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return (int32_t)maximum;
|
||||
}
|
||||
#endif // #if defined(MIPS_DSP_R1_LE)
|
||||
|
||||
// Maximum value of word16 vector. Version for MIPS platform.
|
||||
int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length) {
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
int tmp1;
|
||||
int16_t value;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
__asm__ volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"1: \n\t"
|
||||
"lh %[value], 0(%[vector]) \n\t"
|
||||
"addiu %[length], %[length], -1 \n\t"
|
||||
"slt %[tmp1], %[maximum], %[value] \n\t"
|
||||
"movn %[maximum], %[value], %[tmp1] \n\t"
|
||||
"bgtz %[length], 1b \n\t"
|
||||
" addiu %[vector], %[vector], 2 \n\t"
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [value] "=&r" (value)
|
||||
: [vector] "r" (vector), [length] "r" (length)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word32 vector. Version for MIPS platform.
|
||||
int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length) {
|
||||
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
|
||||
int tmp1, value;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
__asm__ volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"1: \n\t"
|
||||
"lw %[value], 0(%[vector]) \n\t"
|
||||
"addiu %[length], %[length], -1 \n\t"
|
||||
"slt %[tmp1], %[maximum], %[value] \n\t"
|
||||
"movn %[maximum], %[value], %[tmp1] \n\t"
|
||||
"bgtz %[length], 1b \n\t"
|
||||
" addiu %[vector], %[vector], 4 \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [value] "=&r" (value)
|
||||
: [vector] "r" (vector), [length] "r" (length)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Minimum value of word16 vector. Version for MIPS platform.
|
||||
int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length) {
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
int tmp1;
|
||||
int16_t value;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
__asm__ volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"1: \n\t"
|
||||
"lh %[value], 0(%[vector]) \n\t"
|
||||
"addiu %[length], %[length], -1 \n\t"
|
||||
"slt %[tmp1], %[value], %[minimum] \n\t"
|
||||
"movn %[minimum], %[value], %[tmp1] \n\t"
|
||||
"bgtz %[length], 1b \n\t"
|
||||
" addiu %[vector], %[vector], 2 \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [minimum] "+r" (minimum), [value] "=&r" (value)
|
||||
: [vector] "r" (vector), [length] "r" (length)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Minimum value of word32 vector. Version for MIPS platform.
|
||||
int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length) {
|
||||
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
|
||||
int tmp1, value;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
__asm__ volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"1: \n\t"
|
||||
"lw %[value], 0(%[vector]) \n\t"
|
||||
"addiu %[length], %[length], -1 \n\t"
|
||||
"slt %[tmp1], %[value], %[minimum] \n\t"
|
||||
"movn %[minimum], %[value], %[tmp1] \n\t"
|
||||
"bgtz %[length], 1b \n\t"
|
||||
" addiu %[vector], %[vector], 4 \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [tmp1] "=&r" (tmp1), [minimum] "+r" (minimum), [value] "=&r" (value)
|
||||
: [vector] "r" (vector), [length] "r" (length)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return minimum;
|
||||
}
|
283
webrtc/common_audio/signal_processing/min_max_operations_neon.c
Normal file
283
webrtc/common_audio/signal_processing/min_max_operations_neon.c
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// Maximum absolute value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length) {
|
||||
int absolute = 0, maximum = 0;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
const int16_t* p_start = vector;
|
||||
size_t rest = length & 7;
|
||||
const int16_t* p_end = vector + length - rest;
|
||||
|
||||
int16x8_t v;
|
||||
uint16x8_t max_qv;
|
||||
max_qv = vdupq_n_u16(0);
|
||||
|
||||
while (p_start < p_end) {
|
||||
v = vld1q_s16(p_start);
|
||||
// Note vabs doesn't change the value of -32768.
|
||||
v = vabsq_s16(v);
|
||||
// Use u16 so we don't lose the value -32768.
|
||||
max_qv = vmaxq_u16(max_qv, vreinterpretq_u16_s16(v));
|
||||
p_start += 8;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM64
|
||||
maximum = (int)vmaxvq_u16(max_qv);
|
||||
#else
|
||||
uint16x4_t max_dv;
|
||||
max_dv = vmax_u16(vget_low_u16(max_qv), vget_high_u16(max_qv));
|
||||
max_dv = vpmax_u16(max_dv, max_dv);
|
||||
max_dv = vpmax_u16(max_dv, max_dv);
|
||||
|
||||
maximum = (int)vget_lane_u16(max_dv, 0);
|
||||
#endif
|
||||
|
||||
p_end = vector + length;
|
||||
while (p_start < p_end) {
|
||||
absolute = abs((int)(*p_start));
|
||||
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
p_start++;
|
||||
}
|
||||
|
||||
// Guard the case for abs(-32768).
|
||||
if (maximum > WEBRTC_SPL_WORD16_MAX) {
|
||||
maximum = WEBRTC_SPL_WORD16_MAX;
|
||||
}
|
||||
|
||||
return (int16_t)maximum;
|
||||
}
|
||||
|
||||
// Maximum absolute value of word32 vector. NEON intrinsics version for
|
||||
// ARM 32-bit/64-bit platforms.
|
||||
int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length) {
|
||||
// Use uint32_t for the local variables, to accommodate the return value
|
||||
// of abs(0x80000000), which is 0x80000000.
|
||||
|
||||
uint32_t absolute = 0, maximum = 0;
|
||||
size_t i = 0;
|
||||
size_t residual = length & 0x7;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
const int32_t* p_start = vector;
|
||||
uint32x4_t max32x4_0 = vdupq_n_u32(0);
|
||||
uint32x4_t max32x4_1 = vdupq_n_u32(0);
|
||||
|
||||
// First part, unroll the loop 8 times.
|
||||
for (i = 0; i < length - residual; i += 8) {
|
||||
int32x4_t in32x4_0 = vld1q_s32(p_start);
|
||||
p_start += 4;
|
||||
int32x4_t in32x4_1 = vld1q_s32(p_start);
|
||||
p_start += 4;
|
||||
in32x4_0 = vabsq_s32(in32x4_0);
|
||||
in32x4_1 = vabsq_s32(in32x4_1);
|
||||
// vabs doesn't change the value of 0x80000000.
|
||||
// Use u32 so we don't lose the value 0x80000000.
|
||||
max32x4_0 = vmaxq_u32(max32x4_0, vreinterpretq_u32_s32(in32x4_0));
|
||||
max32x4_1 = vmaxq_u32(max32x4_1, vreinterpretq_u32_s32(in32x4_1));
|
||||
}
|
||||
|
||||
uint32x4_t max32x4 = vmaxq_u32(max32x4_0, max32x4_1);
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
maximum = vmaxvq_u32(max32x4);
|
||||
#else
|
||||
uint32x2_t max32x2 = vmax_u32(vget_low_u32(max32x4), vget_high_u32(max32x4));
|
||||
max32x2 = vpmax_u32(max32x2, max32x2);
|
||||
|
||||
maximum = vget_lane_u32(max32x2, 0);
|
||||
#endif
|
||||
|
||||
// Second part, do the remaining iterations (if any).
|
||||
for (i = residual; i > 0; i--) {
|
||||
absolute = abs((int)(*p_start));
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
p_start++;
|
||||
}
|
||||
|
||||
// Guard against the case for 0x80000000.
|
||||
maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX);
|
||||
|
||||
return (int32_t)maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word16 vector. NEON intrinsics version for
|
||||
// ARM 32-bit/64-bit platforms.
|
||||
int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length) {
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
size_t i = 0;
|
||||
size_t residual = length & 0x7;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
const int16_t* p_start = vector;
|
||||
int16x8_t max16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MIN);
|
||||
|
||||
// First part, unroll the loop 8 times.
|
||||
for (i = 0; i < length - residual; i += 8) {
|
||||
int16x8_t in16x8 = vld1q_s16(p_start);
|
||||
max16x8 = vmaxq_s16(max16x8, in16x8);
|
||||
p_start += 8;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
maximum = vmaxvq_s16(max16x8);
|
||||
#else
|
||||
int16x4_t max16x4 = vmax_s16(vget_low_s16(max16x8), vget_high_s16(max16x8));
|
||||
max16x4 = vpmax_s16(max16x4, max16x4);
|
||||
max16x4 = vpmax_s16(max16x4, max16x4);
|
||||
|
||||
maximum = vget_lane_s16(max16x4, 0);
|
||||
#endif
|
||||
|
||||
// Second part, do the remaining iterations (if any).
|
||||
for (i = residual; i > 0; i--) {
|
||||
if (*p_start > maximum)
|
||||
maximum = *p_start;
|
||||
p_start++;
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word32 vector. NEON intrinsics version for
|
||||
// ARM 32-bit/64-bit platforms.
|
||||
int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length) {
|
||||
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
|
||||
size_t i = 0;
|
||||
size_t residual = length & 0x7;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
const int32_t* p_start = vector;
|
||||
int32x4_t max32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN);
|
||||
int32x4_t max32x4_1 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN);
|
||||
|
||||
// First part, unroll the loop 8 times.
|
||||
for (i = 0; i < length - residual; i += 8) {
|
||||
int32x4_t in32x4_0 = vld1q_s32(p_start);
|
||||
p_start += 4;
|
||||
int32x4_t in32x4_1 = vld1q_s32(p_start);
|
||||
p_start += 4;
|
||||
max32x4_0 = vmaxq_s32(max32x4_0, in32x4_0);
|
||||
max32x4_1 = vmaxq_s32(max32x4_1, in32x4_1);
|
||||
}
|
||||
|
||||
int32x4_t max32x4 = vmaxq_s32(max32x4_0, max32x4_1);
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
maximum = vmaxvq_s32(max32x4);
|
||||
#else
|
||||
int32x2_t max32x2 = vmax_s32(vget_low_s32(max32x4), vget_high_s32(max32x4));
|
||||
max32x2 = vpmax_s32(max32x2, max32x2);
|
||||
|
||||
maximum = vget_lane_s32(max32x2, 0);
|
||||
#endif
|
||||
|
||||
// Second part, do the remaining iterations (if any).
|
||||
for (i = residual; i > 0; i--) {
|
||||
if (*p_start > maximum)
|
||||
maximum = *p_start;
|
||||
p_start++;
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Minimum value of word16 vector. NEON intrinsics version for
|
||||
// ARM 32-bit/64-bit platforms.
|
||||
int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length) {
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
size_t i = 0;
|
||||
size_t residual = length & 0x7;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
const int16_t* p_start = vector;
|
||||
int16x8_t min16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MAX);
|
||||
|
||||
// First part, unroll the loop 8 times.
|
||||
for (i = 0; i < length - residual; i += 8) {
|
||||
int16x8_t in16x8 = vld1q_s16(p_start);
|
||||
min16x8 = vminq_s16(min16x8, in16x8);
|
||||
p_start += 8;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
minimum = vminvq_s16(min16x8);
|
||||
#else
|
||||
int16x4_t min16x4 = vmin_s16(vget_low_s16(min16x8), vget_high_s16(min16x8));
|
||||
min16x4 = vpmin_s16(min16x4, min16x4);
|
||||
min16x4 = vpmin_s16(min16x4, min16x4);
|
||||
|
||||
minimum = vget_lane_s16(min16x4, 0);
|
||||
#endif
|
||||
|
||||
// Second part, do the remaining iterations (if any).
|
||||
for (i = residual; i > 0; i--) {
|
||||
if (*p_start < minimum)
|
||||
minimum = *p_start;
|
||||
p_start++;
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Minimum value of word32 vector. NEON intrinsics version for
|
||||
// ARM 32-bit/64-bit platforms.
|
||||
int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length) {
|
||||
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
|
||||
size_t i = 0;
|
||||
size_t residual = length & 0x7;
|
||||
|
||||
assert(length > 0);
|
||||
|
||||
const int32_t* p_start = vector;
|
||||
int32x4_t min32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX);
|
||||
int32x4_t min32x4_1 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX);
|
||||
|
||||
// First part, unroll the loop 8 times.
|
||||
for (i = 0; i < length - residual; i += 8) {
|
||||
int32x4_t in32x4_0 = vld1q_s32(p_start);
|
||||
p_start += 4;
|
||||
int32x4_t in32x4_1 = vld1q_s32(p_start);
|
||||
p_start += 4;
|
||||
min32x4_0 = vminq_s32(min32x4_0, in32x4_0);
|
||||
min32x4_1 = vminq_s32(min32x4_1, in32x4_1);
|
||||
}
|
||||
|
||||
int32x4_t min32x4 = vminq_s32(min32x4_0, min32x4_1);
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
minimum = vminvq_s32(min32x4);
|
||||
#else
|
||||
int32x2_t min32x2 = vmin_s32(vget_low_s32(min32x4), vget_high_s32(min32x4));
|
||||
min32x2 = vpmin_s32(min32x2, min32x2);
|
||||
|
||||
minimum = vget_lane_s32(min32x2, 0);
|
||||
#endif
|
||||
|
||||
// Second part, do the remaining iterations (if any).
|
||||
for (i = residual; i > 0; i--) {
|
||||
if (*p_start < minimum)
|
||||
minimum = *p_start;
|
||||
p_start++;
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
115
webrtc/common_audio/signal_processing/randomization_functions.c
Normal file
115
webrtc/common_audio/signal_processing/randomization_functions.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the randomization functions
|
||||
* WebRtcSpl_RandU()
|
||||
* WebRtcSpl_RandN()
|
||||
* WebRtcSpl_RandUArray()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
static const uint32_t kMaxSeedUsed = 0x80000000;
|
||||
|
||||
static const int16_t kRandNTable[] = {
|
||||
9178, -7260, 40, 10189, 4894, -3531, -13779, 14764,
|
||||
-4008, -8884, -8990, 1008, 7368, 5184, 3251, -5817,
|
||||
-9786, 5963, 1770, 8066, -7135, 10772, -2298, 1361,
|
||||
6484, 2241, -8633, 792, 199, -3344, 6553, -10079,
|
||||
-15040, 95, 11608, -12469, 14161, -4176, 2476, 6403,
|
||||
13685, -16005, 6646, 2239, 10916, -3004, -602, -3141,
|
||||
2142, 14144, -5829, 5305, 8209, 4713, 2697, -5112,
|
||||
16092, -1210, -2891, -6631, -5360, -11878, -6781, -2739,
|
||||
-6392, 536, 10923, 10872, 5059, -4748, -7770, 5477,
|
||||
38, -1025, -2892, 1638, 6304, 14375, -11028, 1553,
|
||||
-1565, 10762, -393, 4040, 5257, 12310, 6554, -4799,
|
||||
4899, -6354, 1603, -1048, -2220, 8247, -186, -8944,
|
||||
-12004, 2332, 4801, -4933, 6371, 131, 8614, -5927,
|
||||
-8287, -22760, 4033, -15162, 3385, 3246, 3153, -5250,
|
||||
3766, 784, 6494, -62, 3531, -1582, 15572, 662,
|
||||
-3952, -330, -3196, 669, 7236, -2678, -6569, 23319,
|
||||
-8645, -741, 14830, -15976, 4903, 315, -11342, 10311,
|
||||
1858, -7777, 2145, 5436, 5677, -113, -10033, 826,
|
||||
-1353, 17210, 7768, 986, -1471, 8291, -4982, 8207,
|
||||
-14911, -6255, -2449, -11881, -7059, -11703, -4338, 8025,
|
||||
7538, -2823, -12490, 9470, -1613, -2529, -10092, -7807,
|
||||
9480, 6970, -12844, 5123, 3532, 4816, 4803, -8455,
|
||||
-5045, 14032, -4378, -1643, 5756, -11041, -2732, -16618,
|
||||
-6430, -18375, -3320, 6098, 5131, -4269, -8840, 2482,
|
||||
-7048, 1547, -21890, -6505, -7414, -424, -11722, 7955,
|
||||
1653, -17299, 1823, 473, -9232, 3337, 1111, 873,
|
||||
4018, -8982, 9889, 3531, -11763, -3799, 7373, -4539,
|
||||
3231, 7054, -8537, 7616, 6244, 16635, 447, -2915,
|
||||
13967, 705, -2669, -1520, -1771, -16188, 5956, 5117,
|
||||
6371, -9936, -1448, 2480, 5128, 7550, -8130, 5236,
|
||||
8213, -6443, 7707, -1950, -13811, 7218, 7031, -3883,
|
||||
67, 5731, -2874, 13480, -3743, 9298, -3280, 3552,
|
||||
-4425, -18, -3785, -9988, -5357, 5477, -11794, 2117,
|
||||
1416, -9935, 3376, 802, -5079, -8243, 12652, 66,
|
||||
3653, -2368, 6781, -21895, -7227, 2487, 7839, -385,
|
||||
6646, -7016, -4658, 5531, -1705, 834, 129, 3694,
|
||||
-1343, 2238, -22640, -6417, -11139, 11301, -2945, -3494,
|
||||
-5626, 185, -3615, -2041, -7972, -3106, -60, -23497,
|
||||
-1566, 17064, 3519, 2518, 304, -6805, -10269, 2105,
|
||||
1936, -426, -736, -8122, -1467, 4238, -6939, -13309,
|
||||
360, 7402, -7970, 12576, 3287, 12194, -6289, -16006,
|
||||
9171, 4042, -9193, 9123, -2512, 6388, -4734, -8739,
|
||||
1028, -5406, -1696, 5889, -666, -4736, 4971, 3565,
|
||||
9362, -6292, 3876, -3652, -19666, 7523, -4061, 391,
|
||||
-11773, 7502, -3763, 4929, -9478, 13278, 2805, 4496,
|
||||
7814, 16419, 12455, -14773, 2127, -2746, 3763, 4847,
|
||||
3698, 6978, 4751, -6957, -3581, -45, 6252, 1513,
|
||||
-4797, -7925, 11270, 16188, -2359, -5269, 9376, -10777,
|
||||
7262, 20031, -6515, -2208, -5353, 8085, -1341, -1303,
|
||||
7333, 5576, 3625, 5763, -7931, 9833, -3371, -10305,
|
||||
6534, -13539, -9971, 997, 8464, -4064, -1495, 1857,
|
||||
13624, 5458, 9490, -11086, -4524, 12022, -550, -198,
|
||||
408, -8455, -7068, 10289, 9712, -3366, 9028, -7621,
|
||||
-5243, 2362, 6909, 4672, -4933, -1799, 4709, -4563,
|
||||
-62, -566, 1624, -7010, 14730, -17791, -3697, -2344,
|
||||
-1741, 7099, -9509, -6855, -1989, 3495, -2289, 2031,
|
||||
12784, 891, 14189, -3963, -5683, 421, -12575, 1724,
|
||||
-12682, -5970, -8169, 3143, -1824, -5488, -5130, 8536,
|
||||
12799, 794, 5738, 3459, -11689, -258, -3738, -3775,
|
||||
-8742, 2333, 8312, -9383, 10331, 13119, 8398, 10644,
|
||||
-19433, -6446, -16277, -11793, 16284, 9345, 15222, 15834,
|
||||
2009, -7349, 130, -14547, 338, -5998, 3337, 21492,
|
||||
2406, 7703, -951, 11196, -564, 3406, 2217, 4806,
|
||||
2374, -5797, 11839, 8940, -11874, 18213, 2855, 10492
|
||||
};
|
||||
|
||||
static uint32_t IncreaseSeed(uint32_t* seed) {
|
||||
seed[0] = (seed[0] * ((int32_t)69069) + 1) & (kMaxSeedUsed - 1);
|
||||
return seed[0];
|
||||
}
|
||||
|
||||
int16_t WebRtcSpl_RandU(uint32_t* seed) {
|
||||
return (int16_t)(IncreaseSeed(seed) >> 16);
|
||||
}
|
||||
|
||||
int16_t WebRtcSpl_RandN(uint32_t* seed) {
|
||||
return kRandNTable[IncreaseSeed(seed) >> 23];
|
||||
}
|
||||
|
||||
// Creates an array of uniformly distributed variables.
|
||||
int16_t WebRtcSpl_RandUArray(int16_t* vector,
|
||||
int16_t vector_length,
|
||||
uint32_t* seed) {
|
||||
int i;
|
||||
for (i = 0; i < vector_length; i++) {
|
||||
vector[i] = WebRtcSpl_RandU(seed);
|
||||
}
|
||||
return vector_length;
|
||||
}
|
102
webrtc/common_audio/signal_processing/real_fft.c
Normal file
102
webrtc/common_audio/signal_processing/real_fft.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/real_fft.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
struct RealFFT {
|
||||
int order;
|
||||
};
|
||||
|
||||
struct RealFFT* WebRtcSpl_CreateRealFFT(int order) {
|
||||
struct RealFFT* self = NULL;
|
||||
|
||||
if (order > kMaxFFTOrder || order < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = malloc(sizeof(struct RealFFT));
|
||||
if (self == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
self->order = order;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void WebRtcSpl_FreeRealFFT(struct RealFFT* self) {
|
||||
if (self != NULL) {
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
// The C version FFT functions (i.e. WebRtcSpl_RealForwardFFT and
|
||||
// WebRtcSpl_RealInverseFFT) are real-valued FFT wrappers for complex-valued
|
||||
// FFT implementation in SPL.
|
||||
|
||||
int WebRtcSpl_RealForwardFFT(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int result = 0;
|
||||
int n = 1 << self->order;
|
||||
// The complex-value FFT implementation needs a buffer to hold 2^order
|
||||
// 16-bit COMPLEX numbers, for both time and frequency data.
|
||||
int16_t complex_buffer[2 << kMaxFFTOrder];
|
||||
|
||||
// Insert zeros to the imaginary parts for complex forward FFT input.
|
||||
for (i = 0, j = 0; i < n; i += 1, j += 2) {
|
||||
complex_buffer[j] = real_data_in[i];
|
||||
complex_buffer[j + 1] = 0;
|
||||
};
|
||||
|
||||
WebRtcSpl_ComplexBitReverse(complex_buffer, self->order);
|
||||
result = WebRtcSpl_ComplexFFT(complex_buffer, self->order, 1);
|
||||
|
||||
// For real FFT output, use only the first N + 2 elements from
|
||||
// complex forward FFT.
|
||||
memcpy(complex_data_out, complex_buffer, sizeof(int16_t) * (n + 2));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int WebRtcSpl_RealInverseFFT(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int result = 0;
|
||||
int n = 1 << self->order;
|
||||
// Create the buffer specific to complex-valued FFT implementation.
|
||||
int16_t complex_buffer[2 << kMaxFFTOrder];
|
||||
|
||||
// For n-point FFT, first copy the first n + 2 elements into complex
|
||||
// FFT, then construct the remaining n - 2 elements by real FFT's
|
||||
// conjugate-symmetric properties.
|
||||
memcpy(complex_buffer, complex_data_in, sizeof(int16_t) * (n + 2));
|
||||
for (i = n + 2; i < 2 * n; i += 2) {
|
||||
complex_buffer[i] = complex_data_in[2 * n - i];
|
||||
complex_buffer[i + 1] = -complex_data_in[2 * n - i + 1];
|
||||
}
|
||||
|
||||
WebRtcSpl_ComplexBitReverse(complex_buffer, self->order);
|
||||
result = WebRtcSpl_ComplexIFFT(complex_buffer, self->order, 1);
|
||||
|
||||
// Strip out the imaginary parts of the complex inverse FFT output.
|
||||
for (i = 0, j = 0; i < n; i += 1, j += 2) {
|
||||
real_data_out[i] = complex_buffer[j];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
59
webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
Normal file
59
webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_ReflCoefToLpc().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_ReflCoefToLpc(const int16_t *k, int use_order, int16_t *a)
|
||||
{
|
||||
int16_t any[WEBRTC_SPL_MAX_LPC_ORDER + 1];
|
||||
int16_t *aptr, *aptr2, *anyptr;
|
||||
const int16_t *kptr;
|
||||
int m, i;
|
||||
|
||||
kptr = k;
|
||||
*a = 4096; // i.e., (Word16_MAX >> 3)+1.
|
||||
*any = *a;
|
||||
a[1] = *k >> 3;
|
||||
|
||||
for (m = 1; m < use_order; m++)
|
||||
{
|
||||
kptr++;
|
||||
aptr = a;
|
||||
aptr++;
|
||||
aptr2 = &a[m];
|
||||
anyptr = any;
|
||||
anyptr++;
|
||||
|
||||
any[m + 1] = *kptr >> 3;
|
||||
for (i = 0; i < m; i++)
|
||||
{
|
||||
*anyptr = *aptr + (int16_t)((*aptr2 * *kptr) >> 15);
|
||||
anyptr++;
|
||||
aptr++;
|
||||
aptr2--;
|
||||
}
|
||||
|
||||
aptr = a;
|
||||
anyptr = any;
|
||||
for (i = 0; i < (m + 2); i++)
|
||||
{
|
||||
*aptr = *anyptr;
|
||||
aptr++;
|
||||
anyptr++;
|
||||
}
|
||||
}
|
||||
}
|
505
webrtc/common_audio/signal_processing/resample.c
Normal file
505
webrtc/common_audio/signal_processing/resample.c
Normal file
@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling functions for 22 kHz.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/common_audio/signal_processing/resample_by_2_internal.h"
|
||||
|
||||
// Declaration of internally used functions
|
||||
static void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, int16_t *Out,
|
||||
int32_t K);
|
||||
|
||||
void WebRtcSpl_32khzTo22khzIntToInt(const int32_t *In, int32_t *Out,
|
||||
int32_t K);
|
||||
|
||||
// interpolation coefficients
|
||||
static const int16_t kCoefficients32To22[5][9] = {
|
||||
{127, -712, 2359, -6333, 23456, 16775, -3695, 945, -154},
|
||||
{-39, 230, -830, 2785, 32366, -2324, 760, -218, 38},
|
||||
{117, -663, 2222, -6133, 26634, 13070, -3174, 831, -137},
|
||||
{-77, 457, -1677, 5958, 31175, -4136, 1405, -408, 71},
|
||||
{ 98, -560, 1900, -5406, 29240, 9423, -2480, 663, -110}
|
||||
};
|
||||
|
||||
//////////////////////
|
||||
// 22 kHz -> 16 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 4, 5, 10
|
||||
#define SUB_BLOCKS_22_16 5
|
||||
|
||||
// 22 -> 16 resampler
|
||||
void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State22khzTo16khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_22_16 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_22_16; k++)
|
||||
{
|
||||
///// 22 --> 44 /////
|
||||
// int16_t in[220/SUB_BLOCKS_22_16]
|
||||
// int32_t out[440/SUB_BLOCKS_22_16]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 220 / SUB_BLOCKS_22_16, tmpmem + 16, state->S_22_44);
|
||||
|
||||
///// 44 --> 32 /////
|
||||
// int32_t in[440/SUB_BLOCKS_22_16]
|
||||
// int32_t out[320/SUB_BLOCKS_22_16]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[8] = state->S_44_32[0];
|
||||
tmpmem[9] = state->S_44_32[1];
|
||||
tmpmem[10] = state->S_44_32[2];
|
||||
tmpmem[11] = state->S_44_32[3];
|
||||
tmpmem[12] = state->S_44_32[4];
|
||||
tmpmem[13] = state->S_44_32[5];
|
||||
tmpmem[14] = state->S_44_32[6];
|
||||
tmpmem[15] = state->S_44_32[7];
|
||||
state->S_44_32[0] = tmpmem[440 / SUB_BLOCKS_22_16 + 8];
|
||||
state->S_44_32[1] = tmpmem[440 / SUB_BLOCKS_22_16 + 9];
|
||||
state->S_44_32[2] = tmpmem[440 / SUB_BLOCKS_22_16 + 10];
|
||||
state->S_44_32[3] = tmpmem[440 / SUB_BLOCKS_22_16 + 11];
|
||||
state->S_44_32[4] = tmpmem[440 / SUB_BLOCKS_22_16 + 12];
|
||||
state->S_44_32[5] = tmpmem[440 / SUB_BLOCKS_22_16 + 13];
|
||||
state->S_44_32[6] = tmpmem[440 / SUB_BLOCKS_22_16 + 14];
|
||||
state->S_44_32[7] = tmpmem[440 / SUB_BLOCKS_22_16 + 15];
|
||||
|
||||
WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 40 / SUB_BLOCKS_22_16);
|
||||
|
||||
///// 32 --> 16 /////
|
||||
// int32_t in[320/SUB_BLOCKS_22_16]
|
||||
// int32_t out[160/SUB_BLOCKS_22_16]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 320 / SUB_BLOCKS_22_16, out, state->S_32_16);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_22_16 ms seconds ahead
|
||||
in += 220 / SUB_BLOCKS_22_16;
|
||||
out += 160 / SUB_BLOCKS_22_16;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 22 -> 16 resampler
|
||||
void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_22_44[k] = 0;
|
||||
state->S_44_32[k] = 0;
|
||||
state->S_32_16[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// 16 kHz -> 22 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 4, 5, 10
|
||||
#define SUB_BLOCKS_16_22 4
|
||||
|
||||
// 16 -> 22 resampler
|
||||
void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State16khzTo22khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_16_22 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_16_22; k++)
|
||||
{
|
||||
///// 16 --> 32 /////
|
||||
// int16_t in[160/SUB_BLOCKS_16_22]
|
||||
// int32_t out[320/SUB_BLOCKS_16_22]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 160 / SUB_BLOCKS_16_22, tmpmem + 8, state->S_16_32);
|
||||
|
||||
///// 32 --> 22 /////
|
||||
// int32_t in[320/SUB_BLOCKS_16_22]
|
||||
// int32_t out[220/SUB_BLOCKS_16_22]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[0] = state->S_32_22[0];
|
||||
tmpmem[1] = state->S_32_22[1];
|
||||
tmpmem[2] = state->S_32_22[2];
|
||||
tmpmem[3] = state->S_32_22[3];
|
||||
tmpmem[4] = state->S_32_22[4];
|
||||
tmpmem[5] = state->S_32_22[5];
|
||||
tmpmem[6] = state->S_32_22[6];
|
||||
tmpmem[7] = state->S_32_22[7];
|
||||
state->S_32_22[0] = tmpmem[320 / SUB_BLOCKS_16_22];
|
||||
state->S_32_22[1] = tmpmem[320 / SUB_BLOCKS_16_22 + 1];
|
||||
state->S_32_22[2] = tmpmem[320 / SUB_BLOCKS_16_22 + 2];
|
||||
state->S_32_22[3] = tmpmem[320 / SUB_BLOCKS_16_22 + 3];
|
||||
state->S_32_22[4] = tmpmem[320 / SUB_BLOCKS_16_22 + 4];
|
||||
state->S_32_22[5] = tmpmem[320 / SUB_BLOCKS_16_22 + 5];
|
||||
state->S_32_22[6] = tmpmem[320 / SUB_BLOCKS_16_22 + 6];
|
||||
state->S_32_22[7] = tmpmem[320 / SUB_BLOCKS_16_22 + 7];
|
||||
|
||||
WebRtcSpl_32khzTo22khzIntToShort(tmpmem, out, 20 / SUB_BLOCKS_16_22);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_16_22 ms seconds ahead
|
||||
in += 160 / SUB_BLOCKS_16_22;
|
||||
out += 220 / SUB_BLOCKS_16_22;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 16 -> 22 resampler
|
||||
void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_16_32[k] = 0;
|
||||
state->S_32_22[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// 22 kHz -> 8 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 5, 10
|
||||
#define SUB_BLOCKS_22_8 2
|
||||
|
||||
// 22 -> 8 resampler
|
||||
void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State22khzTo8khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_22_8 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_22_8; k++)
|
||||
{
|
||||
///// 22 --> 22 lowpass /////
|
||||
// int16_t in[220/SUB_BLOCKS_22_8]
|
||||
// int32_t out[220/SUB_BLOCKS_22_8]
|
||||
/////
|
||||
WebRtcSpl_LPBy2ShortToInt(in, 220 / SUB_BLOCKS_22_8, tmpmem + 16, state->S_22_22);
|
||||
|
||||
///// 22 --> 16 /////
|
||||
// int32_t in[220/SUB_BLOCKS_22_8]
|
||||
// int32_t out[160/SUB_BLOCKS_22_8]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[8] = state->S_22_16[0];
|
||||
tmpmem[9] = state->S_22_16[1];
|
||||
tmpmem[10] = state->S_22_16[2];
|
||||
tmpmem[11] = state->S_22_16[3];
|
||||
tmpmem[12] = state->S_22_16[4];
|
||||
tmpmem[13] = state->S_22_16[5];
|
||||
tmpmem[14] = state->S_22_16[6];
|
||||
tmpmem[15] = state->S_22_16[7];
|
||||
state->S_22_16[0] = tmpmem[220 / SUB_BLOCKS_22_8 + 8];
|
||||
state->S_22_16[1] = tmpmem[220 / SUB_BLOCKS_22_8 + 9];
|
||||
state->S_22_16[2] = tmpmem[220 / SUB_BLOCKS_22_8 + 10];
|
||||
state->S_22_16[3] = tmpmem[220 / SUB_BLOCKS_22_8 + 11];
|
||||
state->S_22_16[4] = tmpmem[220 / SUB_BLOCKS_22_8 + 12];
|
||||
state->S_22_16[5] = tmpmem[220 / SUB_BLOCKS_22_8 + 13];
|
||||
state->S_22_16[6] = tmpmem[220 / SUB_BLOCKS_22_8 + 14];
|
||||
state->S_22_16[7] = tmpmem[220 / SUB_BLOCKS_22_8 + 15];
|
||||
|
||||
WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 20 / SUB_BLOCKS_22_8);
|
||||
|
||||
///// 16 --> 8 /////
|
||||
// int32_t in[160/SUB_BLOCKS_22_8]
|
||||
// int32_t out[80/SUB_BLOCKS_22_8]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 160 / SUB_BLOCKS_22_8, out, state->S_16_8);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_22_8 ms seconds ahead
|
||||
in += 220 / SUB_BLOCKS_22_8;
|
||||
out += 80 / SUB_BLOCKS_22_8;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 22 -> 8 resampler
|
||||
void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_22_22[k] = 0;
|
||||
state->S_22_22[k + 8] = 0;
|
||||
state->S_22_16[k] = 0;
|
||||
state->S_16_8[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// 8 kHz -> 22 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 5, 10
|
||||
#define SUB_BLOCKS_8_22 2
|
||||
|
||||
// 8 -> 22 resampler
|
||||
void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State8khzTo22khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_8_22 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_8_22; k++)
|
||||
{
|
||||
///// 8 --> 16 /////
|
||||
// int16_t in[80/SUB_BLOCKS_8_22]
|
||||
// int32_t out[160/SUB_BLOCKS_8_22]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 80 / SUB_BLOCKS_8_22, tmpmem + 18, state->S_8_16);
|
||||
|
||||
///// 16 --> 11 /////
|
||||
// int32_t in[160/SUB_BLOCKS_8_22]
|
||||
// int32_t out[110/SUB_BLOCKS_8_22]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[10] = state->S_16_11[0];
|
||||
tmpmem[11] = state->S_16_11[1];
|
||||
tmpmem[12] = state->S_16_11[2];
|
||||
tmpmem[13] = state->S_16_11[3];
|
||||
tmpmem[14] = state->S_16_11[4];
|
||||
tmpmem[15] = state->S_16_11[5];
|
||||
tmpmem[16] = state->S_16_11[6];
|
||||
tmpmem[17] = state->S_16_11[7];
|
||||
state->S_16_11[0] = tmpmem[160 / SUB_BLOCKS_8_22 + 10];
|
||||
state->S_16_11[1] = tmpmem[160 / SUB_BLOCKS_8_22 + 11];
|
||||
state->S_16_11[2] = tmpmem[160 / SUB_BLOCKS_8_22 + 12];
|
||||
state->S_16_11[3] = tmpmem[160 / SUB_BLOCKS_8_22 + 13];
|
||||
state->S_16_11[4] = tmpmem[160 / SUB_BLOCKS_8_22 + 14];
|
||||
state->S_16_11[5] = tmpmem[160 / SUB_BLOCKS_8_22 + 15];
|
||||
state->S_16_11[6] = tmpmem[160 / SUB_BLOCKS_8_22 + 16];
|
||||
state->S_16_11[7] = tmpmem[160 / SUB_BLOCKS_8_22 + 17];
|
||||
|
||||
WebRtcSpl_32khzTo22khzIntToInt(tmpmem + 10, tmpmem, 10 / SUB_BLOCKS_8_22);
|
||||
|
||||
///// 11 --> 22 /////
|
||||
// int32_t in[110/SUB_BLOCKS_8_22]
|
||||
// int16_t out[220/SUB_BLOCKS_8_22]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToShort(tmpmem, 110 / SUB_BLOCKS_8_22, out, state->S_11_22);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_8_22 ms seconds ahead
|
||||
in += 80 / SUB_BLOCKS_8_22;
|
||||
out += 220 / SUB_BLOCKS_8_22;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 8 -> 22 resampler
|
||||
void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_8_16[k] = 0;
|
||||
state->S_16_11[k] = 0;
|
||||
state->S_11_22[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// compute two inner-products and store them to output array
|
||||
static void WebRtcSpl_DotProdIntToInt(const int32_t* in1, const int32_t* in2,
|
||||
const int16_t* coef_ptr, int32_t* out1,
|
||||
int32_t* out2)
|
||||
{
|
||||
int32_t tmp1 = 16384;
|
||||
int32_t tmp2 = 16384;
|
||||
int16_t coef;
|
||||
|
||||
coef = coef_ptr[0];
|
||||
tmp1 += coef * in1[0];
|
||||
tmp2 += coef * in2[-0];
|
||||
|
||||
coef = coef_ptr[1];
|
||||
tmp1 += coef * in1[1];
|
||||
tmp2 += coef * in2[-1];
|
||||
|
||||
coef = coef_ptr[2];
|
||||
tmp1 += coef * in1[2];
|
||||
tmp2 += coef * in2[-2];
|
||||
|
||||
coef = coef_ptr[3];
|
||||
tmp1 += coef * in1[3];
|
||||
tmp2 += coef * in2[-3];
|
||||
|
||||
coef = coef_ptr[4];
|
||||
tmp1 += coef * in1[4];
|
||||
tmp2 += coef * in2[-4];
|
||||
|
||||
coef = coef_ptr[5];
|
||||
tmp1 += coef * in1[5];
|
||||
tmp2 += coef * in2[-5];
|
||||
|
||||
coef = coef_ptr[6];
|
||||
tmp1 += coef * in1[6];
|
||||
tmp2 += coef * in2[-6];
|
||||
|
||||
coef = coef_ptr[7];
|
||||
tmp1 += coef * in1[7];
|
||||
tmp2 += coef * in2[-7];
|
||||
|
||||
coef = coef_ptr[8];
|
||||
*out1 = tmp1 + coef * in1[8];
|
||||
*out2 = tmp2 + coef * in2[-8];
|
||||
}
|
||||
|
||||
// compute two inner-products and store them to output array
|
||||
static void WebRtcSpl_DotProdIntToShort(const int32_t* in1, const int32_t* in2,
|
||||
const int16_t* coef_ptr, int16_t* out1,
|
||||
int16_t* out2)
|
||||
{
|
||||
int32_t tmp1 = 16384;
|
||||
int32_t tmp2 = 16384;
|
||||
int16_t coef;
|
||||
|
||||
coef = coef_ptr[0];
|
||||
tmp1 += coef * in1[0];
|
||||
tmp2 += coef * in2[-0];
|
||||
|
||||
coef = coef_ptr[1];
|
||||
tmp1 += coef * in1[1];
|
||||
tmp2 += coef * in2[-1];
|
||||
|
||||
coef = coef_ptr[2];
|
||||
tmp1 += coef * in1[2];
|
||||
tmp2 += coef * in2[-2];
|
||||
|
||||
coef = coef_ptr[3];
|
||||
tmp1 += coef * in1[3];
|
||||
tmp2 += coef * in2[-3];
|
||||
|
||||
coef = coef_ptr[4];
|
||||
tmp1 += coef * in1[4];
|
||||
tmp2 += coef * in2[-4];
|
||||
|
||||
coef = coef_ptr[5];
|
||||
tmp1 += coef * in1[5];
|
||||
tmp2 += coef * in2[-5];
|
||||
|
||||
coef = coef_ptr[6];
|
||||
tmp1 += coef * in1[6];
|
||||
tmp2 += coef * in2[-6];
|
||||
|
||||
coef = coef_ptr[7];
|
||||
tmp1 += coef * in1[7];
|
||||
tmp2 += coef * in2[-7];
|
||||
|
||||
coef = coef_ptr[8];
|
||||
tmp1 += coef * in1[8];
|
||||
tmp2 += coef * in2[-8];
|
||||
|
||||
// scale down, round and saturate
|
||||
tmp1 >>= 15;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
tmp2 >>= 15;
|
||||
if (tmp2 > (int32_t)0x00007FFF)
|
||||
tmp2 = 0x00007FFF;
|
||||
if (tmp2 < (int32_t)0xFFFF8000)
|
||||
tmp2 = 0xFFFF8000;
|
||||
*out1 = (int16_t)tmp1;
|
||||
*out2 = (int16_t)tmp2;
|
||||
}
|
||||
|
||||
// Resampling ratio: 11/16
|
||||
// input: int32_t (normalized, not saturated) :: size 16 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 11 * K
|
||||
// K: Number of blocks
|
||||
|
||||
void WebRtcSpl_32khzTo22khzIntToInt(const int32_t* In,
|
||||
int32_t* Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (16 input samples -> 11 output samples);
|
||||
// process in sub blocks of size 16 samples.
|
||||
int32_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
// first output sample
|
||||
Out[0] = ((int32_t)In[3] << 15) + (1 << 14);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]);
|
||||
|
||||
// update pointers
|
||||
In += 16;
|
||||
Out += 11;
|
||||
}
|
||||
}
|
||||
|
||||
// Resampling ratio: 11/16
|
||||
// input: int32_t (normalized, not saturated) :: size 16 * K
|
||||
// output: int16_t (saturated) :: size 11 * K
|
||||
// K: Number of blocks
|
||||
|
||||
void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In,
|
||||
int16_t *Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (16 input samples -> 11 output samples);
|
||||
// process in sub blocks of size 16 samples.
|
||||
int32_t tmp;
|
||||
int32_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
// first output sample
|
||||
tmp = In[3];
|
||||
if (tmp > (int32_t)0x00007FFF)
|
||||
tmp = 0x00007FFF;
|
||||
if (tmp < (int32_t)0xFFFF8000)
|
||||
tmp = 0xFFFF8000;
|
||||
Out[0] = (int16_t)tmp;
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]);
|
||||
|
||||
// update pointers
|
||||
In += 16;
|
||||
Out += 11;
|
||||
}
|
||||
}
|
186
webrtc/common_audio/signal_processing/resample_48khz.c
Normal file
186
webrtc/common_audio/signal_processing/resample_48khz.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains resampling functions between 48 kHz and nb/wb.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/common_audio/signal_processing/resample_by_2_internal.h"
|
||||
|
||||
////////////////////////////
|
||||
///// 48 kHz -> 16 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 48 -> 16 resampler
|
||||
void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State48khzTo16khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 48 --> 48(LP) /////
|
||||
// int16_t in[480]
|
||||
// int32_t out[480]
|
||||
/////
|
||||
WebRtcSpl_LPBy2ShortToInt(in, 480, tmpmem + 16, state->S_48_48);
|
||||
|
||||
///// 48 --> 32 /////
|
||||
// int32_t in[480]
|
||||
// int32_t out[320]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
memcpy(tmpmem + 8, state->S_48_32, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_48_32, tmpmem + 488, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 160);
|
||||
|
||||
///// 32 --> 16 /////
|
||||
// int32_t in[320]
|
||||
// int16_t out[160]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 320, out, state->S_32_16);
|
||||
}
|
||||
|
||||
// initialize state of 48 -> 16 resampler
|
||||
void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state)
|
||||
{
|
||||
memset(state->S_48_48, 0, 16 * sizeof(int32_t));
|
||||
memset(state->S_48_32, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_32_16, 0, 8 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
///// 16 kHz -> 48 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 16 -> 48 resampler
|
||||
void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State16khzTo48khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 16 --> 32 /////
|
||||
// int16_t in[160]
|
||||
// int32_t out[320]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 160, tmpmem + 16, state->S_16_32);
|
||||
|
||||
///// 32 --> 24 /////
|
||||
// int32_t in[320]
|
||||
// int32_t out[240]
|
||||
// copy state to and from input array
|
||||
/////
|
||||
memcpy(tmpmem + 8, state->S_32_24, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_32_24, tmpmem + 328, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample32khzTo24khz(tmpmem + 8, tmpmem, 80);
|
||||
|
||||
///// 24 --> 48 /////
|
||||
// int32_t in[240]
|
||||
// int16_t out[480]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48);
|
||||
}
|
||||
|
||||
// initialize state of 16 -> 48 resampler
|
||||
void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state)
|
||||
{
|
||||
memset(state->S_16_32, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_32_24, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_24_48, 0, 8 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
///// 48 kHz -> 8 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 48 -> 8 resampler
|
||||
void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State48khzTo8khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 48 --> 24 /////
|
||||
// int16_t in[480]
|
||||
// int32_t out[240]
|
||||
/////
|
||||
WebRtcSpl_DownBy2ShortToInt(in, 480, tmpmem + 256, state->S_48_24);
|
||||
|
||||
///// 24 --> 24(LP) /////
|
||||
// int32_t in[240]
|
||||
// int32_t out[240]
|
||||
/////
|
||||
WebRtcSpl_LPBy2IntToInt(tmpmem + 256, 240, tmpmem + 16, state->S_24_24);
|
||||
|
||||
///// 24 --> 16 /////
|
||||
// int32_t in[240]
|
||||
// int32_t out[160]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
memcpy(tmpmem + 8, state->S_24_16, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_24_16, tmpmem + 248, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 80);
|
||||
|
||||
///// 16 --> 8 /////
|
||||
// int32_t in[160]
|
||||
// int16_t out[80]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 160, out, state->S_16_8);
|
||||
}
|
||||
|
||||
// initialize state of 48 -> 8 resampler
|
||||
void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state)
|
||||
{
|
||||
memset(state->S_48_24, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_24_24, 0, 16 * sizeof(int32_t));
|
||||
memset(state->S_24_16, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_16_8, 0, 8 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
///// 8 kHz -> 48 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 8 -> 48 resampler
|
||||
void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State8khzTo48khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 8 --> 16 /////
|
||||
// int16_t in[80]
|
||||
// int32_t out[160]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 80, tmpmem + 264, state->S_8_16);
|
||||
|
||||
///// 16 --> 12 /////
|
||||
// int32_t in[160]
|
||||
// int32_t out[120]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
memcpy(tmpmem + 256, state->S_16_12, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_16_12, tmpmem + 416, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample32khzTo24khz(tmpmem + 256, tmpmem + 240, 40);
|
||||
|
||||
///// 12 --> 24 /////
|
||||
// int32_t in[120]
|
||||
// int16_t out[240]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToInt(tmpmem + 240, 120, tmpmem, state->S_12_24);
|
||||
|
||||
///// 24 --> 48 /////
|
||||
// int32_t in[240]
|
||||
// int16_t out[480]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48);
|
||||
}
|
||||
|
||||
// initialize state of 8 -> 48 resampler
|
||||
void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state)
|
||||
{
|
||||
memset(state->S_8_16, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_16_12, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_12_24, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_24_48, 0, 8 * sizeof(int32_t));
|
||||
}
|
183
webrtc/common_audio/signal_processing/resample_by_2.c
Normal file
183
webrtc/common_audio/signal_processing/resample_by_2.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling by two functions.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15};
|
||||
static const uint32_t kResampleAllpass2[3] =
|
||||
{12199, 37471 << 15, 60255 << 15};
|
||||
|
||||
// Multiply two 32-bit values and accumulate to another input value.
|
||||
// Return: state + ((diff * tbl_value) >> 16)
|
||||
|
||||
static __inline int32_t MUL_ACCUM_1(int32_t tbl_value,
|
||||
int32_t diff,
|
||||
int32_t state) {
|
||||
int32_t result;
|
||||
__asm __volatile ("smlawb %0, %1, %2, %3": "=r"(result): "r"(diff),
|
||||
"r"(tbl_value), "r"(state));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Multiply two 32-bit values and accumulate to another input value.
|
||||
// Return: Return: state + (((diff << 1) * tbl_value) >> 32)
|
||||
//
|
||||
// The reason to introduce this function is that, in case we can't use smlawb
|
||||
// instruction (in MUL_ACCUM_1) due to input value range, we can still use
|
||||
// smmla to save some cycles.
|
||||
|
||||
static __inline int32_t MUL_ACCUM_2(int32_t tbl_value,
|
||||
int32_t diff,
|
||||
int32_t state) {
|
||||
int32_t result;
|
||||
__asm __volatile ("smmla %0, %1, %2, %3": "=r"(result): "r"(diff << 1),
|
||||
"r"(tbl_value), "r"(state));
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528};
|
||||
static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255};
|
||||
|
||||
// Multiply a 32-bit value with a 16-bit value and accumulate to another input:
|
||||
#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
|
||||
#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
|
||||
|
||||
#endif // WEBRTC_ARCH_ARM_V7
|
||||
|
||||
|
||||
// decimator
|
||||
#if !defined(MIPS32_LE)
|
||||
void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len,
|
||||
int16_t* out, int32_t* filtState) {
|
||||
int32_t tmp1, tmp2, diff, in32, out32;
|
||||
size_t i;
|
||||
|
||||
register int32_t state0 = filtState[0];
|
||||
register int32_t state1 = filtState[1];
|
||||
register int32_t state2 = filtState[2];
|
||||
register int32_t state3 = filtState[3];
|
||||
register int32_t state4 = filtState[4];
|
||||
register int32_t state5 = filtState[5];
|
||||
register int32_t state6 = filtState[6];
|
||||
register int32_t state7 = filtState[7];
|
||||
|
||||
for (i = (len >> 1); i > 0; i--) {
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// upper allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
out32 = (state3 + state7 + 1024) >> 11;
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
}
|
||||
|
||||
filtState[0] = state0;
|
||||
filtState[1] = state1;
|
||||
filtState[2] = state2;
|
||||
filtState[3] = state3;
|
||||
filtState[4] = state4;
|
||||
filtState[5] = state5;
|
||||
filtState[6] = state6;
|
||||
filtState[7] = state7;
|
||||
}
|
||||
#endif // #if defined(MIPS32_LE)
|
||||
|
||||
|
||||
void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len,
|
||||
int16_t* out, int32_t* filtState) {
|
||||
int32_t tmp1, tmp2, diff, in32, out32;
|
||||
size_t i;
|
||||
|
||||
register int32_t state0 = filtState[0];
|
||||
register int32_t state1 = filtState[1];
|
||||
register int32_t state2 = filtState[2];
|
||||
register int32_t state3 = filtState[3];
|
||||
register int32_t state4 = filtState[4];
|
||||
register int32_t state5 = filtState[5];
|
||||
register int32_t state6 = filtState[6];
|
||||
register int32_t state7 = filtState[7];
|
||||
|
||||
for (i = len; i > 0; i--) {
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// round; limit amplitude to prevent wrap-around; write to output array
|
||||
out32 = (state3 + 512) >> 10;
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
|
||||
// upper allpass filter
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// round; limit amplitude to prevent wrap-around; write to output array
|
||||
out32 = (state7 + 512) >> 10;
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
}
|
||||
|
||||
filtState[0] = state0;
|
||||
filtState[1] = state1;
|
||||
filtState[2] = state2;
|
||||
filtState[3] = state3;
|
||||
filtState[4] = state4;
|
||||
filtState[5] = state5;
|
||||
filtState[6] = state6;
|
||||
filtState[7] = state7;
|
||||
}
|
679
webrtc/common_audio/signal_processing/resample_by_2_internal.c
Normal file
679
webrtc/common_audio/signal_processing/resample_by_2_internal.c
Normal file
@ -0,0 +1,679 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file contains some internal resampling functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/resample_by_2_internal.h"
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const int16_t kResampleAllpass[2][3] = {
|
||||
{821, 6110, 12382},
|
||||
{3050, 9368, 15063}
|
||||
};
|
||||
|
||||
//
|
||||
// decimator
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384) OVERWRITTEN!
|
||||
// output: int16_t (saturated) (of length len/2)
|
||||
// state: filter state array; length = 8
|
||||
|
||||
void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter (operates on even input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
in[i << 1] = (state[3] >> 1);
|
||||
}
|
||||
|
||||
in++;
|
||||
|
||||
// upper allpass filter (operates on odd input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
in[i << 1] = (state[7] >> 1);
|
||||
}
|
||||
|
||||
in--;
|
||||
|
||||
// combine allpass outputs
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
// divide by two, add both allpass outputs and round
|
||||
tmp0 = (in[i << 1] + in[(i << 1) + 1]) >> 15;
|
||||
tmp1 = (in[(i << 1) + 2] + in[(i << 1) + 3]) >> 15;
|
||||
if (tmp0 > (int32_t)0x00007FFF)
|
||||
tmp0 = 0x00007FFF;
|
||||
if (tmp0 < (int32_t)0xFFFF8000)
|
||||
tmp0 = 0xFFFF8000;
|
||||
out[i] = (int16_t)tmp0;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
out[i + 1] = (int16_t)tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// decimator
|
||||
// input: int16_t
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len/2)
|
||||
// state: filter state array; length = 8
|
||||
|
||||
void WebRtcSpl_DownBy2ShortToInt(const int16_t *in,
|
||||
int32_t len,
|
||||
int32_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter (operates on even input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
out[i] = (state[3] >> 1);
|
||||
}
|
||||
|
||||
in++;
|
||||
|
||||
// upper allpass filter (operates on odd input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
out[i] += (state[7] >> 1);
|
||||
}
|
||||
|
||||
in--;
|
||||
}
|
||||
|
||||
//
|
||||
// interpolator
|
||||
// input: int16_t
|
||||
// output: int32_t (normalized, not saturated) (of length len*2)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len, int32_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
// upper allpass filter (generates odd output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[7] >> 15;
|
||||
}
|
||||
|
||||
out++;
|
||||
|
||||
// lower allpass filter (generates even output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3] >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// interpolator
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384)
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len*2)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
// upper allpass filter (generates odd output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[7];
|
||||
}
|
||||
|
||||
out++;
|
||||
|
||||
// lower allpass filter (generates even output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// interpolator
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384)
|
||||
// output: int16_t (saturated) (of length len*2)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len, int16_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
// upper allpass filter (generates odd output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// scale down, saturate and store
|
||||
tmp1 = state[7] >> 15;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
out[i << 1] = (int16_t)tmp1;
|
||||
}
|
||||
|
||||
out++;
|
||||
|
||||
// lower allpass filter (generates even output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, saturate and store
|
||||
tmp1 = state[3] >> 15;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
out[i << 1] = (int16_t)tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
// lowpass filter
|
||||
// input: int16_t
|
||||
// output: int32_t (normalized, not saturated)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out,
|
||||
int32_t* state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter: odd input -> even output samples
|
||||
in++;
|
||||
// initial state of polyphase delay element
|
||||
tmp0 = state[12];
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3] >> 1;
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
}
|
||||
in--;
|
||||
|
||||
// upper allpass filter: even input -> even output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15;
|
||||
}
|
||||
|
||||
// switch to odd output samples
|
||||
out++;
|
||||
|
||||
// lower allpass filter: even input -> odd output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[9];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[8] + diff * kResampleAllpass[1][0];
|
||||
state[8] = tmp0;
|
||||
diff = tmp1 - state[10];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[9] + diff * kResampleAllpass[1][1];
|
||||
state[9] = tmp1;
|
||||
diff = tmp0 - state[11];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[11] = state[10] + diff * kResampleAllpass[1][2];
|
||||
state[10] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[11] >> 1;
|
||||
}
|
||||
|
||||
// upper allpass filter: odd input -> odd output samples
|
||||
in++;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[13];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[12] + diff * kResampleAllpass[0][0];
|
||||
state[12] = tmp0;
|
||||
diff = tmp1 - state[14];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[13] + diff * kResampleAllpass[0][1];
|
||||
state[13] = tmp1;
|
||||
diff = tmp0 - state[15];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[15] = state[14] + diff * kResampleAllpass[0][2];
|
||||
state[14] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
// lowpass filter
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384)
|
||||
// output: int32_t (normalized, not saturated)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
|
||||
int32_t* state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter: odd input -> even output samples
|
||||
in++;
|
||||
// initial state of polyphase delay element
|
||||
tmp0 = state[12];
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3] >> 1;
|
||||
tmp0 = in[i << 1];
|
||||
}
|
||||
in--;
|
||||
|
||||
// upper allpass filter: even input -> even output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15;
|
||||
}
|
||||
|
||||
// switch to odd output samples
|
||||
out++;
|
||||
|
||||
// lower allpass filter: even input -> odd output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[9];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[8] + diff * kResampleAllpass[1][0];
|
||||
state[8] = tmp0;
|
||||
diff = tmp1 - state[10];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[9] + diff * kResampleAllpass[1][1];
|
||||
state[9] = tmp1;
|
||||
diff = tmp0 - state[11];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[11] = state[10] + diff * kResampleAllpass[1][2];
|
||||
state[10] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[11] >> 1;
|
||||
}
|
||||
|
||||
// upper allpass filter: odd input -> odd output samples
|
||||
in++;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[13];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[12] + diff * kResampleAllpass[0][0];
|
||||
state[12] = tmp0;
|
||||
diff = tmp1 - state[14];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[13] + diff * kResampleAllpass[0][1];
|
||||
state[13] = tmp1;
|
||||
diff = tmp0 - state[15];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[15] = state[14] + diff * kResampleAllpass[0][2];
|
||||
state[14] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file contains some internal resampling functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
|
||||
#define WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/*******************************************************************
|
||||
* resample_by_2_fast.c
|
||||
* Functions for internal use in the other resample functions
|
||||
******************************************************************/
|
||||
void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
|
||||
int32_t *state);
|
||||
|
||||
void WebRtcSpl_DownBy2ShortToInt(const int16_t *in, int32_t len,
|
||||
int32_t *out, int32_t *state);
|
||||
|
||||
void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len,
|
||||
int32_t *out, int32_t *state);
|
||||
|
||||
void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out,
|
||||
int32_t *state);
|
||||
|
||||
void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len,
|
||||
int16_t *out, int32_t *state);
|
||||
|
||||
void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len,
|
||||
int32_t* out, int32_t* state);
|
||||
|
||||
void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
|
||||
int32_t* state);
|
||||
|
||||
#endif // WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
|
290
webrtc/common_audio/signal_processing/resample_by_2_mips.c
Normal file
290
webrtc/common_audio/signal_processing/resample_by_2_mips.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling by two functions.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(MIPS32_LE)
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528};
|
||||
static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255};
|
||||
|
||||
// Multiply a 32-bit value with a 16-bit value and accumulate to another input:
|
||||
#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
|
||||
#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
|
||||
|
||||
// decimator
|
||||
void WebRtcSpl_DownsampleBy2(const int16_t* in,
|
||||
size_t len,
|
||||
int16_t* out,
|
||||
int32_t* filtState) {
|
||||
int32_t out32;
|
||||
size_t i, len1;
|
||||
|
||||
register int32_t state0 = filtState[0];
|
||||
register int32_t state1 = filtState[1];
|
||||
register int32_t state2 = filtState[2];
|
||||
register int32_t state3 = filtState[3];
|
||||
register int32_t state4 = filtState[4];
|
||||
register int32_t state5 = filtState[5];
|
||||
register int32_t state6 = filtState[6];
|
||||
register int32_t state7 = filtState[7];
|
||||
|
||||
#if defined(MIPS_DSP_R2_LE)
|
||||
int32_t k1Res0, k1Res1, k1Res2, k2Res0, k2Res1, k2Res2;
|
||||
|
||||
k1Res0= 3284;
|
||||
k1Res1= 24441;
|
||||
k1Res2= 49528;
|
||||
k2Res0= 12199;
|
||||
k2Res1= 37471;
|
||||
k2Res2= 60255;
|
||||
len1 = (len >> 1);
|
||||
|
||||
const int32_t* inw = (int32_t*)in;
|
||||
int32_t tmp11, tmp12, tmp21, tmp22;
|
||||
int32_t in322, in321;
|
||||
int32_t diff1, diff2;
|
||||
for (i = len1; i > 0; i--) {
|
||||
__asm__ volatile (
|
||||
"lh %[in321], 0(%[inw]) \n\t"
|
||||
"lh %[in322], 2(%[inw]) \n\t"
|
||||
|
||||
"sll %[in321], %[in321], 10 \n\t"
|
||||
"sll %[in322], %[in322], 10 \n\t"
|
||||
|
||||
"addiu %[inw], %[inw], 4 \n\t"
|
||||
|
||||
"subu %[diff1], %[in321], %[state1] \n\t"
|
||||
"subu %[diff2], %[in322], %[state5] \n\t"
|
||||
|
||||
: [in322] "=&r" (in322), [in321] "=&r" (in321),
|
||||
[diff1] "=&r" (diff1), [diff2] "=r" (diff2), [inw] "+r" (inw)
|
||||
: [state1] "r" (state1), [state5] "r" (state5)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
__asm__ volatile (
|
||||
"mult $ac0, %[diff1], %[k2Res0] \n\t"
|
||||
"mult $ac1, %[diff2], %[k1Res0] \n\t"
|
||||
|
||||
"extr.w %[tmp11], $ac0, 16 \n\t"
|
||||
"extr.w %[tmp12], $ac1, 16 \n\t"
|
||||
|
||||
"addu %[tmp11], %[state0], %[tmp11] \n\t"
|
||||
"addu %[tmp12], %[state4], %[tmp12] \n\t"
|
||||
|
||||
"addiu %[state0], %[in321], 0 \n\t"
|
||||
"addiu %[state4], %[in322], 0 \n\t"
|
||||
|
||||
"subu %[diff1], %[tmp11], %[state2] \n\t"
|
||||
"subu %[diff2], %[tmp12], %[state6] \n\t"
|
||||
|
||||
"mult $ac0, %[diff1], %[k2Res1] \n\t"
|
||||
"mult $ac1, %[diff2], %[k1Res1] \n\t"
|
||||
|
||||
"extr.w %[tmp21], $ac0, 16 \n\t"
|
||||
"extr.w %[tmp22], $ac1, 16 \n\t"
|
||||
|
||||
"addu %[tmp21], %[state1], %[tmp21] \n\t"
|
||||
"addu %[tmp22], %[state5], %[tmp22] \n\t"
|
||||
|
||||
"addiu %[state1], %[tmp11], 0 \n\t"
|
||||
"addiu %[state5], %[tmp12], 0 \n\t"
|
||||
: [tmp22] "=r" (tmp22), [tmp21] "=&r" (tmp21),
|
||||
[tmp11] "=&r" (tmp11), [state0] "+r" (state0),
|
||||
[state1] "+r" (state1),
|
||||
[state2] "+r" (state2),
|
||||
[state4] "+r" (state4), [tmp12] "=&r" (tmp12),
|
||||
[state6] "+r" (state6), [state5] "+r" (state5)
|
||||
: [k1Res1] "r" (k1Res1), [k2Res1] "r" (k2Res1), [k2Res0] "r" (k2Res0),
|
||||
[diff2] "r" (diff2), [diff1] "r" (diff1), [in322] "r" (in322),
|
||||
[in321] "r" (in321), [k1Res0] "r" (k1Res0)
|
||||
: "hi", "lo", "$ac1hi", "$ac1lo"
|
||||
);
|
||||
|
||||
// upper allpass filter
|
||||
__asm__ volatile (
|
||||
"subu %[diff1], %[tmp21], %[state3] \n\t"
|
||||
"subu %[diff2], %[tmp22], %[state7] \n\t"
|
||||
|
||||
"mult $ac0, %[diff1], %[k2Res2] \n\t"
|
||||
"mult $ac1, %[diff2], %[k1Res2] \n\t"
|
||||
"extr.w %[state3], $ac0, 16 \n\t"
|
||||
"extr.w %[state7], $ac1, 16 \n\t"
|
||||
"addu %[state3], %[state2], %[state3] \n\t"
|
||||
"addu %[state7], %[state6], %[state7] \n\t"
|
||||
|
||||
"addiu %[state2], %[tmp21], 0 \n\t"
|
||||
"addiu %[state6], %[tmp22], 0 \n\t"
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
"addu %[out32], %[state3], %[state7] \n\t"
|
||||
"addiu %[out32], %[out32], 1024 \n\t"
|
||||
"sra %[out32], %[out32], 11 \n\t"
|
||||
: [state3] "+r" (state3), [state6] "+r" (state6),
|
||||
[state2] "+r" (state2), [diff2] "=&r" (diff2),
|
||||
[out32] "=r" (out32), [diff1] "=&r" (diff1), [state7] "+r" (state7)
|
||||
: [tmp22] "r" (tmp22), [tmp21] "r" (tmp21),
|
||||
[k1Res2] "r" (k1Res2), [k2Res2] "r" (k2Res2)
|
||||
: "hi", "lo", "$ac1hi", "$ac1lo"
|
||||
);
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
}
|
||||
#else // #if defined(MIPS_DSP_R2_LE)
|
||||
int32_t tmp1, tmp2, diff;
|
||||
int32_t in32;
|
||||
len1 = (len >> 1)/4;
|
||||
for (i = len1; i > 0; i--) {
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// upper allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
out32 = (state3 + state7 + 1024) >> 11;
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// upper allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
out32 = (state3 + state7 + 1024) >> 11;
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// upper allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
out32 = (state3 + state7 + 1024) >> 11;
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// upper allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
out32 = (state3 + state7 + 1024) >> 11;
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
}
|
||||
#endif // #if defined(MIPS_DSP_R2_LE)
|
||||
__asm__ volatile (
|
||||
"sw %[state0], 0(%[filtState]) \n\t"
|
||||
"sw %[state1], 4(%[filtState]) \n\t"
|
||||
"sw %[state2], 8(%[filtState]) \n\t"
|
||||
"sw %[state3], 12(%[filtState]) \n\t"
|
||||
"sw %[state4], 16(%[filtState]) \n\t"
|
||||
"sw %[state5], 20(%[filtState]) \n\t"
|
||||
"sw %[state6], 24(%[filtState]) \n\t"
|
||||
"sw %[state7], 28(%[filtState]) \n\t"
|
||||
:
|
||||
: [state0] "r" (state0), [state1] "r" (state1), [state2] "r" (state2),
|
||||
[state3] "r" (state3), [state4] "r" (state4), [state5] "r" (state5),
|
||||
[state6] "r" (state6), [state7] "r" (state7), [filtState] "r" (filtState)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif // #if defined(MIPS32_LE)
|
239
webrtc/common_audio/signal_processing/resample_fractional.c
Normal file
239
webrtc/common_audio/signal_processing/resample_fractional.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling functions between 48, 44, 32 and 24 kHz.
|
||||
* The description headers can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// interpolation coefficients
|
||||
static const int16_t kCoefficients48To32[2][8] = {
|
||||
{778, -2050, 1087, 23285, 12903, -3783, 441, 222},
|
||||
{222, 441, -3783, 12903, 23285, 1087, -2050, 778}
|
||||
};
|
||||
|
||||
static const int16_t kCoefficients32To24[3][8] = {
|
||||
{767, -2362, 2434, 24406, 10620, -3838, 721, 90},
|
||||
{386, -381, -2646, 19062, 19062, -2646, -381, 386},
|
||||
{90, 721, -3838, 10620, 24406, 2434, -2362, 767}
|
||||
};
|
||||
|
||||
static const int16_t kCoefficients44To32[4][9] = {
|
||||
{117, -669, 2245, -6183, 26267, 13529, -3245, 845, -138},
|
||||
{-101, 612, -2283, 8532, 29790, -5138, 1789, -524, 91},
|
||||
{50, -292, 1016, -3064, 32010, 3933, -1147, 315, -53},
|
||||
{-156, 974, -3863, 18603, 21691, -6246, 2353, -712, 126}
|
||||
};
|
||||
|
||||
// Resampling ratio: 2/3
|
||||
// input: int32_t (normalized, not saturated) :: size 3 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 2 * K
|
||||
// K: number of blocks
|
||||
|
||||
void WebRtcSpl_Resample48khzTo32khz(const int32_t *In, int32_t *Out, size_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (3 input samples -> 2 output samples);
|
||||
// process in sub blocks of size 3 samples.
|
||||
int32_t tmp;
|
||||
size_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients48To32[0][0] * In[0];
|
||||
tmp += kCoefficients48To32[0][1] * In[1];
|
||||
tmp += kCoefficients48To32[0][2] * In[2];
|
||||
tmp += kCoefficients48To32[0][3] * In[3];
|
||||
tmp += kCoefficients48To32[0][4] * In[4];
|
||||
tmp += kCoefficients48To32[0][5] * In[5];
|
||||
tmp += kCoefficients48To32[0][6] * In[6];
|
||||
tmp += kCoefficients48To32[0][7] * In[7];
|
||||
Out[0] = tmp;
|
||||
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients48To32[1][0] * In[1];
|
||||
tmp += kCoefficients48To32[1][1] * In[2];
|
||||
tmp += kCoefficients48To32[1][2] * In[3];
|
||||
tmp += kCoefficients48To32[1][3] * In[4];
|
||||
tmp += kCoefficients48To32[1][4] * In[5];
|
||||
tmp += kCoefficients48To32[1][5] * In[6];
|
||||
tmp += kCoefficients48To32[1][6] * In[7];
|
||||
tmp += kCoefficients48To32[1][7] * In[8];
|
||||
Out[1] = tmp;
|
||||
|
||||
// update pointers
|
||||
In += 3;
|
||||
Out += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Resampling ratio: 3/4
|
||||
// input: int32_t (normalized, not saturated) :: size 4 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 3 * K
|
||||
// K: number of blocks
|
||||
|
||||
void WebRtcSpl_Resample32khzTo24khz(const int32_t *In, int32_t *Out, size_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (4 input samples -> 3 output samples);
|
||||
// process in sub blocks of size 4 samples.
|
||||
size_t m;
|
||||
int32_t tmp;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients32To24[0][0] * In[0];
|
||||
tmp += kCoefficients32To24[0][1] * In[1];
|
||||
tmp += kCoefficients32To24[0][2] * In[2];
|
||||
tmp += kCoefficients32To24[0][3] * In[3];
|
||||
tmp += kCoefficients32To24[0][4] * In[4];
|
||||
tmp += kCoefficients32To24[0][5] * In[5];
|
||||
tmp += kCoefficients32To24[0][6] * In[6];
|
||||
tmp += kCoefficients32To24[0][7] * In[7];
|
||||
Out[0] = tmp;
|
||||
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients32To24[1][0] * In[1];
|
||||
tmp += kCoefficients32To24[1][1] * In[2];
|
||||
tmp += kCoefficients32To24[1][2] * In[3];
|
||||
tmp += kCoefficients32To24[1][3] * In[4];
|
||||
tmp += kCoefficients32To24[1][4] * In[5];
|
||||
tmp += kCoefficients32To24[1][5] * In[6];
|
||||
tmp += kCoefficients32To24[1][6] * In[7];
|
||||
tmp += kCoefficients32To24[1][7] * In[8];
|
||||
Out[1] = tmp;
|
||||
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients32To24[2][0] * In[2];
|
||||
tmp += kCoefficients32To24[2][1] * In[3];
|
||||
tmp += kCoefficients32To24[2][2] * In[4];
|
||||
tmp += kCoefficients32To24[2][3] * In[5];
|
||||
tmp += kCoefficients32To24[2][4] * In[6];
|
||||
tmp += kCoefficients32To24[2][5] * In[7];
|
||||
tmp += kCoefficients32To24[2][6] * In[8];
|
||||
tmp += kCoefficients32To24[2][7] * In[9];
|
||||
Out[2] = tmp;
|
||||
|
||||
// update pointers
|
||||
In += 4;
|
||||
Out += 3;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fractional resampling filters
|
||||
// Fout = 11/16 * Fin
|
||||
// Fout = 8/11 * Fin
|
||||
//
|
||||
|
||||
// compute two inner-products and store them to output array
|
||||
static void WebRtcSpl_ResampDotProduct(const int32_t *in1, const int32_t *in2,
|
||||
const int16_t *coef_ptr, int32_t *out1,
|
||||
int32_t *out2)
|
||||
{
|
||||
int32_t tmp1 = 16384;
|
||||
int32_t tmp2 = 16384;
|
||||
int16_t coef;
|
||||
|
||||
coef = coef_ptr[0];
|
||||
tmp1 += coef * in1[0];
|
||||
tmp2 += coef * in2[-0];
|
||||
|
||||
coef = coef_ptr[1];
|
||||
tmp1 += coef * in1[1];
|
||||
tmp2 += coef * in2[-1];
|
||||
|
||||
coef = coef_ptr[2];
|
||||
tmp1 += coef * in1[2];
|
||||
tmp2 += coef * in2[-2];
|
||||
|
||||
coef = coef_ptr[3];
|
||||
tmp1 += coef * in1[3];
|
||||
tmp2 += coef * in2[-3];
|
||||
|
||||
coef = coef_ptr[4];
|
||||
tmp1 += coef * in1[4];
|
||||
tmp2 += coef * in2[-4];
|
||||
|
||||
coef = coef_ptr[5];
|
||||
tmp1 += coef * in1[5];
|
||||
tmp2 += coef * in2[-5];
|
||||
|
||||
coef = coef_ptr[6];
|
||||
tmp1 += coef * in1[6];
|
||||
tmp2 += coef * in2[-6];
|
||||
|
||||
coef = coef_ptr[7];
|
||||
tmp1 += coef * in1[7];
|
||||
tmp2 += coef * in2[-7];
|
||||
|
||||
coef = coef_ptr[8];
|
||||
*out1 = tmp1 + coef * in1[8];
|
||||
*out2 = tmp2 + coef * in2[-8];
|
||||
}
|
||||
|
||||
// Resampling ratio: 8/11
|
||||
// input: int32_t (normalized, not saturated) :: size 11 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 8 * K
|
||||
// K: number of blocks
|
||||
|
||||
void WebRtcSpl_Resample44khzTo32khz(const int32_t *In, int32_t *Out, size_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (11 input samples -> 8 output samples);
|
||||
// process in sub blocks of size 11 samples.
|
||||
int32_t tmp;
|
||||
size_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
tmp = 1 << 14;
|
||||
|
||||
// first output sample
|
||||
Out[0] = ((int32_t)In[3] << 15) + tmp;
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
tmp += kCoefficients44To32[3][0] * In[5];
|
||||
tmp += kCoefficients44To32[3][1] * In[6];
|
||||
tmp += kCoefficients44To32[3][2] * In[7];
|
||||
tmp += kCoefficients44To32[3][3] * In[8];
|
||||
tmp += kCoefficients44To32[3][4] * In[9];
|
||||
tmp += kCoefficients44To32[3][5] * In[10];
|
||||
tmp += kCoefficients44To32[3][6] * In[11];
|
||||
tmp += kCoefficients44To32[3][7] * In[12];
|
||||
tmp += kCoefficients44To32[3][8] * In[13];
|
||||
Out[4] = tmp;
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_ResampDotProduct(&In[0], &In[17], kCoefficients44To32[0], &Out[1], &Out[7]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_ResampDotProduct(&In[2], &In[15], kCoefficients44To32[1], &Out[2], &Out[6]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_ResampDotProduct(&In[3], &In[14], kCoefficients44To32[2], &Out[3], &Out[5]);
|
||||
|
||||
// update pointers
|
||||
In += 11;
|
||||
Out += 8;
|
||||
}
|
||||
}
|
140
webrtc/common_audio/signal_processing/spl_init.c
Normal file
140
webrtc/common_audio/signal_processing/spl_init.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* The global function contained in this file initializes SPL function
|
||||
* pointers, currently only for ARM platforms.
|
||||
*
|
||||
* Some code came from common/rtcd.c in the WebM project.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
|
||||
|
||||
/* Declare function pointers. */
|
||||
MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
|
||||
MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
|
||||
MaxValueW16 WebRtcSpl_MaxValueW16;
|
||||
MaxValueW32 WebRtcSpl_MaxValueW32;
|
||||
MinValueW16 WebRtcSpl_MinValueW16;
|
||||
MinValueW32 WebRtcSpl_MinValueW32;
|
||||
CrossCorrelation WebRtcSpl_CrossCorrelation;
|
||||
DownsampleFast WebRtcSpl_DownsampleFast;
|
||||
ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
|
||||
|
||||
#if (defined(WEBRTC_DETECT_NEON) || !defined(WEBRTC_HAS_NEON)) && \
|
||||
!defined(MIPS32_LE)
|
||||
/* Initialize function pointers to the generic C version. */
|
||||
static void InitPointersToC() {
|
||||
WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C;
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
|
||||
WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C;
|
||||
WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C;
|
||||
WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C;
|
||||
WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C;
|
||||
WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC;
|
||||
WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRoundC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
|
||||
/* Initialize function pointers to the Neon version. */
|
||||
static void InitPointersToNeon() {
|
||||
WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon;
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon;
|
||||
WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon;
|
||||
WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon;
|
||||
WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon;
|
||||
WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon;
|
||||
WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationNeon;
|
||||
WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRoundC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MIPS32_LE)
|
||||
/* Initialize function pointers to the MIPS version. */
|
||||
static void InitPointersToMIPS() {
|
||||
WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips;
|
||||
WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips;
|
||||
WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips;
|
||||
WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips;
|
||||
WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips;
|
||||
WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelation_mips;
|
||||
WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips;
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32_mips;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound_mips;
|
||||
#else
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRoundC;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void InitFunctionPointers(void) {
|
||||
#if defined(WEBRTC_DETECT_NEON)
|
||||
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
|
||||
InitPointersToNeon();
|
||||
} else {
|
||||
InitPointersToC();
|
||||
}
|
||||
#elif defined(WEBRTC_HAS_NEON)
|
||||
InitPointersToNeon();
|
||||
#elif defined(MIPS32_LE)
|
||||
InitPointersToMIPS();
|
||||
#else
|
||||
InitPointersToC();
|
||||
#endif /* WEBRTC_DETECT_NEON */
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#include <pthread.h>
|
||||
|
||||
static void once(void (*func)(void)) {
|
||||
static pthread_once_t lock = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&lock, func);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
static void once(void (*func)(void)) {
|
||||
/* Didn't use InitializeCriticalSection() since there's no race-free context
|
||||
* in which to execute it.
|
||||
*
|
||||
* TODO(kma): Change to different implementation (e.g.
|
||||
* InterlockedCompareExchangePointer) to avoid issues similar to
|
||||
* http://code.google.com/p/webm/issues/detail?id=467.
|
||||
*/
|
||||
static CRITICAL_SECTION lock = {(void *)((size_t)-1), -1, 0, 0, 0, 0};
|
||||
static int done = 0;
|
||||
|
||||
EnterCriticalSection(&lock);
|
||||
if (!done) {
|
||||
func();
|
||||
done = 1;
|
||||
}
|
||||
LeaveCriticalSection(&lock);
|
||||
}
|
||||
|
||||
/* There's no fallback version as an #else block here to ensure thread safety.
|
||||
* In case of neither pthread for WEBRTC_POSIX nor _WIN32 is present, build
|
||||
* system should pick it up.
|
||||
*/
|
||||
#endif /* WEBRTC_POSIX */
|
||||
|
||||
void WebRtcSpl_Init() {
|
||||
once(InitFunctionPointers);
|
||||
}
|
184
webrtc/common_audio/signal_processing/spl_sqrt.c
Normal file
184
webrtc/common_audio/signal_processing/spl_sqrt.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_Sqrt().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
int32_t WebRtcSpl_SqrtLocal(int32_t in);
|
||||
|
||||
int32_t WebRtcSpl_SqrtLocal(int32_t in)
|
||||
{
|
||||
|
||||
int16_t x_half, t16;
|
||||
int32_t A, B, x2;
|
||||
|
||||
/* The following block performs:
|
||||
y=in/2
|
||||
x=y-2^30
|
||||
x_half=x/2^31
|
||||
t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4)
|
||||
+ 0.875*((x_half)^5)
|
||||
*/
|
||||
|
||||
B = in / 2;
|
||||
|
||||
B = B - ((int32_t)0x40000000); // B = in/2 - 1/2
|
||||
x_half = (int16_t)(B >> 16); // x_half = x/2 = (in-1)/2
|
||||
B = B + ((int32_t)0x40000000); // B = 1 + x/2
|
||||
B = B + ((int32_t)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31)
|
||||
|
||||
x2 = ((int32_t)x_half) * ((int32_t)x_half) * 2; // A = (x/2)^2
|
||||
A = -x2; // A = -(x/2)^2
|
||||
B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2
|
||||
|
||||
A >>= 16;
|
||||
A = A * A * 2; // A = (x/2)^4
|
||||
t16 = (int16_t)(A >> 16);
|
||||
B += -20480 * t16 * 2; // B = B - 0.625*A
|
||||
// After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4
|
||||
|
||||
A = x_half * t16 * 2; // A = (x/2)^5
|
||||
t16 = (int16_t)(A >> 16);
|
||||
B += 28672 * t16 * 2; // B = B + 0.875*A
|
||||
// After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5
|
||||
|
||||
t16 = (int16_t)(x2 >> 16);
|
||||
A = x_half * t16 * 2; // A = x/2^3
|
||||
|
||||
B = B + (A >> 1); // B = B + 0.5*A
|
||||
// After this, B = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 - 0.625*(x/2)^4 + 0.875*(x/2)^5
|
||||
|
||||
B = B + ((int32_t)32768); // Round off bit
|
||||
|
||||
return B;
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_Sqrt(int32_t value)
|
||||
{
|
||||
/*
|
||||
Algorithm:
|
||||
|
||||
Six term Taylor Series is used here to compute the square root of a number
|
||||
y^0.5 = (1+x)^0.5 where x = y-1
|
||||
= 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5)
|
||||
0.5 <= x < 1
|
||||
|
||||
Example of how the algorithm works, with ut=sqrt(in), and
|
||||
with in=73632 and ut=271 (even shift value case):
|
||||
|
||||
in=73632
|
||||
y= in/131072
|
||||
x=y-1
|
||||
t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5)
|
||||
ut=t*(1/sqrt(2))*512
|
||||
|
||||
or:
|
||||
|
||||
in=73632
|
||||
in2=73632*2^14
|
||||
y= in2/2^31
|
||||
x=y-1
|
||||
t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5)
|
||||
ut=t*(1/sqrt(2))
|
||||
ut2=ut*2^9
|
||||
|
||||
which gives:
|
||||
|
||||
in = 73632
|
||||
in2 = 1206386688
|
||||
y = 0.56176757812500
|
||||
x = -0.43823242187500
|
||||
t = 0.74973506527313
|
||||
ut = 0.53014274874797
|
||||
ut2 = 2.714330873589594e+002
|
||||
|
||||
or:
|
||||
|
||||
in=73632
|
||||
in2=73632*2^14
|
||||
y=in2/2
|
||||
x=y-2^30
|
||||
x_half=x/2^31
|
||||
t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4)
|
||||
+ 0.875*((x_half)^5)
|
||||
ut=t*(1/sqrt(2))
|
||||
ut2=ut*2^9
|
||||
|
||||
which gives:
|
||||
|
||||
in = 73632
|
||||
in2 = 1206386688
|
||||
y = 603193344
|
||||
x = -470548480
|
||||
x_half = -0.21911621093750
|
||||
t = 0.74973506527313
|
||||
ut = 0.53014274874797
|
||||
ut2 = 2.714330873589594e+002
|
||||
|
||||
*/
|
||||
|
||||
int16_t x_norm, nshift, t16, sh;
|
||||
int32_t A;
|
||||
|
||||
int16_t k_sqrt_2 = 23170; // 1/sqrt2 (==5a82)
|
||||
|
||||
A = value;
|
||||
|
||||
if (A == 0)
|
||||
return (int32_t)0; // sqrt(0) = 0
|
||||
|
||||
sh = WebRtcSpl_NormW32(A); // # shifts to normalize A
|
||||
A = WEBRTC_SPL_LSHIFT_W32(A, sh); // Normalize A
|
||||
if (A < (WEBRTC_SPL_WORD32_MAX - 32767))
|
||||
{
|
||||
A = A + ((int32_t)32768); // Round off bit
|
||||
} else
|
||||
{
|
||||
A = WEBRTC_SPL_WORD32_MAX;
|
||||
}
|
||||
|
||||
x_norm = (int16_t)(A >> 16); // x_norm = AH
|
||||
|
||||
nshift = (sh / 2);
|
||||
assert(nshift >= 0);
|
||||
|
||||
A = (int32_t)WEBRTC_SPL_LSHIFT_W32((int32_t)x_norm, 16);
|
||||
A = WEBRTC_SPL_ABS_W32(A); // A = abs(x_norm<<16)
|
||||
A = WebRtcSpl_SqrtLocal(A); // A = sqrt(A)
|
||||
|
||||
if (2 * nshift == sh) {
|
||||
// Even shift value case
|
||||
|
||||
t16 = (int16_t)(A >> 16); // t16 = AH
|
||||
|
||||
A = k_sqrt_2 * t16 * 2; // A = 1/sqrt(2)*t16
|
||||
A = A + ((int32_t)32768); // Round off
|
||||
A = A & ((int32_t)0x7fff0000); // Round off
|
||||
|
||||
A >>= 15; // A = A>>16
|
||||
|
||||
} else
|
||||
{
|
||||
A >>= 16; // A = A>>16
|
||||
}
|
||||
|
||||
A = A & ((int32_t)0x0000ffff);
|
||||
A >>= nshift; // De-normalize the result.
|
||||
|
||||
return A;
|
||||
}
|
77
webrtc/common_audio/signal_processing/spl_sqrt_floor.c
Normal file
77
webrtc/common_audio/signal_processing/spl_sqrt_floor.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Written by Wilco Dijkstra, 1996. The following email exchange establishes the
|
||||
* license.
|
||||
*
|
||||
* From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com>
|
||||
* Date: Fri, Jun 24, 2011 at 3:20 AM
|
||||
* Subject: Re: sqrt routine
|
||||
* To: Kevin Ma <kma@google.com>
|
||||
* Hi Kevin,
|
||||
* Thanks for asking. Those routines are public domain (originally posted to
|
||||
* comp.sys.arm a long time ago), so you can use them freely for any purpose.
|
||||
* Cheers,
|
||||
* Wilco
|
||||
*
|
||||
* ----- Original Message -----
|
||||
* From: "Kevin Ma" <kma@google.com>
|
||||
* To: <Wilco.Dijkstra@ntlworld.com>
|
||||
* Sent: Thursday, June 23, 2011 11:44 PM
|
||||
* Subject: Fwd: sqrt routine
|
||||
* Hi Wilco,
|
||||
* I saw your sqrt routine from several web sites, including
|
||||
* http://www.finesse.demon.co.uk/steven/sqrt.html.
|
||||
* Just wonder if there's any copyright information with your Successive
|
||||
* approximation routines, or if I can freely use it for any purpose.
|
||||
* Thanks.
|
||||
* Kevin
|
||||
*/
|
||||
|
||||
// Minor modifications in code style for WebRTC, 2012.
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
/*
|
||||
* Algorithm:
|
||||
* Successive approximation of the equation (root + delta) ^ 2 = N
|
||||
* until delta < 1. If delta < 1 we have the integer part of SQRT (N).
|
||||
* Use delta = 2^i for i = 15 .. 0.
|
||||
*
|
||||
* Output precision is 16 bits. Note for large input values (close to
|
||||
* 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word)
|
||||
* contains the MSB information (a non-sign value). Do with caution
|
||||
* if you need to cast the output to int16_t type.
|
||||
*
|
||||
* If the input value is negative, it returns 0.
|
||||
*/
|
||||
|
||||
#define WEBRTC_SPL_SQRT_ITER(N) \
|
||||
try1 = root + (1 << (N)); \
|
||||
if (value >= try1 << (N)) \
|
||||
{ \
|
||||
value -= try1 << (N); \
|
||||
root |= 2 << (N); \
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_SqrtFloor(int32_t value)
|
||||
{
|
||||
int32_t root = 0, try1;
|
||||
|
||||
WEBRTC_SPL_SQRT_ITER (15);
|
||||
WEBRTC_SPL_SQRT_ITER (14);
|
||||
WEBRTC_SPL_SQRT_ITER (13);
|
||||
WEBRTC_SPL_SQRT_ITER (12);
|
||||
WEBRTC_SPL_SQRT_ITER (11);
|
||||
WEBRTC_SPL_SQRT_ITER (10);
|
||||
WEBRTC_SPL_SQRT_ITER ( 9);
|
||||
WEBRTC_SPL_SQRT_ITER ( 8);
|
||||
WEBRTC_SPL_SQRT_ITER ( 7);
|
||||
WEBRTC_SPL_SQRT_ITER ( 6);
|
||||
WEBRTC_SPL_SQRT_ITER ( 5);
|
||||
WEBRTC_SPL_SQRT_ITER ( 4);
|
||||
WEBRTC_SPL_SQRT_ITER ( 3);
|
||||
WEBRTC_SPL_SQRT_ITER ( 2);
|
||||
WEBRTC_SPL_SQRT_ITER ( 1);
|
||||
WEBRTC_SPL_SQRT_ITER ( 0);
|
||||
|
||||
return root >> 1;
|
||||
}
|
110
webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
Normal file
110
webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
Normal file
@ -0,0 +1,110 @@
|
||||
@
|
||||
@ Written by Wilco Dijkstra, 1996. The following email exchange establishes the
|
||||
@ license.
|
||||
@
|
||||
@ From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com>
|
||||
@ Date: Fri, Jun 24, 2011 at 3:20 AM
|
||||
@ Subject: Re: sqrt routine
|
||||
@ To: Kevin Ma <kma@google.com>
|
||||
@ Hi Kevin,
|
||||
@ Thanks for asking. Those routines are public domain (originally posted to
|
||||
@ comp.sys.arm a long time ago), so you can use them freely for any purpose.
|
||||
@ Cheers,
|
||||
@ Wilco
|
||||
@
|
||||
@ ----- Original Message -----
|
||||
@ From: "Kevin Ma" <kma@google.com>
|
||||
@ To: <Wilco.Dijkstra@ntlworld.com>
|
||||
@ Sent: Thursday, June 23, 2011 11:44 PM
|
||||
@ Subject: Fwd: sqrt routine
|
||||
@ Hi Wilco,
|
||||
@ I saw your sqrt routine from several web sites, including
|
||||
@ http://www.finesse.demon.co.uk/steven/sqrt.html.
|
||||
@ Just wonder if there's any copyright information with your Successive
|
||||
@ approximation routines, or if I can freely use it for any purpose.
|
||||
@ Thanks.
|
||||
@ Kevin
|
||||
|
||||
@ Minor modifications in code style for WebRTC, 2012.
|
||||
@ Output is bit-exact with the reference C code in spl_sqrt_floor.c.
|
||||
|
||||
@ Input : r0 32 bit unsigned integer
|
||||
@ Output: r0 = INT (SQRT (r0)), precision is 16 bits
|
||||
@ Registers touched: r1, r2
|
||||
|
||||
#include "webrtc/system_wrappers/interface/asm_defines.h"
|
||||
|
||||
GLOBAL_FUNCTION WebRtcSpl_SqrtFloor
|
||||
.align 2
|
||||
DEFINE_FUNCTION WebRtcSpl_SqrtFloor
|
||||
mov r1, #3 << 30
|
||||
mov r2, #1 << 30
|
||||
|
||||
@ unroll for i = 0 .. 15
|
||||
|
||||
cmp r0, r2, ror #2 * 0
|
||||
subhs r0, r0, r2, ror #2 * 0
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 1
|
||||
subhs r0, r0, r2, ror #2 * 1
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 2
|
||||
subhs r0, r0, r2, ror #2 * 2
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 3
|
||||
subhs r0, r0, r2, ror #2 * 3
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 4
|
||||
subhs r0, r0, r2, ror #2 * 4
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 5
|
||||
subhs r0, r0, r2, ror #2 * 5
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 6
|
||||
subhs r0, r0, r2, ror #2 * 6
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 7
|
||||
subhs r0, r0, r2, ror #2 * 7
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 8
|
||||
subhs r0, r0, r2, ror #2 * 8
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 9
|
||||
subhs r0, r0, r2, ror #2 * 9
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 10
|
||||
subhs r0, r0, r2, ror #2 * 10
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 11
|
||||
subhs r0, r0, r2, ror #2 * 11
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 12
|
||||
subhs r0, r0, r2, ror #2 * 12
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 13
|
||||
subhs r0, r0, r2, ror #2 * 13
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 14
|
||||
subhs r0, r0, r2, ror #2 * 14
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
cmp r0, r2, ror #2 * 15
|
||||
subhs r0, r0, r2, ror #2 * 15
|
||||
adc r2, r1, r2, lsl #1
|
||||
|
||||
bic r0, r2, #3 << 30 @ for rounding add: cmp r0, r2 adc r2, #1
|
||||
bx lr
|
207
webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c
Normal file
207
webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Written by Wilco Dijkstra, 1996. The following email exchange establishes the
|
||||
* license.
|
||||
*
|
||||
* From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com>
|
||||
* Date: Fri, Jun 24, 2011 at 3:20 AM
|
||||
* Subject: Re: sqrt routine
|
||||
* To: Kevin Ma <kma@google.com>
|
||||
* Hi Kevin,
|
||||
* Thanks for asking. Those routines are public domain (originally posted to
|
||||
* comp.sys.arm a long time ago), so you can use them freely for any purpose.
|
||||
* Cheers,
|
||||
* Wilco
|
||||
*
|
||||
* ----- Original Message -----
|
||||
* From: "Kevin Ma" <kma@google.com>
|
||||
* To: <Wilco.Dijkstra@ntlworld.com>
|
||||
* Sent: Thursday, June 23, 2011 11:44 PM
|
||||
* Subject: Fwd: sqrt routine
|
||||
* Hi Wilco,
|
||||
* I saw your sqrt routine from several web sites, including
|
||||
* http://www.finesse.demon.co.uk/steven/sqrt.html.
|
||||
* Just wonder if there's any copyright information with your Successive
|
||||
* approximation routines, or if I can freely use it for any purpose.
|
||||
* Thanks.
|
||||
* Kevin
|
||||
*/
|
||||
|
||||
// Minor modifications in code style for WebRTC, 2012.
|
||||
// Code optimizations for MIPS, 2013.
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
/*
|
||||
* Algorithm:
|
||||
* Successive approximation of the equation (root + delta) ^ 2 = N
|
||||
* until delta < 1. If delta < 1 we have the integer part of SQRT (N).
|
||||
* Use delta = 2^i for i = 15 .. 0.
|
||||
*
|
||||
* Output precision is 16 bits. Note for large input values (close to
|
||||
* 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word)
|
||||
* contains the MSB information (a non-sign value). Do with caution
|
||||
* if you need to cast the output to int16_t type.
|
||||
*
|
||||
* If the input value is negative, it returns 0.
|
||||
*/
|
||||
|
||||
|
||||
int32_t WebRtcSpl_SqrtFloor(int32_t value)
|
||||
{
|
||||
int32_t root = 0, tmp1, tmp2, tmp3, tmp4;
|
||||
|
||||
__asm __volatile(
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
|
||||
"lui %[tmp1], 0x4000 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"sub %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"lui %[tmp1], 0x1 \n\t"
|
||||
"or %[tmp4], %[root], %[tmp1] \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x4000 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 14 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x8000 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x2000 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 13 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x4000 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x1000 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 12 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x2000 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x800 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 11 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x1000 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x400 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 10 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x800 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x200 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 9 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x400 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x100 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 8 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x200 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x80 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 7 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x100 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x40 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 6 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x80 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x20 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 5 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x40 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x10 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 4 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x20 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x8 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 3 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x10 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x4 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 2 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x8 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x2 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"sll %[tmp1], 1 \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"subu %[tmp3], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x4 \n\t"
|
||||
"movz %[value], %[tmp3], %[tmp2] \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
"addiu %[tmp1], $0, 0x1 \n\t"
|
||||
"addu %[tmp1], %[tmp1], %[root] \n\t"
|
||||
"slt %[tmp2], %[value], %[tmp1] \n\t"
|
||||
"ori %[tmp4], %[root], 0x2 \n\t"
|
||||
"movz %[root], %[tmp4], %[tmp2] \n\t"
|
||||
|
||||
".set pop \n\t"
|
||||
|
||||
: [root] "+r" (root), [value] "+r" (value),
|
||||
[tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2),
|
||||
[tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4)
|
||||
:
|
||||
);
|
||||
|
||||
return root >> 1;
|
||||
}
|
||||
|
208
webrtc/common_audio/signal_processing/splitting_filter.c
Normal file
208
webrtc/common_audio/signal_processing/splitting_filter.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the splitting filter functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// Maximum number of samples in a low/high-band frame.
|
||||
enum
|
||||
{
|
||||
kMaxBandFrameLength = 320 // 10 ms at 64 kHz.
|
||||
};
|
||||
|
||||
// QMF filter coefficients in Q16.
|
||||
static const uint16_t WebRtcSpl_kAllPassFilter1[3] = {6418, 36982, 57261};
|
||||
static const uint16_t WebRtcSpl_kAllPassFilter2[3] = {21333, 49062, 63010};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcSpl_AllPassQMF(...)
|
||||
//
|
||||
// Allpass filter used by the analysis and synthesis parts of the QMF filter.
|
||||
//
|
||||
// Input:
|
||||
// - in_data : Input data sequence (Q10)
|
||||
// - data_length : Length of data sequence (>2)
|
||||
// - filter_coefficients : Filter coefficients (length 3, Q16)
|
||||
//
|
||||
// Input & Output:
|
||||
// - filter_state : Filter state (length 6, Q10).
|
||||
//
|
||||
// Output:
|
||||
// - out_data : Output data sequence (Q10), length equal to
|
||||
// |data_length|
|
||||
//
|
||||
|
||||
void WebRtcSpl_AllPassQMF(int32_t* in_data, size_t data_length,
|
||||
int32_t* out_data, const uint16_t* filter_coefficients,
|
||||
int32_t* filter_state)
|
||||
{
|
||||
// The procedure is to filter the input with three first order all pass filters
|
||||
// (cascade operations).
|
||||
//
|
||||
// a_3 + q^-1 a_2 + q^-1 a_1 + q^-1
|
||||
// y[n] = ----------- ----------- ----------- x[n]
|
||||
// 1 + a_3q^-1 1 + a_2q^-1 1 + a_1q^-1
|
||||
//
|
||||
// The input vector |filter_coefficients| includes these three filter coefficients.
|
||||
// The filter state contains the in_data state, in_data[-1], followed by
|
||||
// the out_data state, out_data[-1]. This is repeated for each cascade.
|
||||
// The first cascade filter will filter the |in_data| and store the output in
|
||||
// |out_data|. The second will the take the |out_data| as input and make an
|
||||
// intermediate storage in |in_data|, to save memory. The third, and final, cascade
|
||||
// filter operation takes the |in_data| (which is the output from the previous cascade
|
||||
// filter) and store the output in |out_data|.
|
||||
// Note that the input vector values are changed during the process.
|
||||
size_t k;
|
||||
int32_t diff;
|
||||
// First all-pass cascade; filter from in_data to out_data.
|
||||
|
||||
// Let y_i[n] indicate the output of cascade filter i (with filter coefficient a_i) at
|
||||
// vector position n. Then the final output will be y[n] = y_3[n]
|
||||
|
||||
// First loop, use the states stored in memory.
|
||||
// "diff" should be safe from wrap around since max values are 2^25
|
||||
// diff = (x[0] - y_1[-1])
|
||||
diff = WebRtcSpl_SubSatW32(in_data[0], filter_state[1]);
|
||||
// y_1[0] = x[-1] + a_1 * (x[0] - y_1[-1])
|
||||
out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, filter_state[0]);
|
||||
|
||||
// For the remaining loops, use previous values.
|
||||
for (k = 1; k < data_length; k++)
|
||||
{
|
||||
// diff = (x[n] - y_1[n-1])
|
||||
diff = WebRtcSpl_SubSatW32(in_data[k], out_data[k - 1]);
|
||||
// y_1[n] = x[n-1] + a_1 * (x[n] - y_1[n-1])
|
||||
out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, in_data[k - 1]);
|
||||
}
|
||||
|
||||
// Update states.
|
||||
filter_state[0] = in_data[data_length - 1]; // x[N-1], becomes x[-1] next time
|
||||
filter_state[1] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time
|
||||
|
||||
// Second all-pass cascade; filter from out_data to in_data.
|
||||
// diff = (y_1[0] - y_2[-1])
|
||||
diff = WebRtcSpl_SubSatW32(out_data[0], filter_state[3]);
|
||||
// y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1])
|
||||
in_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, filter_state[2]);
|
||||
for (k = 1; k < data_length; k++)
|
||||
{
|
||||
// diff = (y_1[n] - y_2[n-1])
|
||||
diff = WebRtcSpl_SubSatW32(out_data[k], in_data[k - 1]);
|
||||
// y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1])
|
||||
in_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, out_data[k-1]);
|
||||
}
|
||||
|
||||
filter_state[2] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time
|
||||
filter_state[3] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time
|
||||
|
||||
// Third all-pass cascade; filter from in_data to out_data.
|
||||
// diff = (y_2[0] - y[-1])
|
||||
diff = WebRtcSpl_SubSatW32(in_data[0], filter_state[5]);
|
||||
// y[0] = y_2[-1] + a_3 * (y_2[0] - y[-1])
|
||||
out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, filter_state[4]);
|
||||
for (k = 1; k < data_length; k++)
|
||||
{
|
||||
// diff = (y_2[n] - y[n-1])
|
||||
diff = WebRtcSpl_SubSatW32(in_data[k], out_data[k - 1]);
|
||||
// y[n] = y_2[n-1] + a_3 * (y_2[n] - y[n-1])
|
||||
out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, in_data[k-1]);
|
||||
}
|
||||
filter_state[4] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time
|
||||
filter_state[5] = out_data[data_length - 1]; // y[N-1], becomes y[-1] next time
|
||||
}
|
||||
|
||||
void WebRtcSpl_AnalysisQMF(const int16_t* in_data, size_t in_data_length,
|
||||
int16_t* low_band, int16_t* high_band,
|
||||
int32_t* filter_state1, int32_t* filter_state2)
|
||||
{
|
||||
size_t i;
|
||||
int16_t k;
|
||||
int32_t tmp;
|
||||
int32_t half_in1[kMaxBandFrameLength];
|
||||
int32_t half_in2[kMaxBandFrameLength];
|
||||
int32_t filter1[kMaxBandFrameLength];
|
||||
int32_t filter2[kMaxBandFrameLength];
|
||||
const size_t band_length = in_data_length / 2;
|
||||
assert(in_data_length % 2 == 0);
|
||||
assert(band_length <= kMaxBandFrameLength);
|
||||
|
||||
// Split even and odd samples. Also shift them to Q10.
|
||||
for (i = 0, k = 0; i < band_length; i++, k += 2)
|
||||
{
|
||||
half_in2[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k], 10);
|
||||
half_in1[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k + 1], 10);
|
||||
}
|
||||
|
||||
// All pass filter even and odd samples, independently.
|
||||
WebRtcSpl_AllPassQMF(half_in1, band_length, filter1,
|
||||
WebRtcSpl_kAllPassFilter1, filter_state1);
|
||||
WebRtcSpl_AllPassQMF(half_in2, band_length, filter2,
|
||||
WebRtcSpl_kAllPassFilter2, filter_state2);
|
||||
|
||||
// Take the sum and difference of filtered version of odd and even
|
||||
// branches to get upper & lower band.
|
||||
for (i = 0; i < band_length; i++)
|
||||
{
|
||||
tmp = (filter1[i] + filter2[i] + 1024) >> 11;
|
||||
low_band[i] = WebRtcSpl_SatW32ToW16(tmp);
|
||||
|
||||
tmp = (filter1[i] - filter2[i] + 1024) >> 11;
|
||||
high_band[i] = WebRtcSpl_SatW32ToW16(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band,
|
||||
size_t band_length, int16_t* out_data,
|
||||
int32_t* filter_state1, int32_t* filter_state2)
|
||||
{
|
||||
int32_t tmp;
|
||||
int32_t half_in1[kMaxBandFrameLength];
|
||||
int32_t half_in2[kMaxBandFrameLength];
|
||||
int32_t filter1[kMaxBandFrameLength];
|
||||
int32_t filter2[kMaxBandFrameLength];
|
||||
size_t i;
|
||||
int16_t k;
|
||||
assert(band_length <= kMaxBandFrameLength);
|
||||
|
||||
// Obtain the sum and difference channels out of upper and lower-band channels.
|
||||
// Also shift to Q10 domain.
|
||||
for (i = 0; i < band_length; i++)
|
||||
{
|
||||
tmp = (int32_t)low_band[i] + (int32_t)high_band[i];
|
||||
half_in1[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10);
|
||||
tmp = (int32_t)low_band[i] - (int32_t)high_band[i];
|
||||
half_in2[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10);
|
||||
}
|
||||
|
||||
// all-pass filter the sum and difference channels
|
||||
WebRtcSpl_AllPassQMF(half_in1, band_length, filter1,
|
||||
WebRtcSpl_kAllPassFilter2, filter_state1);
|
||||
WebRtcSpl_AllPassQMF(half_in2, band_length, filter2,
|
||||
WebRtcSpl_kAllPassFilter1, filter_state2);
|
||||
|
||||
// The filtered signals are even and odd samples of the output. Combine
|
||||
// them. The signals are Q10 should shift them back to Q0 and take care of
|
||||
// saturation.
|
||||
for (i = 0, k = 0; i < band_length; i++)
|
||||
{
|
||||
tmp = (filter2[i] + 512) >> 10;
|
||||
out_data[k++] = WebRtcSpl_SatW32ToW16(tmp);
|
||||
|
||||
tmp = (filter1[i] + 512) >> 10;
|
||||
out_data[k++] = WebRtcSpl_SatW32ToW16(tmp);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_SqrtOfOneMinusXSquared().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t *xQ15, size_t vector_length,
|
||||
int16_t *yQ15)
|
||||
{
|
||||
int32_t sq;
|
||||
size_t m;
|
||||
int16_t tmp;
|
||||
|
||||
for (m = 0; m < vector_length; m++)
|
||||
{
|
||||
tmp = xQ15[m];
|
||||
sq = tmp * tmp; // x^2 in Q30
|
||||
sq = 1073741823 - sq; // 1-x^2, where 1 ~= 0.99999999906 is 1073741823 in Q30
|
||||
sq = WebRtcSpl_Sqrt(sq); // sqrt(1-x^2) in Q15
|
||||
yQ15[m] = (int16_t)sq;
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the functions
|
||||
* WebRtcSpl_VectorBitShiftW16()
|
||||
* WebRtcSpl_VectorBitShiftW32()
|
||||
* WebRtcSpl_VectorBitShiftW32ToW16()
|
||||
* WebRtcSpl_ScaleVector()
|
||||
* WebRtcSpl_ScaleVectorWithSat()
|
||||
* WebRtcSpl_ScaleAndAddVectors()
|
||||
* WebRtcSpl_ScaleAndAddVectorsWithRoundC()
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_VectorBitShiftW16(int16_t *res, size_t length,
|
||||
const int16_t *in, int16_t right_shifts)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (right_shifts > 0)
|
||||
{
|
||||
for (i = length; i > 0; i--)
|
||||
{
|
||||
(*res++) = ((*in++) >> right_shifts);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (i = length; i > 0; i--)
|
||||
{
|
||||
(*res++) = ((*in++) << (-right_shifts));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_VectorBitShiftW32(int32_t *out_vector,
|
||||
size_t vector_length,
|
||||
const int32_t *in_vector,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (right_shifts > 0)
|
||||
{
|
||||
for (i = vector_length; i > 0; i--)
|
||||
{
|
||||
(*out_vector++) = ((*in_vector++) >> right_shifts);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (i = vector_length; i > 0; i--)
|
||||
{
|
||||
(*out_vector++) = ((*in_vector++) << (-right_shifts));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out, size_t length,
|
||||
const int32_t* in, int right_shifts) {
|
||||
size_t i;
|
||||
int32_t tmp_w32;
|
||||
|
||||
if (right_shifts >= 0) {
|
||||
for (i = length; i > 0; i--) {
|
||||
tmp_w32 = (*in++) >> right_shifts;
|
||||
(*out++) = WebRtcSpl_SatW32ToW16(tmp_w32);
|
||||
}
|
||||
} else {
|
||||
int left_shifts = -right_shifts;
|
||||
for (i = length; i > 0; i--) {
|
||||
tmp_w32 = (*in++) << left_shifts;
|
||||
(*out++) = WebRtcSpl_SatW32ToW16(tmp_w32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ScaleVector(const int16_t *in_vector, int16_t *out_vector,
|
||||
int16_t gain, size_t in_vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
// Performs vector operation: out_vector = (gain*in_vector)>>right_shifts
|
||||
size_t i;
|
||||
const int16_t *inptr;
|
||||
int16_t *outptr;
|
||||
|
||||
inptr = in_vector;
|
||||
outptr = out_vector;
|
||||
|
||||
for (i = 0; i < in_vector_length; i++)
|
||||
{
|
||||
*outptr++ = (int16_t)((*inptr++ * gain) >> right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ScaleVectorWithSat(const int16_t *in_vector, int16_t *out_vector,
|
||||
int16_t gain, size_t in_vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
// Performs vector operation: out_vector = (gain*in_vector)>>right_shifts
|
||||
size_t i;
|
||||
const int16_t *inptr;
|
||||
int16_t *outptr;
|
||||
|
||||
inptr = in_vector;
|
||||
outptr = out_vector;
|
||||
|
||||
for (i = 0; i < in_vector_length; i++) {
|
||||
*outptr++ = WebRtcSpl_SatW32ToW16((*inptr++ * gain) >> right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ScaleAndAddVectors(const int16_t *in1, int16_t gain1, int shift1,
|
||||
const int16_t *in2, int16_t gain2, int shift2,
|
||||
int16_t *out, size_t vector_length)
|
||||
{
|
||||
// Performs vector operation: out = (gain1*in1)>>shift1 + (gain2*in2)>>shift2
|
||||
size_t i;
|
||||
const int16_t *in1ptr;
|
||||
const int16_t *in2ptr;
|
||||
int16_t *outptr;
|
||||
|
||||
in1ptr = in1;
|
||||
in2ptr = in2;
|
||||
outptr = out;
|
||||
|
||||
for (i = 0; i < vector_length; i++)
|
||||
{
|
||||
*outptr++ = (int16_t)((gain1 * *in1ptr++) >> shift1) +
|
||||
(int16_t)((gain2 * *in2ptr++) >> shift2);
|
||||
}
|
||||
}
|
||||
|
||||
// C version of WebRtcSpl_ScaleAndAddVectorsWithRound() for generic platforms.
|
||||
int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1,
|
||||
int16_t in_vector1_scale,
|
||||
const int16_t* in_vector2,
|
||||
int16_t in_vector2_scale,
|
||||
int right_shifts,
|
||||
int16_t* out_vector,
|
||||
size_t length) {
|
||||
size_t i = 0;
|
||||
int round_value = (1 << right_shifts) >> 1;
|
||||
|
||||
if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL ||
|
||||
length == 0 || right_shifts < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
out_vector[i] = (int16_t)((
|
||||
in_vector1[i] * in_vector1_scale + in_vector2[i] * in_vector2_scale +
|
||||
round_value) >> right_shifts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the functions
|
||||
* WebRtcSpl_ScaleAndAddVectorsWithRound_mips()
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1,
|
||||
int16_t in_vector1_scale,
|
||||
const int16_t* in_vector2,
|
||||
int16_t in_vector2_scale,
|
||||
int right_shifts,
|
||||
int16_t* out_vector,
|
||||
size_t length) {
|
||||
int16_t r0 = 0, r1 = 0;
|
||||
int16_t *in1 = (int16_t*)in_vector1;
|
||||
int16_t *in2 = (int16_t*)in_vector2;
|
||||
int16_t *out = out_vector;
|
||||
size_t i = 0;
|
||||
int value32 = 0;
|
||||
|
||||
if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL ||
|
||||
length == 0 || right_shifts < 0) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < length; i++) {
|
||||
__asm __volatile (
|
||||
"lh %[r0], 0(%[in1]) \n\t"
|
||||
"lh %[r1], 0(%[in2]) \n\t"
|
||||
"mult %[r0], %[in_vector1_scale] \n\t"
|
||||
"madd %[r1], %[in_vector2_scale] \n\t"
|
||||
"extrv_r.w %[value32], $ac0, %[right_shifts] \n\t"
|
||||
"addiu %[in1], %[in1], 2 \n\t"
|
||||
"addiu %[in2], %[in2], 2 \n\t"
|
||||
"sh %[value32], 0(%[out]) \n\t"
|
||||
"addiu %[out], %[out], 2 \n\t"
|
||||
: [value32] "=&r" (value32), [out] "+r" (out), [in1] "+r" (in1),
|
||||
[in2] "+r" (in2), [r0] "=&r" (r0), [r1] "=&r" (r1)
|
||||
: [in_vector1_scale] "r" (in_vector1_scale),
|
||||
[in_vector2_scale] "r" (in_vector2_scale),
|
||||
[right_shifts] "r" (right_shifts)
|
||||
: "hi", "lo", "memory"
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
50
webrtc/common_audio/vad/include/vad.h
Normal file
50
webrtc/common_audio/vad/include/vad.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_audio/vad/include/webrtc_vad.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Vad {
|
||||
public:
|
||||
enum Aggressiveness {
|
||||
kVadNormal = 0,
|
||||
kVadLowBitrate = 1,
|
||||
kVadAggressive = 2,
|
||||
kVadVeryAggressive = 3
|
||||
};
|
||||
|
||||
enum Activity { kPassive = 0, kActive = 1, kError = -1 };
|
||||
|
||||
virtual ~Vad() = default;
|
||||
|
||||
// Calculates a VAD decision for the given audio frame. Valid sample rates
|
||||
// are 8000, 16000, and 32000 Hz; the number of samples must be such that the
|
||||
// frame is 10, 20, or 30 ms long.
|
||||
virtual Activity VoiceActivity(const int16_t* audio,
|
||||
size_t num_samples,
|
||||
int sample_rate_hz) = 0;
|
||||
|
||||
// Resets VAD state.
|
||||
virtual void Reset() = 0;
|
||||
};
|
||||
|
||||
// Returns a Vad instance that's implemented on top of WebRtcVad.
|
||||
rtc::scoped_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
|
86
webrtc/common_audio/vad/include/webrtc_vad.h
Normal file
86
webrtc/common_audio/vad/include/webrtc_vad.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the VAD API calls. Specific function calls are given below.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
typedef struct WebRtcVadInst VadInst;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Creates an instance to the VAD structure.
|
||||
VadInst* WebRtcVad_Create();
|
||||
|
||||
// Frees the dynamic memory of a specified VAD instance.
|
||||
//
|
||||
// - handle [i] : Pointer to VAD instance that should be freed.
|
||||
void WebRtcVad_Free(VadInst* handle);
|
||||
|
||||
// Initializes a VAD instance.
|
||||
//
|
||||
// - handle [i/o] : Instance that should be initialized.
|
||||
//
|
||||
// returns : 0 - (OK),
|
||||
// -1 - (NULL pointer or Default mode could not be set).
|
||||
int WebRtcVad_Init(VadInst* handle);
|
||||
|
||||
// Sets the VAD operating mode. A more aggressive (higher mode) VAD is more
|
||||
// restrictive in reporting speech. Put in other words the probability of being
|
||||
// speech when the VAD returns 1 is increased with increasing mode. As a
|
||||
// consequence also the missed detection rate goes up.
|
||||
//
|
||||
// - handle [i/o] : VAD instance.
|
||||
// - mode [i] : Aggressiveness mode (0, 1, 2, or 3).
|
||||
//
|
||||
// returns : 0 - (OK),
|
||||
// -1 - (NULL pointer, mode could not be set or the VAD instance
|
||||
// has not been initialized).
|
||||
int WebRtcVad_set_mode(VadInst* handle, int mode);
|
||||
|
||||
// Calculates a VAD decision for the |audio_frame|. For valid sampling rates
|
||||
// frame lengths, see the description of WebRtcVad_ValidRatesAndFrameLengths().
|
||||
//
|
||||
// - handle [i/o] : VAD Instance. Needs to be initialized by
|
||||
// WebRtcVad_Init() before call.
|
||||
// - fs [i] : Sampling frequency (Hz): 8000, 16000, or 32000
|
||||
// - audio_frame [i] : Audio frame buffer.
|
||||
// - frame_length [i] : Length of audio frame buffer in number of samples.
|
||||
//
|
||||
// returns : 1 - (Active Voice),
|
||||
// 0 - (Non-active Voice),
|
||||
// -1 - (Error)
|
||||
int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame,
|
||||
size_t frame_length);
|
||||
|
||||
// Checks for valid combinations of |rate| and |frame_length|. We support 10,
|
||||
// 20 and 30 ms frames and the rates 8000, 16000 and 32000 Hz.
|
||||
//
|
||||
// - rate [i] : Sampling frequency (Hz).
|
||||
// - frame_length [i] : Speech frame buffer length in number of samples.
|
||||
//
|
||||
// returns : 0 - (valid combination), -1 - (invalid combination)
|
||||
int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
|
63
webrtc/common_audio/vad/vad.cc
Normal file
63
webrtc/common_audio/vad/vad.cc
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/vad/include/vad.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
class VadImpl final : public Vad {
|
||||
public:
|
||||
explicit VadImpl(Aggressiveness aggressiveness)
|
||||
: handle_(nullptr), aggressiveness_(aggressiveness) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
~VadImpl() override { WebRtcVad_Free(handle_); }
|
||||
|
||||
Activity VoiceActivity(const int16_t* audio,
|
||||
size_t num_samples,
|
||||
int sample_rate_hz) override {
|
||||
int ret = WebRtcVad_Process(handle_, sample_rate_hz, audio, num_samples);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
return kPassive;
|
||||
case 1:
|
||||
return kActive;
|
||||
default:
|
||||
RTC_DCHECK(false) << "WebRtcVad_Process returned an error.";
|
||||
return kError;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset() override {
|
||||
if (handle_)
|
||||
WebRtcVad_Free(handle_);
|
||||
handle_ = WebRtcVad_Create();
|
||||
RTC_CHECK(handle_);
|
||||
RTC_CHECK_EQ(WebRtcVad_Init(handle_), 0);
|
||||
RTC_CHECK_EQ(WebRtcVad_set_mode(handle_, aggressiveness_), 0);
|
||||
}
|
||||
|
||||
private:
|
||||
VadInst* handle_;
|
||||
Aggressiveness aggressiveness_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
rtc::scoped_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness) {
|
||||
return rtc::scoped_ptr<Vad>(new VadImpl(aggressiveness));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
676
webrtc/common_audio/vad/vad_core.c
Normal file
676
webrtc/common_audio/vad/vad_core.c
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/vad/vad_core.h"
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/common_audio/vad/vad_filterbank.h"
|
||||
#include "webrtc/common_audio/vad/vad_gmm.h"
|
||||
#include "webrtc/common_audio/vad/vad_sp.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Spectrum Weighting
|
||||
static const int16_t kSpectrumWeight[kNumChannels] = { 6, 8, 10, 12, 14, 16 };
|
||||
static const int16_t kNoiseUpdateConst = 655; // Q15
|
||||
static const int16_t kSpeechUpdateConst = 6554; // Q15
|
||||
static const int16_t kBackEta = 154; // Q8
|
||||
// Minimum difference between the two models, Q5
|
||||
static const int16_t kMinimumDifference[kNumChannels] = {
|
||||
544, 544, 576, 576, 576, 576 };
|
||||
// Upper limit of mean value for speech model, Q7
|
||||
static const int16_t kMaximumSpeech[kNumChannels] = {
|
||||
11392, 11392, 11520, 11520, 11520, 11520 };
|
||||
// Minimum value for mean value
|
||||
static const int16_t kMinimumMean[kNumGaussians] = { 640, 768 };
|
||||
// Upper limit of mean value for noise model, Q7
|
||||
static const int16_t kMaximumNoise[kNumChannels] = {
|
||||
9216, 9088, 8960, 8832, 8704, 8576 };
|
||||
// Start values for the Gaussian models, Q7
|
||||
// Weights for the two Gaussians for the six channels (noise)
|
||||
static const int16_t kNoiseDataWeights[kTableSize] = {
|
||||
34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103 };
|
||||
// Weights for the two Gaussians for the six channels (speech)
|
||||
static const int16_t kSpeechDataWeights[kTableSize] = {
|
||||
48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81 };
|
||||
// Means for the two Gaussians for the six channels (noise)
|
||||
static const int16_t kNoiseDataMeans[kTableSize] = {
|
||||
6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, 7820, 7266, 5020, 4362 };
|
||||
// Means for the two Gaussians for the six channels (speech)
|
||||
static const int16_t kSpeechDataMeans[kTableSize] = {
|
||||
8306, 10085, 10078, 11823, 11843, 6309, 9473, 9571, 10879, 7581, 8180, 7483
|
||||
};
|
||||
// Stds for the two Gaussians for the six channels (noise)
|
||||
static const int16_t kNoiseDataStds[kTableSize] = {
|
||||
378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, 421, 455 };
|
||||
// Stds for the two Gaussians for the six channels (speech)
|
||||
static const int16_t kSpeechDataStds[kTableSize] = {
|
||||
555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, 1079, 850 };
|
||||
|
||||
// Constants used in GmmProbability().
|
||||
//
|
||||
// Maximum number of counted speech (VAD = 1) frames in a row.
|
||||
static const int16_t kMaxSpeechFrames = 6;
|
||||
// Minimum standard deviation for both speech and noise.
|
||||
static const int16_t kMinStd = 384;
|
||||
|
||||
// Constants in WebRtcVad_InitCore().
|
||||
// Default aggressiveness mode.
|
||||
static const short kDefaultMode = 0;
|
||||
static const int kInitCheck = 42;
|
||||
|
||||
// Constants used in WebRtcVad_set_mode_core().
|
||||
//
|
||||
// Thresholds for different frame lengths (10 ms, 20 ms and 30 ms).
|
||||
//
|
||||
// Mode 0, Quality.
|
||||
static const int16_t kOverHangMax1Q[3] = { 8, 4, 3 };
|
||||
static const int16_t kOverHangMax2Q[3] = { 14, 7, 5 };
|
||||
static const int16_t kLocalThresholdQ[3] = { 24, 21, 24 };
|
||||
static const int16_t kGlobalThresholdQ[3] = { 57, 48, 57 };
|
||||
// Mode 1, Low bitrate.
|
||||
static const int16_t kOverHangMax1LBR[3] = { 8, 4, 3 };
|
||||
static const int16_t kOverHangMax2LBR[3] = { 14, 7, 5 };
|
||||
static const int16_t kLocalThresholdLBR[3] = { 37, 32, 37 };
|
||||
static const int16_t kGlobalThresholdLBR[3] = { 100, 80, 100 };
|
||||
// Mode 2, Aggressive.
|
||||
static const int16_t kOverHangMax1AGG[3] = { 6, 3, 2 };
|
||||
static const int16_t kOverHangMax2AGG[3] = { 9, 5, 3 };
|
||||
static const int16_t kLocalThresholdAGG[3] = { 82, 78, 82 };
|
||||
static const int16_t kGlobalThresholdAGG[3] = { 285, 260, 285 };
|
||||
// Mode 3, Very aggressive.
|
||||
static const int16_t kOverHangMax1VAG[3] = { 6, 3, 2 };
|
||||
static const int16_t kOverHangMax2VAG[3] = { 9, 5, 3 };
|
||||
static const int16_t kLocalThresholdVAG[3] = { 94, 94, 94 };
|
||||
static const int16_t kGlobalThresholdVAG[3] = { 1100, 1050, 1100 };
|
||||
|
||||
// Calculates the weighted average w.r.t. number of Gaussians. The |data| are
|
||||
// updated with an |offset| before averaging.
|
||||
//
|
||||
// - data [i/o] : Data to average.
|
||||
// - offset [i] : An offset added to |data|.
|
||||
// - weights [i] : Weights used for averaging.
|
||||
//
|
||||
// returns : The weighted average.
|
||||
static int32_t WeightedAverage(int16_t* data, int16_t offset,
|
||||
const int16_t* weights) {
|
||||
int k;
|
||||
int32_t weighted_average = 0;
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
data[k * kNumChannels] += offset;
|
||||
weighted_average += data[k * kNumChannels] * weights[k * kNumChannels];
|
||||
}
|
||||
return weighted_average;
|
||||
}
|
||||
|
||||
// Calculates the probabilities for both speech and background noise using
|
||||
// Gaussian Mixture Models (GMM). A hypothesis-test is performed to decide which
|
||||
// type of signal is most probable.
|
||||
//
|
||||
// - self [i/o] : Pointer to VAD instance
|
||||
// - features [i] : Feature vector of length |kNumChannels|
|
||||
// = log10(energy in frequency band)
|
||||
// - total_power [i] : Total power in audio frame.
|
||||
// - frame_length [i] : Number of input samples
|
||||
//
|
||||
// - returns : the VAD decision (0 - noise, 1 - speech).
|
||||
static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
int16_t total_power, size_t frame_length) {
|
||||
int channel, k;
|
||||
int16_t feature_minimum;
|
||||
int16_t h0, h1;
|
||||
int16_t log_likelihood_ratio;
|
||||
int16_t vadflag = 0;
|
||||
int16_t shifts_h0, shifts_h1;
|
||||
int16_t tmp_s16, tmp1_s16, tmp2_s16;
|
||||
int16_t diff;
|
||||
int gaussian;
|
||||
int16_t nmk, nmk2, nmk3, smk, smk2, nsk, ssk;
|
||||
int16_t delt, ndelt;
|
||||
int16_t maxspe, maxmu;
|
||||
int16_t deltaN[kTableSize], deltaS[kTableSize];
|
||||
int16_t ngprvec[kTableSize] = { 0 }; // Conditional probability = 0.
|
||||
int16_t sgprvec[kTableSize] = { 0 }; // Conditional probability = 0.
|
||||
int32_t h0_test, h1_test;
|
||||
int32_t tmp1_s32, tmp2_s32;
|
||||
int32_t sum_log_likelihood_ratios = 0;
|
||||
int32_t noise_global_mean, speech_global_mean;
|
||||
int32_t noise_probability[kNumGaussians], speech_probability[kNumGaussians];
|
||||
int16_t overhead1, overhead2, individualTest, totalTest;
|
||||
|
||||
// Set various thresholds based on frame lengths (80, 160 or 240 samples).
|
||||
if (frame_length == 80) {
|
||||
overhead1 = self->over_hang_max_1[0];
|
||||
overhead2 = self->over_hang_max_2[0];
|
||||
individualTest = self->individual[0];
|
||||
totalTest = self->total[0];
|
||||
} else if (frame_length == 160) {
|
||||
overhead1 = self->over_hang_max_1[1];
|
||||
overhead2 = self->over_hang_max_2[1];
|
||||
individualTest = self->individual[1];
|
||||
totalTest = self->total[1];
|
||||
} else {
|
||||
overhead1 = self->over_hang_max_1[2];
|
||||
overhead2 = self->over_hang_max_2[2];
|
||||
individualTest = self->individual[2];
|
||||
totalTest = self->total[2];
|
||||
}
|
||||
|
||||
if (total_power > kMinEnergy) {
|
||||
// The signal power of current frame is large enough for processing. The
|
||||
// processing consists of two parts:
|
||||
// 1) Calculating the likelihood of speech and thereby a VAD decision.
|
||||
// 2) Updating the underlying model, w.r.t., the decision made.
|
||||
|
||||
// The detection scheme is an LRT with hypothesis
|
||||
// H0: Noise
|
||||
// H1: Speech
|
||||
//
|
||||
// We combine a global LRT with local tests, for each frequency sub-band,
|
||||
// here defined as |channel|.
|
||||
for (channel = 0; channel < kNumChannels; channel++) {
|
||||
// For each channel we model the probability with a GMM consisting of
|
||||
// |kNumGaussians|, with different means and standard deviations depending
|
||||
// on H0 or H1.
|
||||
h0_test = 0;
|
||||
h1_test = 0;
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
gaussian = channel + k * kNumChannels;
|
||||
// Probability under H0, that is, probability of frame being noise.
|
||||
// Value given in Q27 = Q7 * Q20.
|
||||
tmp1_s32 = WebRtcVad_GaussianProbability(features[channel],
|
||||
self->noise_means[gaussian],
|
||||
self->noise_stds[gaussian],
|
||||
&deltaN[gaussian]);
|
||||
noise_probability[k] = kNoiseDataWeights[gaussian] * tmp1_s32;
|
||||
h0_test += noise_probability[k]; // Q27
|
||||
|
||||
// Probability under H1, that is, probability of frame being speech.
|
||||
// Value given in Q27 = Q7 * Q20.
|
||||
tmp1_s32 = WebRtcVad_GaussianProbability(features[channel],
|
||||
self->speech_means[gaussian],
|
||||
self->speech_stds[gaussian],
|
||||
&deltaS[gaussian]);
|
||||
speech_probability[k] = kSpeechDataWeights[gaussian] * tmp1_s32;
|
||||
h1_test += speech_probability[k]; // Q27
|
||||
}
|
||||
|
||||
// Calculate the log likelihood ratio: log2(Pr{X|H1} / Pr{X|H1}).
|
||||
// Approximation:
|
||||
// log2(Pr{X|H1} / Pr{X|H1}) = log2(Pr{X|H1}*2^Q) - log2(Pr{X|H1}*2^Q)
|
||||
// = log2(h1_test) - log2(h0_test)
|
||||
// = log2(2^(31-shifts_h1)*(1+b1))
|
||||
// - log2(2^(31-shifts_h0)*(1+b0))
|
||||
// = shifts_h0 - shifts_h1
|
||||
// + log2(1+b1) - log2(1+b0)
|
||||
// ~= shifts_h0 - shifts_h1
|
||||
//
|
||||
// Note that b0 and b1 are values less than 1, hence, 0 <= log2(1+b0) < 1.
|
||||
// Further, b0 and b1 are independent and on the average the two terms
|
||||
// cancel.
|
||||
shifts_h0 = WebRtcSpl_NormW32(h0_test);
|
||||
shifts_h1 = WebRtcSpl_NormW32(h1_test);
|
||||
if (h0_test == 0) {
|
||||
shifts_h0 = 31;
|
||||
}
|
||||
if (h1_test == 0) {
|
||||
shifts_h1 = 31;
|
||||
}
|
||||
log_likelihood_ratio = shifts_h0 - shifts_h1;
|
||||
|
||||
// Update |sum_log_likelihood_ratios| with spectrum weighting. This is
|
||||
// used for the global VAD decision.
|
||||
sum_log_likelihood_ratios +=
|
||||
(int32_t) (log_likelihood_ratio * kSpectrumWeight[channel]);
|
||||
|
||||
// Local VAD decision.
|
||||
if ((log_likelihood_ratio << 2) > individualTest) {
|
||||
vadflag = 1;
|
||||
}
|
||||
|
||||
// TODO(bjornv): The conditional probabilities below are applied on the
|
||||
// hard coded number of Gaussians set to two. Find a way to generalize.
|
||||
// Calculate local noise probabilities used later when updating the GMM.
|
||||
h0 = (int16_t) (h0_test >> 12); // Q15
|
||||
if (h0 > 0) {
|
||||
// High probability of noise. Assign conditional probabilities for each
|
||||
// Gaussian in the GMM.
|
||||
tmp1_s32 = (noise_probability[0] & 0xFFFFF000) << 2; // Q29
|
||||
ngprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h0); // Q14
|
||||
ngprvec[channel + kNumChannels] = 16384 - ngprvec[channel];
|
||||
} else {
|
||||
// Low noise probability. Assign conditional probability 1 to the first
|
||||
// Gaussian and 0 to the rest (which is already set at initialization).
|
||||
ngprvec[channel] = 16384;
|
||||
}
|
||||
|
||||
// Calculate local speech probabilities used later when updating the GMM.
|
||||
h1 = (int16_t) (h1_test >> 12); // Q15
|
||||
if (h1 > 0) {
|
||||
// High probability of speech. Assign conditional probabilities for each
|
||||
// Gaussian in the GMM. Otherwise use the initialized values, i.e., 0.
|
||||
tmp1_s32 = (speech_probability[0] & 0xFFFFF000) << 2; // Q29
|
||||
sgprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h1); // Q14
|
||||
sgprvec[channel + kNumChannels] = 16384 - sgprvec[channel];
|
||||
}
|
||||
}
|
||||
|
||||
// Make a global VAD decision.
|
||||
vadflag |= (sum_log_likelihood_ratios >= totalTest);
|
||||
|
||||
// Update the model parameters.
|
||||
maxspe = 12800;
|
||||
for (channel = 0; channel < kNumChannels; channel++) {
|
||||
|
||||
// Get minimum value in past which is used for long term correction in Q4.
|
||||
feature_minimum = WebRtcVad_FindMinimum(self, features[channel], channel);
|
||||
|
||||
// Compute the "global" mean, that is the sum of the two means weighted.
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel], 0,
|
||||
&kNoiseDataWeights[channel]);
|
||||
tmp1_s16 = (int16_t) (noise_global_mean >> 6); // Q8
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
gaussian = channel + k * kNumChannels;
|
||||
|
||||
nmk = self->noise_means[gaussian];
|
||||
smk = self->speech_means[gaussian];
|
||||
nsk = self->noise_stds[gaussian];
|
||||
ssk = self->speech_stds[gaussian];
|
||||
|
||||
// Update noise mean vector if the frame consists of noise only.
|
||||
nmk2 = nmk;
|
||||
if (!vadflag) {
|
||||
// deltaN = (x-mu)/sigma^2
|
||||
// ngprvec[k] = |noise_probability[k]| /
|
||||
// (|noise_probability[0]| + |noise_probability[1]|)
|
||||
|
||||
// (Q14 * Q11 >> 11) = Q14.
|
||||
delt = (int16_t)((ngprvec[gaussian] * deltaN[gaussian]) >> 11);
|
||||
// Q7 + (Q14 * Q15 >> 22) = Q7.
|
||||
nmk2 = nmk + (int16_t)((delt * kNoiseUpdateConst) >> 22);
|
||||
}
|
||||
|
||||
// Long term correction of the noise mean.
|
||||
// Q8 - Q8 = Q8.
|
||||
ndelt = (feature_minimum << 4) - tmp1_s16;
|
||||
// Q7 + (Q8 * Q8) >> 9 = Q7.
|
||||
nmk3 = nmk2 + (int16_t)((ndelt * kBackEta) >> 9);
|
||||
|
||||
// Control that the noise mean does not drift to much.
|
||||
tmp_s16 = (int16_t) ((k + 5) << 7);
|
||||
if (nmk3 < tmp_s16) {
|
||||
nmk3 = tmp_s16;
|
||||
}
|
||||
tmp_s16 = (int16_t) ((72 + k - channel) << 7);
|
||||
if (nmk3 > tmp_s16) {
|
||||
nmk3 = tmp_s16;
|
||||
}
|
||||
self->noise_means[gaussian] = nmk3;
|
||||
|
||||
if (vadflag) {
|
||||
// Update speech mean vector:
|
||||
// |deltaS| = (x-mu)/sigma^2
|
||||
// sgprvec[k] = |speech_probability[k]| /
|
||||
// (|speech_probability[0]| + |speech_probability[1]|)
|
||||
|
||||
// (Q14 * Q11) >> 11 = Q14.
|
||||
delt = (int16_t)((sgprvec[gaussian] * deltaS[gaussian]) >> 11);
|
||||
// Q14 * Q15 >> 21 = Q8.
|
||||
tmp_s16 = (int16_t)((delt * kSpeechUpdateConst) >> 21);
|
||||
// Q7 + (Q8 >> 1) = Q7. With rounding.
|
||||
smk2 = smk + ((tmp_s16 + 1) >> 1);
|
||||
|
||||
// Control that the speech mean does not drift to much.
|
||||
maxmu = maxspe + 640;
|
||||
if (smk2 < kMinimumMean[k]) {
|
||||
smk2 = kMinimumMean[k];
|
||||
}
|
||||
if (smk2 > maxmu) {
|
||||
smk2 = maxmu;
|
||||
}
|
||||
self->speech_means[gaussian] = smk2; // Q7.
|
||||
|
||||
// (Q7 >> 3) = Q4. With rounding.
|
||||
tmp_s16 = ((smk + 4) >> 3);
|
||||
|
||||
tmp_s16 = features[channel] - tmp_s16; // Q4
|
||||
// (Q11 * Q4 >> 3) = Q12.
|
||||
tmp1_s32 = (deltaS[gaussian] * tmp_s16) >> 3;
|
||||
tmp2_s32 = tmp1_s32 - 4096;
|
||||
tmp_s16 = sgprvec[gaussian] >> 2;
|
||||
// (Q14 >> 2) * Q12 = Q24.
|
||||
tmp1_s32 = tmp_s16 * tmp2_s32;
|
||||
|
||||
tmp2_s32 = tmp1_s32 >> 4; // Q20
|
||||
|
||||
// 0.1 * Q20 / Q7 = Q13.
|
||||
if (tmp2_s32 > 0) {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp2_s32, ssk * 10);
|
||||
} else {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp2_s32, ssk * 10);
|
||||
tmp_s16 = -tmp_s16;
|
||||
}
|
||||
// Divide by 4 giving an update factor of 0.025 (= 0.1 / 4).
|
||||
// Note that division by 4 equals shift by 2, hence,
|
||||
// (Q13 >> 8) = (Q13 >> 6) / 4 = Q7.
|
||||
tmp_s16 += 128; // Rounding.
|
||||
ssk += (tmp_s16 >> 8);
|
||||
if (ssk < kMinStd) {
|
||||
ssk = kMinStd;
|
||||
}
|
||||
self->speech_stds[gaussian] = ssk;
|
||||
} else {
|
||||
// Update GMM variance vectors.
|
||||
// deltaN * (features[channel] - nmk) - 1
|
||||
// Q4 - (Q7 >> 3) = Q4.
|
||||
tmp_s16 = features[channel] - (nmk >> 3);
|
||||
// (Q11 * Q4 >> 3) = Q12.
|
||||
tmp1_s32 = (deltaN[gaussian] * tmp_s16) >> 3;
|
||||
tmp1_s32 -= 4096;
|
||||
|
||||
// (Q14 >> 2) * Q12 = Q24.
|
||||
tmp_s16 = (ngprvec[gaussian] + 2) >> 2;
|
||||
tmp2_s32 = tmp_s16 * tmp1_s32;
|
||||
// Q20 * approx 0.001 (2^-10=0.0009766), hence,
|
||||
// (Q24 >> 14) = (Q24 >> 4) / 2^10 = Q20.
|
||||
tmp1_s32 = tmp2_s32 >> 14;
|
||||
|
||||
// Q20 / Q7 = Q13.
|
||||
if (tmp1_s32 > 0) {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, nsk);
|
||||
} else {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp1_s32, nsk);
|
||||
tmp_s16 = -tmp_s16;
|
||||
}
|
||||
tmp_s16 += 32; // Rounding
|
||||
nsk += tmp_s16 >> 6; // Q13 >> 6 = Q7.
|
||||
if (nsk < kMinStd) {
|
||||
nsk = kMinStd;
|
||||
}
|
||||
self->noise_stds[gaussian] = nsk;
|
||||
}
|
||||
}
|
||||
|
||||
// Separate models if they are too close.
|
||||
// |noise_global_mean| in Q14 (= Q7 * Q7).
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel], 0,
|
||||
&kNoiseDataWeights[channel]);
|
||||
|
||||
// |speech_global_mean| in Q14 (= Q7 * Q7).
|
||||
speech_global_mean = WeightedAverage(&self->speech_means[channel], 0,
|
||||
&kSpeechDataWeights[channel]);
|
||||
|
||||
// |diff| = "global" speech mean - "global" noise mean.
|
||||
// (Q14 >> 9) - (Q14 >> 9) = Q5.
|
||||
diff = (int16_t) (speech_global_mean >> 9) -
|
||||
(int16_t) (noise_global_mean >> 9);
|
||||
if (diff < kMinimumDifference[channel]) {
|
||||
tmp_s16 = kMinimumDifference[channel] - diff;
|
||||
|
||||
// |tmp1_s16| = ~0.8 * (kMinimumDifference - diff) in Q7.
|
||||
// |tmp2_s16| = ~0.2 * (kMinimumDifference - diff) in Q7.
|
||||
tmp1_s16 = (int16_t)((13 * tmp_s16) >> 2);
|
||||
tmp2_s16 = (int16_t)((3 * tmp_s16) >> 2);
|
||||
|
||||
// Move Gaussian means for speech model by |tmp1_s16| and update
|
||||
// |speech_global_mean|. Note that |self->speech_means[channel]| is
|
||||
// changed after the call.
|
||||
speech_global_mean = WeightedAverage(&self->speech_means[channel],
|
||||
tmp1_s16,
|
||||
&kSpeechDataWeights[channel]);
|
||||
|
||||
// Move Gaussian means for noise model by -|tmp2_s16| and update
|
||||
// |noise_global_mean|. Note that |self->noise_means[channel]| is
|
||||
// changed after the call.
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel],
|
||||
-tmp2_s16,
|
||||
&kNoiseDataWeights[channel]);
|
||||
}
|
||||
|
||||
// Control that the speech & noise means do not drift to much.
|
||||
maxspe = kMaximumSpeech[channel];
|
||||
tmp2_s16 = (int16_t) (speech_global_mean >> 7);
|
||||
if (tmp2_s16 > maxspe) {
|
||||
// Upper limit of speech model.
|
||||
tmp2_s16 -= maxspe;
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
self->speech_means[channel + k * kNumChannels] -= tmp2_s16;
|
||||
}
|
||||
}
|
||||
|
||||
tmp2_s16 = (int16_t) (noise_global_mean >> 7);
|
||||
if (tmp2_s16 > kMaximumNoise[channel]) {
|
||||
tmp2_s16 -= kMaximumNoise[channel];
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
self->noise_means[channel + k * kNumChannels] -= tmp2_s16;
|
||||
}
|
||||
}
|
||||
}
|
||||
self->frame_counter++;
|
||||
}
|
||||
|
||||
// Smooth with respect to transition hysteresis.
|
||||
if (!vadflag) {
|
||||
if (self->over_hang > 0) {
|
||||
vadflag = 2 + self->over_hang;
|
||||
self->over_hang--;
|
||||
}
|
||||
self->num_of_speech = 0;
|
||||
} else {
|
||||
self->num_of_speech++;
|
||||
if (self->num_of_speech > kMaxSpeechFrames) {
|
||||
self->num_of_speech = kMaxSpeechFrames;
|
||||
self->over_hang = overhead2;
|
||||
} else {
|
||||
self->over_hang = overhead1;
|
||||
}
|
||||
}
|
||||
return vadflag;
|
||||
}
|
||||
|
||||
// Initialize the VAD. Set aggressiveness mode to default value.
|
||||
int WebRtcVad_InitCore(VadInstT* self) {
|
||||
int i;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialization of general struct variables.
|
||||
self->vad = 1; // Speech active (=1).
|
||||
self->frame_counter = 0;
|
||||
self->over_hang = 0;
|
||||
self->num_of_speech = 0;
|
||||
|
||||
// Initialization of downsampling filter state.
|
||||
memset(self->downsampling_filter_states, 0,
|
||||
sizeof(self->downsampling_filter_states));
|
||||
|
||||
// Initialization of 48 to 8 kHz downsampling.
|
||||
WebRtcSpl_ResetResample48khzTo8khz(&self->state_48_to_8);
|
||||
|
||||
// Read initial PDF parameters.
|
||||
for (i = 0; i < kTableSize; i++) {
|
||||
self->noise_means[i] = kNoiseDataMeans[i];
|
||||
self->speech_means[i] = kSpeechDataMeans[i];
|
||||
self->noise_stds[i] = kNoiseDataStds[i];
|
||||
self->speech_stds[i] = kSpeechDataStds[i];
|
||||
}
|
||||
|
||||
// Initialize Index and Minimum value vectors.
|
||||
for (i = 0; i < 16 * kNumChannels; i++) {
|
||||
self->low_value_vector[i] = 10000;
|
||||
self->index_vector[i] = 0;
|
||||
}
|
||||
|
||||
// Initialize splitting filter states.
|
||||
memset(self->upper_state, 0, sizeof(self->upper_state));
|
||||
memset(self->lower_state, 0, sizeof(self->lower_state));
|
||||
|
||||
// Initialize high pass filter states.
|
||||
memset(self->hp_filter_state, 0, sizeof(self->hp_filter_state));
|
||||
|
||||
// Initialize mean value memory, for WebRtcVad_FindMinimum().
|
||||
for (i = 0; i < kNumChannels; i++) {
|
||||
self->mean_value[i] = 1600;
|
||||
}
|
||||
|
||||
// Set aggressiveness mode to default (=|kDefaultMode|).
|
||||
if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->init_flag = kInitCheck;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set aggressiveness mode
|
||||
int WebRtcVad_set_mode_core(VadInstT* self, int mode) {
|
||||
int return_value = 0;
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
// Quality mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1Q,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2Q,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdQ,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdQ,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
case 1:
|
||||
// Low bitrate mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1LBR,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2LBR,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdLBR,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdLBR,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
case 2:
|
||||
// Aggressive mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1AGG,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2AGG,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdAGG,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdAGG,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
case 3:
|
||||
// Very aggressive mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1VAG,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2VAG,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdVAG,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdVAG,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
default:
|
||||
return_value = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Calculate VAD decision by first extracting feature values and then calculate
|
||||
// probability for both speech and background noise.
|
||||
|
||||
int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length) {
|
||||
int vad;
|
||||
size_t i;
|
||||
int16_t speech_nb[240]; // 30 ms in 8 kHz.
|
||||
// |tmp_mem| is a temporary memory used by resample function, length is
|
||||
// frame length in 10 ms (480 samples) + 256 extra.
|
||||
int32_t tmp_mem[480 + 256] = { 0 };
|
||||
const size_t kFrameLen10ms48khz = 480;
|
||||
const size_t kFrameLen10ms8khz = 80;
|
||||
size_t num_10ms_frames = frame_length / kFrameLen10ms48khz;
|
||||
|
||||
for (i = 0; i < num_10ms_frames; i++) {
|
||||
WebRtcSpl_Resample48khzTo8khz(speech_frame,
|
||||
&speech_nb[i * kFrameLen10ms8khz],
|
||||
&inst->state_48_to_8,
|
||||
tmp_mem);
|
||||
}
|
||||
|
||||
// Do VAD on an 8 kHz signal
|
||||
vad = WebRtcVad_CalcVad8khz(inst, speech_nb, frame_length / 6);
|
||||
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length)
|
||||
{
|
||||
size_t len;
|
||||
int vad;
|
||||
int16_t speechWB[480]; // Downsampled speech frame: 960 samples (30ms in SWB)
|
||||
int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB)
|
||||
|
||||
|
||||
// Downsample signal 32->16->8 before doing VAD
|
||||
WebRtcVad_Downsampling(speech_frame, speechWB, &(inst->downsampling_filter_states[2]),
|
||||
frame_length);
|
||||
len = frame_length / 2;
|
||||
|
||||
WebRtcVad_Downsampling(speechWB, speechNB, inst->downsampling_filter_states, len);
|
||||
len /= 2;
|
||||
|
||||
// Do VAD on an 8 kHz signal
|
||||
vad = WebRtcVad_CalcVad8khz(inst, speechNB, len);
|
||||
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length)
|
||||
{
|
||||
size_t len;
|
||||
int vad;
|
||||
int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB)
|
||||
|
||||
// Wideband: Downsample signal before doing VAD
|
||||
WebRtcVad_Downsampling(speech_frame, speechNB, inst->downsampling_filter_states,
|
||||
frame_length);
|
||||
|
||||
len = frame_length / 2;
|
||||
vad = WebRtcVad_CalcVad8khz(inst, speechNB, len);
|
||||
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length)
|
||||
{
|
||||
int16_t feature_vector[kNumChannels], total_power;
|
||||
|
||||
// Get power in the bands
|
||||
total_power = WebRtcVad_CalculateFeatures(inst, speech_frame, frame_length,
|
||||
feature_vector);
|
||||
|
||||
// Make a VAD
|
||||
inst->vad = GmmProbability(inst, feature_vector, total_power, frame_length);
|
||||
|
||||
return inst->vad;
|
||||
}
|
115
webrtc/common_audio/vad/vad_core.h
Normal file
115
webrtc/common_audio/vad/vad_core.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the descriptions of the core VAD calls.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
enum { kNumChannels = 6 }; // Number of frequency bands (named channels).
|
||||
enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM.
|
||||
enum { kTableSize = kNumChannels * kNumGaussians };
|
||||
enum { kMinEnergy = 10 }; // Minimum energy required to trigger audio signal.
|
||||
|
||||
typedef struct VadInstT_
|
||||
{
|
||||
|
||||
int vad;
|
||||
int32_t downsampling_filter_states[4];
|
||||
WebRtcSpl_State48khzTo8khz state_48_to_8;
|
||||
int16_t noise_means[kTableSize];
|
||||
int16_t speech_means[kTableSize];
|
||||
int16_t noise_stds[kTableSize];
|
||||
int16_t speech_stds[kTableSize];
|
||||
// TODO(bjornv): Change to |frame_count|.
|
||||
int32_t frame_counter;
|
||||
int16_t over_hang; // Over Hang
|
||||
int16_t num_of_speech;
|
||||
// TODO(bjornv): Change to |age_vector|.
|
||||
int16_t index_vector[16 * kNumChannels];
|
||||
int16_t low_value_vector[16 * kNumChannels];
|
||||
// TODO(bjornv): Change to |median|.
|
||||
int16_t mean_value[kNumChannels];
|
||||
int16_t upper_state[5];
|
||||
int16_t lower_state[5];
|
||||
int16_t hp_filter_state[4];
|
||||
int16_t over_hang_max_1[3];
|
||||
int16_t over_hang_max_2[3];
|
||||
int16_t individual[3];
|
||||
int16_t total[3];
|
||||
|
||||
int init_flag;
|
||||
|
||||
} VadInstT;
|
||||
|
||||
// Initializes the core VAD component. The default aggressiveness mode is
|
||||
// controlled by |kDefaultMode| in vad_core.c.
|
||||
//
|
||||
// - self [i/o] : Instance that should be initialized
|
||||
//
|
||||
// returns : 0 (OK), -1 (NULL pointer in or if the default mode can't be
|
||||
// set)
|
||||
int WebRtcVad_InitCore(VadInstT* self);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_set_mode_core(...)
|
||||
*
|
||||
* This function changes the VAD settings
|
||||
*
|
||||
* Input:
|
||||
* - inst : VAD instance
|
||||
* - mode : Aggressiveness degree
|
||||
* 0 (High quality) - 3 (Highly aggressive)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Changed instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcVad_set_mode_core(VadInstT* self, int mode);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_CalcVad48khz(...)
|
||||
* WebRtcVad_CalcVad32khz(...)
|
||||
* WebRtcVad_CalcVad16khz(...)
|
||||
* WebRtcVad_CalcVad8khz(...)
|
||||
*
|
||||
* Calculate probability for active speech and make VAD decision.
|
||||
*
|
||||
* Input:
|
||||
* - inst : Instance that should be initialized
|
||||
* - speech_frame : Input speech frame
|
||||
* - frame_length : Number of input samples
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated filter states etc.
|
||||
*
|
||||
* Return value : VAD decision
|
||||
* 0 - No active speech
|
||||
* 1-6 - Active speech
|
||||
*/
|
||||
int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length);
|
||||
int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length);
|
||||
int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length);
|
||||
int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
size_t frame_length);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
|
95
webrtc/common_audio/vad/vad_defines.h
Normal file
95
webrtc/common_audio/vad/vad_defines.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the macros used in VAD.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_VAD_DEFINES_H_
|
||||
#define WEBRTC_VAD_DEFINES_H_
|
||||
|
||||
#define NUM_CHANNELS 6 // Eight frequency bands
|
||||
#define NUM_MODELS 2 // Number of Gaussian models
|
||||
#define NUM_TABLE_VALUES NUM_CHANNELS * NUM_MODELS
|
||||
|
||||
#define MIN_ENERGY 10
|
||||
#define ALPHA1 6553 // 0.2 in Q15
|
||||
#define ALPHA2 32439 // 0.99 in Q15
|
||||
#define NSP_MAX 6 // Maximum number of VAD=1 frames in a row counted
|
||||
#define MIN_STD 384 // Minimum standard deviation
|
||||
// Mode 0, Quality thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_Q 24
|
||||
#define INDIVIDUAL_20MS_Q 21 // (log10(2)*66)<<2 ~=16
|
||||
#define INDIVIDUAL_30MS_Q 24
|
||||
|
||||
#define TOTAL_10MS_Q 57
|
||||
#define TOTAL_20MS_Q 48
|
||||
#define TOTAL_30MS_Q 57
|
||||
|
||||
#define OHMAX1_10MS_Q 8 // Max Overhang 1
|
||||
#define OHMAX2_10MS_Q 14 // Max Overhang 2
|
||||
#define OHMAX1_20MS_Q 4 // Max Overhang 1
|
||||
#define OHMAX2_20MS_Q 7 // Max Overhang 2
|
||||
#define OHMAX1_30MS_Q 3
|
||||
#define OHMAX2_30MS_Q 5
|
||||
|
||||
// Mode 1, Low bitrate thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_LBR 37
|
||||
#define INDIVIDUAL_20MS_LBR 32
|
||||
#define INDIVIDUAL_30MS_LBR 37
|
||||
|
||||
#define TOTAL_10MS_LBR 100
|
||||
#define TOTAL_20MS_LBR 80
|
||||
#define TOTAL_30MS_LBR 100
|
||||
|
||||
#define OHMAX1_10MS_LBR 8 // Max Overhang 1
|
||||
#define OHMAX2_10MS_LBR 14 // Max Overhang 2
|
||||
#define OHMAX1_20MS_LBR 4
|
||||
#define OHMAX2_20MS_LBR 7
|
||||
|
||||
#define OHMAX1_30MS_LBR 3
|
||||
#define OHMAX2_30MS_LBR 5
|
||||
|
||||
// Mode 2, Very aggressive thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_AGG 82
|
||||
#define INDIVIDUAL_20MS_AGG 78
|
||||
#define INDIVIDUAL_30MS_AGG 82
|
||||
|
||||
#define TOTAL_10MS_AGG 285 //580
|
||||
#define TOTAL_20MS_AGG 260
|
||||
#define TOTAL_30MS_AGG 285
|
||||
|
||||
#define OHMAX1_10MS_AGG 6 // Max Overhang 1
|
||||
#define OHMAX2_10MS_AGG 9 // Max Overhang 2
|
||||
#define OHMAX1_20MS_AGG 3
|
||||
#define OHMAX2_20MS_AGG 5
|
||||
|
||||
#define OHMAX1_30MS_AGG 2
|
||||
#define OHMAX2_30MS_AGG 3
|
||||
|
||||
// Mode 3, Super aggressive thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_VAG 94
|
||||
#define INDIVIDUAL_20MS_VAG 94
|
||||
#define INDIVIDUAL_30MS_VAG 94
|
||||
|
||||
#define TOTAL_10MS_VAG 1100 //1700
|
||||
#define TOTAL_20MS_VAG 1050
|
||||
#define TOTAL_30MS_VAG 1100
|
||||
|
||||
#define OHMAX1_10MS_VAG 6 // Max Overhang 1
|
||||
#define OHMAX2_10MS_VAG 9 // Max Overhang 2
|
||||
#define OHMAX1_20MS_VAG 3
|
||||
#define OHMAX2_20MS_VAG 5
|
||||
|
||||
#define OHMAX1_30MS_VAG 2
|
||||
#define OHMAX2_30MS_VAG 3
|
||||
|
||||
#endif // WEBRTC_VAD_DEFINES_H_
|
331
webrtc/common_audio/vad/vad_filterbank.c
Normal file
331
webrtc/common_audio/vad/vad_filterbank.c
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/vad/vad_filterbank.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Constants used in LogOfEnergy().
|
||||
static const int16_t kLogConst = 24660; // 160*log10(2) in Q9.
|
||||
static const int16_t kLogEnergyIntPart = 14336; // 14 in Q10
|
||||
|
||||
// Coefficients used by HighPassFilter, Q14.
|
||||
static const int16_t kHpZeroCoefs[3] = { 6631, -13262, 6631 };
|
||||
static const int16_t kHpPoleCoefs[3] = { 16384, -7756, 5620 };
|
||||
|
||||
// Allpass filter coefficients, upper and lower, in Q15.
|
||||
// Upper: 0.64, Lower: 0.17
|
||||
static const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 };
|
||||
|
||||
// Adjustment for division with two in SplitFilter.
|
||||
static const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 };
|
||||
|
||||
// High pass filtering, with a cut-off frequency at 80 Hz, if the |data_in| is
|
||||
// sampled at 500 Hz.
|
||||
//
|
||||
// - data_in [i] : Input audio data sampled at 500 Hz.
|
||||
// - data_length [i] : Length of input and output data.
|
||||
// - filter_state [i/o] : State of the filter.
|
||||
// - data_out [o] : Output audio data in the frequency interval
|
||||
// 80 - 250 Hz.
|
||||
static void HighPassFilter(const int16_t* data_in, size_t data_length,
|
||||
int16_t* filter_state, int16_t* data_out) {
|
||||
size_t i;
|
||||
const int16_t* in_ptr = data_in;
|
||||
int16_t* out_ptr = data_out;
|
||||
int32_t tmp32 = 0;
|
||||
|
||||
|
||||
// The sum of the absolute values of the impulse response:
|
||||
// The zero/pole-filter has a max amplification of a single sample of: 1.4546
|
||||
// Impulse response: 0.4047 -0.6179 -0.0266 0.1993 0.1035 -0.0194
|
||||
// The all-zero section has a max amplification of a single sample of: 1.6189
|
||||
// Impulse response: 0.4047 -0.8094 0.4047 0 0 0
|
||||
// The all-pole section has a max amplification of a single sample of: 1.9931
|
||||
// Impulse response: 1.0000 0.4734 -0.1189 -0.2187 -0.0627 0.04532
|
||||
|
||||
for (i = 0; i < data_length; i++) {
|
||||
// All-zero section (filter coefficients in Q14).
|
||||
tmp32 = kHpZeroCoefs[0] * *in_ptr;
|
||||
tmp32 += kHpZeroCoefs[1] * filter_state[0];
|
||||
tmp32 += kHpZeroCoefs[2] * filter_state[1];
|
||||
filter_state[1] = filter_state[0];
|
||||
filter_state[0] = *in_ptr++;
|
||||
|
||||
// All-pole section (filter coefficients in Q14).
|
||||
tmp32 -= kHpPoleCoefs[1] * filter_state[2];
|
||||
tmp32 -= kHpPoleCoefs[2] * filter_state[3];
|
||||
filter_state[3] = filter_state[2];
|
||||
filter_state[2] = (int16_t) (tmp32 >> 14);
|
||||
*out_ptr++ = filter_state[2];
|
||||
}
|
||||
}
|
||||
|
||||
// All pass filtering of |data_in|, used before splitting the signal into two
|
||||
// frequency bands (low pass vs high pass).
|
||||
// Note that |data_in| and |data_out| can NOT correspond to the same address.
|
||||
//
|
||||
// - data_in [i] : Input audio signal given in Q0.
|
||||
// - data_length [i] : Length of input and output data.
|
||||
// - filter_coefficient [i] : Given in Q15.
|
||||
// - filter_state [i/o] : State of the filter given in Q(-1).
|
||||
// - data_out [o] : Output audio signal given in Q(-1).
|
||||
static void AllPassFilter(const int16_t* data_in, size_t data_length,
|
||||
int16_t filter_coefficient, int16_t* filter_state,
|
||||
int16_t* data_out) {
|
||||
// The filter can only cause overflow (in the w16 output variable)
|
||||
// if more than 4 consecutive input numbers are of maximum value and
|
||||
// has the the same sign as the impulse responses first taps.
|
||||
// First 6 taps of the impulse response:
|
||||
// 0.6399 0.5905 -0.3779 0.2418 -0.1547 0.0990
|
||||
|
||||
size_t i;
|
||||
int16_t tmp16 = 0;
|
||||
int32_t tmp32 = 0;
|
||||
int32_t state32 = ((int32_t) (*filter_state) << 16); // Q15
|
||||
|
||||
for (i = 0; i < data_length; i++) {
|
||||
tmp32 = state32 + filter_coefficient * *data_in;
|
||||
tmp16 = (int16_t) (tmp32 >> 16); // Q(-1)
|
||||
*data_out++ = tmp16;
|
||||
state32 = (*data_in << 14) - filter_coefficient * tmp16; // Q14
|
||||
state32 <<= 1; // Q15.
|
||||
data_in += 2;
|
||||
}
|
||||
|
||||
*filter_state = (int16_t) (state32 >> 16); // Q(-1)
|
||||
}
|
||||
|
||||
// Splits |data_in| into |hp_data_out| and |lp_data_out| corresponding to
|
||||
// an upper (high pass) part and a lower (low pass) part respectively.
|
||||
//
|
||||
// - data_in [i] : Input audio data to be split into two frequency bands.
|
||||
// - data_length [i] : Length of |data_in|.
|
||||
// - upper_state [i/o] : State of the upper filter, given in Q(-1).
|
||||
// - lower_state [i/o] : State of the lower filter, given in Q(-1).
|
||||
// - hp_data_out [o] : Output audio data of the upper half of the spectrum.
|
||||
// The length is |data_length| / 2.
|
||||
// - lp_data_out [o] : Output audio data of the lower half of the spectrum.
|
||||
// The length is |data_length| / 2.
|
||||
static void SplitFilter(const int16_t* data_in, size_t data_length,
|
||||
int16_t* upper_state, int16_t* lower_state,
|
||||
int16_t* hp_data_out, int16_t* lp_data_out) {
|
||||
size_t i;
|
||||
size_t half_length = data_length >> 1; // Downsampling by 2.
|
||||
int16_t tmp_out;
|
||||
|
||||
// All-pass filtering upper branch.
|
||||
AllPassFilter(&data_in[0], half_length, kAllPassCoefsQ15[0], upper_state,
|
||||
hp_data_out);
|
||||
|
||||
// All-pass filtering lower branch.
|
||||
AllPassFilter(&data_in[1], half_length, kAllPassCoefsQ15[1], lower_state,
|
||||
lp_data_out);
|
||||
|
||||
// Make LP and HP signals.
|
||||
for (i = 0; i < half_length; i++) {
|
||||
tmp_out = *hp_data_out;
|
||||
*hp_data_out++ -= *lp_data_out;
|
||||
*lp_data_out++ += tmp_out;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates the energy of |data_in| in dB, and also updates an overall
|
||||
// |total_energy| if necessary.
|
||||
//
|
||||
// - data_in [i] : Input audio data for energy calculation.
|
||||
// - data_length [i] : Length of input data.
|
||||
// - offset [i] : Offset value added to |log_energy|.
|
||||
// - total_energy [i/o] : An external energy updated with the energy of
|
||||
// |data_in|.
|
||||
// NOTE: |total_energy| is only updated if
|
||||
// |total_energy| <= |kMinEnergy|.
|
||||
// - log_energy [o] : 10 * log10("energy of |data_in|") given in Q4.
|
||||
static void LogOfEnergy(const int16_t* data_in, size_t data_length,
|
||||
int16_t offset, int16_t* total_energy,
|
||||
int16_t* log_energy) {
|
||||
// |tot_rshifts| accumulates the number of right shifts performed on |energy|.
|
||||
int tot_rshifts = 0;
|
||||
// The |energy| will be normalized to 15 bits. We use unsigned integer because
|
||||
// we eventually will mask out the fractional part.
|
||||
uint32_t energy = 0;
|
||||
|
||||
assert(data_in != NULL);
|
||||
assert(data_length > 0);
|
||||
|
||||
energy = (uint32_t) WebRtcSpl_Energy((int16_t*) data_in, data_length,
|
||||
&tot_rshifts);
|
||||
|
||||
if (energy != 0) {
|
||||
// By construction, normalizing to 15 bits is equivalent with 17 leading
|
||||
// zeros of an unsigned 32 bit value.
|
||||
int normalizing_rshifts = 17 - WebRtcSpl_NormU32(energy);
|
||||
// In a 15 bit representation the leading bit is 2^14. log2(2^14) in Q10 is
|
||||
// (14 << 10), which is what we initialize |log2_energy| with. For a more
|
||||
// detailed derivations, see below.
|
||||
int16_t log2_energy = kLogEnergyIntPart;
|
||||
|
||||
tot_rshifts += normalizing_rshifts;
|
||||
// Normalize |energy| to 15 bits.
|
||||
// |tot_rshifts| is now the total number of right shifts performed on
|
||||
// |energy| after normalization. This means that |energy| is in
|
||||
// Q(-tot_rshifts).
|
||||
if (normalizing_rshifts < 0) {
|
||||
energy <<= -normalizing_rshifts;
|
||||
} else {
|
||||
energy >>= normalizing_rshifts;
|
||||
}
|
||||
|
||||
// Calculate the energy of |data_in| in dB, in Q4.
|
||||
//
|
||||
// 10 * log10("true energy") in Q4 = 2^4 * 10 * log10("true energy") =
|
||||
// 160 * log10(|energy| * 2^|tot_rshifts|) =
|
||||
// 160 * log10(2) * log2(|energy| * 2^|tot_rshifts|) =
|
||||
// 160 * log10(2) * (log2(|energy|) + log2(2^|tot_rshifts|)) =
|
||||
// (160 * log10(2)) * (log2(|energy|) + |tot_rshifts|) =
|
||||
// |kLogConst| * (|log2_energy| + |tot_rshifts|)
|
||||
//
|
||||
// We know by construction that |energy| is normalized to 15 bits. Hence,
|
||||
// |energy| = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15.
|
||||
// Further, we'd like |log2_energy| in Q10
|
||||
// log2(|energy|) in Q10 = 2^10 * log2(2^14 + frac_Q15) =
|
||||
// 2^10 * log2(2^14 * (1 + frac_Q15 * 2^-14)) =
|
||||
// 2^10 * (14 + log2(1 + frac_Q15 * 2^-14)) ~=
|
||||
// (14 << 10) + 2^10 * (frac_Q15 * 2^-14) =
|
||||
// (14 << 10) + (frac_Q15 * 2^-4) = (14 << 10) + (frac_Q15 >> 4)
|
||||
//
|
||||
// Note that frac_Q15 = (|energy| & 0x00003FFF)
|
||||
|
||||
// Calculate and add the fractional part to |log2_energy|.
|
||||
log2_energy += (int16_t) ((energy & 0x00003FFF) >> 4);
|
||||
|
||||
// |kLogConst| is in Q9, |log2_energy| in Q10 and |tot_rshifts| in Q0.
|
||||
// Note that we in our derivation above have accounted for an output in Q4.
|
||||
*log_energy = (int16_t)(((kLogConst * log2_energy) >> 19) +
|
||||
((tot_rshifts * kLogConst) >> 9));
|
||||
|
||||
if (*log_energy < 0) {
|
||||
*log_energy = 0;
|
||||
}
|
||||
} else {
|
||||
*log_energy = offset;
|
||||
return;
|
||||
}
|
||||
|
||||
*log_energy += offset;
|
||||
|
||||
// Update the approximate |total_energy| with the energy of |data_in|, if
|
||||
// |total_energy| has not exceeded |kMinEnergy|. |total_energy| is used as an
|
||||
// energy indicator in WebRtcVad_GmmProbability() in vad_core.c.
|
||||
if (*total_energy <= kMinEnergy) {
|
||||
if (tot_rshifts >= 0) {
|
||||
// We know by construction that the |energy| > |kMinEnergy| in Q0, so add
|
||||
// an arbitrary value such that |total_energy| exceeds |kMinEnergy|.
|
||||
*total_energy += kMinEnergy + 1;
|
||||
} else {
|
||||
// By construction |energy| is represented by 15 bits, hence any number of
|
||||
// right shifted |energy| will fit in an int16_t. In addition, adding the
|
||||
// value to |total_energy| is wrap around safe as long as
|
||||
// |kMinEnergy| < 8192.
|
||||
*total_energy += (int16_t) (energy >> -tot_rshifts); // Q0.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
size_t data_length, int16_t* features) {
|
||||
int16_t total_energy = 0;
|
||||
// We expect |data_length| to be 80, 160 or 240 samples, which corresponds to
|
||||
// 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will
|
||||
// have at most 120 samples after the first split and at most 60 samples after
|
||||
// the second split.
|
||||
int16_t hp_120[120], lp_120[120];
|
||||
int16_t hp_60[60], lp_60[60];
|
||||
const size_t half_data_length = data_length >> 1;
|
||||
size_t length = half_data_length; // |data_length| / 2, corresponds to
|
||||
// bandwidth = 2000 Hz after downsampling.
|
||||
|
||||
// Initialize variables for the first SplitFilter().
|
||||
int frequency_band = 0;
|
||||
const int16_t* in_ptr = data_in; // [0 - 4000] Hz.
|
||||
int16_t* hp_out_ptr = hp_120; // [2000 - 4000] Hz.
|
||||
int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz.
|
||||
|
||||
assert(data_length <= 240);
|
||||
assert(4 < kNumChannels - 1); // Checking maximum |frequency_band|.
|
||||
|
||||
// Split at 2000 Hz and downsample.
|
||||
SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// For the upper band (2000 Hz - 4000 Hz) split at 3000 Hz and downsample.
|
||||
frequency_band = 1;
|
||||
in_ptr = hp_120; // [2000 - 4000] Hz.
|
||||
hp_out_ptr = hp_60; // [3000 - 4000] Hz.
|
||||
lp_out_ptr = lp_60; // [2000 - 3000] Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 3000 Hz - 4000 Hz.
|
||||
length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz.
|
||||
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[5], &total_energy, &features[5]);
|
||||
|
||||
// Energy in 2000 Hz - 3000 Hz.
|
||||
LogOfEnergy(lp_60, length, kOffsetVector[4], &total_energy, &features[4]);
|
||||
|
||||
// For the lower band (0 Hz - 2000 Hz) split at 1000 Hz and downsample.
|
||||
frequency_band = 2;
|
||||
in_ptr = lp_120; // [0 - 2000] Hz.
|
||||
hp_out_ptr = hp_60; // [1000 - 2000] Hz.
|
||||
lp_out_ptr = lp_60; // [0 - 1000] Hz.
|
||||
length = half_data_length; // |data_length| / 2 <=> bandwidth = 2000 Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 1000 Hz - 2000 Hz.
|
||||
length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz.
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[3], &total_energy, &features[3]);
|
||||
|
||||
// For the lower band (0 Hz - 1000 Hz) split at 500 Hz and downsample.
|
||||
frequency_band = 3;
|
||||
in_ptr = lp_60; // [0 - 1000] Hz.
|
||||
hp_out_ptr = hp_120; // [500 - 1000] Hz.
|
||||
lp_out_ptr = lp_120; // [0 - 500] Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 500 Hz - 1000 Hz.
|
||||
length >>= 1; // |data_length| / 8 <=> bandwidth = 500 Hz.
|
||||
LogOfEnergy(hp_120, length, kOffsetVector[2], &total_energy, &features[2]);
|
||||
|
||||
// For the lower band (0 Hz - 500 Hz) split at 250 Hz and downsample.
|
||||
frequency_band = 4;
|
||||
in_ptr = lp_120; // [0 - 500] Hz.
|
||||
hp_out_ptr = hp_60; // [250 - 500] Hz.
|
||||
lp_out_ptr = lp_60; // [0 - 250] Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 250 Hz - 500 Hz.
|
||||
length >>= 1; // |data_length| / 16 <=> bandwidth = 250 Hz.
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[1], &total_energy, &features[1]);
|
||||
|
||||
// Remove 0 Hz - 80 Hz, by high pass filtering the lower band.
|
||||
HighPassFilter(lp_60, length, self->hp_filter_state, hp_120);
|
||||
|
||||
// Energy in 80 Hz - 250 Hz.
|
||||
LogOfEnergy(hp_120, length, kOffsetVector[0], &total_energy, &features[0]);
|
||||
|
||||
return total_energy;
|
||||
}
|
44
webrtc/common_audio/vad/vad_filterbank.h
Normal file
44
webrtc/common_audio/vad/vad_filterbank.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file includes feature calculating functionality used in vad_core.c.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
|
||||
|
||||
#include "webrtc/common_audio/vad/vad_core.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Takes |data_length| samples of |data_in| and calculates the logarithm of the
|
||||
// energy of each of the |kNumChannels| = 6 frequency bands used by the VAD:
|
||||
// 80 Hz - 250 Hz
|
||||
// 250 Hz - 500 Hz
|
||||
// 500 Hz - 1000 Hz
|
||||
// 1000 Hz - 2000 Hz
|
||||
// 2000 Hz - 3000 Hz
|
||||
// 3000 Hz - 4000 Hz
|
||||
//
|
||||
// The values are given in Q4 and written to |features|. Further, an approximate
|
||||
// overall energy is returned. The return value is used in
|
||||
// WebRtcVad_GmmProbability() as a signal indicator, hence it is arbitrary above
|
||||
// the threshold |kMinEnergy|.
|
||||
//
|
||||
// - self [i/o] : State information of the VAD.
|
||||
// - data_in [i] : Input audio data, for feature extraction.
|
||||
// - data_length [i] : Audio data size, in number of samples.
|
||||
// - features [o] : 10 * log10(energy in each frequency band), Q4.
|
||||
// - returns : Total energy of the signal (NOTE! This value is not
|
||||
// exact. It is only used in a comparison.)
|
||||
int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
size_t data_length, int16_t* features);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
|
83
webrtc/common_audio/vad/vad_gmm.c
Normal file
83
webrtc/common_audio/vad/vad_gmm.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/vad/vad_gmm.h"
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
static const int32_t kCompVar = 22005;
|
||||
static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12.
|
||||
|
||||
// For a normal distribution, the probability of |input| is calculated and
|
||||
// returned (in Q20). The formula for normal distributed probability is
|
||||
//
|
||||
// 1 / s * exp(-(x - m)^2 / (2 * s^2))
|
||||
//
|
||||
// where the parameters are given in the following Q domains:
|
||||
// m = |mean| (Q7)
|
||||
// s = |std| (Q7)
|
||||
// x = |input| (Q4)
|
||||
// in addition to the probability we output |delta| (in Q11) used when updating
|
||||
// the noise/speech model.
|
||||
int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t mean,
|
||||
int16_t std,
|
||||
int16_t* delta) {
|
||||
int16_t tmp16, inv_std, inv_std2, exp_value = 0;
|
||||
int32_t tmp32;
|
||||
|
||||
// Calculate |inv_std| = 1 / s, in Q10.
|
||||
// 131072 = 1 in Q17, and (|std| >> 1) is for rounding instead of truncation.
|
||||
// Q-domain: Q17 / Q7 = Q10.
|
||||
tmp32 = (int32_t) 131072 + (int32_t) (std >> 1);
|
||||
inv_std = (int16_t) WebRtcSpl_DivW32W16(tmp32, std);
|
||||
|
||||
// Calculate |inv_std2| = 1 / s^2, in Q14.
|
||||
tmp16 = (inv_std >> 2); // Q10 -> Q8.
|
||||
// Q-domain: (Q8 * Q8) >> 2 = Q14.
|
||||
inv_std2 = (int16_t)((tmp16 * tmp16) >> 2);
|
||||
// TODO(bjornv): Investigate if changing to
|
||||
// inv_std2 = (int16_t)((inv_std * inv_std) >> 6);
|
||||
// gives better accuracy.
|
||||
|
||||
tmp16 = (input << 3); // Q4 -> Q7
|
||||
tmp16 = tmp16 - mean; // Q7 - Q7 = Q7
|
||||
|
||||
// To be used later, when updating noise/speech model.
|
||||
// |delta| = (x - m) / s^2, in Q11.
|
||||
// Q-domain: (Q14 * Q7) >> 10 = Q11.
|
||||
*delta = (int16_t)((inv_std2 * tmp16) >> 10);
|
||||
|
||||
// Calculate the exponent |tmp32| = (x - m)^2 / (2 * s^2), in Q10. Replacing
|
||||
// division by two with one shift.
|
||||
// Q-domain: (Q11 * Q7) >> 8 = Q10.
|
||||
tmp32 = (*delta * tmp16) >> 9;
|
||||
|
||||
// If the exponent is small enough to give a non-zero probability we calculate
|
||||
// |exp_value| ~= exp(-(x - m)^2 / (2 * s^2))
|
||||
// ~= exp2(-log2(exp(1)) * |tmp32|).
|
||||
if (tmp32 < kCompVar) {
|
||||
// Calculate |tmp16| = log2(exp(1)) * |tmp32|, in Q10.
|
||||
// Q-domain: (Q12 * Q10) >> 12 = Q10.
|
||||
tmp16 = (int16_t)((kLog2Exp * tmp32) >> 12);
|
||||
tmp16 = -tmp16;
|
||||
exp_value = (0x0400 | (tmp16 & 0x03FF));
|
||||
tmp16 ^= 0xFFFF;
|
||||
tmp16 >>= 10;
|
||||
tmp16 += 1;
|
||||
// Get |exp_value| = exp(-|tmp32|) in Q10.
|
||||
exp_value >>= tmp16;
|
||||
}
|
||||
|
||||
// Calculate and return (1 / s) * exp(-(x - m)^2 / (2 * s^2)), in Q20.
|
||||
// Q-domain: Q10 * Q10 = Q20.
|
||||
return inv_std * exp_value;
|
||||
}
|
39
webrtc/common_audio/vad/vad_gmm.h
Normal file
39
webrtc/common_audio/vad/vad_gmm.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Gaussian probability calculations internally used in vad_core.c.
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Calculates the probability for |input|, given that |input| comes from a
|
||||
// normal distribution with mean and standard deviation (|mean|, |std|).
|
||||
//
|
||||
// Inputs:
|
||||
// - input : input sample in Q4.
|
||||
// - mean : mean input in the statistical model, Q7.
|
||||
// - std : standard deviation, Q7.
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// - delta : input used when updating the model, Q11.
|
||||
// |delta| = (|input| - |mean|) / |std|^2.
|
||||
//
|
||||
// Return:
|
||||
// (probability for |input|) =
|
||||
// 1 / |std| * exp(-(|input| - |mean|)^2 / (2 * |std|^2));
|
||||
int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t mean,
|
||||
int16_t std,
|
||||
int16_t* delta);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
|
178
webrtc/common_audio/vad/vad_sp.c
Normal file
178
webrtc/common_audio/vad/vad_sp.c
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/vad/vad_sp.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/common_audio/vad/vad_core.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Allpass filter coefficients, upper and lower, in Q13.
|
||||
// Upper: 0.64, Lower: 0.17.
|
||||
static const int16_t kAllPassCoefsQ13[2] = { 5243, 1392 }; // Q13.
|
||||
static const int16_t kSmoothingDown = 6553; // 0.2 in Q15.
|
||||
static const int16_t kSmoothingUp = 32439; // 0.99 in Q15.
|
||||
|
||||
// TODO(bjornv): Move this function to vad_filterbank.c.
|
||||
// Downsampling filter based on splitting filter and allpass functions.
|
||||
void WebRtcVad_Downsampling(const int16_t* signal_in,
|
||||
int16_t* signal_out,
|
||||
int32_t* filter_state,
|
||||
size_t in_length) {
|
||||
int16_t tmp16_1 = 0, tmp16_2 = 0;
|
||||
int32_t tmp32_1 = filter_state[0];
|
||||
int32_t tmp32_2 = filter_state[1];
|
||||
size_t n = 0;
|
||||
// Downsampling by 2 gives half length.
|
||||
size_t half_length = (in_length >> 1);
|
||||
|
||||
// Filter coefficients in Q13, filter state in Q0.
|
||||
for (n = 0; n < half_length; n++) {
|
||||
// All-pass filtering upper branch.
|
||||
tmp16_1 = (int16_t) ((tmp32_1 >> 1) +
|
||||
((kAllPassCoefsQ13[0] * *signal_in) >> 14));
|
||||
*signal_out = tmp16_1;
|
||||
tmp32_1 = (int32_t)(*signal_in++) - ((kAllPassCoefsQ13[0] * tmp16_1) >> 12);
|
||||
|
||||
// All-pass filtering lower branch.
|
||||
tmp16_2 = (int16_t) ((tmp32_2 >> 1) +
|
||||
((kAllPassCoefsQ13[1] * *signal_in) >> 14));
|
||||
*signal_out++ += tmp16_2;
|
||||
tmp32_2 = (int32_t)(*signal_in++) - ((kAllPassCoefsQ13[1] * tmp16_2) >> 12);
|
||||
}
|
||||
// Store the filter states.
|
||||
filter_state[0] = tmp32_1;
|
||||
filter_state[1] = tmp32_2;
|
||||
}
|
||||
|
||||
// Inserts |feature_value| into |low_value_vector|, if it is one of the 16
|
||||
// smallest values the last 100 frames. Then calculates and returns the median
|
||||
// of the five smallest values.
|
||||
int16_t WebRtcVad_FindMinimum(VadInstT* self,
|
||||
int16_t feature_value,
|
||||
int channel) {
|
||||
int i = 0, j = 0;
|
||||
int position = -1;
|
||||
// Offset to beginning of the 16 minimum values in memory.
|
||||
const int offset = (channel << 4);
|
||||
int16_t current_median = 1600;
|
||||
int16_t alpha = 0;
|
||||
int32_t tmp32 = 0;
|
||||
// Pointer to memory for the 16 minimum values and the age of each value of
|
||||
// the |channel|.
|
||||
int16_t* age = &self->index_vector[offset];
|
||||
int16_t* smallest_values = &self->low_value_vector[offset];
|
||||
|
||||
assert(channel < kNumChannels);
|
||||
|
||||
// Each value in |smallest_values| is getting 1 loop older. Update |age|, and
|
||||
// remove old values.
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (age[i] != 100) {
|
||||
age[i]++;
|
||||
} else {
|
||||
// Too old value. Remove from memory and shift larger values downwards.
|
||||
for (j = i; j < 16; j++) {
|
||||
smallest_values[j] = smallest_values[j + 1];
|
||||
age[j] = age[j + 1];
|
||||
}
|
||||
age[15] = 101;
|
||||
smallest_values[15] = 10000;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if |feature_value| is smaller than any of the values in
|
||||
// |smallest_values|. If so, find the |position| where to insert the new value
|
||||
// (|feature_value|).
|
||||
if (feature_value < smallest_values[7]) {
|
||||
if (feature_value < smallest_values[3]) {
|
||||
if (feature_value < smallest_values[1]) {
|
||||
if (feature_value < smallest_values[0]) {
|
||||
position = 0;
|
||||
} else {
|
||||
position = 1;
|
||||
}
|
||||
} else if (feature_value < smallest_values[2]) {
|
||||
position = 2;
|
||||
} else {
|
||||
position = 3;
|
||||
}
|
||||
} else if (feature_value < smallest_values[5]) {
|
||||
if (feature_value < smallest_values[4]) {
|
||||
position = 4;
|
||||
} else {
|
||||
position = 5;
|
||||
}
|
||||
} else if (feature_value < smallest_values[6]) {
|
||||
position = 6;
|
||||
} else {
|
||||
position = 7;
|
||||
}
|
||||
} else if (feature_value < smallest_values[15]) {
|
||||
if (feature_value < smallest_values[11]) {
|
||||
if (feature_value < smallest_values[9]) {
|
||||
if (feature_value < smallest_values[8]) {
|
||||
position = 8;
|
||||
} else {
|
||||
position = 9;
|
||||
}
|
||||
} else if (feature_value < smallest_values[10]) {
|
||||
position = 10;
|
||||
} else {
|
||||
position = 11;
|
||||
}
|
||||
} else if (feature_value < smallest_values[13]) {
|
||||
if (feature_value < smallest_values[12]) {
|
||||
position = 12;
|
||||
} else {
|
||||
position = 13;
|
||||
}
|
||||
} else if (feature_value < smallest_values[14]) {
|
||||
position = 14;
|
||||
} else {
|
||||
position = 15;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have detected a new small value, insert it at the correct position
|
||||
// and shift larger values up.
|
||||
if (position > -1) {
|
||||
for (i = 15; i > position; i--) {
|
||||
smallest_values[i] = smallest_values[i - 1];
|
||||
age[i] = age[i - 1];
|
||||
}
|
||||
smallest_values[position] = feature_value;
|
||||
age[position] = 1;
|
||||
}
|
||||
|
||||
// Get |current_median|.
|
||||
if (self->frame_counter > 2) {
|
||||
current_median = smallest_values[2];
|
||||
} else if (self->frame_counter > 0) {
|
||||
current_median = smallest_values[0];
|
||||
}
|
||||
|
||||
// Smooth the median value.
|
||||
if (self->frame_counter > 0) {
|
||||
if (current_median < self->mean_value[channel]) {
|
||||
alpha = kSmoothingDown; // 0.2 in Q15.
|
||||
} else {
|
||||
alpha = kSmoothingUp; // 0.99 in Q15.
|
||||
}
|
||||
}
|
||||
tmp32 = (alpha + 1) * self->mean_value[channel];
|
||||
tmp32 += (WEBRTC_SPL_WORD16_MAX - alpha) * current_median;
|
||||
tmp32 += 16384;
|
||||
self->mean_value[channel] = (int16_t) (tmp32 >> 15);
|
||||
|
||||
return self->mean_value[channel];
|
||||
}
|
56
webrtc/common_audio/vad/vad_sp.h
Normal file
56
webrtc/common_audio/vad/vad_sp.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This file includes specific signal processing tools used in vad_core.c.
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
|
||||
|
||||
#include "webrtc/common_audio/vad/vad_core.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Downsamples the signal by a factor 2, eg. 32->16 or 16->8.
|
||||
//
|
||||
// Inputs:
|
||||
// - signal_in : Input signal.
|
||||
// - in_length : Length of input signal in samples.
|
||||
//
|
||||
// Input & Output:
|
||||
// - filter_state : Current filter states of the two all-pass filters. The
|
||||
// |filter_state| is updated after all samples have been
|
||||
// processed.
|
||||
//
|
||||
// Output:
|
||||
// - signal_out : Downsampled signal (of length |in_length| / 2).
|
||||
void WebRtcVad_Downsampling(const int16_t* signal_in,
|
||||
int16_t* signal_out,
|
||||
int32_t* filter_state,
|
||||
size_t in_length);
|
||||
|
||||
// Updates and returns the smoothed feature minimum. As minimum we use the
|
||||
// median of the five smallest feature values in a 100 frames long window.
|
||||
// As long as |handle->frame_counter| is zero, that is, we haven't received any
|
||||
// "valid" data, FindMinimum() outputs the default value of 1600.
|
||||
//
|
||||
// Inputs:
|
||||
// - feature_value : New feature value to update with.
|
||||
// - channel : Channel number.
|
||||
//
|
||||
// Input & Output:
|
||||
// - handle : State information of the VAD.
|
||||
//
|
||||
// Returns:
|
||||
// : Smoothed minimum value for a moving window.
|
||||
int16_t WebRtcVad_FindMinimum(VadInstT* handle,
|
||||
int16_t feature_value,
|
||||
int channel);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
|
116
webrtc/common_audio/vad/webrtc_vad.c
Normal file
116
webrtc/common_audio/vad/webrtc_vad.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/vad/include/webrtc_vad.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/common_audio/vad/vad_core.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
static const int kInitCheck = 42;
|
||||
static const int kValidRates[] = { 8000, 16000, 32000, 48000 };
|
||||
static const size_t kRatesSize = sizeof(kValidRates) / sizeof(*kValidRates);
|
||||
static const int kMaxFrameLengthMs = 30;
|
||||
|
||||
VadInst* WebRtcVad_Create() {
|
||||
VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT));
|
||||
|
||||
WebRtcSpl_Init();
|
||||
self->init_flag = 0;
|
||||
|
||||
return (VadInst*)self;
|
||||
}
|
||||
|
||||
void WebRtcVad_Free(VadInst* handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
// TODO(bjornv): Move WebRtcVad_InitCore() code here.
|
||||
int WebRtcVad_Init(VadInst* handle) {
|
||||
// Initialize the core VAD component.
|
||||
return WebRtcVad_InitCore((VadInstT*) handle);
|
||||
}
|
||||
|
||||
// TODO(bjornv): Move WebRtcVad_set_mode_core() code here.
|
||||
int WebRtcVad_set_mode(VadInst* handle, int mode) {
|
||||
VadInstT* self = (VadInstT*) handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (self->init_flag != kInitCheck) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return WebRtcVad_set_mode_core(self, mode);
|
||||
}
|
||||
|
||||
int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame,
|
||||
size_t frame_length) {
|
||||
int vad = -1;
|
||||
VadInstT* self = (VadInstT*) handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->init_flag != kInitCheck) {
|
||||
return -1;
|
||||
}
|
||||
if (audio_frame == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (WebRtcVad_ValidRateAndFrameLength(fs, frame_length) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs == 48000) {
|
||||
vad = WebRtcVad_CalcVad48khz(self, audio_frame, frame_length);
|
||||
} else if (fs == 32000) {
|
||||
vad = WebRtcVad_CalcVad32khz(self, audio_frame, frame_length);
|
||||
} else if (fs == 16000) {
|
||||
vad = WebRtcVad_CalcVad16khz(self, audio_frame, frame_length);
|
||||
} else if (fs == 8000) {
|
||||
vad = WebRtcVad_CalcVad8khz(self, audio_frame, frame_length);
|
||||
}
|
||||
|
||||
if (vad > 0) {
|
||||
vad = 1;
|
||||
}
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length) {
|
||||
int return_value = -1;
|
||||
size_t i;
|
||||
int valid_length_ms;
|
||||
size_t valid_length;
|
||||
|
||||
// We only allow 10, 20 or 30 ms frames. Loop through valid frame rates and
|
||||
// see if we have a matching pair.
|
||||
for (i = 0; i < kRatesSize; i++) {
|
||||
if (kValidRates[i] == rate) {
|
||||
for (valid_length_ms = 10; valid_length_ms <= kMaxFrameLengthMs;
|
||||
valid_length_ms += 10) {
|
||||
valid_length = (size_t)(kValidRates[i] / 1000 * valid_length_ms);
|
||||
if (frame_length == valid_length) {
|
||||
return_value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
903
webrtc/common_types.h
Normal file
903
webrtc/common_types.h
Normal file
@ -0,0 +1,903 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_TYPES_H_
|
||||
#define WEBRTC_COMMON_TYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Disable "new behavior: elements of array will be default initialized"
|
||||
// warning. Affects OverUseDetectorOptions.
|
||||
#pragma warning(disable:4351)
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_EXPORT
|
||||
#define WEBRTC_DLLEXPORT _declspec(dllexport)
|
||||
#elif WEBRTC_DLL
|
||||
#define WEBRTC_DLLEXPORT _declspec(dllimport)
|
||||
#else
|
||||
#define WEBRTC_DLLEXPORT
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define RTP_PAYLOAD_NAME_SIZE 32
|
||||
|
||||
#if defined(WEBRTC_WIN) || defined(WIN32)
|
||||
// Compares two strings without regard to case.
|
||||
#define STR_CASE_CMP(s1, s2) ::_stricmp(s1, s2)
|
||||
// Compares characters of two strings without regard to case.
|
||||
#define STR_NCASE_CMP(s1, s2, n) ::_strnicmp(s1, s2, n)
|
||||
#else
|
||||
#define STR_CASE_CMP(s1, s2) ::strcasecmp(s1, s2)
|
||||
#define STR_NCASE_CMP(s1, s2, n) ::strncasecmp(s1, s2, n)
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Config;
|
||||
|
||||
class InStream
|
||||
{
|
||||
public:
|
||||
// Reads |length| bytes from file to |buf|. Returns the number of bytes read
|
||||
// or -1 on error.
|
||||
virtual int Read(void *buf, size_t len) = 0;
|
||||
virtual int Rewind();
|
||||
virtual ~InStream() {}
|
||||
protected:
|
||||
InStream() {}
|
||||
};
|
||||
|
||||
class OutStream
|
||||
{
|
||||
public:
|
||||
// Writes |length| bytes from |buf| to file. The actual writing may happen
|
||||
// some time later. Call Flush() to force a write.
|
||||
virtual bool Write(const void *buf, size_t len) = 0;
|
||||
virtual int Rewind();
|
||||
virtual ~OutStream() {}
|
||||
protected:
|
||||
OutStream() {}
|
||||
};
|
||||
|
||||
enum TraceModule
|
||||
{
|
||||
kTraceUndefined = 0,
|
||||
// not a module, triggered from the engine code
|
||||
kTraceVoice = 0x0001,
|
||||
// not a module, triggered from the engine code
|
||||
kTraceVideo = 0x0002,
|
||||
// not a module, triggered from the utility code
|
||||
kTraceUtility = 0x0003,
|
||||
kTraceRtpRtcp = 0x0004,
|
||||
kTraceTransport = 0x0005,
|
||||
kTraceSrtp = 0x0006,
|
||||
kTraceAudioCoding = 0x0007,
|
||||
kTraceAudioMixerServer = 0x0008,
|
||||
kTraceAudioMixerClient = 0x0009,
|
||||
kTraceFile = 0x000a,
|
||||
kTraceAudioProcessing = 0x000b,
|
||||
kTraceVideoCoding = 0x0010,
|
||||
kTraceVideoMixer = 0x0011,
|
||||
kTraceAudioDevice = 0x0012,
|
||||
kTraceVideoRenderer = 0x0014,
|
||||
kTraceVideoCapture = 0x0015,
|
||||
kTraceRemoteBitrateEstimator = 0x0017,
|
||||
};
|
||||
|
||||
enum TraceLevel
|
||||
{
|
||||
kTraceNone = 0x0000, // no trace
|
||||
kTraceStateInfo = 0x0001,
|
||||
kTraceWarning = 0x0002,
|
||||
kTraceError = 0x0004,
|
||||
kTraceCritical = 0x0008,
|
||||
kTraceApiCall = 0x0010,
|
||||
kTraceDefault = 0x00ff,
|
||||
|
||||
kTraceModuleCall = 0x0020,
|
||||
kTraceMemory = 0x0100, // memory info
|
||||
kTraceTimer = 0x0200, // timing info
|
||||
kTraceStream = 0x0400, // "continuous" stream of data
|
||||
|
||||
// used for debug purposes
|
||||
kTraceDebug = 0x0800, // debug
|
||||
kTraceInfo = 0x1000, // debug info
|
||||
|
||||
// Non-verbose level used by LS_INFO of logging.h. Do not use directly.
|
||||
kTraceTerseInfo = 0x2000,
|
||||
|
||||
kTraceAll = 0xffff
|
||||
};
|
||||
|
||||
// External Trace API
|
||||
class TraceCallback {
|
||||
public:
|
||||
virtual void Print(TraceLevel level, const char* message, int length) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~TraceCallback() {}
|
||||
TraceCallback() {}
|
||||
};
|
||||
|
||||
enum FileFormats
|
||||
{
|
||||
kFileFormatWavFile = 1,
|
||||
kFileFormatCompressedFile = 2,
|
||||
kFileFormatPreencodedFile = 4,
|
||||
kFileFormatPcm16kHzFile = 7,
|
||||
kFileFormatPcm8kHzFile = 8,
|
||||
kFileFormatPcm32kHzFile = 9
|
||||
};
|
||||
|
||||
enum ProcessingTypes
|
||||
{
|
||||
kPlaybackPerChannel = 0,
|
||||
kPlaybackAllChannelsMixed,
|
||||
kRecordingPerChannel,
|
||||
kRecordingAllChannelsMixed,
|
||||
kRecordingPreprocessing
|
||||
};
|
||||
|
||||
enum FrameType
|
||||
{
|
||||
kFrameEmpty = 0,
|
||||
kAudioFrameSpeech = 1,
|
||||
kAudioFrameCN = 2,
|
||||
kVideoFrameKey = 3, // independent frame
|
||||
kVideoFrameDelta = 4, // depends on the previus frame
|
||||
};
|
||||
|
||||
// Statistics for an RTCP channel
|
||||
struct RtcpStatistics {
|
||||
RtcpStatistics()
|
||||
: fraction_lost(0),
|
||||
cumulative_lost(0),
|
||||
extended_max_sequence_number(0),
|
||||
jitter(0) {}
|
||||
|
||||
uint8_t fraction_lost;
|
||||
uint32_t cumulative_lost;
|
||||
uint32_t extended_max_sequence_number;
|
||||
uint32_t jitter;
|
||||
};
|
||||
|
||||
class RtcpStatisticsCallback {
|
||||
public:
|
||||
virtual ~RtcpStatisticsCallback() {}
|
||||
|
||||
virtual void StatisticsUpdated(const RtcpStatistics& statistics,
|
||||
uint32_t ssrc) = 0;
|
||||
virtual void CNameChanged(const char* cname, uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
// Statistics for RTCP packet types.
|
||||
struct RtcpPacketTypeCounter {
|
||||
RtcpPacketTypeCounter()
|
||||
: first_packet_time_ms(-1),
|
||||
nack_packets(0),
|
||||
fir_packets(0),
|
||||
pli_packets(0),
|
||||
nack_requests(0),
|
||||
unique_nack_requests(0) {}
|
||||
|
||||
void Add(const RtcpPacketTypeCounter& other) {
|
||||
nack_packets += other.nack_packets;
|
||||
fir_packets += other.fir_packets;
|
||||
pli_packets += other.pli_packets;
|
||||
nack_requests += other.nack_requests;
|
||||
unique_nack_requests += other.unique_nack_requests;
|
||||
if (other.first_packet_time_ms != -1 &&
|
||||
(other.first_packet_time_ms < first_packet_time_ms ||
|
||||
first_packet_time_ms == -1)) {
|
||||
// Use oldest time.
|
||||
first_packet_time_ms = other.first_packet_time_ms;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
|
||||
return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
|
||||
}
|
||||
|
||||
int UniqueNackRequestsInPercent() const {
|
||||
if (nack_requests == 0) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(
|
||||
(unique_nack_requests * 100.0f / nack_requests) + 0.5f);
|
||||
}
|
||||
|
||||
int64_t first_packet_time_ms; // Time when first packet is sent/received.
|
||||
uint32_t nack_packets; // Number of RTCP NACK packets.
|
||||
uint32_t fir_packets; // Number of RTCP FIR packets.
|
||||
uint32_t pli_packets; // Number of RTCP PLI packets.
|
||||
uint32_t nack_requests; // Number of NACKed RTP packets.
|
||||
uint32_t unique_nack_requests; // Number of unique NACKed RTP packets.
|
||||
};
|
||||
|
||||
class RtcpPacketTypeCounterObserver {
|
||||
public:
|
||||
virtual ~RtcpPacketTypeCounterObserver() {}
|
||||
virtual void RtcpPacketTypesCounterUpdated(
|
||||
uint32_t ssrc,
|
||||
const RtcpPacketTypeCounter& packet_counter) = 0;
|
||||
};
|
||||
|
||||
// Rate statistics for a stream.
|
||||
struct BitrateStatistics {
|
||||
BitrateStatistics() : bitrate_bps(0), packet_rate(0), timestamp_ms(0) {}
|
||||
|
||||
uint32_t bitrate_bps; // Bitrate in bits per second.
|
||||
uint32_t packet_rate; // Packet rate in packets per second.
|
||||
uint64_t timestamp_ms; // Ntp timestamp in ms at time of rate estimation.
|
||||
};
|
||||
|
||||
// Callback, used to notify an observer whenever new rates have been estimated.
|
||||
class BitrateStatisticsObserver {
|
||||
public:
|
||||
virtual ~BitrateStatisticsObserver() {}
|
||||
|
||||
virtual void Notify(const BitrateStatistics& total_stats,
|
||||
const BitrateStatistics& retransmit_stats,
|
||||
uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
struct FrameCounts {
|
||||
FrameCounts() : key_frames(0), delta_frames(0) {}
|
||||
int key_frames;
|
||||
int delta_frames;
|
||||
};
|
||||
|
||||
// Callback, used to notify an observer whenever frame counts have been updated.
|
||||
class FrameCountObserver {
|
||||
public:
|
||||
virtual ~FrameCountObserver() {}
|
||||
virtual void FrameCountUpdated(const FrameCounts& frame_counts,
|
||||
uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
// Callback, used to notify an observer whenever the send-side delay is updated.
|
||||
class SendSideDelayObserver {
|
||||
public:
|
||||
virtual ~SendSideDelayObserver() {}
|
||||
virtual void SendSideDelayUpdated(int avg_delay_ms,
|
||||
int max_delay_ms,
|
||||
uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
// ==================================================================
|
||||
// Voice specific types
|
||||
// ==================================================================
|
||||
|
||||
// Each codec supported can be described by this structure.
|
||||
struct CodecInst {
|
||||
int pltype;
|
||||
char plname[RTP_PAYLOAD_NAME_SIZE];
|
||||
int plfreq;
|
||||
int pacsize;
|
||||
int channels;
|
||||
int rate; // bits/sec unlike {start,min,max}Bitrate elsewhere in this file!
|
||||
|
||||
bool operator==(const CodecInst& other) const {
|
||||
return pltype == other.pltype &&
|
||||
(STR_CASE_CMP(plname, other.plname) == 0) &&
|
||||
plfreq == other.plfreq &&
|
||||
pacsize == other.pacsize &&
|
||||
channels == other.channels &&
|
||||
rate == other.rate;
|
||||
}
|
||||
|
||||
bool operator!=(const CodecInst& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
// RTP
|
||||
enum {kRtpCsrcSize = 15}; // RFC 3550 page 13
|
||||
|
||||
enum RTPDirections
|
||||
{
|
||||
kRtpIncoming = 0,
|
||||
kRtpOutgoing
|
||||
};
|
||||
|
||||
enum PayloadFrequencies
|
||||
{
|
||||
kFreq8000Hz = 8000,
|
||||
kFreq16000Hz = 16000,
|
||||
kFreq32000Hz = 32000
|
||||
};
|
||||
|
||||
enum VadModes // degree of bandwidth reduction
|
||||
{
|
||||
kVadConventional = 0, // lowest reduction
|
||||
kVadAggressiveLow,
|
||||
kVadAggressiveMid,
|
||||
kVadAggressiveHigh // highest reduction
|
||||
};
|
||||
|
||||
struct NetworkStatistics // NETEQ statistics
|
||||
{
|
||||
// current jitter buffer size in ms
|
||||
uint16_t currentBufferSize;
|
||||
// preferred (optimal) buffer size in ms
|
||||
uint16_t preferredBufferSize;
|
||||
// adding extra delay due to "peaky jitter"
|
||||
bool jitterPeaksFound;
|
||||
// Loss rate (network + late); fraction between 0 and 1, scaled to Q14.
|
||||
uint16_t currentPacketLossRate;
|
||||
// Late loss rate; fraction between 0 and 1, scaled to Q14.
|
||||
uint16_t currentDiscardRate;
|
||||
// fraction (of original stream) of synthesized audio inserted through
|
||||
// expansion (in Q14)
|
||||
uint16_t currentExpandRate;
|
||||
// fraction (of original stream) of synthesized speech inserted through
|
||||
// expansion (in Q14)
|
||||
uint16_t currentSpeechExpandRate;
|
||||
// fraction of synthesized speech inserted through pre-emptive expansion
|
||||
// (in Q14)
|
||||
uint16_t currentPreemptiveRate;
|
||||
// fraction of data removed through acceleration (in Q14)
|
||||
uint16_t currentAccelerateRate;
|
||||
// fraction of data coming from secondary decoding (in Q14)
|
||||
uint16_t currentSecondaryDecodedRate;
|
||||
// clock-drift in parts-per-million (negative or positive)
|
||||
int32_t clockDriftPPM;
|
||||
// average packet waiting time in the jitter buffer (ms)
|
||||
int meanWaitingTimeMs;
|
||||
// median packet waiting time in the jitter buffer (ms)
|
||||
int medianWaitingTimeMs;
|
||||
// min packet waiting time in the jitter buffer (ms)
|
||||
int minWaitingTimeMs;
|
||||
// max packet waiting time in the jitter buffer (ms)
|
||||
int maxWaitingTimeMs;
|
||||
// added samples in off mode due to packet loss
|
||||
size_t addedSamples;
|
||||
};
|
||||
|
||||
// Statistics for calls to AudioCodingModule::PlayoutData10Ms().
|
||||
struct AudioDecodingCallStats {
|
||||
AudioDecodingCallStats()
|
||||
: calls_to_silence_generator(0),
|
||||
calls_to_neteq(0),
|
||||
decoded_normal(0),
|
||||
decoded_plc(0),
|
||||
decoded_cng(0),
|
||||
decoded_plc_cng(0) {}
|
||||
|
||||
int calls_to_silence_generator; // Number of calls where silence generated,
|
||||
// and NetEq was disengaged from decoding.
|
||||
int calls_to_neteq; // Number of calls to NetEq.
|
||||
int decoded_normal; // Number of calls where audio RTP packet decoded.
|
||||
int decoded_plc; // Number of calls resulted in PLC.
|
||||
int decoded_cng; // Number of calls where comfort noise generated due to DTX.
|
||||
int decoded_plc_cng; // Number of calls resulted where PLC faded to CNG.
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int min; // minumum
|
||||
int max; // maximum
|
||||
int average; // average
|
||||
} StatVal;
|
||||
|
||||
typedef struct // All levels are reported in dBm0
|
||||
{
|
||||
StatVal speech_rx; // long-term speech levels on receiving side
|
||||
StatVal speech_tx; // long-term speech levels on transmitting side
|
||||
StatVal noise_rx; // long-term noise/silence levels on receiving side
|
||||
StatVal noise_tx; // long-term noise/silence levels on transmitting side
|
||||
} LevelStatistics;
|
||||
|
||||
typedef struct // All levels are reported in dB
|
||||
{
|
||||
StatVal erl; // Echo Return Loss
|
||||
StatVal erle; // Echo Return Loss Enhancement
|
||||
StatVal rerl; // RERL = ERL + ERLE
|
||||
// Echo suppression inside EC at the point just before its NLP
|
||||
StatVal a_nlp;
|
||||
} EchoStatistics;
|
||||
|
||||
enum NsModes // type of Noise Suppression
|
||||
{
|
||||
kNsUnchanged = 0, // previously set mode
|
||||
kNsDefault, // platform default
|
||||
kNsConference, // conferencing default
|
||||
kNsLowSuppression, // lowest suppression
|
||||
kNsModerateSuppression,
|
||||
kNsHighSuppression,
|
||||
kNsVeryHighSuppression, // highest suppression
|
||||
};
|
||||
|
||||
enum AgcModes // type of Automatic Gain Control
|
||||
{
|
||||
kAgcUnchanged = 0, // previously set mode
|
||||
kAgcDefault, // platform default
|
||||
// adaptive mode for use when analog volume control exists (e.g. for
|
||||
// PC softphone)
|
||||
kAgcAdaptiveAnalog,
|
||||
// scaling takes place in the digital domain (e.g. for conference servers
|
||||
// and embedded devices)
|
||||
kAgcAdaptiveDigital,
|
||||
// can be used on embedded devices where the capture signal level
|
||||
// is predictable
|
||||
kAgcFixedDigital
|
||||
};
|
||||
|
||||
// EC modes
|
||||
enum EcModes // type of Echo Control
|
||||
{
|
||||
kEcUnchanged = 0, // previously set mode
|
||||
kEcDefault, // platform default
|
||||
kEcConference, // conferencing default (aggressive AEC)
|
||||
kEcAec, // Acoustic Echo Cancellation
|
||||
kEcAecm, // AEC mobile
|
||||
};
|
||||
|
||||
// AECM modes
|
||||
enum AecmModes // mode of AECM
|
||||
{
|
||||
kAecmQuietEarpieceOrHeadset = 0,
|
||||
// Quiet earpiece or headset use
|
||||
kAecmEarpiece, // most earpiece use
|
||||
kAecmLoudEarpiece, // Loud earpiece or quiet speakerphone use
|
||||
kAecmSpeakerphone, // most speakerphone use (default)
|
||||
kAecmLoudSpeakerphone // Loud speakerphone
|
||||
};
|
||||
|
||||
// AGC configuration
|
||||
typedef struct
|
||||
{
|
||||
unsigned short targetLeveldBOv;
|
||||
unsigned short digitalCompressionGaindB;
|
||||
bool limiterEnable;
|
||||
} AgcConfig; // AGC configuration parameters
|
||||
|
||||
enum StereoChannel
|
||||
{
|
||||
kStereoLeft = 0,
|
||||
kStereoRight,
|
||||
kStereoBoth
|
||||
};
|
||||
|
||||
// Audio device layers
|
||||
enum AudioLayers
|
||||
{
|
||||
kAudioPlatformDefault = 0,
|
||||
kAudioWindowsWave = 1,
|
||||
kAudioWindowsCore = 2,
|
||||
kAudioLinuxAlsa = 3,
|
||||
kAudioLinuxPulse = 4
|
||||
};
|
||||
|
||||
// TODO(henrika): to be removed.
|
||||
enum NetEqModes // NetEQ playout configurations
|
||||
{
|
||||
// Optimized trade-off between low delay and jitter robustness for two-way
|
||||
// communication.
|
||||
kNetEqDefault = 0,
|
||||
// Improved jitter robustness at the cost of increased delay. Can be
|
||||
// used in one-way communication.
|
||||
kNetEqStreaming = 1,
|
||||
// Optimzed for decodability of fax signals rather than for perceived audio
|
||||
// quality.
|
||||
kNetEqFax = 2,
|
||||
// Minimal buffer management. Inserts zeros for lost packets and during
|
||||
// buffer increases.
|
||||
kNetEqOff = 3,
|
||||
};
|
||||
|
||||
// TODO(henrika): to be removed.
|
||||
enum OnHoldModes // On Hold direction
|
||||
{
|
||||
kHoldSendAndPlay = 0, // Put both sending and playing in on-hold state.
|
||||
kHoldSendOnly, // Put only sending in on-hold state.
|
||||
kHoldPlayOnly // Put only playing in on-hold state.
|
||||
};
|
||||
|
||||
// TODO(henrika): to be removed.
|
||||
enum AmrMode
|
||||
{
|
||||
kRfc3267BwEfficient = 0,
|
||||
kRfc3267OctetAligned = 1,
|
||||
kRfc3267FileStorage = 2,
|
||||
};
|
||||
|
||||
// ==================================================================
|
||||
// Video specific types
|
||||
// ==================================================================
|
||||
|
||||
// Raw video types
|
||||
enum RawVideoType
|
||||
{
|
||||
kVideoI420 = 0,
|
||||
kVideoYV12 = 1,
|
||||
kVideoYUY2 = 2,
|
||||
kVideoUYVY = 3,
|
||||
kVideoIYUV = 4,
|
||||
kVideoARGB = 5,
|
||||
kVideoRGB24 = 6,
|
||||
kVideoRGB565 = 7,
|
||||
kVideoARGB4444 = 8,
|
||||
kVideoARGB1555 = 9,
|
||||
kVideoMJPEG = 10,
|
||||
kVideoNV12 = 11,
|
||||
kVideoNV21 = 12,
|
||||
kVideoBGRA = 13,
|
||||
kVideoUnknown = 99
|
||||
};
|
||||
|
||||
// Video codec
|
||||
enum { kConfigParameterSize = 128};
|
||||
enum { kPayloadNameSize = 32};
|
||||
enum { kMaxSimulcastStreams = 4};
|
||||
enum { kMaxTemporalStreams = 4};
|
||||
|
||||
enum VideoCodecComplexity
|
||||
{
|
||||
kComplexityNormal = 0,
|
||||
kComplexityHigh = 1,
|
||||
kComplexityHigher = 2,
|
||||
kComplexityMax = 3
|
||||
};
|
||||
|
||||
enum VideoCodecProfile
|
||||
{
|
||||
kProfileBase = 0x00,
|
||||
kProfileMain = 0x01
|
||||
};
|
||||
|
||||
enum VP8ResilienceMode {
|
||||
kResilienceOff, // The stream produced by the encoder requires a
|
||||
// recovery frame (typically a key frame) to be
|
||||
// decodable after a packet loss.
|
||||
kResilientStream, // A stream produced by the encoder is resilient to
|
||||
// packet losses, but packets within a frame subsequent
|
||||
// to a loss can't be decoded.
|
||||
kResilientFrames // Same as kResilientStream but with added resilience
|
||||
// within a frame.
|
||||
};
|
||||
|
||||
// VP8 specific
|
||||
struct VideoCodecVP8 {
|
||||
bool pictureLossIndicationOn;
|
||||
bool feedbackModeOn;
|
||||
VideoCodecComplexity complexity;
|
||||
VP8ResilienceMode resilience;
|
||||
unsigned char numberOfTemporalLayers;
|
||||
bool denoisingOn;
|
||||
bool errorConcealmentOn;
|
||||
bool automaticResizeOn;
|
||||
bool frameDroppingOn;
|
||||
int keyFrameInterval;
|
||||
|
||||
bool operator==(const VideoCodecVP8& other) const {
|
||||
return pictureLossIndicationOn == other.pictureLossIndicationOn &&
|
||||
feedbackModeOn == other.feedbackModeOn &&
|
||||
complexity == other.complexity &&
|
||||
resilience == other.resilience &&
|
||||
numberOfTemporalLayers == other.numberOfTemporalLayers &&
|
||||
denoisingOn == other.denoisingOn &&
|
||||
errorConcealmentOn == other.errorConcealmentOn &&
|
||||
automaticResizeOn == other.automaticResizeOn &&
|
||||
frameDroppingOn == other.frameDroppingOn &&
|
||||
keyFrameInterval == other.keyFrameInterval;
|
||||
}
|
||||
|
||||
bool operator!=(const VideoCodecVP8& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
// VP9 specific.
|
||||
struct VideoCodecVP9 {
|
||||
VideoCodecComplexity complexity;
|
||||
int resilience;
|
||||
unsigned char numberOfTemporalLayers;
|
||||
bool denoisingOn;
|
||||
bool frameDroppingOn;
|
||||
int keyFrameInterval;
|
||||
bool adaptiveQpMode;
|
||||
bool automaticResizeOn;
|
||||
unsigned char numberOfSpatialLayers;
|
||||
bool flexibleMode;
|
||||
};
|
||||
|
||||
// H264 specific.
|
||||
struct VideoCodecH264 {
|
||||
VideoCodecProfile profile;
|
||||
bool frameDroppingOn;
|
||||
int keyFrameInterval;
|
||||
// These are NULL/0 if not externally negotiated.
|
||||
const uint8_t* spsData;
|
||||
size_t spsLen;
|
||||
const uint8_t* ppsData;
|
||||
size_t ppsLen;
|
||||
};
|
||||
|
||||
// Video codec types
|
||||
enum VideoCodecType {
|
||||
kVideoCodecVP8,
|
||||
kVideoCodecVP9,
|
||||
kVideoCodecH264,
|
||||
kVideoCodecI420,
|
||||
kVideoCodecRED,
|
||||
kVideoCodecULPFEC,
|
||||
kVideoCodecGeneric,
|
||||
kVideoCodecUnknown
|
||||
};
|
||||
|
||||
union VideoCodecUnion {
|
||||
VideoCodecVP8 VP8;
|
||||
VideoCodecVP9 VP9;
|
||||
VideoCodecH264 H264;
|
||||
};
|
||||
|
||||
|
||||
// Simulcast is when the same stream is encoded multiple times with different
|
||||
// settings such as resolution.
|
||||
struct SimulcastStream {
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned char numberOfTemporalLayers;
|
||||
unsigned int maxBitrate; // kilobits/sec.
|
||||
unsigned int targetBitrate; // kilobits/sec.
|
||||
unsigned int minBitrate; // kilobits/sec.
|
||||
unsigned int qpMax; // minimum quality
|
||||
|
||||
bool operator==(const SimulcastStream& other) const {
|
||||
return width == other.width &&
|
||||
height == other.height &&
|
||||
numberOfTemporalLayers == other.numberOfTemporalLayers &&
|
||||
maxBitrate == other.maxBitrate &&
|
||||
targetBitrate == other.targetBitrate &&
|
||||
minBitrate == other.minBitrate &&
|
||||
qpMax == other.qpMax;
|
||||
}
|
||||
|
||||
bool operator!=(const SimulcastStream& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
enum VideoCodecMode {
|
||||
kRealtimeVideo,
|
||||
kScreensharing
|
||||
};
|
||||
|
||||
// Common video codec properties
|
||||
struct VideoCodec {
|
||||
VideoCodecType codecType;
|
||||
char plName[kPayloadNameSize];
|
||||
unsigned char plType;
|
||||
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
|
||||
unsigned int startBitrate; // kilobits/sec.
|
||||
unsigned int maxBitrate; // kilobits/sec.
|
||||
unsigned int minBitrate; // kilobits/sec.
|
||||
unsigned int targetBitrate; // kilobits/sec.
|
||||
|
||||
unsigned char maxFramerate;
|
||||
|
||||
VideoCodecUnion codecSpecific;
|
||||
|
||||
unsigned int qpMax;
|
||||
unsigned char numberOfSimulcastStreams;
|
||||
SimulcastStream simulcastStream[kMaxSimulcastStreams];
|
||||
|
||||
VideoCodecMode mode;
|
||||
|
||||
// When using an external encoder/decoder this allows to pass
|
||||
// extra options without requiring webrtc to be aware of them.
|
||||
Config* extra_options;
|
||||
|
||||
bool operator==(const VideoCodec& other) const {
|
||||
bool ret = codecType == other.codecType &&
|
||||
(STR_CASE_CMP(plName, other.plName) == 0) &&
|
||||
plType == other.plType &&
|
||||
width == other.width &&
|
||||
height == other.height &&
|
||||
startBitrate == other.startBitrate &&
|
||||
maxBitrate == other.maxBitrate &&
|
||||
minBitrate == other.minBitrate &&
|
||||
targetBitrate == other.targetBitrate &&
|
||||
maxFramerate == other.maxFramerate &&
|
||||
qpMax == other.qpMax &&
|
||||
numberOfSimulcastStreams == other.numberOfSimulcastStreams &&
|
||||
mode == other.mode;
|
||||
if (ret && codecType == kVideoCodecVP8) {
|
||||
ret &= (codecSpecific.VP8 == other.codecSpecific.VP8);
|
||||
}
|
||||
|
||||
for (unsigned char i = 0; i < other.numberOfSimulcastStreams && ret; ++i) {
|
||||
ret &= (simulcastStream[i] == other.simulcastStream[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool operator!=(const VideoCodec& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
// Bandwidth over-use detector options. These are used to drive
|
||||
// experimentation with bandwidth estimation parameters.
|
||||
// See modules/remote_bitrate_estimator/overuse_detector.h
|
||||
struct OverUseDetectorOptions {
|
||||
OverUseDetectorOptions()
|
||||
: initial_slope(8.0/512.0),
|
||||
initial_offset(0),
|
||||
initial_e(),
|
||||
initial_process_noise(),
|
||||
initial_avg_noise(0.0),
|
||||
initial_var_noise(50) {
|
||||
initial_e[0][0] = 100;
|
||||
initial_e[1][1] = 1e-1;
|
||||
initial_e[0][1] = initial_e[1][0] = 0;
|
||||
initial_process_noise[0] = 1e-13;
|
||||
initial_process_noise[1] = 1e-2;
|
||||
}
|
||||
double initial_slope;
|
||||
double initial_offset;
|
||||
double initial_e[2][2];
|
||||
double initial_process_noise[2];
|
||||
double initial_avg_noise;
|
||||
double initial_var_noise;
|
||||
};
|
||||
|
||||
// This structure will have the information about when packet is actually
|
||||
// received by socket.
|
||||
struct PacketTime {
|
||||
PacketTime() : timestamp(-1), not_before(-1) {}
|
||||
PacketTime(int64_t timestamp, int64_t not_before)
|
||||
: timestamp(timestamp), not_before(not_before) {
|
||||
}
|
||||
|
||||
int64_t timestamp; // Receive time after socket delivers the data.
|
||||
int64_t not_before; // Earliest possible time the data could have arrived,
|
||||
// indicating the potential error in the |timestamp|
|
||||
// value,in case the system is busy.
|
||||
// For example, the time of the last select() call.
|
||||
// If unknown, this value will be set to zero.
|
||||
};
|
||||
|
||||
struct RTPHeaderExtension {
|
||||
RTPHeaderExtension();
|
||||
|
||||
bool hasTransmissionTimeOffset;
|
||||
int32_t transmissionTimeOffset;
|
||||
bool hasAbsoluteSendTime;
|
||||
uint32_t absoluteSendTime;
|
||||
bool hasTransportSequenceNumber;
|
||||
uint16_t transportSequenceNumber;
|
||||
|
||||
// Audio Level includes both level in dBov and voiced/unvoiced bit. See:
|
||||
// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
|
||||
bool hasAudioLevel;
|
||||
bool voiceActivity;
|
||||
uint8_t audioLevel;
|
||||
|
||||
// For Coordination of Video Orientation. See
|
||||
// http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
|
||||
// ts_126114v120700p.pdf
|
||||
bool hasVideoRotation;
|
||||
uint8_t videoRotation;
|
||||
};
|
||||
|
||||
struct RTPHeader {
|
||||
RTPHeader();
|
||||
|
||||
bool markerBit;
|
||||
uint8_t payloadType;
|
||||
uint16_t sequenceNumber;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint8_t numCSRCs;
|
||||
uint32_t arrOfCSRCs[kRtpCsrcSize];
|
||||
size_t paddingLength;
|
||||
size_t headerLength;
|
||||
int payload_type_frequency;
|
||||
RTPHeaderExtension extension;
|
||||
};
|
||||
|
||||
struct RtpPacketCounter {
|
||||
RtpPacketCounter()
|
||||
: header_bytes(0),
|
||||
payload_bytes(0),
|
||||
padding_bytes(0),
|
||||
packets(0) {}
|
||||
|
||||
void Add(const RtpPacketCounter& other) {
|
||||
header_bytes += other.header_bytes;
|
||||
payload_bytes += other.payload_bytes;
|
||||
padding_bytes += other.padding_bytes;
|
||||
packets += other.packets;
|
||||
}
|
||||
|
||||
void AddPacket(size_t packet_length, const RTPHeader& header) {
|
||||
++packets;
|
||||
header_bytes += header.headerLength;
|
||||
padding_bytes += header.paddingLength;
|
||||
payload_bytes +=
|
||||
packet_length - (header.headerLength + header.paddingLength);
|
||||
}
|
||||
|
||||
size_t TotalBytes() const {
|
||||
return header_bytes + payload_bytes + padding_bytes;
|
||||
}
|
||||
|
||||
size_t header_bytes; // Number of bytes used by RTP headers.
|
||||
size_t payload_bytes; // Payload bytes, excluding RTP headers and padding.
|
||||
size_t padding_bytes; // Number of padding bytes.
|
||||
uint32_t packets; // Number of packets.
|
||||
};
|
||||
|
||||
// Data usage statistics for a (rtp) stream.
|
||||
struct StreamDataCounters {
|
||||
StreamDataCounters();
|
||||
|
||||
void Add(const StreamDataCounters& other) {
|
||||
transmitted.Add(other.transmitted);
|
||||
retransmitted.Add(other.retransmitted);
|
||||
fec.Add(other.fec);
|
||||
if (other.first_packet_time_ms != -1 &&
|
||||
(other.first_packet_time_ms < first_packet_time_ms ||
|
||||
first_packet_time_ms == -1)) {
|
||||
// Use oldest time.
|
||||
first_packet_time_ms = other.first_packet_time_ms;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
|
||||
return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
|
||||
}
|
||||
|
||||
// Returns the number of bytes corresponding to the actual media payload (i.e.
|
||||
// RTP headers, padding, retransmissions and fec packets are excluded).
|
||||
// Note this function does not have meaning for an RTX stream.
|
||||
size_t MediaPayloadBytes() const {
|
||||
return transmitted.payload_bytes - retransmitted.payload_bytes -
|
||||
fec.payload_bytes;
|
||||
}
|
||||
|
||||
int64_t first_packet_time_ms; // Time when first packet is sent/received.
|
||||
RtpPacketCounter transmitted; // Number of transmitted packets/bytes.
|
||||
RtpPacketCounter retransmitted; // Number of retransmitted packets/bytes.
|
||||
RtpPacketCounter fec; // Number of redundancy packets/bytes.
|
||||
};
|
||||
|
||||
// Callback, called whenever byte/packet counts have been updated.
|
||||
class StreamDataCountersCallback {
|
||||
public:
|
||||
virtual ~StreamDataCountersCallback() {}
|
||||
|
||||
virtual void DataCountersUpdated(const StreamDataCounters& counters,
|
||||
uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
// RTCP mode to use. Compound mode is described by RFC 4585 and reduced-size
|
||||
// RTCP mode is described by RFC 5506.
|
||||
enum class RtcpMode { kOff, kCompound, kReducedSize };
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_COMMON_TYPES_H_
|
1
webrtc/modules/Makefile.am
Normal file
1
webrtc/modules/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = audio_processing
|
59
webrtc/modules/audio_processing/Makefile.am
Normal file
59
webrtc/modules/audio_processing/Makefile.am
Normal file
@ -0,0 +1,59 @@
|
||||
SUBDIRS = utility ns aec aecm agc
|
||||
lib_LTLIBRARIES = libwebrtc_audio_processing.la
|
||||
|
||||
if NS_FIXED
|
||||
COMMON_CXXFLAGS += -DWEBRTC_NS_FIXED=1
|
||||
NS_LIB = libns_fix
|
||||
else
|
||||
COMMON_CXXFLAGS += -DWEBRTC_NS_FLOAT=1
|
||||
NS_LIB = libns
|
||||
endif
|
||||
|
||||
webrtcincludedir = $(includedir)/webrtc_audio_processing
|
||||
webrtcinclude_HEADERS = $(top_srcdir)/src/typedefs.h \
|
||||
$(top_srcdir)/src/modules/interface/module.h \
|
||||
interface/audio_processing.h \
|
||||
$(top_srcdir)/src/common_types.h \
|
||||
$(top_srcdir)/src/modules/interface/module_common_types.h
|
||||
|
||||
libwebrtc_audio_processing_la_SOURCES = interface/audio_processing.h \
|
||||
audio_buffer.cc \
|
||||
audio_buffer.h \
|
||||
audio_processing_impl.cc \
|
||||
audio_processing_impl.h \
|
||||
echo_cancellation_impl.cc \
|
||||
echo_cancellation_impl.h \
|
||||
echo_control_mobile_impl.cc \
|
||||
echo_control_mobile_impl.h \
|
||||
gain_control_impl.cc \
|
||||
gain_control_impl.h \
|
||||
high_pass_filter_impl.cc \
|
||||
high_pass_filter_impl.h \
|
||||
level_estimator_impl.cc \
|
||||
level_estimator_impl.h \
|
||||
noise_suppression_impl.cc \
|
||||
noise_suppression_impl.h \
|
||||
splitting_filter.cc \
|
||||
splitting_filter.h \
|
||||
processing_component.cc \
|
||||
processing_component.h \
|
||||
voice_detection_impl.cc \
|
||||
voice_detection_impl.h
|
||||
libwebrtc_audio_processing_la_CXXFLAGS = $(AM_CXXFLAGS) $(COMMON_CXXFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/common_audio/vad/main/interface \
|
||||
-I$(top_srcdir)/src/system_wrappers/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/ns/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/aec/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/aecm/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/agc/interface
|
||||
libwebrtc_audio_processing_la_LIBADD = $(top_builddir)/src/system_wrappers/libsystem_wrappers.la \
|
||||
$(top_builddir)/src/common_audio/signal_processing_library/libspl.la \
|
||||
$(top_builddir)/src/common_audio/vad/libvad.la \
|
||||
$(top_builddir)/src/modules/audio_processing/utility/libapm_util.la \
|
||||
$(top_builddir)/src/modules/audio_processing/ns/$(NS_LIB).la \
|
||||
$(top_builddir)/src/modules/audio_processing/aec/libaec.la \
|
||||
$(top_builddir)/src/modules/audio_processing/aecm/libaecm.la \
|
||||
$(top_builddir)/src/modules/audio_processing/agc/libagc.la
|
||||
libwebrtc_audio_processing_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBWEBRTC_AUDIO_PROCESSING_VERSION_INFO)
|
2
webrtc/modules/audio_processing/OWNERS
Normal file
2
webrtc/modules/audio_processing/OWNERS
Normal file
@ -0,0 +1,2 @@
|
||||
andrew@webrtc.org
|
||||
bjornv@webrtc.org
|
16
webrtc/modules/audio_processing/aec/Makefile.am
Normal file
16
webrtc/modules/audio_processing/aec/Makefile.am
Normal file
@ -0,0 +1,16 @@
|
||||
noinst_LTLIBRARIES = libaec.la
|
||||
|
||||
libaec_la_SOURCES = interface/echo_cancellation.h \
|
||||
echo_cancellation.c \
|
||||
aec_core.h \
|
||||
aec_core.c \
|
||||
aec_core_sse2.c \
|
||||
aec_rdft.h \
|
||||
aec_rdft.c \
|
||||
aec_rdft_sse2.c \
|
||||
resampler.h \
|
||||
resampler.c
|
||||
libaec_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/system_wrappers/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility
|
40
webrtc/modules/audio_processing/aec/aec.gypi
Normal file
40
webrtc/modules/audio_processing/aec/aec.gypi
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'aec',
|
||||
'type': '<(library)',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:spl',
|
||||
'apm_util'
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/echo_cancellation.h',
|
||||
'echo_cancellation.c',
|
||||
'aec_core.h',
|
||||
'aec_core.c',
|
||||
'aec_core_sse2.c',
|
||||
'aec_rdft.h',
|
||||
'aec_rdft.c',
|
||||
'aec_rdft_sse2.c',
|
||||
'resampler.h',
|
||||
'resampler.c',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
1466
webrtc/modules/audio_processing/aec/aec_core.c
Normal file
1466
webrtc/modules/audio_processing/aec/aec_core.c
Normal file
File diff suppressed because it is too large
Load Diff
181
webrtc/modules/audio_processing/aec/aec_core.h
Normal file
181
webrtc/modules/audio_processing/aec/aec_core.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Specifies the interface for the AEC core.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
//#define AEC_DEBUG // for recording files
|
||||
|
||||
#define FRAME_LEN 80
|
||||
#define PART_LEN 64 // Length of partition
|
||||
#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
|
||||
#define PART_LEN2 (PART_LEN * 2) // Length of partition * 2
|
||||
#define NR_PART 12 // Number of partitions
|
||||
#define FILT_LEN (PART_LEN * NR_PART) // Filter length
|
||||
#define FILT_LEN2 (FILT_LEN * 2) // Double filter length
|
||||
#define FAR_BUF_LEN (FILT_LEN2 * 2)
|
||||
#define PREF_BAND_SIZE 24
|
||||
|
||||
#define BLOCKL_MAX FRAME_LEN
|
||||
// Maximum delay in fixed point delay estimator, used for logging
|
||||
enum {kMaxDelay = 100};
|
||||
|
||||
typedef float complex_t[2];
|
||||
// For performance reasons, some arrays of complex numbers are replaced by twice
|
||||
// as long arrays of float, all the real parts followed by all the imaginary
|
||||
// ones (complex_t[SIZE] -> float[2][SIZE]). This allows SIMD optimizations and
|
||||
// is better than two arrays (one for the real parts and one for the imaginary
|
||||
// parts) as this other way would require two pointers instead of one and cause
|
||||
// extra register spilling. This also allows the offsets to be calculated at
|
||||
// compile time.
|
||||
|
||||
// Metrics
|
||||
enum {offsetLevel = -100};
|
||||
|
||||
typedef struct {
|
||||
float sfrsum;
|
||||
int sfrcounter;
|
||||
float framelevel;
|
||||
float frsum;
|
||||
int frcounter;
|
||||
float minlevel;
|
||||
float averagelevel;
|
||||
} power_level_t;
|
||||
|
||||
typedef struct {
|
||||
float instant;
|
||||
float average;
|
||||
float min;
|
||||
float max;
|
||||
float sum;
|
||||
float hisum;
|
||||
float himean;
|
||||
int counter;
|
||||
int hicounter;
|
||||
} stats_t;
|
||||
|
||||
typedef struct {
|
||||
int farBufWritePos, farBufReadPos;
|
||||
|
||||
int knownDelay;
|
||||
int inSamples, outSamples;
|
||||
int delayEstCtr;
|
||||
|
||||
void *farFrBuf, *nearFrBuf, *outFrBuf;
|
||||
|
||||
void *nearFrBufH;
|
||||
void *outFrBufH;
|
||||
|
||||
float xBuf[PART_LEN2]; // farend
|
||||
float dBuf[PART_LEN2]; // nearend
|
||||
float eBuf[PART_LEN2]; // error
|
||||
|
||||
float dBufH[PART_LEN2]; // nearend
|
||||
|
||||
float xPow[PART_LEN1];
|
||||
float dPow[PART_LEN1];
|
||||
float dMinPow[PART_LEN1];
|
||||
float dInitMinPow[PART_LEN1];
|
||||
float *noisePow;
|
||||
|
||||
float xfBuf[2][NR_PART * PART_LEN1]; // farend fft buffer
|
||||
float wfBuf[2][NR_PART * PART_LEN1]; // filter fft
|
||||
complex_t sde[PART_LEN1]; // cross-psd of nearend and error
|
||||
complex_t sxd[PART_LEN1]; // cross-psd of farend and nearend
|
||||
complex_t xfwBuf[NR_PART * PART_LEN1]; // farend windowed fft buffer
|
||||
|
||||
float sx[PART_LEN1], sd[PART_LEN1], se[PART_LEN1]; // far, near and error psd
|
||||
float hNs[PART_LEN1];
|
||||
float hNlFbMin, hNlFbLocalMin;
|
||||
float hNlXdAvgMin;
|
||||
int hNlNewMin, hNlMinCtr;
|
||||
float overDrive, overDriveSm;
|
||||
float targetSupp, minOverDrive;
|
||||
float outBuf[PART_LEN];
|
||||
int delayIdx;
|
||||
|
||||
short stNearState, echoState;
|
||||
short divergeState;
|
||||
|
||||
int xfBufBlockPos;
|
||||
|
||||
short farBuf[FILT_LEN2 * 2];
|
||||
|
||||
short mult; // sampling frequency multiple
|
||||
int sampFreq;
|
||||
WebRtc_UWord32 seed;
|
||||
|
||||
float mu; // stepsize
|
||||
float errThresh; // error threshold
|
||||
|
||||
int noiseEstCtr;
|
||||
|
||||
power_level_t farlevel;
|
||||
power_level_t nearlevel;
|
||||
power_level_t linoutlevel;
|
||||
power_level_t nlpoutlevel;
|
||||
|
||||
int metricsMode;
|
||||
int stateCounter;
|
||||
stats_t erl;
|
||||
stats_t erle;
|
||||
stats_t aNlp;
|
||||
stats_t rerl;
|
||||
|
||||
// Quantities to control H band scaling for SWB input
|
||||
int freq_avg_ic; //initial bin for averaging nlp gain
|
||||
int flag_Hband_cn; //for comfort noise
|
||||
float cn_scale_Hband; //scale for comfort noise in H band
|
||||
|
||||
int delay_histogram[kMaxDelay];
|
||||
int delay_logging_enabled;
|
||||
void* delay_estimator;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *farFile;
|
||||
FILE *nearFile;
|
||||
FILE *outFile;
|
||||
FILE *outLpFile;
|
||||
#endif
|
||||
} aec_t;
|
||||
|
||||
typedef void (*WebRtcAec_FilterFar_t)(aec_t *aec, float yf[2][PART_LEN1]);
|
||||
extern WebRtcAec_FilterFar_t WebRtcAec_FilterFar;
|
||||
typedef void (*WebRtcAec_ScaleErrorSignal_t)(aec_t *aec, float ef[2][PART_LEN1]);
|
||||
extern WebRtcAec_ScaleErrorSignal_t WebRtcAec_ScaleErrorSignal;
|
||||
typedef void (*WebRtcAec_FilterAdaptation_t)
|
||||
(aec_t *aec, float *fft, float ef[2][PART_LEN1]);
|
||||
extern WebRtcAec_FilterAdaptation_t WebRtcAec_FilterAdaptation;
|
||||
typedef void (*WebRtcAec_OverdriveAndSuppress_t)
|
||||
(aec_t *aec, float hNl[PART_LEN1], const float hNlFb, float efw[2][PART_LEN1]);
|
||||
extern WebRtcAec_OverdriveAndSuppress_t WebRtcAec_OverdriveAndSuppress;
|
||||
|
||||
int WebRtcAec_CreateAec(aec_t **aec);
|
||||
int WebRtcAec_FreeAec(aec_t *aec);
|
||||
int WebRtcAec_InitAec(aec_t *aec, int sampFreq);
|
||||
void WebRtcAec_InitAec_SSE2(void);
|
||||
|
||||
void WebRtcAec_InitMetrics(aec_t *aec);
|
||||
void WebRtcAec_ProcessFrame(aec_t *aec, const short *farend,
|
||||
const short *nearend, const short *nearendH,
|
||||
short *out, short *outH,
|
||||
int knownDelay);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_
|
||||
|
417
webrtc/modules/audio_processing/aec/aec_core_sse2.c
Normal file
417
webrtc/modules/audio_processing/aec/aec_core_sse2.c
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The core AEC algorithm, SSE2 version of speed-critical functions.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#if defined(WEBRTC_USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "aec_core.h"
|
||||
#include "aec_rdft.h"
|
||||
|
||||
__inline static float MulRe(float aRe, float aIm, float bRe, float bIm)
|
||||
{
|
||||
return aRe * bRe - aIm * bIm;
|
||||
}
|
||||
|
||||
__inline static float MulIm(float aRe, float aIm, float bRe, float bIm)
|
||||
{
|
||||
return aRe * bIm + aIm * bRe;
|
||||
}
|
||||
|
||||
static void FilterFarSSE2(aec_t *aec, float yf[2][PART_LEN1])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NR_PART; i++) {
|
||||
int j;
|
||||
int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
|
||||
int pos = i * PART_LEN1;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= NR_PART) {
|
||||
xPos -= NR_PART*(PART_LEN1);
|
||||
}
|
||||
|
||||
// vectorized code (four at once)
|
||||
for (j = 0; j + 3 < PART_LEN1; j += 4) {
|
||||
const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]);
|
||||
const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]);
|
||||
const __m128 wfBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
|
||||
const __m128 wfBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
|
||||
const __m128 yf_re = _mm_loadu_ps(&yf[0][j]);
|
||||
const __m128 yf_im = _mm_loadu_ps(&yf[1][j]);
|
||||
const __m128 a = _mm_mul_ps(xfBuf_re, wfBuf_re);
|
||||
const __m128 b = _mm_mul_ps(xfBuf_im, wfBuf_im);
|
||||
const __m128 c = _mm_mul_ps(xfBuf_re, wfBuf_im);
|
||||
const __m128 d = _mm_mul_ps(xfBuf_im, wfBuf_re);
|
||||
const __m128 e = _mm_sub_ps(a, b);
|
||||
const __m128 f = _mm_add_ps(c, d);
|
||||
const __m128 g = _mm_add_ps(yf_re, e);
|
||||
const __m128 h = _mm_add_ps(yf_im, f);
|
||||
_mm_storeu_ps(&yf[0][j], g);
|
||||
_mm_storeu_ps(&yf[1][j], h);
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; j < PART_LEN1; j++) {
|
||||
yf[0][j] += MulRe(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]);
|
||||
yf[1][j] += MulIm(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleErrorSignalSSE2(aec_t *aec, float ef[2][PART_LEN1])
|
||||
{
|
||||
const __m128 k1e_10f = _mm_set1_ps(1e-10f);
|
||||
const __m128 kThresh = _mm_set1_ps(aec->errThresh);
|
||||
const __m128 kMu = _mm_set1_ps(aec->mu);
|
||||
|
||||
int i;
|
||||
// vectorized code (four at once)
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const __m128 xPow = _mm_loadu_ps(&aec->xPow[i]);
|
||||
const __m128 ef_re_base = _mm_loadu_ps(&ef[0][i]);
|
||||
const __m128 ef_im_base = _mm_loadu_ps(&ef[1][i]);
|
||||
|
||||
const __m128 xPowPlus = _mm_add_ps(xPow, k1e_10f);
|
||||
__m128 ef_re = _mm_div_ps(ef_re_base, xPowPlus);
|
||||
__m128 ef_im = _mm_div_ps(ef_im_base, xPowPlus);
|
||||
const __m128 ef_re2 = _mm_mul_ps(ef_re, ef_re);
|
||||
const __m128 ef_im2 = _mm_mul_ps(ef_im, ef_im);
|
||||
const __m128 ef_sum2 = _mm_add_ps(ef_re2, ef_im2);
|
||||
const __m128 absEf = _mm_sqrt_ps(ef_sum2);
|
||||
const __m128 bigger = _mm_cmpgt_ps(absEf, kThresh);
|
||||
__m128 absEfPlus = _mm_add_ps(absEf, k1e_10f);
|
||||
const __m128 absEfInv = _mm_div_ps(kThresh, absEfPlus);
|
||||
__m128 ef_re_if = _mm_mul_ps(ef_re, absEfInv);
|
||||
__m128 ef_im_if = _mm_mul_ps(ef_im, absEfInv);
|
||||
ef_re_if = _mm_and_ps(bigger, ef_re_if);
|
||||
ef_im_if = _mm_and_ps(bigger, ef_im_if);
|
||||
ef_re = _mm_andnot_ps(bigger, ef_re);
|
||||
ef_im = _mm_andnot_ps(bigger, ef_im);
|
||||
ef_re = _mm_or_ps(ef_re, ef_re_if);
|
||||
ef_im = _mm_or_ps(ef_im, ef_im_if);
|
||||
ef_re = _mm_mul_ps(ef_re, kMu);
|
||||
ef_im = _mm_mul_ps(ef_im, kMu);
|
||||
|
||||
_mm_storeu_ps(&ef[0][i], ef_re);
|
||||
_mm_storeu_ps(&ef[1][i], ef_im);
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; i < (PART_LEN1); i++) {
|
||||
float absEf;
|
||||
ef[0][i] /= (aec->xPow[i] + 1e-10f);
|
||||
ef[1][i] /= (aec->xPow[i] + 1e-10f);
|
||||
absEf = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
|
||||
|
||||
if (absEf > aec->errThresh) {
|
||||
absEf = aec->errThresh / (absEf + 1e-10f);
|
||||
ef[0][i] *= absEf;
|
||||
ef[1][i] *= absEf;
|
||||
}
|
||||
|
||||
// Stepsize factor
|
||||
ef[0][i] *= aec->mu;
|
||||
ef[1][i] *= aec->mu;
|
||||
}
|
||||
}
|
||||
|
||||
static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1]) {
|
||||
int i, j;
|
||||
for (i = 0; i < NR_PART; i++) {
|
||||
int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1);
|
||||
int pos = i * PART_LEN1;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= NR_PART) {
|
||||
xPos -= NR_PART * PART_LEN1;
|
||||
}
|
||||
|
||||
// Process the whole array...
|
||||
for (j = 0; j < PART_LEN; j+= 4) {
|
||||
// Load xfBuf and ef.
|
||||
const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]);
|
||||
const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]);
|
||||
const __m128 ef_re = _mm_loadu_ps(&ef[0][j]);
|
||||
const __m128 ef_im = _mm_loadu_ps(&ef[1][j]);
|
||||
// Calculate the product of conjugate(xfBuf) by ef.
|
||||
// re(conjugate(a) * b) = aRe * bRe + aIm * bIm
|
||||
// im(conjugate(a) * b)= aRe * bIm - aIm * bRe
|
||||
const __m128 a = _mm_mul_ps(xfBuf_re, ef_re);
|
||||
const __m128 b = _mm_mul_ps(xfBuf_im, ef_im);
|
||||
const __m128 c = _mm_mul_ps(xfBuf_re, ef_im);
|
||||
const __m128 d = _mm_mul_ps(xfBuf_im, ef_re);
|
||||
const __m128 e = _mm_add_ps(a, b);
|
||||
const __m128 f = _mm_sub_ps(c, d);
|
||||
// Interleave real and imaginary parts.
|
||||
const __m128 g = _mm_unpacklo_ps(e, f);
|
||||
const __m128 h = _mm_unpackhi_ps(e, f);
|
||||
// Store
|
||||
_mm_storeu_ps(&fft[2*j + 0], g);
|
||||
_mm_storeu_ps(&fft[2*j + 4], h);
|
||||
}
|
||||
// ... and fixup the first imaginary entry.
|
||||
fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN],
|
||||
-aec->xfBuf[1][xPos + PART_LEN],
|
||||
ef[0][PART_LEN], ef[1][PART_LEN]);
|
||||
|
||||
aec_rdft_inverse_128(fft);
|
||||
memset(fft + PART_LEN, 0, sizeof(float)*PART_LEN);
|
||||
|
||||
// fft scaling
|
||||
{
|
||||
float scale = 2.0f / PART_LEN2;
|
||||
const __m128 scale_ps = _mm_load_ps1(&scale);
|
||||
for (j = 0; j < PART_LEN; j+=4) {
|
||||
const __m128 fft_ps = _mm_loadu_ps(&fft[j]);
|
||||
const __m128 fft_scale = _mm_mul_ps(fft_ps, scale_ps);
|
||||
_mm_storeu_ps(&fft[j], fft_scale);
|
||||
}
|
||||
}
|
||||
aec_rdft_forward_128(fft);
|
||||
|
||||
{
|
||||
float wt1 = aec->wfBuf[1][pos];
|
||||
aec->wfBuf[0][pos + PART_LEN] += fft[1];
|
||||
for (j = 0; j < PART_LEN; j+= 4) {
|
||||
__m128 wtBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
|
||||
__m128 wtBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
|
||||
const __m128 fft0 = _mm_loadu_ps(&fft[2 * j + 0]);
|
||||
const __m128 fft4 = _mm_loadu_ps(&fft[2 * j + 4]);
|
||||
const __m128 fft_re = _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(2, 0, 2 ,0));
|
||||
const __m128 fft_im = _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(3, 1, 3 ,1));
|
||||
wtBuf_re = _mm_add_ps(wtBuf_re, fft_re);
|
||||
wtBuf_im = _mm_add_ps(wtBuf_im, fft_im);
|
||||
_mm_storeu_ps(&aec->wfBuf[0][pos + j], wtBuf_re);
|
||||
_mm_storeu_ps(&aec->wfBuf[1][pos + j], wtBuf_im);
|
||||
}
|
||||
aec->wfBuf[1][pos] = wt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __m128 mm_pow_ps(__m128 a, __m128 b)
|
||||
{
|
||||
// a^b = exp2(b * log2(a))
|
||||
// exp2(x) and log2(x) are calculated using polynomial approximations.
|
||||
__m128 log2_a, b_log2_a, a_exp_b;
|
||||
|
||||
// Calculate log2(x), x = a.
|
||||
{
|
||||
// To calculate log2(x), we decompose x like this:
|
||||
// x = y * 2^n
|
||||
// n is an integer
|
||||
// y is in the [1.0, 2.0) range
|
||||
//
|
||||
// log2(x) = log2(y) + n
|
||||
// n can be evaluated by playing with float representation.
|
||||
// log2(y) in a small range can be approximated, this code uses an order
|
||||
// five polynomial approximation. The coefficients have been
|
||||
// estimated with the Remez algorithm and the resulting
|
||||
// polynomial has a maximum relative error of 0.00086%.
|
||||
|
||||
// Compute n.
|
||||
// This is done by masking the exponent, shifting it into the top bit of
|
||||
// the mantissa, putting eight into the biased exponent (to shift/
|
||||
// compensate the fact that the exponent has been shifted in the top/
|
||||
// fractional part and finally getting rid of the implicit leading one
|
||||
// from the mantissa by substracting it out.
|
||||
static const ALIGN16_BEG int float_exponent_mask[4] ALIGN16_END =
|
||||
{0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000};
|
||||
static const ALIGN16_BEG int eight_biased_exponent[4] ALIGN16_END =
|
||||
{0x43800000, 0x43800000, 0x43800000, 0x43800000};
|
||||
static const ALIGN16_BEG int implicit_leading_one[4] ALIGN16_END =
|
||||
{0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000};
|
||||
static const int shift_exponent_into_top_mantissa = 8;
|
||||
const __m128 two_n = _mm_and_ps(a, *((__m128 *)float_exponent_mask));
|
||||
const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(two_n),
|
||||
shift_exponent_into_top_mantissa));
|
||||
const __m128 n_0 = _mm_or_ps(n_1, *((__m128 *)eight_biased_exponent));
|
||||
const __m128 n = _mm_sub_ps(n_0, *((__m128 *)implicit_leading_one));
|
||||
|
||||
// Compute y.
|
||||
static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END =
|
||||
{0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF};
|
||||
static const ALIGN16_BEG int zero_biased_exponent_is_one[4] ALIGN16_END =
|
||||
{0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000};
|
||||
const __m128 mantissa = _mm_and_ps(a, *((__m128 *)mantissa_mask));
|
||||
const __m128 y = _mm_or_ps(
|
||||
mantissa, *((__m128 *)zero_biased_exponent_is_one));
|
||||
|
||||
// Approximate log2(y) ~= (y - 1) * pol5(y).
|
||||
// pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
|
||||
static const ALIGN16_BEG float ALIGN16_END C5[4] =
|
||||
{-3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C4[4] =
|
||||
{3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C3[4] =
|
||||
{-1.2315303f, -1.2315303f, -1.2315303f, -1.2315303f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C2[4] =
|
||||
{2.5988452f, 2.5988452f, 2.5988452f, 2.5988452f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C1[4] =
|
||||
{-3.3241990f, -3.3241990f, -3.3241990f, -3.3241990f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C0[4] =
|
||||
{3.1157899f, 3.1157899f, 3.1157899f, 3.1157899f};
|
||||
const __m128 pol5_y_0 = _mm_mul_ps(y, *((__m128 *)C5));
|
||||
const __m128 pol5_y_1 = _mm_add_ps(pol5_y_0, *((__m128 *)C4));
|
||||
const __m128 pol5_y_2 = _mm_mul_ps(pol5_y_1, y);
|
||||
const __m128 pol5_y_3 = _mm_add_ps(pol5_y_2, *((__m128 *)C3));
|
||||
const __m128 pol5_y_4 = _mm_mul_ps(pol5_y_3, y);
|
||||
const __m128 pol5_y_5 = _mm_add_ps(pol5_y_4, *((__m128 *)C2));
|
||||
const __m128 pol5_y_6 = _mm_mul_ps(pol5_y_5, y);
|
||||
const __m128 pol5_y_7 = _mm_add_ps(pol5_y_6, *((__m128 *)C1));
|
||||
const __m128 pol5_y_8 = _mm_mul_ps(pol5_y_7, y);
|
||||
const __m128 pol5_y = _mm_add_ps(pol5_y_8, *((__m128 *)C0));
|
||||
const __m128 y_minus_one = _mm_sub_ps(
|
||||
y, *((__m128 *)zero_biased_exponent_is_one));
|
||||
const __m128 log2_y = _mm_mul_ps(y_minus_one , pol5_y);
|
||||
|
||||
// Combine parts.
|
||||
log2_a = _mm_add_ps(n, log2_y);
|
||||
}
|
||||
|
||||
// b * log2(a)
|
||||
b_log2_a = _mm_mul_ps(b, log2_a);
|
||||
|
||||
// Calculate exp2(x), x = b * log2(a).
|
||||
{
|
||||
// To calculate 2^x, we decompose x like this:
|
||||
// x = n + y
|
||||
// n is an integer, the value of x - 0.5 rounded down, therefore
|
||||
// y is in the [0.5, 1.5) range
|
||||
//
|
||||
// 2^x = 2^n * 2^y
|
||||
// 2^n can be evaluated by playing with float representation.
|
||||
// 2^y in a small range can be approximated, this code uses an order two
|
||||
// polynomial approximation. The coefficients have been estimated
|
||||
// with the Remez algorithm and the resulting polynomial has a
|
||||
// maximum relative error of 0.17%.
|
||||
|
||||
// To avoid over/underflow, we reduce the range of input to ]-127, 129].
|
||||
static const ALIGN16_BEG float max_input[4] ALIGN16_END =
|
||||
{129.f, 129.f, 129.f, 129.f};
|
||||
static const ALIGN16_BEG float min_input[4] ALIGN16_END =
|
||||
{-126.99999f, -126.99999f, -126.99999f, -126.99999f};
|
||||
const __m128 x_min = _mm_min_ps(b_log2_a, *((__m128 *)max_input));
|
||||
const __m128 x_max = _mm_max_ps(x_min, *((__m128 *)min_input));
|
||||
// Compute n.
|
||||
static const ALIGN16_BEG float half[4] ALIGN16_END =
|
||||
{0.5f, 0.5f, 0.5f, 0.5f};
|
||||
const __m128 x_minus_half = _mm_sub_ps(x_max, *((__m128 *)half));
|
||||
const __m128i x_minus_half_floor = _mm_cvtps_epi32(x_minus_half);
|
||||
// Compute 2^n.
|
||||
static const ALIGN16_BEG int float_exponent_bias[4] ALIGN16_END =
|
||||
{127, 127, 127, 127};
|
||||
static const int float_exponent_shift = 23;
|
||||
const __m128i two_n_exponent = _mm_add_epi32(
|
||||
x_minus_half_floor, *((__m128i *)float_exponent_bias));
|
||||
const __m128 two_n = _mm_castsi128_ps(_mm_slli_epi32(
|
||||
two_n_exponent, float_exponent_shift));
|
||||
// Compute y.
|
||||
const __m128 y = _mm_sub_ps(x_max, _mm_cvtepi32_ps(x_minus_half_floor));
|
||||
// Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
|
||||
static const ALIGN16_BEG float C2[4] ALIGN16_END =
|
||||
{3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f};
|
||||
static const ALIGN16_BEG float C1[4] ALIGN16_END =
|
||||
{6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f};
|
||||
static const ALIGN16_BEG float C0[4] ALIGN16_END =
|
||||
{1.0017247f, 1.0017247f, 1.0017247f, 1.0017247f};
|
||||
const __m128 exp2_y_0 = _mm_mul_ps(y, *((__m128 *)C2));
|
||||
const __m128 exp2_y_1 = _mm_add_ps(exp2_y_0, *((__m128 *)C1));
|
||||
const __m128 exp2_y_2 = _mm_mul_ps(exp2_y_1, y);
|
||||
const __m128 exp2_y = _mm_add_ps(exp2_y_2, *((__m128 *)C0));
|
||||
|
||||
// Combine parts.
|
||||
a_exp_b = _mm_mul_ps(exp2_y, two_n);
|
||||
}
|
||||
return a_exp_b;
|
||||
}
|
||||
|
||||
extern const float WebRtcAec_weightCurve[65];
|
||||
extern const float WebRtcAec_overDriveCurve[65];
|
||||
|
||||
static void OverdriveAndSuppressSSE2(aec_t *aec, float hNl[PART_LEN1],
|
||||
const float hNlFb,
|
||||
float efw[2][PART_LEN1]) {
|
||||
int i;
|
||||
const __m128 vec_hNlFb = _mm_set1_ps(hNlFb);
|
||||
const __m128 vec_one = _mm_set1_ps(1.0f);
|
||||
const __m128 vec_minus_one = _mm_set1_ps(-1.0f);
|
||||
const __m128 vec_overDriveSm = _mm_set1_ps(aec->overDriveSm);
|
||||
// vectorized code (four at once)
|
||||
for (i = 0; i + 3 < PART_LEN1; i+=4) {
|
||||
// Weight subbands
|
||||
__m128 vec_hNl = _mm_loadu_ps(&hNl[i]);
|
||||
const __m128 vec_weightCurve = _mm_loadu_ps(&WebRtcAec_weightCurve[i]);
|
||||
const __m128 bigger = _mm_cmpgt_ps(vec_hNl, vec_hNlFb);
|
||||
const __m128 vec_weightCurve_hNlFb = _mm_mul_ps(
|
||||
vec_weightCurve, vec_hNlFb);
|
||||
const __m128 vec_one_weightCurve = _mm_sub_ps(vec_one, vec_weightCurve);
|
||||
const __m128 vec_one_weightCurve_hNl = _mm_mul_ps(
|
||||
vec_one_weightCurve, vec_hNl);
|
||||
const __m128 vec_if0 = _mm_andnot_ps(bigger, vec_hNl);
|
||||
const __m128 vec_if1 = _mm_and_ps(
|
||||
bigger, _mm_add_ps(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl));
|
||||
vec_hNl = _mm_or_ps(vec_if0, vec_if1);
|
||||
|
||||
{
|
||||
const __m128 vec_overDriveCurve = _mm_loadu_ps(
|
||||
&WebRtcAec_overDriveCurve[i]);
|
||||
const __m128 vec_overDriveSm_overDriveCurve = _mm_mul_ps(
|
||||
vec_overDriveSm, vec_overDriveCurve);
|
||||
vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve);
|
||||
_mm_storeu_ps(&hNl[i], vec_hNl);
|
||||
}
|
||||
|
||||
// Suppress error signal
|
||||
{
|
||||
__m128 vec_efw_re = _mm_loadu_ps(&efw[0][i]);
|
||||
__m128 vec_efw_im = _mm_loadu_ps(&efw[1][i]);
|
||||
vec_efw_re = _mm_mul_ps(vec_efw_re, vec_hNl);
|
||||
vec_efw_im = _mm_mul_ps(vec_efw_im, vec_hNl);
|
||||
|
||||
// Ooura fft returns incorrect sign on imaginary component. It matters
|
||||
// here because we are making an additive change with comfort noise.
|
||||
vec_efw_im = _mm_mul_ps(vec_efw_im, vec_minus_one);
|
||||
_mm_storeu_ps(&efw[0][i], vec_efw_re);
|
||||
_mm_storeu_ps(&efw[1][i], vec_efw_im);
|
||||
}
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; i < PART_LEN1; i++) {
|
||||
// Weight subbands
|
||||
if (hNl[i] > hNlFb) {
|
||||
hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
|
||||
(1 - WebRtcAec_weightCurve[i]) * hNl[i];
|
||||
}
|
||||
hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
|
||||
|
||||
// Suppress error signal
|
||||
efw[0][i] *= hNl[i];
|
||||
efw[1][i] *= hNl[i];
|
||||
|
||||
// Ooura fft returns incorrect sign on imaginary component. It matters
|
||||
// here because we are making an additive change with comfort noise.
|
||||
efw[1][i] *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_InitAec_SSE2(void) {
|
||||
WebRtcAec_FilterFar = FilterFarSSE2;
|
||||
WebRtcAec_ScaleErrorSignal = ScaleErrorSignalSSE2;
|
||||
WebRtcAec_FilterAdaptation = FilterAdaptationSSE2;
|
||||
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressSSE2;
|
||||
}
|
||||
|
||||
#endif // WEBRTC_USE_SSE2
|
587
webrtc/modules/audio_processing/aec/aec_rdft.c
Normal file
587
webrtc/modules/audio_processing/aec/aec_rdft.c
Normal file
@ -0,0 +1,587 @@
|
||||
/*
|
||||
* http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
|
||||
* Copyright Takuya OOURA, 1996-2001
|
||||
*
|
||||
* You may use, copy, modify and distribute this code for any purpose (include
|
||||
* commercial use) and without fee. Please refer to this package when you modify
|
||||
* this code.
|
||||
*
|
||||
* Changes by the WebRTC authors:
|
||||
* - Trivial type modifications.
|
||||
* - Minimal code subset to do rdft of length 128.
|
||||
* - Optimizations because of known length.
|
||||
*
|
||||
* All changes are covered by the WebRTC license and IP grant:
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "aec_rdft.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "system_wrappers/interface/cpu_features_wrapper.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
// constants shared by all paths (C, SSE2).
|
||||
float rdft_w[64];
|
||||
// constants used by the C path.
|
||||
float rdft_wk3ri_first[32];
|
||||
float rdft_wk3ri_second[32];
|
||||
// constants used by SSE2 but initialized in C path.
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk1r[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk2r[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk3r[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk1i[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk2i[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk3i[32];
|
||||
ALIGN16_BEG float ALIGN16_END cftmdl_wk1r[4];
|
||||
|
||||
static int ip[16];
|
||||
|
||||
static void bitrv2_32or128(int n, int *ip, float *a) {
|
||||
// n is 32 or 128
|
||||
int j, j1, k, k1, m, m2;
|
||||
float xr, xi, yr, yi;
|
||||
|
||||
ip[0] = 0;
|
||||
{
|
||||
int l = n;
|
||||
m = 1;
|
||||
while ((m << 3) < l) {
|
||||
l >>= 1;
|
||||
for (j = 0; j < m; j++) {
|
||||
ip[m + j] = ip[j] + l;
|
||||
}
|
||||
m <<= 1;
|
||||
}
|
||||
}
|
||||
m2 = 2 * m;
|
||||
for (k = 0; k < m; k++) {
|
||||
for (j = 0; j < k; j++) {
|
||||
j1 = 2 * j + ip[k];
|
||||
k1 = 2 * k + ip[j];
|
||||
xr = a[j1];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += m2;
|
||||
k1 += 2 * m2;
|
||||
xr = a[j1];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += m2;
|
||||
k1 -= m2;
|
||||
xr = a[j1];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += m2;
|
||||
k1 += 2 * m2;
|
||||
xr = a[j1];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
}
|
||||
j1 = 2 * k + m2 + ip[k];
|
||||
k1 = j1 + m2;
|
||||
xr = a[j1];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
}
|
||||
}
|
||||
|
||||
static void makewt_32(void) {
|
||||
const int nw = 32;
|
||||
int j, nwh;
|
||||
float delta, x, y;
|
||||
|
||||
ip[0] = nw;
|
||||
ip[1] = 1;
|
||||
nwh = nw >> 1;
|
||||
delta = atanf(1.0f) / nwh;
|
||||
rdft_w[0] = 1;
|
||||
rdft_w[1] = 0;
|
||||
rdft_w[nwh] = cosf(delta * nwh);
|
||||
rdft_w[nwh + 1] = rdft_w[nwh];
|
||||
for (j = 2; j < nwh; j += 2) {
|
||||
x = cosf(delta * j);
|
||||
y = sinf(delta * j);
|
||||
rdft_w[j] = x;
|
||||
rdft_w[j + 1] = y;
|
||||
rdft_w[nw - j] = y;
|
||||
rdft_w[nw - j + 1] = x;
|
||||
}
|
||||
bitrv2_32or128(nw, ip + 2, rdft_w);
|
||||
|
||||
// pre-calculate constants used by cft1st_128 and cftmdl_128...
|
||||
cftmdl_wk1r[0] = rdft_w[2];
|
||||
cftmdl_wk1r[1] = rdft_w[2];
|
||||
cftmdl_wk1r[2] = rdft_w[2];
|
||||
cftmdl_wk1r[3] = -rdft_w[2];
|
||||
{
|
||||
int k1;
|
||||
|
||||
for (k1 = 0, j = 0; j < 128; j += 16, k1 += 2) {
|
||||
const int k2 = 2 * k1;
|
||||
const float wk2r = rdft_w[k1 + 0];
|
||||
const float wk2i = rdft_w[k1 + 1];
|
||||
float wk1r, wk1i;
|
||||
// ... scalar version.
|
||||
wk1r = rdft_w[k2 + 0];
|
||||
wk1i = rdft_w[k2 + 1];
|
||||
rdft_wk3ri_first[k1 + 0] = wk1r - 2 * wk2i * wk1i;
|
||||
rdft_wk3ri_first[k1 + 1] = 2 * wk2i * wk1r - wk1i;
|
||||
wk1r = rdft_w[k2 + 2];
|
||||
wk1i = rdft_w[k2 + 3];
|
||||
rdft_wk3ri_second[k1 + 0] = wk1r - 2 * wk2r * wk1i;
|
||||
rdft_wk3ri_second[k1 + 1] = 2 * wk2r * wk1r - wk1i;
|
||||
// ... vector version.
|
||||
rdft_wk1r[k2 + 0] = rdft_w[k2 + 0];
|
||||
rdft_wk1r[k2 + 1] = rdft_w[k2 + 0];
|
||||
rdft_wk1r[k2 + 2] = rdft_w[k2 + 2];
|
||||
rdft_wk1r[k2 + 3] = rdft_w[k2 + 2];
|
||||
rdft_wk2r[k2 + 0] = rdft_w[k1 + 0];
|
||||
rdft_wk2r[k2 + 1] = rdft_w[k1 + 0];
|
||||
rdft_wk2r[k2 + 2] = -rdft_w[k1 + 1];
|
||||
rdft_wk2r[k2 + 3] = -rdft_w[k1 + 1];
|
||||
rdft_wk3r[k2 + 0] = rdft_wk3ri_first[k1 + 0];
|
||||
rdft_wk3r[k2 + 1] = rdft_wk3ri_first[k1 + 0];
|
||||
rdft_wk3r[k2 + 2] = rdft_wk3ri_second[k1 + 0];
|
||||
rdft_wk3r[k2 + 3] = rdft_wk3ri_second[k1 + 0];
|
||||
rdft_wk1i[k2 + 0] = -rdft_w[k2 + 1];
|
||||
rdft_wk1i[k2 + 1] = rdft_w[k2 + 1];
|
||||
rdft_wk1i[k2 + 2] = -rdft_w[k2 + 3];
|
||||
rdft_wk1i[k2 + 3] = rdft_w[k2 + 3];
|
||||
rdft_wk2i[k2 + 0] = -rdft_w[k1 + 1];
|
||||
rdft_wk2i[k2 + 1] = rdft_w[k1 + 1];
|
||||
rdft_wk2i[k2 + 2] = -rdft_w[k1 + 0];
|
||||
rdft_wk2i[k2 + 3] = rdft_w[k1 + 0];
|
||||
rdft_wk3i[k2 + 0] = -rdft_wk3ri_first[k1 + 1];
|
||||
rdft_wk3i[k2 + 1] = rdft_wk3ri_first[k1 + 1];
|
||||
rdft_wk3i[k2 + 2] = -rdft_wk3ri_second[k1 + 1];
|
||||
rdft_wk3i[k2 + 3] = rdft_wk3ri_second[k1 + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void makect_32(void) {
|
||||
float *c = rdft_w + 32;
|
||||
const int nc = 32;
|
||||
int j, nch;
|
||||
float delta;
|
||||
|
||||
ip[1] = nc;
|
||||
nch = nc >> 1;
|
||||
delta = atanf(1.0f) / nch;
|
||||
c[0] = cosf(delta * nch);
|
||||
c[nch] = 0.5f * c[0];
|
||||
for (j = 1; j < nch; j++) {
|
||||
c[j] = 0.5f * cosf(delta * j);
|
||||
c[nc - j] = 0.5f * sinf(delta * j);
|
||||
}
|
||||
}
|
||||
|
||||
static void cft1st_128_C(float *a) {
|
||||
const int n = 128;
|
||||
int j, k1, k2;
|
||||
float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
x0r = a[0] + a[2];
|
||||
x0i = a[1] + a[3];
|
||||
x1r = a[0] - a[2];
|
||||
x1i = a[1] - a[3];
|
||||
x2r = a[4] + a[6];
|
||||
x2i = a[5] + a[7];
|
||||
x3r = a[4] - a[6];
|
||||
x3i = a[5] - a[7];
|
||||
a[0] = x0r + x2r;
|
||||
a[1] = x0i + x2i;
|
||||
a[4] = x0r - x2r;
|
||||
a[5] = x0i - x2i;
|
||||
a[2] = x1r - x3i;
|
||||
a[3] = x1i + x3r;
|
||||
a[6] = x1r + x3i;
|
||||
a[7] = x1i - x3r;
|
||||
wk1r = rdft_w[2];
|
||||
x0r = a[8] + a[10];
|
||||
x0i = a[9] + a[11];
|
||||
x1r = a[8] - a[10];
|
||||
x1i = a[9] - a[11];
|
||||
x2r = a[12] + a[14];
|
||||
x2i = a[13] + a[15];
|
||||
x3r = a[12] - a[14];
|
||||
x3i = a[13] - a[15];
|
||||
a[8] = x0r + x2r;
|
||||
a[9] = x0i + x2i;
|
||||
a[12] = x2i - x0i;
|
||||
a[13] = x0r - x2r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[10] = wk1r * (x0r - x0i);
|
||||
a[11] = wk1r * (x0r + x0i);
|
||||
x0r = x3i + x1r;
|
||||
x0i = x3r - x1i;
|
||||
a[14] = wk1r * (x0i - x0r);
|
||||
a[15] = wk1r * (x0i + x0r);
|
||||
k1 = 0;
|
||||
for (j = 16; j < n; j += 16) {
|
||||
k1 += 2;
|
||||
k2 = 2 * k1;
|
||||
wk2r = rdft_w[k1 + 0];
|
||||
wk2i = rdft_w[k1 + 1];
|
||||
wk1r = rdft_w[k2 + 0];
|
||||
wk1i = rdft_w[k2 + 1];
|
||||
wk3r = rdft_wk3ri_first[k1 + 0];
|
||||
wk3i = rdft_wk3ri_first[k1 + 1];
|
||||
x0r = a[j + 0] + a[j + 2];
|
||||
x0i = a[j + 1] + a[j + 3];
|
||||
x1r = a[j + 0] - a[j + 2];
|
||||
x1i = a[j + 1] - a[j + 3];
|
||||
x2r = a[j + 4] + a[j + 6];
|
||||
x2i = a[j + 5] + a[j + 7];
|
||||
x3r = a[j + 4] - a[j + 6];
|
||||
x3i = a[j + 5] - a[j + 7];
|
||||
a[j + 0] = x0r + x2r;
|
||||
a[j + 1] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j + 4] = wk2r * x0r - wk2i * x0i;
|
||||
a[j + 5] = wk2r * x0i + wk2i * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j + 2] = wk1r * x0r - wk1i * x0i;
|
||||
a[j + 3] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j + 6] = wk3r * x0r - wk3i * x0i;
|
||||
a[j + 7] = wk3r * x0i + wk3i * x0r;
|
||||
wk1r = rdft_w[k2 + 2];
|
||||
wk1i = rdft_w[k2 + 3];
|
||||
wk3r = rdft_wk3ri_second[k1 + 0];
|
||||
wk3i = rdft_wk3ri_second[k1 + 1];
|
||||
x0r = a[j + 8] + a[j + 10];
|
||||
x0i = a[j + 9] + a[j + 11];
|
||||
x1r = a[j + 8] - a[j + 10];
|
||||
x1i = a[j + 9] - a[j + 11];
|
||||
x2r = a[j + 12] + a[j + 14];
|
||||
x2i = a[j + 13] + a[j + 15];
|
||||
x3r = a[j + 12] - a[j + 14];
|
||||
x3i = a[j + 13] - a[j + 15];
|
||||
a[j + 8] = x0r + x2r;
|
||||
a[j + 9] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j + 12] = -wk2i * x0r - wk2r * x0i;
|
||||
a[j + 13] = -wk2i * x0i + wk2r * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j + 10] = wk1r * x0r - wk1i * x0i;
|
||||
a[j + 11] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j + 14] = wk3r * x0r - wk3i * x0i;
|
||||
a[j + 15] = wk3r * x0i + wk3i * x0r;
|
||||
}
|
||||
}
|
||||
|
||||
static void cftmdl_128_C(float *a) {
|
||||
const int l = 8;
|
||||
const int n = 128;
|
||||
const int m = 32;
|
||||
int j0, j1, j2, j3, k, k1, k2, m2;
|
||||
float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
for (j0 = 0; j0 < l; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
a[j2 + 0] = x0r - x2r;
|
||||
a[j2 + 1] = x0i - x2i;
|
||||
a[j1 + 0] = x1r - x3i;
|
||||
a[j1 + 1] = x1i + x3r;
|
||||
a[j3 + 0] = x1r + x3i;
|
||||
a[j3 + 1] = x1i - x3r;
|
||||
}
|
||||
wk1r = rdft_w[2];
|
||||
for (j0 = m; j0 < l + m; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
a[j2 + 0] = x2i - x0i;
|
||||
a[j2 + 1] = x0r - x2r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j1 + 0] = wk1r * (x0r - x0i);
|
||||
a[j1 + 1] = wk1r * (x0r + x0i);
|
||||
x0r = x3i + x1r;
|
||||
x0i = x3r - x1i;
|
||||
a[j3 + 0] = wk1r * (x0i - x0r);
|
||||
a[j3 + 1] = wk1r * (x0i + x0r);
|
||||
}
|
||||
k1 = 0;
|
||||
m2 = 2 * m;
|
||||
for (k = m2; k < n; k += m2) {
|
||||
k1 += 2;
|
||||
k2 = 2 * k1;
|
||||
wk2r = rdft_w[k1 + 0];
|
||||
wk2i = rdft_w[k1 + 1];
|
||||
wk1r = rdft_w[k2 + 0];
|
||||
wk1i = rdft_w[k2 + 1];
|
||||
wk3r = rdft_wk3ri_first[k1 + 0];
|
||||
wk3i = rdft_wk3ri_first[k1 + 1];
|
||||
for (j0 = k; j0 < l + k; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j2 + 0] = wk2r * x0r - wk2i * x0i;
|
||||
a[j2 + 1] = wk2r * x0i + wk2i * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j1 + 0] = wk1r * x0r - wk1i * x0i;
|
||||
a[j1 + 1] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j3 + 0] = wk3r * x0r - wk3i * x0i;
|
||||
a[j3 + 1] = wk3r * x0i + wk3i * x0r;
|
||||
}
|
||||
wk1r = rdft_w[k2 + 2];
|
||||
wk1i = rdft_w[k2 + 3];
|
||||
wk3r = rdft_wk3ri_second[k1 + 0];
|
||||
wk3i = rdft_wk3ri_second[k1 + 1];
|
||||
for (j0 = k + m; j0 < l + (k + m); j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j2 + 0] = -wk2i * x0r - wk2r * x0i;
|
||||
a[j2 + 1] = -wk2i * x0i + wk2r * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j1 + 0] = wk1r * x0r - wk1i * x0i;
|
||||
a[j1 + 1] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j3 + 0] = wk3r * x0r - wk3i * x0i;
|
||||
a[j3 + 1] = wk3r * x0i + wk3i * x0r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cftfsub_128(float *a) {
|
||||
int j, j1, j2, j3, l;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
cft1st_128(a);
|
||||
cftmdl_128(a);
|
||||
l = 32;
|
||||
for (j = 0; j < l; j += 2) {
|
||||
j1 = j + l;
|
||||
j2 = j1 + l;
|
||||
j3 = j2 + l;
|
||||
x0r = a[j] + a[j1];
|
||||
x0i = a[j + 1] + a[j1 + 1];
|
||||
x1r = a[j] - a[j1];
|
||||
x1i = a[j + 1] - a[j1 + 1];
|
||||
x2r = a[j2] + a[j3];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2] - a[j3];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j] = x0r + x2r;
|
||||
a[j + 1] = x0i + x2i;
|
||||
a[j2] = x0r - x2r;
|
||||
a[j2 + 1] = x0i - x2i;
|
||||
a[j1] = x1r - x3i;
|
||||
a[j1 + 1] = x1i + x3r;
|
||||
a[j3] = x1r + x3i;
|
||||
a[j3 + 1] = x1i - x3r;
|
||||
}
|
||||
}
|
||||
|
||||
static void cftbsub_128(float *a) {
|
||||
int j, j1, j2, j3, l;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
cft1st_128(a);
|
||||
cftmdl_128(a);
|
||||
l = 32;
|
||||
|
||||
for (j = 0; j < l; j += 2) {
|
||||
j1 = j + l;
|
||||
j2 = j1 + l;
|
||||
j3 = j2 + l;
|
||||
x0r = a[j] + a[j1];
|
||||
x0i = -a[j + 1] - a[j1 + 1];
|
||||
x1r = a[j] - a[j1];
|
||||
x1i = -a[j + 1] + a[j1 + 1];
|
||||
x2r = a[j2] + a[j3];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2] - a[j3];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j] = x0r + x2r;
|
||||
a[j + 1] = x0i - x2i;
|
||||
a[j2] = x0r - x2r;
|
||||
a[j2 + 1] = x0i + x2i;
|
||||
a[j1] = x1r - x3i;
|
||||
a[j1 + 1] = x1i - x3r;
|
||||
a[j3] = x1r + x3i;
|
||||
a[j3 + 1] = x1i + x3r;
|
||||
}
|
||||
}
|
||||
|
||||
static void rftfsub_128_C(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr - wki * xi;
|
||||
yi = wkr * xi + wki * xr;
|
||||
a[j2 + 0] -= yr;
|
||||
a[j2 + 1] -= yi;
|
||||
a[k2 + 0] += yr;
|
||||
a[k2 + 1] -= yi;
|
||||
}
|
||||
}
|
||||
|
||||
static void rftbsub_128_C(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
a[1] = -a[1];
|
||||
for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr + wki * xi;
|
||||
yi = wkr * xi - wki * xr;
|
||||
a[j2 + 0] = a[j2 + 0] - yr;
|
||||
a[j2 + 1] = yi - a[j2 + 1];
|
||||
a[k2 + 0] = yr + a[k2 + 0];
|
||||
a[k2 + 1] = yi - a[k2 + 1];
|
||||
}
|
||||
a[65] = -a[65];
|
||||
}
|
||||
|
||||
void aec_rdft_forward_128(float *a) {
|
||||
const int n = 128;
|
||||
float xi;
|
||||
|
||||
bitrv2_32or128(n, ip + 2, a);
|
||||
cftfsub_128(a);
|
||||
rftfsub_128(a);
|
||||
xi = a[0] - a[1];
|
||||
a[0] += a[1];
|
||||
a[1] = xi;
|
||||
}
|
||||
|
||||
void aec_rdft_inverse_128(float *a) {
|
||||
const int n = 128;
|
||||
|
||||
a[1] = 0.5f * (a[0] - a[1]);
|
||||
a[0] -= a[1];
|
||||
rftbsub_128(a);
|
||||
bitrv2_32or128(n, ip + 2, a);
|
||||
cftbsub_128(a);
|
||||
}
|
||||
|
||||
// code path selection
|
||||
rft_sub_128_t cft1st_128;
|
||||
rft_sub_128_t cftmdl_128;
|
||||
rft_sub_128_t rftfsub_128;
|
||||
rft_sub_128_t rftbsub_128;
|
||||
|
||||
void aec_rdft_init(void) {
|
||||
cft1st_128 = cft1st_128_C;
|
||||
cftmdl_128 = cftmdl_128_C;
|
||||
rftfsub_128 = rftfsub_128_C;
|
||||
rftbsub_128 = rftbsub_128_C;
|
||||
if (WebRtc_GetCPUInfo(kSSE2)) {
|
||||
#if defined(WEBRTC_USE_SSE2)
|
||||
aec_rdft_init_sse2();
|
||||
#endif
|
||||
}
|
||||
// init library constants.
|
||||
makewt_32();
|
||||
makect_32();
|
||||
}
|
57
webrtc/modules/audio_processing/aec/aec_rdft.h
Normal file
57
webrtc/modules/audio_processing/aec/aec_rdft.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
|
||||
|
||||
// These intrinsics were unavailable before VS 2008.
|
||||
// TODO(andrew): move to a common file.
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1500
|
||||
#include <emmintrin.h>
|
||||
static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; }
|
||||
static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; }
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER /* visual c++ */
|
||||
# define ALIGN16_BEG __declspec(align(16))
|
||||
# define ALIGN16_END
|
||||
#else /* gcc or icc */
|
||||
# define ALIGN16_BEG
|
||||
# define ALIGN16_END __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
// constants shared by all paths (C, SSE2).
|
||||
extern float rdft_w[64];
|
||||
// constants used by the C path.
|
||||
extern float rdft_wk3ri_first[32];
|
||||
extern float rdft_wk3ri_second[32];
|
||||
// constants used by SSE2 but initialized in C path.
|
||||
extern float rdft_wk1r[32];
|
||||
extern float rdft_wk2r[32];
|
||||
extern float rdft_wk3r[32];
|
||||
extern float rdft_wk1i[32];
|
||||
extern float rdft_wk2i[32];
|
||||
extern float rdft_wk3i[32];
|
||||
extern float cftmdl_wk1r[4];
|
||||
|
||||
// code path selection function pointers
|
||||
typedef void (*rft_sub_128_t)(float *a);
|
||||
extern rft_sub_128_t rftfsub_128;
|
||||
extern rft_sub_128_t rftbsub_128;
|
||||
extern rft_sub_128_t cft1st_128;
|
||||
extern rft_sub_128_t cftmdl_128;
|
||||
|
||||
// entry points
|
||||
void aec_rdft_init(void);
|
||||
void aec_rdft_init_sse2(void);
|
||||
void aec_rdft_forward_128(float *a);
|
||||
void aec_rdft_inverse_128(float *a);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
|
431
webrtc/modules/audio_processing/aec/aec_rdft_sse2.c
Normal file
431
webrtc/modules/audio_processing/aec/aec_rdft_sse2.c
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#if defined(WEBRTC_USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
|
||||
#include "aec_rdft.h"
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END k_swap_sign[4] =
|
||||
{-1.f, 1.f, -1.f, 1.f};
|
||||
|
||||
static void cft1st_128_SSE2(float *a) {
|
||||
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
|
||||
int j, k2;
|
||||
|
||||
for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) {
|
||||
__m128 a00v = _mm_loadu_ps(&a[j + 0]);
|
||||
__m128 a04v = _mm_loadu_ps(&a[j + 4]);
|
||||
__m128 a08v = _mm_loadu_ps(&a[j + 8]);
|
||||
__m128 a12v = _mm_loadu_ps(&a[j + 12]);
|
||||
__m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
__m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
|
||||
const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]);
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]);
|
||||
__m128 x0v = _mm_add_ps(a01v, a23v);
|
||||
const __m128 x1v = _mm_sub_ps(a01v, a23v);
|
||||
const __m128 x2v = _mm_add_ps(a45v, a67v);
|
||||
const __m128 x3v = _mm_sub_ps(a45v, a67v);
|
||||
__m128 x0w;
|
||||
a01v = _mm_add_ps(x0v, x2v);
|
||||
x0v = _mm_sub_ps(x0v, x2v);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
{
|
||||
const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v);
|
||||
const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w);
|
||||
a45v = _mm_add_ps(a45_0v, a45_1v);
|
||||
}
|
||||
{
|
||||
__m128 a23_0v, a23_1v;
|
||||
const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w);
|
||||
x0v = _mm_add_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
a23_0v = _mm_mul_ps(wk1rv, x0v);
|
||||
a23_1v = _mm_mul_ps(wk1iv, x0w);
|
||||
a23v = _mm_add_ps(a23_0v, a23_1v);
|
||||
|
||||
x0v = _mm_sub_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
}
|
||||
{
|
||||
const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v);
|
||||
const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w);
|
||||
a67v = _mm_add_ps(a67_0v, a67_1v);
|
||||
}
|
||||
|
||||
a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
_mm_storeu_ps(&a[j + 0], a00v);
|
||||
_mm_storeu_ps(&a[j + 4], a04v);
|
||||
_mm_storeu_ps(&a[j + 8], a08v);
|
||||
_mm_storeu_ps(&a[j + 12], a12v);
|
||||
}
|
||||
}
|
||||
|
||||
static void cftmdl_128_SSE2(float *a) {
|
||||
const int l = 8;
|
||||
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
|
||||
int j0;
|
||||
|
||||
__m128 wk1rv = _mm_load_ps(cftmdl_wk1r);
|
||||
for (j0 = 0; j0 < l; j0 += 2) {
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
|
||||
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
|
||||
const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]);
|
||||
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
|
||||
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
|
||||
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
|
||||
const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(
|
||||
_mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1),
|
||||
_MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
|
||||
const __m128 yy0 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub,
|
||||
_MM_SHUFFLE(2, 2, 2 ,2));
|
||||
const __m128 yy1 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub,
|
||||
_MM_SHUFFLE(3, 3, 3 ,3));
|
||||
const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1);
|
||||
const __m128 yy3 = _mm_add_ps(yy0, yy2);
|
||||
const __m128 yy4 = _mm_mul_ps(wk1rv, yy3);
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx0),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx1),
|
||||
_MM_SHUFFLE(2, 3, 2, 3)));
|
||||
a[j0 + 48] = -a[j0 + 48];
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(yy4),
|
||||
_MM_SHUFFLE(2, 3, 2, 3)));
|
||||
}
|
||||
|
||||
{
|
||||
int k = 64;
|
||||
int k1 = 2;
|
||||
int k2 = 2 * k1;
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2+0]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2+0]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2+0]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2+0]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2+0]);
|
||||
wk1rv = _mm_load_ps(&rdft_wk1r[k2+0]);
|
||||
for (j0 = k; j0 < l + k; j0 += 2) {
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
|
||||
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
|
||||
const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]);
|
||||
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
|
||||
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
|
||||
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
|
||||
const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx2 = _mm_mul_ps(xx1 , wk2rv);
|
||||
const __m128 xx3 = _mm_mul_ps(wk2iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx4 = _mm_add_ps(xx2, xx3);
|
||||
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(
|
||||
_mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1),
|
||||
_MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
|
||||
const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv);
|
||||
const __m128 xx11 = _mm_mul_ps(wk1iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx12 = _mm_add_ps(xx10, xx11);
|
||||
|
||||
const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv);
|
||||
const __m128 xx21 = _mm_mul_ps(wk3iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx22 = _mm_add_ps(xx20, xx21);
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx4),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 40],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx12),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx22),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rftfsub_128_SSE2(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END k_half[4] =
|
||||
{0.5f, 0.5f, 0.5f, 0.5f};
|
||||
const __m128 mm_half = _mm_load_ps(k_half);
|
||||
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[ j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 wkr_ =
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(2, 0, 2 ,0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(3, 1, 3 ,1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(0, 2, 0 ,2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(1, 3, 1 ,3)); // 127, 125, 123, 121,
|
||||
// Calculate 'x'.
|
||||
const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr - wki * xi;
|
||||
// yi = wkr * xi + wki * xr;
|
||||
const __m128 a_ = _mm_mul_ps(wkr_, xr_);
|
||||
const __m128 b_ = _mm_mul_ps(wki_, xi_);
|
||||
const __m128 c_ = _mm_mul_ps(wkr_, xi_);
|
||||
const __m128 d_ = _mm_mul_ps(wki_, xr_);
|
||||
const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] -= yr;
|
||||
// a[j2 + 1] -= yi;
|
||||
// a[k2 + 0] += yr;
|
||||
// a[k2 + 1] -= yi;
|
||||
const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1n = _mm_sub_ps(a_j2_p1, yi_); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1n = _mm_sub_ps(a_k2_p1, yi_); // 127, 125, 123, 121,
|
||||
// Shuffle in right order and store.
|
||||
const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 2, 3, 4, 5,
|
||||
const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 6, 7, 8, 9,
|
||||
const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 122, 123, 120, 121,
|
||||
const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(a_k2_0nt, a_k2_0nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(a_k2_4nt, a_k2_4nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
_mm_storeu_ps(&a[122 - j2], a_k2_0n);
|
||||
_mm_storeu_ps(&a[126 - j2], a_k2_4n);
|
||||
}
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr - wki * xi;
|
||||
yi = wkr * xi + wki * xr;
|
||||
a[j2 + 0] -= yr;
|
||||
a[j2 + 1] -= yi;
|
||||
a[k2 + 0] += yr;
|
||||
a[k2 + 1] -= yi;
|
||||
}
|
||||
}
|
||||
|
||||
static void rftbsub_128_SSE2(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END k_half[4] =
|
||||
{0.5f, 0.5f, 0.5f, 0.5f};
|
||||
const __m128 mm_half = _mm_load_ps(k_half);
|
||||
|
||||
a[1] = -a[1];
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[ j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 wkr_ =
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(2, 0, 2 ,0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(3, 1, 3 ,1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(0, 2, 0 ,2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(1, 3, 1 ,3)); // 127, 125, 123, 121,
|
||||
// Calculate 'x'.
|
||||
const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr + wki * xi;
|
||||
// yi = wkr * xi - wki * xr;
|
||||
const __m128 a_ = _mm_mul_ps(wkr_, xr_);
|
||||
const __m128 b_ = _mm_mul_ps(wki_, xi_);
|
||||
const __m128 c_ = _mm_mul_ps(wkr_, xi_);
|
||||
const __m128 d_ = _mm_mul_ps(wki_, xr_);
|
||||
const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] = a[j2 + 0] - yr;
|
||||
// a[j2 + 1] = yi - a[j2 + 1];
|
||||
// a[k2 + 0] = yr + a[k2 + 0];
|
||||
// a[k2 + 1] = yi - a[k2 + 1];
|
||||
const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1n = _mm_sub_ps(yi_, a_j2_p1); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1n = _mm_sub_ps(yi_, a_k2_p1); // 127, 125, 123, 121,
|
||||
// Shuffle in right order and store.
|
||||
const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 2, 3, 4, 5,
|
||||
const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 6, 7, 8, 9,
|
||||
const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 122, 123, 120, 121,
|
||||
const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(a_k2_0nt, a_k2_0nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(a_k2_4nt, a_k2_4nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
_mm_storeu_ps(&a[122 - j2], a_k2_0n);
|
||||
_mm_storeu_ps(&a[126 - j2], a_k2_4n);
|
||||
}
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr + wki * xi;
|
||||
yi = wkr * xi - wki * xr;
|
||||
a[j2 + 0] = a[j2 + 0] - yr;
|
||||
a[j2 + 1] = yi - a[j2 + 1];
|
||||
a[k2 + 0] = yr + a[k2 + 0];
|
||||
a[k2 + 1] = yi - a[k2 + 1];
|
||||
}
|
||||
a[65] = -a[65];
|
||||
}
|
||||
|
||||
void aec_rdft_init_sse2(void) {
|
||||
cft1st_128 = cft1st_128_SSE2;
|
||||
cftmdl_128 = cftmdl_128_SSE2;
|
||||
rftfsub_128 = rftfsub_128_SSE2;
|
||||
rftbsub_128 = rftbsub_128_SSE2;
|
||||
}
|
||||
|
||||
#endif // WEBRTC_USE_SS2
|
901
webrtc/modules/audio_processing/aec/echo_cancellation.c
Normal file
901
webrtc/modules/audio_processing/aec/echo_cancellation.c
Normal file
@ -0,0 +1,901 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Contains the API functions for the AEC.
|
||||
*/
|
||||
#include "echo_cancellation.h"
|
||||
|
||||
#include <math.h>
|
||||
#ifdef AEC_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aec_core.h"
|
||||
#include "resampler.h"
|
||||
#include "ring_buffer.h"
|
||||
|
||||
#define BUF_SIZE_FRAMES 50 // buffer size (frames)
|
||||
// Maximum length of resampled signal. Must be an integer multiple of frames
|
||||
// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
|
||||
// The factor of 2 handles wb, and the + 1 is as a safety margin
|
||||
#define MAX_RESAMP_LEN (5 * FRAME_LEN)
|
||||
|
||||
static const int bufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
|
||||
static const int sampMsNb = 8; // samples per ms in nb
|
||||
// Target suppression levels for nlp modes
|
||||
// log{0.001, 0.00001, 0.00000001}
|
||||
static const float targetSupp[3] = {-6.9f, -11.5f, -18.4f};
|
||||
static const float minOverDrive[3] = {1.0f, 2.0f, 5.0f};
|
||||
static const int initCheck = 42;
|
||||
|
||||
typedef struct {
|
||||
int delayCtr;
|
||||
int sampFreq;
|
||||
int splitSampFreq;
|
||||
int scSampFreq;
|
||||
float sampFactor; // scSampRate / sampFreq
|
||||
short nlpMode;
|
||||
short autoOnOff;
|
||||
short activity;
|
||||
short skewMode;
|
||||
short bufSizeStart;
|
||||
//short bufResetCtr; // counts number of noncausal frames
|
||||
int knownDelay;
|
||||
|
||||
// Stores the last frame added to the farend buffer
|
||||
short farendOld[2][FRAME_LEN];
|
||||
short initFlag; // indicates if AEC has been initialized
|
||||
|
||||
// Variables used for averaging far end buffer size
|
||||
short counter;
|
||||
short sum;
|
||||
short firstVal;
|
||||
short checkBufSizeCtr;
|
||||
|
||||
// Variables used for delay shifts
|
||||
short msInSndCardBuf;
|
||||
short filtDelay;
|
||||
int timeForDelayChange;
|
||||
int ECstartup;
|
||||
int checkBuffSize;
|
||||
int delayChange;
|
||||
short lastDelayDiff;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *bufFile;
|
||||
FILE *delayFile;
|
||||
FILE *skewFile;
|
||||
FILE *preCompFile;
|
||||
FILE *postCompFile;
|
||||
#endif // AEC_DEBUG
|
||||
|
||||
// Structures
|
||||
void *farendBuf;
|
||||
void *resampler;
|
||||
|
||||
int skewFrCtr;
|
||||
int resample; // if the skew is small enough we don't resample
|
||||
int highSkewCtr;
|
||||
float skew;
|
||||
|
||||
int lastError;
|
||||
|
||||
aec_t *aec;
|
||||
} aecpc_t;
|
||||
|
||||
// Estimates delay to set the position of the farend buffer read pointer
|
||||
// (controlled by knownDelay)
|
||||
static int EstBufDelay(aecpc_t *aecInst, short msInSndCardBuf);
|
||||
|
||||
// Stuffs the farend buffer if the estimated delay is too large
|
||||
static int DelayComp(aecpc_t *aecInst);
|
||||
|
||||
WebRtc_Word32 WebRtcAec_Create(void **aecInst)
|
||||
{
|
||||
aecpc_t *aecpc;
|
||||
if (aecInst == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecpc = malloc(sizeof(aecpc_t));
|
||||
*aecInst = aecpc;
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAec_CreateAec(&aecpc->aec) == -1) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcApm_CreateBuffer(&aecpc->farendBuf, bufSizeSamp) == -1) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAec_CreateResampler(&aecpc->resampler) == -1) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecpc->initFlag = 0;
|
||||
aecpc->lastError = 0;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
aecpc->aec->farFile = fopen("aecFar.pcm","wb");
|
||||
aecpc->aec->nearFile = fopen("aecNear.pcm","wb");
|
||||
aecpc->aec->outFile = fopen("aecOut.pcm","wb");
|
||||
aecpc->aec->outLpFile = fopen("aecOutLp.pcm","wb");
|
||||
|
||||
aecpc->bufFile = fopen("aecBuf.dat", "wb");
|
||||
aecpc->skewFile = fopen("aecSkew.dat", "wb");
|
||||
aecpc->delayFile = fopen("aecDelay.dat", "wb");
|
||||
aecpc->preCompFile = fopen("preComp.pcm", "wb");
|
||||
aecpc->postCompFile = fopen("postComp.pcm", "wb");
|
||||
#endif // AEC_DEBUG
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_Free(void *aecInst)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
fclose(aecpc->aec->farFile);
|
||||
fclose(aecpc->aec->nearFile);
|
||||
fclose(aecpc->aec->outFile);
|
||||
fclose(aecpc->aec->outLpFile);
|
||||
|
||||
fclose(aecpc->bufFile);
|
||||
fclose(aecpc->skewFile);
|
||||
fclose(aecpc->delayFile);
|
||||
fclose(aecpc->preCompFile);
|
||||
fclose(aecpc->postCompFile);
|
||||
#endif // AEC_DEBUG
|
||||
|
||||
WebRtcAec_FreeAec(aecpc->aec);
|
||||
WebRtcApm_FreeBuffer(aecpc->farendBuf);
|
||||
WebRtcAec_FreeResampler(aecpc->resampler);
|
||||
free(aecpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word32 scSampFreq)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
AecConfig aecConfig;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sampFreq != 8000 && sampFreq != 16000 && sampFreq != 32000) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->sampFreq = sampFreq;
|
||||
|
||||
if (scSampFreq < 1 || scSampFreq > 96000) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->scSampFreq = scSampFreq;
|
||||
|
||||
// Initialize echo canceller core
|
||||
if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize farend buffer
|
||||
if (WebRtcApm_InitBuffer(aecpc->farendBuf) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecpc->initFlag = initCheck; // indicates that initialization has been done
|
||||
|
||||
if (aecpc->sampFreq == 32000) {
|
||||
aecpc->splitSampFreq = 16000;
|
||||
}
|
||||
else {
|
||||
aecpc->splitSampFreq = sampFreq;
|
||||
}
|
||||
|
||||
aecpc->skewFrCtr = 0;
|
||||
aecpc->activity = 0;
|
||||
|
||||
aecpc->delayChange = 1;
|
||||
aecpc->delayCtr = 0;
|
||||
|
||||
aecpc->sum = 0;
|
||||
aecpc->counter = 0;
|
||||
aecpc->checkBuffSize = 1;
|
||||
aecpc->firstVal = 0;
|
||||
|
||||
aecpc->ECstartup = 1;
|
||||
aecpc->bufSizeStart = 0;
|
||||
aecpc->checkBufSizeCtr = 0;
|
||||
aecpc->filtDelay = 0;
|
||||
aecpc->timeForDelayChange =0;
|
||||
aecpc->knownDelay = 0;
|
||||
aecpc->lastDelayDiff = 0;
|
||||
|
||||
aecpc->skew = 0;
|
||||
aecpc->resample = kAecFalse;
|
||||
aecpc->highSkewCtr = 0;
|
||||
aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
|
||||
|
||||
memset(&aecpc->farendOld[0][0], 0, 160);
|
||||
|
||||
// Default settings.
|
||||
aecConfig.nlpMode = kAecNlpModerate;
|
||||
aecConfig.skewMode = kAecFalse;
|
||||
aecConfig.metricsMode = kAecFalse;
|
||||
aecConfig.delay_logging = kAecFalse;
|
||||
|
||||
if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// only buffer L band for farend
|
||||
WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, const WebRtc_Word16 *farend,
|
||||
WebRtc_Word16 nrOfSamples)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
WebRtc_Word32 retVal = 0;
|
||||
short newNrOfSamples;
|
||||
short newFarend[MAX_RESAMP_LEN];
|
||||
float skew;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (farend == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
skew = aecpc->skew;
|
||||
|
||||
// TODO: Is this really a good idea?
|
||||
if (!aecpc->ECstartup) {
|
||||
DelayComp(aecpc);
|
||||
}
|
||||
|
||||
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
|
||||
// Resample and get a new number of samples
|
||||
newNrOfSamples = WebRtcAec_ResampleLinear(aecpc->resampler,
|
||||
farend,
|
||||
nrOfSamples,
|
||||
skew,
|
||||
newFarend);
|
||||
WebRtcApm_WriteBuffer(aecpc->farendBuf, newFarend, newNrOfSamples);
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
fwrite(farend, 2, nrOfSamples, aecpc->preCompFile);
|
||||
fwrite(newFarend, 2, newNrOfSamples, aecpc->postCompFile);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
WebRtcApm_WriteBuffer(aecpc->farendBuf, farend, nrOfSamples);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend,
|
||||
const WebRtc_Word16 *nearendH, WebRtc_Word16 *out, WebRtc_Word16 *outH,
|
||||
WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf, WebRtc_Word32 skew)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
WebRtc_Word32 retVal = 0;
|
||||
short i;
|
||||
short farend[FRAME_LEN];
|
||||
short nmbrOfFilledBuffers;
|
||||
short nBlocks10ms;
|
||||
short nFrames;
|
||||
#ifdef AEC_DEBUG
|
||||
short msInAECBuf;
|
||||
#endif
|
||||
// Limit resampling to doubling/halving of signal
|
||||
const float minSkewEst = -0.5f;
|
||||
const float maxSkewEst = 1.0f;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nearend == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check for valid pointers based on sampling rate
|
||||
if (aecpc->sampFreq == 32000 && nearendH == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msInSndCardBuf < 0) {
|
||||
msInSndCardBuf = 0;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
}
|
||||
else if (msInSndCardBuf > 500) {
|
||||
msInSndCardBuf = 500;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
}
|
||||
msInSndCardBuf += 10;
|
||||
aecpc->msInSndCardBuf = msInSndCardBuf;
|
||||
|
||||
if (aecpc->skewMode == kAecTrue) {
|
||||
if (aecpc->skewFrCtr < 25) {
|
||||
aecpc->skewFrCtr++;
|
||||
}
|
||||
else {
|
||||
retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
|
||||
if (retVal == -1) {
|
||||
aecpc->skew = 0;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
}
|
||||
|
||||
aecpc->skew /= aecpc->sampFactor*nrOfSamples;
|
||||
|
||||
if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
|
||||
aecpc->resample = kAecFalse;
|
||||
}
|
||||
else {
|
||||
aecpc->resample = kAecTrue;
|
||||
}
|
||||
|
||||
if (aecpc->skew < minSkewEst) {
|
||||
aecpc->skew = minSkewEst;
|
||||
}
|
||||
else if (aecpc->skew > maxSkewEst) {
|
||||
aecpc->skew = maxSkewEst;
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
nFrames = nrOfSamples / FRAME_LEN;
|
||||
nBlocks10ms = nFrames / aecpc->aec->mult;
|
||||
|
||||
if (aecpc->ECstartup) {
|
||||
if (nearend != out) {
|
||||
// Only needed if they don't already point to the same place.
|
||||
memcpy(out, nearend, sizeof(short) * nrOfSamples);
|
||||
}
|
||||
nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecpc->farendBuf) / FRAME_LEN;
|
||||
|
||||
// The AEC is in the start up mode
|
||||
// AEC is disabled until the soundcard buffer and farend buffers are OK
|
||||
|
||||
// Mechanism to ensure that the soundcard buffer is reasonably stable.
|
||||
if (aecpc->checkBuffSize) {
|
||||
|
||||
aecpc->checkBufSizeCtr++;
|
||||
// Before we fill up the far end buffer we require the amount of data on the
|
||||
// sound card to be stable (+/-8 ms) compared to the first value. This
|
||||
// comparison is made during the following 4 consecutive frames. If it seems
|
||||
// to be stable then we start to fill up the far end buffer.
|
||||
|
||||
if (aecpc->counter == 0) {
|
||||
aecpc->firstVal = aecpc->msInSndCardBuf;
|
||||
aecpc->sum = 0;
|
||||
}
|
||||
|
||||
if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
|
||||
WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
|
||||
aecpc->sum += aecpc->msInSndCardBuf;
|
||||
aecpc->counter++;
|
||||
}
|
||||
else {
|
||||
aecpc->counter = 0;
|
||||
}
|
||||
|
||||
if (aecpc->counter*nBlocks10ms >= 6) {
|
||||
// The farend buffer size is determined in blocks of 80 samples
|
||||
// Use 75% of the average value of the soundcard buffer
|
||||
aecpc->bufSizeStart = WEBRTC_SPL_MIN((int) (0.75 * (aecpc->sum *
|
||||
aecpc->aec->mult) / (aecpc->counter * 10)), BUF_SIZE_FRAMES);
|
||||
// buffersize has now been determined
|
||||
aecpc->checkBuffSize = 0;
|
||||
}
|
||||
|
||||
if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
|
||||
// for really bad sound cards, don't disable echocanceller for more than 0.5 sec
|
||||
aecpc->bufSizeStart = WEBRTC_SPL_MIN((int) (0.75 * (aecpc->msInSndCardBuf *
|
||||
aecpc->aec->mult) / 10), BUF_SIZE_FRAMES);
|
||||
aecpc->checkBuffSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if checkBuffSize changed in the if-statement above
|
||||
if (!aecpc->checkBuffSize) {
|
||||
// soundcard buffer is now reasonably stable
|
||||
// When the far end buffer is filled with approximately the same amount of
|
||||
// data as the amount on the sound card we end the start up phase and start
|
||||
// to cancel echoes.
|
||||
|
||||
if (nmbrOfFilledBuffers == aecpc->bufSizeStart) {
|
||||
aecpc->ECstartup = 0; // Enable the AEC
|
||||
}
|
||||
else if (nmbrOfFilledBuffers > aecpc->bufSizeStart) {
|
||||
WebRtcApm_FlushBuffer(aecpc->farendBuf, WebRtcApm_get_buffer_size(aecpc->farendBuf) -
|
||||
aecpc->bufSizeStart * FRAME_LEN);
|
||||
aecpc->ECstartup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// AEC is enabled
|
||||
|
||||
// Note only 1 block supported for nb and 2 blocks for wb
|
||||
for (i = 0; i < nFrames; i++) {
|
||||
nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecpc->farendBuf) / FRAME_LEN;
|
||||
|
||||
// Check that there is data in the far end buffer
|
||||
if (nmbrOfFilledBuffers > 0) {
|
||||
// Get the next 80 samples from the farend buffer
|
||||
WebRtcApm_ReadBuffer(aecpc->farendBuf, farend, FRAME_LEN);
|
||||
|
||||
// Always store the last frame for use when we run out of data
|
||||
memcpy(&(aecpc->farendOld[i][0]), farend, FRAME_LEN * sizeof(short));
|
||||
}
|
||||
else {
|
||||
// We have no data so we use the last played frame
|
||||
memcpy(farend, &(aecpc->farendOld[i][0]), FRAME_LEN * sizeof(short));
|
||||
}
|
||||
|
||||
// Call buffer delay estimator when all data is extracted,
|
||||
// i.e. i = 0 for NB and i = 1 for WB or SWB
|
||||
if ((i == 0 && aecpc->splitSampFreq == 8000) ||
|
||||
(i == 1 && (aecpc->splitSampFreq == 16000))) {
|
||||
EstBufDelay(aecpc, aecpc->msInSndCardBuf);
|
||||
}
|
||||
|
||||
// Call the AEC
|
||||
WebRtcAec_ProcessFrame(aecpc->aec, farend, &nearend[FRAME_LEN * i], &nearendH[FRAME_LEN * i],
|
||||
&out[FRAME_LEN * i], &outH[FRAME_LEN * i], aecpc->knownDelay);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
msInAECBuf = WebRtcApm_get_buffer_size(aecpc->farendBuf) / (sampMsNb*aecpc->aec->mult);
|
||||
fwrite(&msInAECBuf, 2, 1, aecpc->bufFile);
|
||||
fwrite(&(aecpc->knownDelay), sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->skewMode = config.skewMode;
|
||||
|
||||
if (config.nlpMode != kAecNlpConservative && config.nlpMode !=
|
||||
kAecNlpModerate && config.nlpMode != kAecNlpAggressive) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->nlpMode = config.nlpMode;
|
||||
aecpc->aec->targetSupp = targetSupp[aecpc->nlpMode];
|
||||
aecpc->aec->minOverDrive = minOverDrive[aecpc->nlpMode];
|
||||
|
||||
if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->aec->metricsMode = config.metricsMode;
|
||||
if (aecpc->aec->metricsMode == kAecTrue) {
|
||||
WebRtcAec_InitMetrics(aecpc->aec);
|
||||
}
|
||||
|
||||
if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->aec->delay_logging_enabled = config.delay_logging;
|
||||
if (aecpc->aec->delay_logging_enabled == kAecTrue) {
|
||||
memset(aecpc->aec->delay_histogram, 0, sizeof(aecpc->aec->delay_histogram));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
config->nlpMode = aecpc->nlpMode;
|
||||
config->skewMode = aecpc->skewMode;
|
||||
config->metricsMode = aecpc->aec->metricsMode;
|
||||
config->delay_logging = aecpc->aec->delay_logging_enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*status = aecpc->aec->echoState;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics)
|
||||
{
|
||||
const float upweight = 0.7f;
|
||||
float dtmp;
|
||||
short stmp;
|
||||
aecpc_t *aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (metrics == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ERL
|
||||
metrics->erl.instant = (short) aecpc->aec->erl.instant;
|
||||
|
||||
if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) {
|
||||
// Use a mix between regular average and upper part average
|
||||
dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average;
|
||||
metrics->erl.average = (short) dtmp;
|
||||
}
|
||||
else {
|
||||
metrics->erl.average = offsetLevel;
|
||||
}
|
||||
|
||||
metrics->erl.max = (short) aecpc->aec->erl.max;
|
||||
|
||||
if (aecpc->aec->erl.min < (offsetLevel * (-1))) {
|
||||
metrics->erl.min = (short) aecpc->aec->erl.min;
|
||||
}
|
||||
else {
|
||||
metrics->erl.min = offsetLevel;
|
||||
}
|
||||
|
||||
// ERLE
|
||||
metrics->erle.instant = (short) aecpc->aec->erle.instant;
|
||||
|
||||
if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) {
|
||||
// Use a mix between regular average and upper part average
|
||||
dtmp = upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average;
|
||||
metrics->erle.average = (short) dtmp;
|
||||
}
|
||||
else {
|
||||
metrics->erle.average = offsetLevel;
|
||||
}
|
||||
|
||||
metrics->erle.max = (short) aecpc->aec->erle.max;
|
||||
|
||||
if (aecpc->aec->erle.min < (offsetLevel * (-1))) {
|
||||
metrics->erle.min = (short) aecpc->aec->erle.min;
|
||||
} else {
|
||||
metrics->erle.min = offsetLevel;
|
||||
}
|
||||
|
||||
// RERL
|
||||
if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) {
|
||||
stmp = metrics->erl.average + metrics->erle.average;
|
||||
}
|
||||
else {
|
||||
stmp = offsetLevel;
|
||||
}
|
||||
metrics->rerl.average = stmp;
|
||||
|
||||
// No other statistics needed, but returned for completeness
|
||||
metrics->rerl.instant = stmp;
|
||||
metrics->rerl.max = stmp;
|
||||
metrics->rerl.min = stmp;
|
||||
|
||||
// A_NLP
|
||||
metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant;
|
||||
|
||||
if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) {
|
||||
// Use a mix between regular average and upper part average
|
||||
dtmp = upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average;
|
||||
metrics->aNlp.average = (short) dtmp;
|
||||
}
|
||||
else {
|
||||
metrics->aNlp.average = offsetLevel;
|
||||
}
|
||||
|
||||
metrics->aNlp.max = (short) aecpc->aec->aNlp.max;
|
||||
|
||||
if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) {
|
||||
metrics->aNlp.min = (short) aecpc->aec->aNlp.min;
|
||||
}
|
||||
else {
|
||||
metrics->aNlp.min = offsetLevel;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std) {
|
||||
aecpc_t* self = handle;
|
||||
int i = 0;
|
||||
int delay_values = 0;
|
||||
int num_delay_values = 0;
|
||||
int my_median = 0;
|
||||
const int kMsPerBlock = (PART_LEN * 1000) / self->splitSampFreq;
|
||||
float l1_norm = 0;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (median == NULL) {
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (std == NULL) {
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->aec->delay_logging_enabled == 0) {
|
||||
// Logging disabled
|
||||
self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get number of delay values since last update
|
||||
for (i = 0; i < kMaxDelay; i++) {
|
||||
num_delay_values += self->aec->delay_histogram[i];
|
||||
}
|
||||
if (num_delay_values == 0) {
|
||||
// We have no new delay value data
|
||||
*median = -1;
|
||||
*std = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delay_values = num_delay_values >> 1; // Start value for median count down
|
||||
// Get median of delay values since last update
|
||||
for (i = 0; i < kMaxDelay; i++) {
|
||||
delay_values -= self->aec->delay_histogram[i];
|
||||
if (delay_values < 0) {
|
||||
my_median = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*median = my_median * kMsPerBlock;
|
||||
|
||||
// Calculate the L1 norm, with median value as central moment
|
||||
for (i = 0; i < kMaxDelay; i++) {
|
||||
l1_norm += (float) (fabs(i - my_median) * self->aec->delay_histogram[i]);
|
||||
}
|
||||
*std = (int) (l1_norm / (float) num_delay_values + 0.5f) * kMsPerBlock;
|
||||
|
||||
// Reset histogram
|
||||
memset(self->aec->delay_histogram, 0, sizeof(self->aec->delay_histogram));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len)
|
||||
{
|
||||
const char version[] = "AEC 2.5.0";
|
||||
const short versionLen = (short)strlen(version) + 1; // +1 for null-termination
|
||||
|
||||
if (versionStr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (versionLen > len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(versionStr, version, versionLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst)
|
||||
{
|
||||
aecpc_t *aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return aecpc->lastError;
|
||||
}
|
||||
|
||||
static int EstBufDelay(aecpc_t *aecpc, short msInSndCardBuf)
|
||||
{
|
||||
short delayNew, nSampFar, nSampSndCard;
|
||||
short diff;
|
||||
|
||||
nSampFar = WebRtcApm_get_buffer_size(aecpc->farendBuf);
|
||||
nSampSndCard = msInSndCardBuf * sampMsNb * aecpc->aec->mult;
|
||||
|
||||
delayNew = nSampSndCard - nSampFar;
|
||||
|
||||
// Account for resampling frame delay
|
||||
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
|
||||
delayNew -= kResamplingDelay;
|
||||
}
|
||||
|
||||
if (delayNew < FRAME_LEN) {
|
||||
WebRtcApm_FlushBuffer(aecpc->farendBuf, FRAME_LEN);
|
||||
delayNew += FRAME_LEN;
|
||||
}
|
||||
|
||||
aecpc->filtDelay = WEBRTC_SPL_MAX(0, (short)(0.8*aecpc->filtDelay + 0.2*delayNew));
|
||||
|
||||
diff = aecpc->filtDelay - aecpc->knownDelay;
|
||||
if (diff > 224) {
|
||||
if (aecpc->lastDelayDiff < 96) {
|
||||
aecpc->timeForDelayChange = 0;
|
||||
}
|
||||
else {
|
||||
aecpc->timeForDelayChange++;
|
||||
}
|
||||
}
|
||||
else if (diff < 96 && aecpc->knownDelay > 0) {
|
||||
if (aecpc->lastDelayDiff > 224) {
|
||||
aecpc->timeForDelayChange = 0;
|
||||
}
|
||||
else {
|
||||
aecpc->timeForDelayChange++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
aecpc->timeForDelayChange = 0;
|
||||
}
|
||||
aecpc->lastDelayDiff = diff;
|
||||
|
||||
if (aecpc->timeForDelayChange > 25) {
|
||||
aecpc->knownDelay = WEBRTC_SPL_MAX((int)aecpc->filtDelay - 160, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DelayComp(aecpc_t *aecpc)
|
||||
{
|
||||
int nSampFar, nSampSndCard, delayNew, nSampAdd;
|
||||
const int maxStuffSamp = 10 * FRAME_LEN;
|
||||
|
||||
nSampFar = WebRtcApm_get_buffer_size(aecpc->farendBuf);
|
||||
nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->aec->mult;
|
||||
delayNew = nSampSndCard - nSampFar;
|
||||
|
||||
// Account for resampling frame delay
|
||||
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
|
||||
delayNew -= kResamplingDelay;
|
||||
}
|
||||
|
||||
if (delayNew > FAR_BUF_LEN - FRAME_LEN*aecpc->aec->mult) {
|
||||
// The difference of the buffersizes is larger than the maximum
|
||||
// allowed known delay. Compensate by stuffing the buffer.
|
||||
nSampAdd = (int)(WEBRTC_SPL_MAX((int)(0.5 * nSampSndCard - nSampFar),
|
||||
FRAME_LEN));
|
||||
nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
|
||||
|
||||
WebRtcApm_StuffBuffer(aecpc->farendBuf, nSampAdd);
|
||||
aecpc->delayChange = 1; // the delay needs to be updated
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_INTERFACE_ECHO_CANCELLATION_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_INTERFACE_ECHO_CANCELLATION_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
// Errors
|
||||
#define AEC_UNSPECIFIED_ERROR 12000
|
||||
#define AEC_UNSUPPORTED_FUNCTION_ERROR 12001
|
||||
#define AEC_UNINITIALIZED_ERROR 12002
|
||||
#define AEC_NULL_POINTER_ERROR 12003
|
||||
#define AEC_BAD_PARAMETER_ERROR 12004
|
||||
|
||||
// Warnings
|
||||
#define AEC_BAD_PARAMETER_WARNING 12050
|
||||
|
||||
enum {
|
||||
kAecNlpConservative = 0,
|
||||
kAecNlpModerate,
|
||||
kAecNlpAggressive
|
||||
};
|
||||
|
||||
enum {
|
||||
kAecFalse = 0,
|
||||
kAecTrue
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 nlpMode; // default kAecNlpModerate
|
||||
WebRtc_Word16 skewMode; // default kAecFalse
|
||||
WebRtc_Word16 metricsMode; // default kAecFalse
|
||||
int delay_logging; // default kAecFalse
|
||||
//float realSkew;
|
||||
} AecConfig;
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 instant;
|
||||
WebRtc_Word16 average;
|
||||
WebRtc_Word16 max;
|
||||
WebRtc_Word16 min;
|
||||
} AecLevel;
|
||||
|
||||
typedef struct {
|
||||
AecLevel rerl;
|
||||
AecLevel erl;
|
||||
AecLevel erle;
|
||||
AecLevel aNlp;
|
||||
} AecMetrics;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocates the memory needed by the AEC. The memory needs to be initialized
|
||||
* separately using the WebRtcAec_Init() function.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void **aecInst Pointer to the AEC instance to be created
|
||||
* and initialized
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Create(void **aecInst);
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAec_Create().
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Free(void *aecInst);
|
||||
|
||||
/*
|
||||
* Initializes an AEC instance.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* WebRtc_Word32 sampFreq Sampling frequency of data
|
||||
* WebRtc_Word32 scSampFreq Soundcard sampling frequency
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Init(void *aecInst,
|
||||
WebRtc_Word32 sampFreq,
|
||||
WebRtc_Word32 scSampFreq);
|
||||
|
||||
/*
|
||||
* Inserts an 80 or 160 sample block of data into the farend buffer.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* WebRtc_Word16 *farend In buffer containing one frame of
|
||||
* farend signal for L band
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst,
|
||||
const WebRtc_Word16 *farend,
|
||||
WebRtc_Word16 nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the echo canceller on an 80 or 160 sample blocks of data.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* WebRtc_Word16 *nearend In buffer containing one frame of
|
||||
* nearend+echo signal for L band
|
||||
* WebRtc_Word16 *nearendH In buffer containing one frame of
|
||||
* nearend+echo signal for H band
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in nearend buffer
|
||||
* WebRtc_Word16 msInSndCardBuf Delay estimate for sound card and
|
||||
* system buffers
|
||||
* WebRtc_Word16 skew Difference between number of samples played
|
||||
* and recorded at the soundcard (for clock skew
|
||||
* compensation)
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word16 *out Out buffer, one frame of processed nearend
|
||||
* for L band
|
||||
* WebRtc_Word16 *outH Out buffer, one frame of processed nearend
|
||||
* for H band
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Process(void *aecInst,
|
||||
const WebRtc_Word16 *nearend,
|
||||
const WebRtc_Word16 *nearendH,
|
||||
WebRtc_Word16 *out,
|
||||
WebRtc_Word16 *outH,
|
||||
WebRtc_Word16 nrOfSamples,
|
||||
WebRtc_Word16 msInSndCardBuf,
|
||||
WebRtc_Word32 skew);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* AecConfig config Config instance that contains all
|
||||
* properties to be set
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config);
|
||||
|
||||
/*
|
||||
* Gets the on-the-fly paramters.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecConfig *config Pointer to the config instance that
|
||||
* all properties will be written to
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config);
|
||||
|
||||
/*
|
||||
* Gets the current echo status of the nearend signal.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word16 *status 0: Almost certainly nearend single-talk
|
||||
* 1: Might not be neared single-talk
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status);
|
||||
|
||||
/*
|
||||
* Gets the current echo metrics for the session.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecMetrics *metrics Struct which will be filled out with the
|
||||
* current echo metrics.
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics);
|
||||
|
||||
/*
|
||||
* Gets the current delay metrics for the session.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* handle Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int* median Delay median value.
|
||||
* int* std Delay standard deviation.
|
||||
*
|
||||
* int return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std);
|
||||
|
||||
/*
|
||||
* Gets the last error code.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 11000-11100: error code
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst);
|
||||
|
||||
/*
|
||||
* Gets a version string.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* char *versionStr Pointer to a string array
|
||||
* WebRtc_Word16 len The maximum length of the string
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word8 *versionStr Pointer to a string array
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_INTERFACE_ECHO_CANCELLATION_H_ */
|
233
webrtc/modules/audio_processing/aec/resampler.c
Normal file
233
webrtc/modules/audio_processing/aec/resampler.c
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for clock
|
||||
* skew by resampling the farend signal.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "resampler.h"
|
||||
#include "aec_core.h"
|
||||
|
||||
enum { kFrameBufferSize = FRAME_LEN * 4 };
|
||||
enum { kEstimateLengthFrames = 400 };
|
||||
|
||||
typedef struct {
|
||||
short buffer[kFrameBufferSize];
|
||||
float position;
|
||||
|
||||
int deviceSampleRateHz;
|
||||
int skewData[kEstimateLengthFrames];
|
||||
int skewDataIndex;
|
||||
float skewEstimate;
|
||||
} resampler_t;
|
||||
|
||||
static int EstimateSkew(const int* rawSkew,
|
||||
int size,
|
||||
int absLimit,
|
||||
float *skewEst);
|
||||
|
||||
int WebRtcAec_CreateResampler(void **resampInst)
|
||||
{
|
||||
resampler_t *obj = malloc(sizeof(resampler_t));
|
||||
*resampInst = obj;
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*) resampInst;
|
||||
memset(obj->buffer, 0, sizeof(obj->buffer));
|
||||
obj->position = 0.0;
|
||||
|
||||
obj->deviceSampleRateHz = deviceSampleRateHz;
|
||||
memset(obj->skewData, 0, sizeof(obj->skewData));
|
||||
obj->skewDataIndex = 0;
|
||||
obj->skewEstimate = 0.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_FreeResampler(void *resampInst)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*) resampInst;
|
||||
free(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_ResampleLinear(void *resampInst,
|
||||
const short *inspeech,
|
||||
int size,
|
||||
float skew,
|
||||
short *outspeech)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*) resampInst;
|
||||
|
||||
short *y;
|
||||
float be, tnew, interp;
|
||||
int tn, outsize, mm;
|
||||
|
||||
if (size < 0 || size > 2 * FRAME_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add new frame data in lookahead
|
||||
memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
|
||||
inspeech,
|
||||
size * sizeof(short));
|
||||
|
||||
// Sample rate ratio
|
||||
be = 1 + skew;
|
||||
|
||||
// Loop over input frame
|
||||
mm = 0;
|
||||
y = &obj->buffer[FRAME_LEN]; // Point at current frame
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (int) tnew;
|
||||
|
||||
while (tn < size) {
|
||||
|
||||
// Interpolation
|
||||
interp = y[tn] + (tnew - tn) * (y[tn+1] - y[tn]);
|
||||
|
||||
if (interp > 32767) {
|
||||
interp = 32767;
|
||||
}
|
||||
else if (interp < -32768) {
|
||||
interp = -32768;
|
||||
}
|
||||
|
||||
outspeech[mm] = (short) interp;
|
||||
mm++;
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (int) tnew;
|
||||
}
|
||||
|
||||
outsize = mm;
|
||||
obj->position += outsize * be - size;
|
||||
|
||||
// Shift buffer
|
||||
memmove(obj->buffer,
|
||||
&obj->buffer[size],
|
||||
(kFrameBufferSize - size) * sizeof(short));
|
||||
|
||||
return outsize;
|
||||
}
|
||||
|
||||
int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*)resampInst;
|
||||
int err = 0;
|
||||
|
||||
if (obj->skewDataIndex < kEstimateLengthFrames) {
|
||||
obj->skewData[obj->skewDataIndex] = rawSkew;
|
||||
obj->skewDataIndex++;
|
||||
}
|
||||
else if (obj->skewDataIndex == kEstimateLengthFrames) {
|
||||
err = EstimateSkew(obj->skewData,
|
||||
kEstimateLengthFrames,
|
||||
obj->deviceSampleRateHz,
|
||||
skewEst);
|
||||
obj->skewEstimate = *skewEst;
|
||||
obj->skewDataIndex++;
|
||||
}
|
||||
else {
|
||||
*skewEst = obj->skewEstimate;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int EstimateSkew(const int* rawSkew,
|
||||
int size,
|
||||
int deviceSampleRateHz,
|
||||
float *skewEst)
|
||||
{
|
||||
const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
|
||||
const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
|
||||
int i = 0;
|
||||
int n = 0;
|
||||
float rawAvg = 0;
|
||||
float err = 0;
|
||||
float rawAbsDev = 0;
|
||||
int upperLimit = 0;
|
||||
int lowerLimit = 0;
|
||||
float cumSum = 0;
|
||||
float x = 0;
|
||||
float x2 = 0;
|
||||
float y = 0;
|
||||
float xy = 0;
|
||||
float xAvg = 0;
|
||||
float denom = 0;
|
||||
float skew = 0;
|
||||
|
||||
*skewEst = 0; // Set in case of error below.
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
|
||||
n++;
|
||||
rawAvg += rawSkew[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
assert(n > 0);
|
||||
rawAvg /= n;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
|
||||
err = rawSkew[i] - rawAvg;
|
||||
rawAbsDev += err >= 0 ? err : -err;
|
||||
}
|
||||
}
|
||||
assert(n > 0);
|
||||
rawAbsDev /= n;
|
||||
upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
|
||||
lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
|
||||
(rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
|
||||
n++;
|
||||
cumSum += rawSkew[i];
|
||||
x += n;
|
||||
x2 += n*n;
|
||||
y += cumSum;
|
||||
xy += n * cumSum;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
assert(n > 0);
|
||||
xAvg = x / n;
|
||||
denom = x2 - xAvg*x;
|
||||
|
||||
if (denom != 0) {
|
||||
skew = (xy - xAvg*y) / denom;
|
||||
}
|
||||
|
||||
*skewEst = skew;
|
||||
return 0;
|
||||
}
|
32
webrtc/modules/audio_processing/aec/resampler.h
Normal file
32
webrtc/modules/audio_processing/aec/resampler.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_RESAMPLER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_RESAMPLER_H_
|
||||
|
||||
enum { kResamplingDelay = 1 };
|
||||
|
||||
// Unless otherwise specified, functions return 0 on success and -1 on error
|
||||
int WebRtcAec_CreateResampler(void **resampInst);
|
||||
int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz);
|
||||
int WebRtcAec_FreeResampler(void *resampInst);
|
||||
|
||||
// Estimates skew from raw measurement.
|
||||
int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst);
|
||||
|
||||
// Resamples input using linear interpolation.
|
||||
// Returns size of resampled array.
|
||||
int WebRtcAec_ResampleLinear(void *resampInst,
|
||||
const short *inspeech,
|
||||
int size,
|
||||
float skew,
|
||||
short *outspeech);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_RESAMPLER_H_
|
9
webrtc/modules/audio_processing/aecm/Makefile.am
Normal file
9
webrtc/modules/audio_processing/aecm/Makefile.am
Normal file
@ -0,0 +1,9 @@
|
||||
noinst_LTLIBRARIES = libaecm.la
|
||||
|
||||
libaecm_la_SOURCES = interface/echo_control_mobile.h \
|
||||
echo_control_mobile.c \
|
||||
aecm_core.c \
|
||||
aecm_core.h
|
||||
libaecm_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility
|
34
webrtc/modules/audio_processing/aecm/aecm.gypi
Normal file
34
webrtc/modules/audio_processing/aecm/aecm.gypi
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'aecm',
|
||||
'type': '<(library)',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:spl',
|
||||
'apm_util'
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/echo_control_mobile.h',
|
||||
'echo_control_mobile.c',
|
||||
'aecm_core.c',
|
||||
'aecm_core.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
1932
webrtc/modules/audio_processing/aecm/aecm_core.c
Normal file
1932
webrtc/modules/audio_processing/aecm/aecm_core.c
Normal file
File diff suppressed because it is too large
Load Diff
358
webrtc/modules/audio_processing/aecm/aecm_core.h
Normal file
358
webrtc/modules/audio_processing/aecm/aecm_core.h
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Performs echo control (suppression) with fft routines in fixed-point
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_
|
||||
|
||||
#define AECM_DYNAMIC_Q // turn on/off dynamic Q-domain
|
||||
//#define AECM_WITH_ABS_APPROX
|
||||
//#define AECM_SHORT // for 32 sample partition length (otherwise 64)
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
// Algorithm parameters
|
||||
|
||||
#define FRAME_LEN 80 // Total frame length, 10 ms
|
||||
#ifdef AECM_SHORT
|
||||
|
||||
#define PART_LEN 32 // Length of partition
|
||||
#define PART_LEN_SHIFT 6 // Length of (PART_LEN * 2) in base 2
|
||||
|
||||
#else
|
||||
|
||||
#define PART_LEN 64 // Length of partition
|
||||
#define PART_LEN_SHIFT 7 // Length of (PART_LEN * 2) in base 2
|
||||
|
||||
#endif
|
||||
|
||||
#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
|
||||
#define PART_LEN2 (PART_LEN << 1) // Length of partition * 2
|
||||
#define PART_LEN4 (PART_LEN << 2) // Length of partition * 4
|
||||
#define FAR_BUF_LEN PART_LEN4 // Length of buffers
|
||||
#define MAX_DELAY 100
|
||||
|
||||
// Counter parameters
|
||||
#ifdef AECM_SHORT
|
||||
|
||||
#define CONV_LEN 1024 // Convergence length used at startup
|
||||
#else
|
||||
|
||||
#define CONV_LEN 512 // Convergence length used at startup
|
||||
#endif
|
||||
|
||||
#define CONV_LEN2 (CONV_LEN << 1) // Convergence length * 2 used at startup
|
||||
// Energy parameters
|
||||
#define MAX_BUF_LEN 64 // History length of energy signals
|
||||
|
||||
#define FAR_ENERGY_MIN 1025 // Lowest Far energy level: At least 2 in energy
|
||||
#define FAR_ENERGY_DIFF 929 // Allowed difference between max and min
|
||||
|
||||
#define ENERGY_DEV_OFFSET 0 // The energy error offset in Q8
|
||||
#define ENERGY_DEV_TOL 400 // The energy estimation tolerance in Q8
|
||||
#define FAR_ENERGY_VAD_REGION 230 // Far VAD tolerance region
|
||||
// Stepsize parameters
|
||||
#define MU_MIN 10 // Min stepsize 2^-MU_MIN (far end energy dependent)
|
||||
#define MU_MAX 1 // Max stepsize 2^-MU_MAX (far end energy dependent)
|
||||
#define MU_DIFF 9 // MU_MIN - MU_MAX
|
||||
// Channel parameters
|
||||
#define MIN_MSE_COUNT 20 // Min number of consecutive blocks with enough far end
|
||||
// energy to compare channel estimates
|
||||
#define MIN_MSE_DIFF 29 // The ratio between adapted and stored channel to
|
||||
// accept a new storage (0.8 in Q-MSE_RESOLUTION)
|
||||
#define MSE_RESOLUTION 5 // MSE parameter resolution
|
||||
#define RESOLUTION_CHANNEL16 12 // W16 Channel in Q-RESOLUTION_CHANNEL16
|
||||
#define RESOLUTION_CHANNEL32 28 // W32 Channel in Q-RESOLUTION_CHANNEL
|
||||
#define CHANNEL_VAD 16 // Minimum energy in frequency band to update channel
|
||||
// Suppression gain parameters: SUPGAIN_ parameters in Q-(RESOLUTION_SUPGAIN)
|
||||
#define RESOLUTION_SUPGAIN 8 // Channel in Q-(RESOLUTION_SUPGAIN)
|
||||
#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) // Default suppression gain
|
||||
#define SUPGAIN_ERROR_PARAM_A 3072 // Estimation error parameter (Maximum gain) (8 in Q8)
|
||||
#define SUPGAIN_ERROR_PARAM_B 1536 // Estimation error parameter (Gain before going down)
|
||||
#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT // Estimation error parameter
|
||||
// (Should be the same as Default) (1 in Q8)
|
||||
#define SUPGAIN_EPC_DT 200 // = SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL
|
||||
// Defines for "check delay estimation"
|
||||
#define CORR_WIDTH 31 // Number of samples to correlate over.
|
||||
#define CORR_MAX 16 // Maximum correlation offset
|
||||
#define CORR_MAX_BUF 63
|
||||
#define CORR_DEV 4
|
||||
#define CORR_MAX_LEVEL 20
|
||||
#define CORR_MAX_LOW 4
|
||||
#define CORR_BUF_LEN (CORR_MAX << 1) + 1
|
||||
// Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN
|
||||
|
||||
#define ONE_Q14 (1 << 14)
|
||||
|
||||
// NLP defines
|
||||
#define NLP_COMP_LOW 3277 // 0.2 in Q14
|
||||
#define NLP_COMP_HIGH ONE_Q14 // 1 in Q14
|
||||
|
||||
extern const WebRtc_Word16 WebRtcAecm_kSqrtHanning[];
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 real;
|
||||
WebRtc_Word16 imag;
|
||||
} complex16_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int farBufWritePos;
|
||||
int farBufReadPos;
|
||||
int knownDelay;
|
||||
int lastKnownDelay;
|
||||
int firstVAD; // Parameter to control poorly initialized channels
|
||||
|
||||
void *farFrameBuf;
|
||||
void *nearNoisyFrameBuf;
|
||||
void *nearCleanFrameBuf;
|
||||
void *outFrameBuf;
|
||||
|
||||
WebRtc_Word16 farBuf[FAR_BUF_LEN];
|
||||
|
||||
WebRtc_Word16 mult;
|
||||
WebRtc_UWord32 seed;
|
||||
|
||||
// Delay estimation variables
|
||||
void* delay_estimator;
|
||||
WebRtc_UWord16 currentDelay;
|
||||
|
||||
WebRtc_Word16 nlpFlag;
|
||||
WebRtc_Word16 fixedDelay;
|
||||
|
||||
WebRtc_UWord32 totCount;
|
||||
|
||||
WebRtc_Word16 dfaCleanQDomain;
|
||||
WebRtc_Word16 dfaCleanQDomainOld;
|
||||
WebRtc_Word16 dfaNoisyQDomain;
|
||||
WebRtc_Word16 dfaNoisyQDomainOld;
|
||||
|
||||
WebRtc_Word16 nearLogEnergy[MAX_BUF_LEN];
|
||||
WebRtc_Word16 farLogEnergy;
|
||||
WebRtc_Word16 echoAdaptLogEnergy[MAX_BUF_LEN];
|
||||
WebRtc_Word16 echoStoredLogEnergy[MAX_BUF_LEN];
|
||||
|
||||
// The extra 16 or 32 bytes in the following buffers are for alignment based Neon code.
|
||||
// It's designed this way since the current GCC compiler can't align a buffer in 16 or 32
|
||||
// byte boundaries properly.
|
||||
WebRtc_Word16 channelStored_buf[PART_LEN1 + 8];
|
||||
WebRtc_Word16 channelAdapt16_buf[PART_LEN1 + 8];
|
||||
WebRtc_Word32 channelAdapt32_buf[PART_LEN1 + 8];
|
||||
WebRtc_Word16 xBuf_buf[PART_LEN2 + 16]; // farend
|
||||
WebRtc_Word16 dBufClean_buf[PART_LEN2 + 16]; // nearend
|
||||
WebRtc_Word16 dBufNoisy_buf[PART_LEN2 + 16]; // nearend
|
||||
WebRtc_Word16 outBuf_buf[PART_LEN + 8];
|
||||
|
||||
// Pointers to the above buffers
|
||||
WebRtc_Word16 *channelStored;
|
||||
WebRtc_Word16 *channelAdapt16;
|
||||
WebRtc_Word32 *channelAdapt32;
|
||||
WebRtc_Word16 *xBuf;
|
||||
WebRtc_Word16 *dBufClean;
|
||||
WebRtc_Word16 *dBufNoisy;
|
||||
WebRtc_Word16 *outBuf;
|
||||
|
||||
WebRtc_Word32 echoFilt[PART_LEN1];
|
||||
WebRtc_Word16 nearFilt[PART_LEN1];
|
||||
WebRtc_Word32 noiseEst[PART_LEN1];
|
||||
int noiseEstTooLowCtr[PART_LEN1];
|
||||
int noiseEstTooHighCtr[PART_LEN1];
|
||||
WebRtc_Word16 noiseEstCtr;
|
||||
WebRtc_Word16 cngMode;
|
||||
|
||||
WebRtc_Word32 mseAdaptOld;
|
||||
WebRtc_Word32 mseStoredOld;
|
||||
WebRtc_Word32 mseThreshold;
|
||||
|
||||
WebRtc_Word16 farEnergyMin;
|
||||
WebRtc_Word16 farEnergyMax;
|
||||
WebRtc_Word16 farEnergyMaxMin;
|
||||
WebRtc_Word16 farEnergyVAD;
|
||||
WebRtc_Word16 farEnergyMSE;
|
||||
int currentVADValue;
|
||||
WebRtc_Word16 vadUpdateCount;
|
||||
|
||||
WebRtc_Word16 startupState;
|
||||
WebRtc_Word16 mseChannelCount;
|
||||
WebRtc_Word16 supGain;
|
||||
WebRtc_Word16 supGainOld;
|
||||
|
||||
WebRtc_Word16 supGainErrParamA;
|
||||
WebRtc_Word16 supGainErrParamD;
|
||||
WebRtc_Word16 supGainErrParamDiffAB;
|
||||
WebRtc_Word16 supGainErrParamDiffBD;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *farFile;
|
||||
FILE *nearFile;
|
||||
FILE *outFile;
|
||||
#endif
|
||||
} AecmCore_t;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CreateCore(...)
|
||||
//
|
||||
// Allocates the memory needed by the AECM. The memory needs to be
|
||||
// initialized separately using the WebRtcAecm_InitCore() function.
|
||||
//
|
||||
// Input:
|
||||
// - aecm : Instance that should be created
|
||||
//
|
||||
// Output:
|
||||
// - aecm : Created instance
|
||||
//
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
//
|
||||
int WebRtcAecm_CreateCore(AecmCore_t **aecm);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_InitCore(...)
|
||||
//
|
||||
// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - samplingFreq : Sampling Frequency
|
||||
//
|
||||
// Output:
|
||||
// - aecm : Initialized instance
|
||||
//
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
//
|
||||
int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_FreeCore(...)
|
||||
//
|
||||
// This function releases the memory allocated by WebRtcAecm_CreateCore()
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
//
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
// 11001-11016: Error
|
||||
//
|
||||
int WebRtcAecm_FreeCore(AecmCore_t *aecm);
|
||||
|
||||
int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_InitEchoPathCore(...)
|
||||
//
|
||||
// This function resets the echo channel adaptation with the specified channel.
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - echo_path : Pointer to the data that should initialize the echo path
|
||||
//
|
||||
// Output:
|
||||
// - aecm : Initialized instance
|
||||
//
|
||||
void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_ProcessFrame(...)
|
||||
//
|
||||
// This function processes frames and sends blocks to WebRtcAecm_ProcessBlock(...)
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - farend : In buffer containing one frame of echo signal
|
||||
// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS
|
||||
// - nearendClean : In buffer containing one frame of nearend+echo signal with NS
|
||||
//
|
||||
// Output:
|
||||
// - out : Out buffer, one frame of nearend signal :
|
||||
//
|
||||
//
|
||||
int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, const WebRtc_Word16 * farend,
|
||||
const WebRtc_Word16 * nearendNoisy,
|
||||
const WebRtc_Word16 * nearendClean,
|
||||
WebRtc_Word16 * out);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_ProcessBlock(...)
|
||||
//
|
||||
// This function is called for every block within one frame
|
||||
// This function is called by WebRtcAecm_ProcessFrame(...)
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - farend : In buffer containing one block of echo signal
|
||||
// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS
|
||||
// - nearendClean : In buffer containing one frame of nearend+echo signal with NS
|
||||
//
|
||||
// Output:
|
||||
// - out : Out buffer, one block of nearend signal :
|
||||
//
|
||||
//
|
||||
int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, const WebRtc_Word16 * farend,
|
||||
const WebRtc_Word16 * nearendNoisy,
|
||||
const WebRtc_Word16 * noisyClean,
|
||||
WebRtc_Word16 * out);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_BufferFarFrame()
|
||||
//
|
||||
// Inserts a frame of data into farend buffer.
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - farend : In buffer containing one frame of farend signal
|
||||
// - farLen : Length of frame
|
||||
//
|
||||
void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
|
||||
const int farLen);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_FetchFarFrame()
|
||||
//
|
||||
// Read the farend buffer to account for known delay
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - farend : In buffer containing one frame of farend signal
|
||||
// - farLen : Length of frame
|
||||
// - knownDelay : known delay
|
||||
//
|
||||
void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend,
|
||||
const int farLen, const int knownDelay);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Some internal functions shared by ARM NEON and generic C code:
|
||||
//
|
||||
|
||||
void WebRtcAecm_CalcLinearEnergies(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echoEst,
|
||||
WebRtc_UWord32* far_energy,
|
||||
WebRtc_UWord32* echo_energy_adapt,
|
||||
WebRtc_UWord32* echo_energy_stored);
|
||||
|
||||
void WebRtcAecm_StoreAdaptiveChannel(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echo_est);
|
||||
|
||||
void WebRtcAecm_ResetAdaptiveChannel(AecmCore_t *aecm);
|
||||
|
||||
void WebRtcAecm_WindowAndFFT(WebRtc_Word16* fft,
|
||||
const WebRtc_Word16* time_signal,
|
||||
complex16_t* freq_signal,
|
||||
int time_signal_scaling);
|
||||
|
||||
void WebRtcAecm_InverseFFTAndWindow(AecmCore_t* aecm,
|
||||
WebRtc_Word16* fft,
|
||||
complex16_t* efw,
|
||||
WebRtc_Word16* output,
|
||||
const WebRtc_Word16* nearendClean);
|
||||
|
||||
#endif
|
314
webrtc/modules/audio_processing/aecm/aecm_core_neon.c
Normal file
314
webrtc/modules/audio_processing/aecm/aecm_core_neon.c
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)
|
||||
|
||||
#include "aecm_core.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// Square root of Hanning window in Q14.
|
||||
static const WebRtc_Word16 kSqrtHanningReversed[] __attribute__ ((aligned (8))) = {
|
||||
16384, 16373, 16354, 16325,
|
||||
16286, 16237, 16179, 16111,
|
||||
16034, 15947, 15851, 15746,
|
||||
15631, 15506, 15373, 15231,
|
||||
15079, 14918, 14749, 14571,
|
||||
14384, 14189, 13985, 13773,
|
||||
13553, 13325, 13089, 12845,
|
||||
12594, 12335, 12068, 11795,
|
||||
11514, 11227, 10933, 10633,
|
||||
10326, 10013, 9695, 9370,
|
||||
9040, 8705, 8364, 8019,
|
||||
7668, 7313, 6954, 6591,
|
||||
6224, 5853, 5478, 5101,
|
||||
4720, 4337, 3951, 3562,
|
||||
3172, 2780, 2386, 1990,
|
||||
1594, 1196, 798, 399
|
||||
};
|
||||
|
||||
void WebRtcAecm_WindowAndFFT(WebRtc_Word16* fft,
|
||||
const WebRtc_Word16* time_signal,
|
||||
complex16_t* freq_signal,
|
||||
int time_signal_scaling)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
int16x4_t tmp16x4_scaling = vdup_n_s16(time_signal_scaling);
|
||||
__asm__("vmov.i16 d21, #0" ::: "d21");
|
||||
|
||||
for(i = 0, j = 0; i < PART_LEN; i += 4, j += 8)
|
||||
{
|
||||
int16x4_t tmp16x4_0;
|
||||
int16x4_t tmp16x4_1;
|
||||
int32x4_t tmp32x4_0;
|
||||
|
||||
/* Window near end */
|
||||
// fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((time_signal[i]
|
||||
// << time_signal_scaling), WebRtcAecm_kSqrtHanning[i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&time_signal[i]));
|
||||
tmp16x4_0 = vshl_s16(tmp16x4_0, tmp16x4_scaling);
|
||||
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&WebRtcAecm_kSqrtHanning[i]));
|
||||
tmp32x4_0 = vmull_s16(tmp16x4_0, tmp16x4_1);
|
||||
|
||||
__asm__("vshrn.i32 d20, %q0, #14" : : "w"(tmp32x4_0) : "d20");
|
||||
__asm__("vst2.16 {d20, d21}, [%0, :128]" : : "r"(&fft[j]) : "q10");
|
||||
|
||||
// fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
|
||||
// (time_signal[PART_LEN + i] << time_signal_scaling),
|
||||
// WebRtcAecm_kSqrtHanning[PART_LEN - i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&time_signal[i + PART_LEN]));
|
||||
tmp16x4_0 = vshl_s16(tmp16x4_0, tmp16x4_scaling);
|
||||
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&kSqrtHanningReversed[i]));
|
||||
tmp32x4_0 = vmull_s16(tmp16x4_0, tmp16x4_1);
|
||||
|
||||
__asm__("vshrn.i32 d20, %q0, #14" : : "w"(tmp32x4_0) : "d20");
|
||||
__asm__("vst2.16 {d20, d21}, [%0, :128]" : : "r"(&fft[PART_LEN2 + j]) : "q10");
|
||||
}
|
||||
|
||||
WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
|
||||
WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
|
||||
|
||||
// Take only the first PART_LEN2 samples, and switch the sign of the imaginary part.
|
||||
for(i = 0, j = 0; j < PART_LEN2; i += 8, j += 16)
|
||||
{
|
||||
__asm__("vld2.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&fft[j]) : "q10", "q11");
|
||||
__asm__("vneg.s16 d22, d22" : : : "q10");
|
||||
__asm__("vneg.s16 d23, d23" : : : "q11");
|
||||
__asm__("vst2.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&freq_signal[i].real): "q10", "q11");
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAecm_InverseFFTAndWindow(AecmCore_t* aecm,
|
||||
WebRtc_Word16* fft,
|
||||
complex16_t* efw,
|
||||
WebRtc_Word16* output,
|
||||
const WebRtc_Word16* nearendClean)
|
||||
{
|
||||
int i, j, outCFFT;
|
||||
WebRtc_Word32 tmp32no1;
|
||||
|
||||
// Synthesis
|
||||
for(i = 0, j = 0; i < PART_LEN; i += 4, j += 8)
|
||||
{
|
||||
// We overwrite two more elements in fft[], but it's ok.
|
||||
__asm__("vld2.16 {d20, d21}, [%0, :128]" : : "r"(&(efw[i].real)) : "q10");
|
||||
__asm__("vmov q11, q10" : : : "q10", "q11");
|
||||
|
||||
__asm__("vneg.s16 d23, d23" : : : "q11");
|
||||
__asm__("vst2.16 {d22, d23}, [%0, :128]" : : "r"(&fft[j]): "q11");
|
||||
|
||||
__asm__("vrev64.16 q10, q10" : : : "q10");
|
||||
__asm__("vst2.16 {d20, d21}, [%0]" : : "r"(&fft[PART_LEN4 - j - 6]): "q10");
|
||||
}
|
||||
|
||||
fft[PART_LEN2] = efw[PART_LEN].real;
|
||||
fft[PART_LEN2 + 1] = -efw[PART_LEN].imag;
|
||||
|
||||
// Inverse FFT, result should be scaled with outCFFT.
|
||||
WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
|
||||
outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
|
||||
|
||||
// Take only the real values and scale with outCFFT.
|
||||
for (i = 0, j = 0; i < PART_LEN2; i += 8, j+= 16)
|
||||
{
|
||||
__asm__("vld2.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&fft[j]) : "q10", "q11");
|
||||
__asm__("vst1.16 {d20, d21}, [%0, :128]" : : "r"(&fft[i]): "q10");
|
||||
}
|
||||
|
||||
int32x4_t tmp32x4_2;
|
||||
__asm__("vdup.32 %q0, %1" : "=w"(tmp32x4_2) : "r"((WebRtc_Word32)
|
||||
(outCFFT - aecm->dfaCleanQDomain)));
|
||||
for (i = 0; i < PART_LEN; i += 4)
|
||||
{
|
||||
int16x4_t tmp16x4_0;
|
||||
int16x4_t tmp16x4_1;
|
||||
int32x4_t tmp32x4_0;
|
||||
int32x4_t tmp32x4_1;
|
||||
|
||||
// fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
|
||||
// fft[i], WebRtcAecm_kSqrtHanning[i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&fft[i]));
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&WebRtcAecm_kSqrtHanning[i]));
|
||||
__asm__("vmull.s16 %q0, %P1, %P2" : "=w"(tmp32x4_0) : "w"(tmp16x4_0), "w"(tmp16x4_1));
|
||||
__asm__("vrshr.s32 %q0, %q1, #14" : "=w"(tmp32x4_0) : "0"(tmp32x4_0));
|
||||
|
||||
// tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i],
|
||||
// outCFFT - aecm->dfaCleanQDomain);
|
||||
__asm__("vshl.s32 %q0, %q1, %q2" : "=w"(tmp32x4_0) : "0"(tmp32x4_0), "w"(tmp32x4_2));
|
||||
|
||||
// fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
|
||||
// tmp32no1 + outBuf[i], WEBRTC_SPL_WORD16_MIN);
|
||||
// output[i] = fft[i];
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&aecm->outBuf[i]));
|
||||
__asm__("vmovl.s16 %q0, %P1" : "=w"(tmp32x4_1) : "w"(tmp16x4_0));
|
||||
__asm__("vadd.i32 %q0, %q1" : : "w"(tmp32x4_0), "w"(tmp32x4_1));
|
||||
__asm__("vqshrn.s32 %P0, %q1, #0" : "=w"(tmp16x4_0) : "w"(tmp32x4_0));
|
||||
__asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&fft[i]));
|
||||
__asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&output[i]));
|
||||
|
||||
// tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT(
|
||||
// fft[PART_LEN + i], WebRtcAecm_kSqrtHanning[PART_LEN - i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&fft[PART_LEN + i]));
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&kSqrtHanningReversed[i]));
|
||||
__asm__("vmull.s16 %q0, %P1, %P2" : "=w"(tmp32x4_0) : "w"(tmp16x4_0), "w"(tmp16x4_1));
|
||||
__asm__("vshr.s32 %q0, %q1, #14" : "=w"(tmp32x4_0) : "0"(tmp32x4_0));
|
||||
|
||||
// tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain);
|
||||
__asm__("vshl.s32 %q0, %q1, %q2" : "=w"(tmp32x4_0) : "0"(tmp32x4_0), "w"(tmp32x4_2));
|
||||
// outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(
|
||||
// WEBRTC_SPL_WORD16_MAX, tmp32no1, WEBRTC_SPL_WORD16_MIN);
|
||||
__asm__("vqshrn.s32 %P0, %q1, #0" : "=w"(tmp16x4_0) : "w"(tmp32x4_0));
|
||||
__asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&aecm->outBuf[i]));
|
||||
}
|
||||
|
||||
// Copy the current block to the old position (outBuf is shifted elsewhere).
|
||||
for (i = 0; i < PART_LEN; i += 16)
|
||||
{
|
||||
__asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->xBuf[i + PART_LEN]) : "q10");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&aecm->xBuf[i]): "q10");
|
||||
}
|
||||
for (i = 0; i < PART_LEN; i += 16)
|
||||
{
|
||||
__asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufNoisy[i + PART_LEN]) : "q10");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufNoisy[i]): "q10");
|
||||
}
|
||||
if (nearendClean != NULL) {
|
||||
for (i = 0; i < PART_LEN; i += 16)
|
||||
{
|
||||
__asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufClean[i + PART_LEN]) : "q10");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufClean[i]): "q10");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAecm_CalcLinearEnergies(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echo_est,
|
||||
WebRtc_UWord32* far_energy,
|
||||
WebRtc_UWord32* echo_energy_adapt,
|
||||
WebRtc_UWord32* echo_energy_stored)
|
||||
{
|
||||
int i;
|
||||
|
||||
register WebRtc_UWord32 far_energy_r;
|
||||
register WebRtc_UWord32 echo_energy_stored_r;
|
||||
register WebRtc_UWord32 echo_energy_adapt_r;
|
||||
uint32x4_t tmp32x4_0;
|
||||
|
||||
__asm__("vmov.i32 q14, #0" : : : "q14"); // far_energy
|
||||
__asm__("vmov.i32 q8, #0" : : : "q8"); // echo_energy_stored
|
||||
__asm__("vmov.i32 q9, #0" : : : "q9"); // echo_energy_adapt
|
||||
|
||||
for(i = 0; i < PART_LEN -7; i += 8)
|
||||
{
|
||||
// far_energy += (WebRtc_UWord32)(far_spectrum[i]);
|
||||
__asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13");
|
||||
__asm__("vaddw.u16 q14, q14, d26" : : : "q14", "q13");
|
||||
__asm__("vaddw.u16 q14, q14, d27" : : : "q14", "q13");
|
||||
|
||||
// Get estimated echo energies for adaptive channel and stored channel.
|
||||
// echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12");
|
||||
__asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
|
||||
__asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
|
||||
__asm__("vst1.32 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&echo_est[i]):
|
||||
"q10", "q11");
|
||||
|
||||
// echo_energy_stored += (WebRtc_UWord32)echoEst[i];
|
||||
__asm__("vadd.u32 q8, q10" : : : "q10", "q8");
|
||||
__asm__("vadd.u32 q8, q11" : : : "q11", "q8");
|
||||
|
||||
// echo_energy_adapt += WEBRTC_SPL_UMUL_16_16(
|
||||
// aecm->channelAdapt16[i], far_spectrum[i]);
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12");
|
||||
__asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
|
||||
__asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
|
||||
__asm__("vadd.u32 q9, q10" : : : "q9", "q15");
|
||||
__asm__("vadd.u32 q9, q11" : : : "q9", "q11");
|
||||
}
|
||||
|
||||
__asm__("vadd.u32 d28, d29" : : : "q14");
|
||||
__asm__("vpadd.u32 d28, d28" : : : "q14");
|
||||
__asm__("vmov.32 %0, d28[0]" : "=r"(far_energy_r): : "q14");
|
||||
|
||||
__asm__("vadd.u32 d18, d19" : : : "q9");
|
||||
__asm__("vpadd.u32 d18, d18" : : : "q9");
|
||||
__asm__("vmov.32 %0, d18[0]" : "=r"(echo_energy_adapt_r): : "q9");
|
||||
|
||||
__asm__("vadd.u32 d16, d17" : : : "q8");
|
||||
__asm__("vpadd.u32 d16, d16" : : : "q8");
|
||||
__asm__("vmov.32 %0, d16[0]" : "=r"(echo_energy_stored_r): : "q8");
|
||||
|
||||
// Get estimated echo energies for adaptive channel and stored channel.
|
||||
echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
*echo_energy_stored = echo_energy_stored_r + (WebRtc_UWord32)echo_est[i];
|
||||
*far_energy = far_energy_r + (WebRtc_UWord32)(far_spectrum[i]);
|
||||
*echo_energy_adapt = echo_energy_adapt_r + WEBRTC_SPL_UMUL_16_16(
|
||||
aecm->channelAdapt16[i], far_spectrum[i]);
|
||||
}
|
||||
|
||||
void WebRtcAecm_StoreAdaptiveChannel(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echo_est)
|
||||
{
|
||||
int i;
|
||||
|
||||
// During startup we store the channel every block.
|
||||
// Recalculate echo estimate.
|
||||
for(i = 0; i < PART_LEN -7; i += 8)
|
||||
{
|
||||
// aecm->channelStored[i] = acem->channelAdapt16[i];
|
||||
// echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
__asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13");
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12");
|
||||
__asm__("vst1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12");
|
||||
__asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
|
||||
__asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&echo_est[i]) : "q10", "q11");
|
||||
}
|
||||
aecm->channelStored[i] = aecm->channelAdapt16[i];
|
||||
echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
}
|
||||
|
||||
void WebRtcAecm_ResetAdaptiveChannel(AecmCore_t* aecm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < PART_LEN -7; i += 8)
|
||||
{
|
||||
// aecm->channelAdapt16[i] = aecm->channelStored[i];
|
||||
// aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)
|
||||
// aecm->channelStored[i], 16);
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : :
|
||||
"r"(&aecm->channelStored[i]) : "q12");
|
||||
__asm__("vst1.16 {d24, d25}, [%0, :128]" : :
|
||||
"r"(&aecm->channelAdapt16[i]) : "q12");
|
||||
__asm__("vshll.s16 q10, d24, #16" : : : "q12", "q13", "q10");
|
||||
__asm__("vshll.s16 q11, d25, #16" : : : "q12", "q13", "q11");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->channelAdapt32[i]): "q10", "q11");
|
||||
}
|
||||
aecm->channelAdapt16[i] = aecm->channelStored[i];
|
||||
aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
|
||||
(WebRtc_Word32)aecm->channelStored[i], 16);
|
||||
}
|
||||
|
||||
#endif // #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)
|
800
webrtc/modules/audio_processing/aecm/echo_control_mobile.c
Normal file
800
webrtc/modules/audio_processing/aecm/echo_control_mobile.c
Normal file
@ -0,0 +1,800 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
|
||||
#include "echo_control_mobile.h"
|
||||
#include "aecm_core.h"
|
||||
#include "ring_buffer.h"
|
||||
#ifdef AEC_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef MAC_IPHONE_PRINT
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#elif defined ARM_WINM_LOG
|
||||
#include "windows.h"
|
||||
extern HANDLE logFile;
|
||||
#endif
|
||||
|
||||
#define BUF_SIZE_FRAMES 50 // buffer size (frames)
|
||||
// Maximum length of resampled signal. Must be an integer multiple of frames
|
||||
// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
|
||||
// The factor of 2 handles wb, and the + 1 is as a safety margin
|
||||
#define MAX_RESAMP_LEN (5 * FRAME_LEN)
|
||||
|
||||
static const int kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
|
||||
static const int kSampMsNb = 8; // samples per ms in nb
|
||||
// Target suppression levels for nlp modes
|
||||
// log{0.001, 0.00001, 0.00000001}
|
||||
static const int kInitCheck = 42;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sampFreq;
|
||||
int scSampFreq;
|
||||
short bufSizeStart;
|
||||
int knownDelay;
|
||||
|
||||
// Stores the last frame added to the farend buffer
|
||||
short farendOld[2][FRAME_LEN];
|
||||
short initFlag; // indicates if AEC has been initialized
|
||||
|
||||
// Variables used for averaging far end buffer size
|
||||
short counter;
|
||||
short sum;
|
||||
short firstVal;
|
||||
short checkBufSizeCtr;
|
||||
|
||||
// Variables used for delay shifts
|
||||
short msInSndCardBuf;
|
||||
short filtDelay;
|
||||
int timeForDelayChange;
|
||||
int ECstartup;
|
||||
int checkBuffSize;
|
||||
int delayChange;
|
||||
short lastDelayDiff;
|
||||
|
||||
WebRtc_Word16 echoMode;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *bufFile;
|
||||
FILE *delayFile;
|
||||
FILE *preCompFile;
|
||||
FILE *postCompFile;
|
||||
#endif // AEC_DEBUG
|
||||
// Structures
|
||||
void *farendBuf;
|
||||
|
||||
int lastError;
|
||||
|
||||
AecmCore_t *aecmCore;
|
||||
} aecmob_t;
|
||||
|
||||
// Estimates delay to set the position of the farend buffer read pointer
|
||||
// (controlled by knownDelay)
|
||||
static int WebRtcAecm_EstBufDelay(aecmob_t *aecmInst, short msInSndCardBuf);
|
||||
|
||||
// Stuffs the farend buffer if the estimated delay is too large
|
||||
static int WebRtcAecm_DelayComp(aecmob_t *aecmInst);
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Create(void **aecmInst)
|
||||
{
|
||||
aecmob_t *aecm;
|
||||
if (aecmInst == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm = malloc(sizeof(aecmob_t));
|
||||
*aecmInst = aecm;
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1)
|
||||
{
|
||||
WebRtcAecm_Free(aecm);
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcApm_CreateBuffer(&aecm->farendBuf, kBufSizeSamp) == -1)
|
||||
{
|
||||
WebRtcAecm_Free(aecm);
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->initFlag = 0;
|
||||
aecm->lastError = 0;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
|
||||
aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb");
|
||||
aecm->aecmCore->outFile = fopen("aecOut.pcm","wb");
|
||||
//aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
|
||||
|
||||
aecm->bufFile = fopen("aecBuf.dat", "wb");
|
||||
aecm->delayFile = fopen("aecDelay.dat", "wb");
|
||||
aecm->preCompFile = fopen("preComp.pcm", "wb");
|
||||
aecm->postCompFile = fopen("postComp.pcm", "wb");
|
||||
#endif // AEC_DEBUG
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Free(void *aecmInst)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
fclose(aecm->aecmCore->farFile);
|
||||
fclose(aecm->aecmCore->nearFile);
|
||||
fclose(aecm->aecmCore->outFile);
|
||||
//fclose(aecm->aecmCore->outLpFile);
|
||||
|
||||
fclose(aecm->bufFile);
|
||||
fclose(aecm->delayFile);
|
||||
fclose(aecm->preCompFile);
|
||||
fclose(aecm->postCompFile);
|
||||
#endif // AEC_DEBUG
|
||||
WebRtcAecm_FreeCore(aecm->aecmCore);
|
||||
WebRtcApm_FreeBuffer(aecm->farendBuf);
|
||||
free(aecm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Init(void *aecmInst, WebRtc_Word32 sampFreq)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
AecmConfig aecConfig;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sampFreq != 8000 && sampFreq != 16000)
|
||||
{
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecm->sampFreq = sampFreq;
|
||||
|
||||
// Initialize AECM core
|
||||
if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
|
||||
{
|
||||
aecm->lastError = AECM_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize farend buffer
|
||||
if (WebRtcApm_InitBuffer(aecm->farendBuf) == -1)
|
||||
{
|
||||
aecm->lastError = AECM_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
aecm->initFlag = kInitCheck; // indicates that initialization has been done
|
||||
|
||||
aecm->delayChange = 1;
|
||||
|
||||
aecm->sum = 0;
|
||||
aecm->counter = 0;
|
||||
aecm->checkBuffSize = 1;
|
||||
aecm->firstVal = 0;
|
||||
|
||||
aecm->ECstartup = 1;
|
||||
aecm->bufSizeStart = 0;
|
||||
aecm->checkBufSizeCtr = 0;
|
||||
aecm->filtDelay = 0;
|
||||
aecm->timeForDelayChange = 0;
|
||||
aecm->knownDelay = 0;
|
||||
aecm->lastDelayDiff = 0;
|
||||
|
||||
memset(&aecm->farendOld[0][0], 0, 160);
|
||||
|
||||
// Default settings.
|
||||
aecConfig.cngMode = AecmTrue;
|
||||
aecConfig.echoMode = 3;
|
||||
|
||||
if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
|
||||
{
|
||||
aecm->lastError = AECM_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_BufferFarend(void *aecmInst, const WebRtc_Word16 *farend,
|
||||
WebRtc_Word16 nrOfSamples)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
WebRtc_Word32 retVal = 0;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (farend == NULL)
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160)
|
||||
{
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: Is this really a good idea?
|
||||
if (!aecm->ECstartup)
|
||||
{
|
||||
WebRtcAecm_DelayComp(aecm);
|
||||
}
|
||||
|
||||
WebRtcApm_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoisy,
|
||||
const WebRtc_Word16 *nearendClean, WebRtc_Word16 *out,
|
||||
WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
WebRtc_Word32 retVal = 0;
|
||||
short i;
|
||||
short farend[FRAME_LEN];
|
||||
short nmbrOfFilledBuffers;
|
||||
short nBlocks10ms;
|
||||
short nFrames;
|
||||
#ifdef AEC_DEBUG
|
||||
short msInAECBuf;
|
||||
#endif
|
||||
|
||||
#ifdef ARM_WINM_LOG
|
||||
__int64 freq, start, end, diff;
|
||||
unsigned int milliseconds;
|
||||
DWORD temp;
|
||||
#elif defined MAC_IPHONE_PRINT
|
||||
// double endtime = 0, starttime = 0;
|
||||
struct timeval starttime;
|
||||
struct timeval endtime;
|
||||
static long int timeused = 0;
|
||||
static int timecount = 0;
|
||||
#endif
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nearendNoisy == NULL)
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out == NULL)
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160)
|
||||
{
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msInSndCardBuf < 0)
|
||||
{
|
||||
msInSndCardBuf = 0;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
} else if (msInSndCardBuf > 500)
|
||||
{
|
||||
msInSndCardBuf = 500;
|
||||
aecm->lastError = AECM_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
}
|
||||
msInSndCardBuf += 10;
|
||||
aecm->msInSndCardBuf = msInSndCardBuf;
|
||||
|
||||
nFrames = nrOfSamples / FRAME_LEN;
|
||||
nBlocks10ms = nFrames / aecm->aecmCore->mult;
|
||||
|
||||
if (aecm->ECstartup)
|
||||
{
|
||||
if (nearendClean == NULL)
|
||||
{
|
||||
memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
|
||||
} else
|
||||
{
|
||||
memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
|
||||
}
|
||||
|
||||
nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecm->farendBuf) / FRAME_LEN;
|
||||
// The AECM is in the start up mode
|
||||
// AECM is disabled until the soundcard buffer and farend buffers are OK
|
||||
|
||||
// Mechanism to ensure that the soundcard buffer is reasonably stable.
|
||||
if (aecm->checkBuffSize)
|
||||
{
|
||||
aecm->checkBufSizeCtr++;
|
||||
// Before we fill up the far end buffer we require the amount of data on the
|
||||
// sound card to be stable (+/-8 ms) compared to the first value. This
|
||||
// comparison is made during the following 4 consecutive frames. If it seems
|
||||
// to be stable then we start to fill up the far end buffer.
|
||||
|
||||
if (aecm->counter == 0)
|
||||
{
|
||||
aecm->firstVal = aecm->msInSndCardBuf;
|
||||
aecm->sum = 0;
|
||||
}
|
||||
|
||||
if (abs(aecm->firstVal - aecm->msInSndCardBuf)
|
||||
< WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
|
||||
{
|
||||
aecm->sum += aecm->msInSndCardBuf;
|
||||
aecm->counter++;
|
||||
} else
|
||||
{
|
||||
aecm->counter = 0;
|
||||
}
|
||||
|
||||
if (aecm->counter * nBlocks10ms >= 6)
|
||||
{
|
||||
// The farend buffer size is determined in blocks of 80 samples
|
||||
// Use 75% of the average value of the soundcard buffer
|
||||
aecm->bufSizeStart
|
||||
= WEBRTC_SPL_MIN((3 * aecm->sum
|
||||
* aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
|
||||
// buffersize has now been determined
|
||||
aecm->checkBuffSize = 0;
|
||||
}
|
||||
|
||||
if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
|
||||
{
|
||||
// for really bad sound cards, don't disable echocanceller for more than 0.5 sec
|
||||
aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
|
||||
* aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
|
||||
aecm->checkBuffSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if checkBuffSize changed in the if-statement above
|
||||
if (!aecm->checkBuffSize)
|
||||
{
|
||||
// soundcard buffer is now reasonably stable
|
||||
// When the far end buffer is filled with approximately the same amount of
|
||||
// data as the amount on the sound card we end the start up phase and start
|
||||
// to cancel echoes.
|
||||
|
||||
if (nmbrOfFilledBuffers == aecm->bufSizeStart)
|
||||
{
|
||||
aecm->ECstartup = 0; // Enable the AECM
|
||||
} else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
|
||||
{
|
||||
WebRtcApm_FlushBuffer(
|
||||
aecm->farendBuf,
|
||||
WebRtcApm_get_buffer_size(aecm->farendBuf)
|
||||
- aecm->bufSizeStart * FRAME_LEN);
|
||||
aecm->ECstartup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
// AECM is enabled
|
||||
|
||||
// Note only 1 block supported for nb and 2 blocks for wb
|
||||
for (i = 0; i < nFrames; i++)
|
||||
{
|
||||
nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecm->farendBuf) / FRAME_LEN;
|
||||
|
||||
// Check that there is data in the far end buffer
|
||||
if (nmbrOfFilledBuffers > 0)
|
||||
{
|
||||
// Get the next 80 samples from the farend buffer
|
||||
WebRtcApm_ReadBuffer(aecm->farendBuf, farend, FRAME_LEN);
|
||||
|
||||
// Always store the last frame for use when we run out of data
|
||||
memcpy(&(aecm->farendOld[i][0]), farend, FRAME_LEN * sizeof(short));
|
||||
} else
|
||||
{
|
||||
// We have no data so we use the last played frame
|
||||
memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
|
||||
}
|
||||
|
||||
// Call buffer delay estimator when all data is extracted,
|
||||
// i,e. i = 0 for NB and i = 1 for WB
|
||||
if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
|
||||
{
|
||||
WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
|
||||
}
|
||||
|
||||
#ifdef ARM_WINM_LOG
|
||||
// measure tick start
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&start);
|
||||
#elif defined MAC_IPHONE_PRINT
|
||||
// starttime = clock()/(double)CLOCKS_PER_SEC;
|
||||
gettimeofday(&starttime, NULL);
|
||||
#endif
|
||||
// Call the AECM
|
||||
/*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
|
||||
&out[FRAME_LEN * i], aecm->knownDelay);*/
|
||||
if (nearendClean == NULL)
|
||||
{
|
||||
if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
|
||||
farend,
|
||||
&nearendNoisy[FRAME_LEN * i],
|
||||
NULL,
|
||||
&out[FRAME_LEN * i]) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
|
||||
farend,
|
||||
&nearendNoisy[FRAME_LEN * i],
|
||||
&nearendClean[FRAME_LEN * i],
|
||||
&out[FRAME_LEN * i]) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM_WINM_LOG
|
||||
|
||||
// measure tick end
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&end);
|
||||
|
||||
if(end > start)
|
||||
{
|
||||
diff = ((end - start) * 1000) / (freq/1000);
|
||||
milliseconds = (unsigned int)(diff & 0xffffffff);
|
||||
WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
|
||||
}
|
||||
#elif defined MAC_IPHONE_PRINT
|
||||
// endtime = clock()/(double)CLOCKS_PER_SEC;
|
||||
// printf("%f\n", endtime - starttime);
|
||||
|
||||
gettimeofday(&endtime, NULL);
|
||||
|
||||
if( endtime.tv_usec > starttime.tv_usec)
|
||||
{
|
||||
timeused += endtime.tv_usec - starttime.tv_usec;
|
||||
} else
|
||||
{
|
||||
timeused += endtime.tv_usec + 1000000 - starttime.tv_usec;
|
||||
}
|
||||
|
||||
if(++timecount == 1000)
|
||||
{
|
||||
timecount = 0;
|
||||
printf("AEC: %ld\n", timeused);
|
||||
timeused = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
msInAECBuf = WebRtcApm_get_buffer_size(aecm->farendBuf) / (kSampMsNb*aecm->aecmCore->mult);
|
||||
fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
|
||||
fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
|
||||
{
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecm->aecmCore->cngMode = config.cngMode;
|
||||
|
||||
if (config.echoMode < 0 || config.echoMode > 4)
|
||||
{
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecm->echoMode = config.echoMode;
|
||||
|
||||
if (aecm->echoMode == 0)
|
||||
{
|
||||
aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
|
||||
aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
|
||||
aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
|
||||
aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
|
||||
aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
|
||||
- (SUPGAIN_ERROR_PARAM_B >> 3);
|
||||
aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
|
||||
- (SUPGAIN_ERROR_PARAM_D >> 3);
|
||||
} else if (aecm->echoMode == 1)
|
||||
{
|
||||
aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
|
||||
aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
|
||||
aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
|
||||
aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
|
||||
aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
|
||||
- (SUPGAIN_ERROR_PARAM_B >> 2);
|
||||
aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
|
||||
- (SUPGAIN_ERROR_PARAM_D >> 2);
|
||||
} else if (aecm->echoMode == 2)
|
||||
{
|
||||
aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
|
||||
aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
|
||||
aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
|
||||
aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
|
||||
aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
|
||||
- (SUPGAIN_ERROR_PARAM_B >> 1);
|
||||
aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
|
||||
- (SUPGAIN_ERROR_PARAM_D >> 1);
|
||||
} else if (aecm->echoMode == 3)
|
||||
{
|
||||
aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
|
||||
aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
|
||||
aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
|
||||
aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
|
||||
aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
|
||||
aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
|
||||
} else if (aecm->echoMode == 4)
|
||||
{
|
||||
aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
|
||||
aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
|
||||
aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
|
||||
aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
|
||||
aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
|
||||
- (SUPGAIN_ERROR_PARAM_B << 1);
|
||||
aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
|
||||
- (SUPGAIN_ERROR_PARAM_D << 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config == NULL)
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
config->cngMode = aecm->aecmCore->cngMode;
|
||||
config->echoMode = aecm->echoMode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
const WebRtc_Word16* echo_path_ptr = echo_path;
|
||||
|
||||
if ((aecm == NULL) || (echo_path == NULL))
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (size_bytes != WebRtcAecm_echo_path_size_bytes())
|
||||
{
|
||||
// Input channel size does not match the size of AECM
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
size_t size_bytes)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
WebRtc_Word16* echo_path_ptr = echo_path;
|
||||
|
||||
if ((aecm == NULL) || (echo_path == NULL))
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (size_bytes != WebRtcAecm_echo_path_size_bytes())
|
||||
{
|
||||
// Input channel size does not match the size of AECM
|
||||
aecm->lastError = AECM_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (aecm->initFlag != kInitCheck)
|
||||
{
|
||||
aecm->lastError = AECM_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t WebRtcAecm_echo_path_size_bytes()
|
||||
{
|
||||
return (PART_LEN1 * sizeof(WebRtc_Word16));
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len)
|
||||
{
|
||||
const char version[] = "AECM 1.2.0";
|
||||
const short versionLen = (short)strlen(version) + 1; // +1 for null-termination
|
||||
|
||||
if (versionStr == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (versionLen > len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(versionStr, version, versionLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return aecm->lastError;
|
||||
}
|
||||
|
||||
static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf)
|
||||
{
|
||||
short delayNew, nSampFar, nSampSndCard;
|
||||
short diff;
|
||||
|
||||
nSampFar = WebRtcApm_get_buffer_size(aecm->farendBuf);
|
||||
nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
|
||||
|
||||
delayNew = nSampSndCard - nSampFar;
|
||||
|
||||
if (delayNew < FRAME_LEN)
|
||||
{
|
||||
WebRtcApm_FlushBuffer(aecm->farendBuf, FRAME_LEN);
|
||||
delayNew += FRAME_LEN;
|
||||
}
|
||||
|
||||
aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
|
||||
|
||||
diff = aecm->filtDelay - aecm->knownDelay;
|
||||
if (diff > 224)
|
||||
{
|
||||
if (aecm->lastDelayDiff < 96)
|
||||
{
|
||||
aecm->timeForDelayChange = 0;
|
||||
} else
|
||||
{
|
||||
aecm->timeForDelayChange++;
|
||||
}
|
||||
} else if (diff < 96 && aecm->knownDelay > 0)
|
||||
{
|
||||
if (aecm->lastDelayDiff > 224)
|
||||
{
|
||||
aecm->timeForDelayChange = 0;
|
||||
} else
|
||||
{
|
||||
aecm->timeForDelayChange++;
|
||||
}
|
||||
} else
|
||||
{
|
||||
aecm->timeForDelayChange = 0;
|
||||
}
|
||||
aecm->lastDelayDiff = diff;
|
||||
|
||||
if (aecm->timeForDelayChange > 25)
|
||||
{
|
||||
aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WebRtcAecm_DelayComp(aecmob_t *aecm)
|
||||
{
|
||||
int nSampFar, nSampSndCard, delayNew, nSampAdd;
|
||||
const int maxStuffSamp = 10 * FRAME_LEN;
|
||||
|
||||
nSampFar = WebRtcApm_get_buffer_size(aecm->farendBuf);
|
||||
nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
|
||||
delayNew = nSampSndCard - nSampFar;
|
||||
|
||||
if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
|
||||
{
|
||||
// The difference of the buffer sizes is larger than the maximum
|
||||
// allowed known delay. Compensate by stuffing the buffer.
|
||||
nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
|
||||
FRAME_LEN));
|
||||
nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
|
||||
|
||||
WebRtcApm_StuffBuffer(aecm->farendBuf, nSampAdd);
|
||||
aecm->delayChange = 1; // the delay needs to be updated
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_INTERFACE_ECHO_CONTROL_MOBILE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_INTERFACE_ECHO_CONTROL_MOBILE_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
enum {
|
||||
AecmFalse = 0,
|
||||
AecmTrue
|
||||
};
|
||||
|
||||
// Errors
|
||||
#define AECM_UNSPECIFIED_ERROR 12000
|
||||
#define AECM_UNSUPPORTED_FUNCTION_ERROR 12001
|
||||
#define AECM_UNINITIALIZED_ERROR 12002
|
||||
#define AECM_NULL_POINTER_ERROR 12003
|
||||
#define AECM_BAD_PARAMETER_ERROR 12004
|
||||
|
||||
// Warnings
|
||||
#define AECM_BAD_PARAMETER_WARNING 12100
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 cngMode; // AECM_FALSE, AECM_TRUE (default)
|
||||
WebRtc_Word16 echoMode; // 0, 1, 2, 3 (default), 4
|
||||
} AecmConfig;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocates the memory needed by the AECM. The memory needs to be
|
||||
* initialized separately using the WebRtcAecm_Init() function.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void **aecmInst Pointer to the AECM instance to be
|
||||
* created and initialized
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Create(void **aecmInst);
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAecm_Create()
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Free(void *aecmInst);
|
||||
|
||||
/*
|
||||
* Initializes an AECM instance.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* WebRtc_Word32 sampFreq Sampling frequency of data
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Init(void* aecmInst,
|
||||
WebRtc_Word32 sampFreq);
|
||||
|
||||
/*
|
||||
* Inserts an 80 or 160 sample block of data into the farend buffer.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* WebRtc_Word16 *farend In buffer containing one frame of
|
||||
* farend signal
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_BufferFarend(void* aecmInst,
|
||||
const WebRtc_Word16* farend,
|
||||
WebRtc_Word16 nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the AECM on an 80 or 160 sample blocks of data.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* WebRtc_Word16 *nearendNoisy In buffer containing one frame of
|
||||
* reference nearend+echo signal. If
|
||||
* noise reduction is active, provide
|
||||
* the noisy signal here.
|
||||
* WebRtc_Word16 *nearendClean In buffer containing one frame of
|
||||
* nearend+echo signal. If noise
|
||||
* reduction is active, provide the
|
||||
* clean signal here. Otherwise pass a
|
||||
* NULL pointer.
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in nearend buffer
|
||||
* WebRtc_Word16 msInSndCardBuf Delay estimate for sound card and
|
||||
* system buffers
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word16 *out Out buffer, one frame of processed nearend
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Process(void* aecmInst,
|
||||
const WebRtc_Word16* nearendNoisy,
|
||||
const WebRtc_Word16* nearendClean,
|
||||
WebRtc_Word16* out,
|
||||
WebRtc_Word16 nrOfSamples,
|
||||
WebRtc_Word16 msInSndCardBuf);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* AecmConfig config Config instance that contains all
|
||||
* properties to be set
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_set_config(void* aecmInst,
|
||||
AecmConfig config);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecmConfig *config Pointer to the config instance that
|
||||
* all properties will be written to
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst,
|
||||
AecmConfig *config);
|
||||
|
||||
/*
|
||||
* This function enables the user to set the echo path on-the-fly.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* void* echo_path Pointer to the echo path to be set
|
||||
* size_t size_bytes Size in bytes of the echo path
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes);
|
||||
|
||||
/*
|
||||
* This function enables the user to get the currently used echo path
|
||||
* on-the-fly
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* void* echo_path Pointer to echo path
|
||||
* size_t size_bytes Size in bytes of the echo path
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
size_t size_bytes);
|
||||
|
||||
/*
|
||||
* This function enables the user to get the echo path size in bytes
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* size_t return : size in bytes
|
||||
*/
|
||||
size_t WebRtcAecm_echo_path_size_bytes();
|
||||
|
||||
/*
|
||||
* Gets the last error code.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 11000-11100: error code
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst);
|
||||
|
||||
/*
|
||||
* Gets a version string
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* char *versionStr Pointer to a string array
|
||||
* WebRtc_Word16 len The maximum length of the string
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word8 *versionStr Pointer to a string array
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_get_version(WebRtc_Word8 *versionStr,
|
||||
WebRtc_Word16 len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_INTERFACE_ECHO_CONTROL_MOBILE_H_ */
|
10
webrtc/modules/audio_processing/agc/Makefile.am
Normal file
10
webrtc/modules/audio_processing/agc/Makefile.am
Normal file
@ -0,0 +1,10 @@
|
||||
noinst_LTLIBRARIES = libagc.la
|
||||
|
||||
libagc_la_SOURCES = interface/gain_control.h \
|
||||
analog_agc.c \
|
||||
analog_agc.h \
|
||||
digital_agc.c \
|
||||
digital_agc.h
|
||||
libagc_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility
|
34
webrtc/modules/audio_processing/agc/agc.gypi
Normal file
34
webrtc/modules/audio_processing/agc/agc.gypi
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'agc',
|
||||
'type': '<(library)',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:spl',
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/gain_control.h',
|
||||
'analog_agc.c',
|
||||
'analog_agc.h',
|
||||
'digital_agc.c',
|
||||
'digital_agc.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user