Merge branch 'master' of https://github.com/okamstudio/godot
Conflicts: platform/windows/detect.py
This commit is contained in:
commit
b3cda43a0f
|
@ -0,0 +1,4 @@
|
|||
*.cpp eol=lf
|
||||
*.h eol=lf
|
||||
*.py eol=lf
|
||||
*.hpp eol=lf
|
|
@ -50,6 +50,14 @@ platform/android/libs/play_licensing/gen/*
|
|||
*.d
|
||||
*.so
|
||||
*.os
|
||||
*.Plo
|
||||
*.lo
|
||||
*.Po
|
||||
|
||||
# Libs generated files
|
||||
.deps/*
|
||||
.dirstamp
|
||||
|
||||
|
||||
# QT project files
|
||||
*.config
|
||||
|
|
|
@ -102,6 +102,7 @@ opts.Add('p','Platform (same as platform=).',"")
|
|||
opts.Add('tools','Build Tools (Including Editor): (yes/no)','yes')
|
||||
opts.Add('gdscript','Build GDSCript support: (yes/no)','yes')
|
||||
opts.Add('vorbis','Build Ogg Vorbis Support: (yes/no)','yes')
|
||||
opts.Add('opus','Build Opus Audio Format Support: (yes/no)','yes')
|
||||
opts.Add('minizip','Build Minizip Archive Support: (yes/no)','yes')
|
||||
opts.Add('squish','Squish BC Texture Compression in editor (yes/no)','yes')
|
||||
opts.Add('theora','Theora Video (yes/no)','yes')
|
||||
|
@ -299,6 +300,8 @@ if selected_platform in platform_list:
|
|||
|
||||
if (env['vorbis']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DVORBIS_ENABLED']);
|
||||
if (env['opus']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DOPUS_ENABLED']);
|
||||
|
||||
if (env['theora']=='yes'):
|
||||
env.Append(CPPFLAGS=['-DTHEORA_ENABLED']);
|
||||
|
|
107
core/image.cpp
107
core/image.cpp
|
@ -400,6 +400,102 @@ Image::Format Image::get_format() const{
|
|||
return format;
|
||||
}
|
||||
|
||||
static double _bicubic_interp_kernel( double x ) {
|
||||
|
||||
x = ABS(x);
|
||||
|
||||
double bc = 0;
|
||||
|
||||
if ( x <= 1 )
|
||||
bc = ( 1.5 * x - 2.5 ) * x * x + 1;
|
||||
else if ( x < 2 )
|
||||
bc = ( ( -0.5 * x + 2.5 ) * x - 4 ) * x + 2;
|
||||
|
||||
|
||||
return bc;
|
||||
}
|
||||
|
||||
template<int CC>
|
||||
static void _scale_cubic(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
|
||||
|
||||
|
||||
// get source image size
|
||||
int width = p_src_width;
|
||||
int height = p_src_height;
|
||||
double xfac = (double) width / p_dst_width;
|
||||
double yfac = (double) height / p_dst_height;
|
||||
// coordinates of source points and cooefficiens
|
||||
double ox, oy, dx, dy, k1, k2;
|
||||
int ox1, oy1, ox2, oy2;
|
||||
// destination pixel values
|
||||
// width and height decreased by 1
|
||||
int ymax = height - 1;
|
||||
int xmax = width - 1;
|
||||
// temporary pointer
|
||||
|
||||
for ( int y = 0; y < p_dst_height; y++ ) {
|
||||
// Y coordinates
|
||||
oy = (double) y * yfac - 0.5f;
|
||||
oy1 = (int) oy;
|
||||
dy = oy - (double) oy1;
|
||||
|
||||
for ( int x = 0; x < p_dst_width; x++ ) {
|
||||
// X coordinates
|
||||
ox = (double) x * xfac - 0.5f;
|
||||
ox1 = (int) ox;
|
||||
dx = ox - (double) ox1;
|
||||
|
||||
// initial pixel value
|
||||
|
||||
uint8_t *dst=p_dst + (y*p_dst_width+x)*CC;
|
||||
|
||||
double color[CC];
|
||||
for(int i=0;i<CC;i++) {
|
||||
color[i]=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for ( int n = -1; n < 3; n++ ) {
|
||||
// get Y cooefficient
|
||||
k1 = _bicubic_interp_kernel( dy - (double) n );
|
||||
|
||||
oy2 = oy1 + n;
|
||||
if ( oy2 < 0 )
|
||||
oy2 = 0;
|
||||
if ( oy2 > ymax )
|
||||
oy2 = ymax;
|
||||
|
||||
for ( int m = -1; m < 3; m++ ) {
|
||||
// get X cooefficient
|
||||
k2 = k1 * _bicubic_interp_kernel( (double) m - dx );
|
||||
|
||||
ox2 = ox1 + m;
|
||||
if ( ox2 < 0 )
|
||||
ox2 = 0;
|
||||
if ( ox2 > xmax )
|
||||
ox2 = xmax;
|
||||
|
||||
// get pixel of original image
|
||||
const uint8_t *p = p_src + (oy2 * p_src_width + ox2)*CC;
|
||||
|
||||
for(int i=0;i<CC;i++) {
|
||||
|
||||
color[i]+=p[i]*k2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<CC;i++) {
|
||||
dst[i]=CLAMP(Math::fast_ftoi(color[i]),0,255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<int CC>
|
||||
static void _scale_bilinear(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
|
||||
|
||||
|
@ -559,6 +655,17 @@ void Image::resize( int p_width, int p_height, Interpolation p_interpolation ) {
|
|||
}
|
||||
|
||||
} break;
|
||||
case INTERPOLATE_CUBIC: {
|
||||
|
||||
switch(get_format_pixel_size(format)) {
|
||||
case 1: _scale_cubic<1>(r_ptr,w_ptr,width,height,p_width,p_height); break;
|
||||
case 2: _scale_cubic<2>(r_ptr,w_ptr,width,height,p_width,p_height); break;
|
||||
case 3: _scale_cubic<3>(r_ptr,w_ptr,width,height,p_width,p_height); break;
|
||||
case 4: _scale_cubic<4>(r_ptr,w_ptr,width,height,p_width,p_height); break;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ public:
|
|||
|
||||
INTERPOLATE_NEAREST,
|
||||
INTERPOLATE_BILINEAR,
|
||||
INTERPOLATE_CUBIC,
|
||||
/* INTERPOLATE GAUSS */
|
||||
};
|
||||
|
||||
|
|
|
@ -79,9 +79,9 @@ public:
|
|||
return Math::log( p_linear ) * 8.6858896380650365530225783783321;
|
||||
}
|
||||
|
||||
static inline double db2linear(double p_linear) {
|
||||
static inline double db2linear(double p_db) {
|
||||
|
||||
return Math::exp( p_linear * 0.11512925464970228420089957273422 );
|
||||
return Math::exp( p_db * 0.11512925464970228420089957273422 );
|
||||
}
|
||||
|
||||
static bool is_nan(double p_val);
|
||||
|
|
|
@ -64,6 +64,7 @@ void Input::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("warp_mouse_pos","to"),&Input::warp_mouse_pos);
|
||||
ObjectTypeDB::bind_method(_MD("action_press"),&Input::action_press);
|
||||
ObjectTypeDB::bind_method(_MD("action_release"),&Input::action_release);
|
||||
ObjectTypeDB::bind_method(_MD("set_custom_mouse_cursor","image:Texture","hotspot"),&Input::set_custom_mouse_cursor,DEFVAL(Vector2()));
|
||||
|
||||
BIND_CONSTANT( MOUSE_MODE_VISIBLE );
|
||||
BIND_CONSTANT( MOUSE_MODE_HIDDEN );
|
||||
|
@ -104,309 +105,3 @@ Input::Input() {
|
|||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void InputDefault::SpeedTrack::update(const Vector2& p_delta_p) {
|
||||
|
||||
uint64_t tick = OS::get_singleton()->get_ticks_usec();
|
||||
uint32_t tdiff = tick-last_tick;
|
||||
float delta_t = tdiff / 1000000.0;
|
||||
last_tick=tick;
|
||||
|
||||
|
||||
accum+=p_delta_p;
|
||||
accum_t+=delta_t;
|
||||
|
||||
if (accum_t>max_ref_frame*10)
|
||||
accum_t=max_ref_frame*10;
|
||||
|
||||
while( accum_t>=min_ref_frame ) {
|
||||
|
||||
float slice_t = min_ref_frame / accum_t;
|
||||
Vector2 slice = accum*slice_t;
|
||||
accum=accum-slice;
|
||||
accum_t-=min_ref_frame;
|
||||
|
||||
speed=(slice/min_ref_frame).linear_interpolate(speed,min_ref_frame/max_ref_frame);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void InputDefault::SpeedTrack::reset() {
|
||||
last_tick = OS::get_singleton()->get_ticks_usec();
|
||||
speed=Vector2();
|
||||
accum_t=0;
|
||||
}
|
||||
|
||||
InputDefault::SpeedTrack::SpeedTrack() {
|
||||
|
||||
min_ref_frame=0.1;
|
||||
max_ref_frame=0.3;
|
||||
reset();
|
||||
}
|
||||
|
||||
bool InputDefault::is_key_pressed(int p_scancode) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
return keys_pressed.has(p_scancode);
|
||||
}
|
||||
|
||||
bool InputDefault::is_mouse_button_pressed(int p_button) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
return (mouse_button_mask&(1<<p_button))!=0;
|
||||
}
|
||||
|
||||
|
||||
static int _combine_device(int p_value,int p_device) {
|
||||
|
||||
return p_value|(p_device<<20);
|
||||
}
|
||||
|
||||
bool InputDefault::is_joy_button_pressed(int p_device, int p_button) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
return joy_buttons_pressed.has(_combine_device(p_button,p_device));
|
||||
}
|
||||
|
||||
bool InputDefault::is_action_pressed(const StringName& p_action) {
|
||||
|
||||
if (custom_action_press.has(p_action))
|
||||
return true; //simpler
|
||||
|
||||
const List<InputEvent> *alist = InputMap::get_singleton()->get_action_list(p_action);
|
||||
if (!alist)
|
||||
return NULL;
|
||||
|
||||
|
||||
for (const List<InputEvent>::Element *E=alist->front();E;E=E->next()) {
|
||||
|
||||
|
||||
int device=E->get().device;
|
||||
|
||||
switch(E->get().type) {
|
||||
|
||||
case InputEvent::KEY: {
|
||||
|
||||
const InputEventKey &iek=E->get().key;
|
||||
if ((keys_pressed.has(iek.scancode)))
|
||||
return true;
|
||||
} break;
|
||||
case InputEvent::MOUSE_BUTTON: {
|
||||
|
||||
const InputEventMouseButton &iemb=E->get().mouse_button;
|
||||
if(mouse_button_mask&(1<<iemb.button_index))
|
||||
return true;
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_BUTTON: {
|
||||
|
||||
const InputEventJoystickButton &iejb=E->get().joy_button;
|
||||
int c = _combine_device(iejb.button_index,device);
|
||||
if (joy_buttons_pressed.has(c))
|
||||
return true;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float InputDefault::get_joy_axis(int p_device,int p_axis) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
int c = _combine_device(p_axis,p_device);
|
||||
if (joy_axis.has(c)) {
|
||||
return joy_axis[c];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
String InputDefault::get_joy_name(int p_idx) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
return joy_names[p_idx];
|
||||
};
|
||||
|
||||
void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
joy_names[p_idx] = p_connected ? p_name : "";
|
||||
|
||||
emit_signal("joy_connection_changed", p_idx, p_connected);
|
||||
};
|
||||
|
||||
Vector3 InputDefault::get_accelerometer() {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
return accelerometer;
|
||||
}
|
||||
|
||||
void InputDefault::parse_input_event(const InputEvent& p_event) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
switch(p_event.type) {
|
||||
|
||||
case InputEvent::KEY: {
|
||||
|
||||
if (p_event.key.echo)
|
||||
break;
|
||||
if (p_event.key.scancode==0)
|
||||
break;
|
||||
|
||||
// print_line(p_event);
|
||||
|
||||
if (p_event.key.pressed)
|
||||
keys_pressed.insert(p_event.key.scancode);
|
||||
else
|
||||
keys_pressed.erase(p_event.key.scancode);
|
||||
} break;
|
||||
case InputEvent::MOUSE_BUTTON: {
|
||||
|
||||
if (p_event.mouse_button.doubleclick)
|
||||
break;
|
||||
|
||||
if (p_event.mouse_button.pressed)
|
||||
mouse_button_mask|=(1<<p_event.mouse_button.button_index);
|
||||
else
|
||||
mouse_button_mask&=~(1<<p_event.mouse_button.button_index);
|
||||
|
||||
if (main_loop && emulate_touch && p_event.mouse_button.button_index==1) {
|
||||
InputEventScreenTouch touch_event;
|
||||
touch_event.index=0;
|
||||
touch_event.pressed=p_event.mouse_button.pressed;
|
||||
touch_event.x=p_event.mouse_button.x;
|
||||
touch_event.y=p_event.mouse_button.y;
|
||||
InputEvent ev;
|
||||
ev.type=InputEvent::SCREEN_TOUCH;
|
||||
ev.screen_touch=touch_event;
|
||||
main_loop->input_event(ev);
|
||||
}
|
||||
} break;
|
||||
case InputEvent::MOUSE_MOTION: {
|
||||
|
||||
if (main_loop && emulate_touch && p_event.mouse_motion.button_mask&1) {
|
||||
InputEventScreenDrag drag_event;
|
||||
drag_event.index=0;
|
||||
drag_event.x=p_event.mouse_motion.x;
|
||||
drag_event.y=p_event.mouse_motion.y;
|
||||
drag_event.relative_x=p_event.mouse_motion.relative_x;
|
||||
drag_event.relative_y=p_event.mouse_motion.relative_y;
|
||||
drag_event.speed_x=p_event.mouse_motion.speed_x;
|
||||
drag_event.speed_y=p_event.mouse_motion.speed_y;
|
||||
|
||||
InputEvent ev;
|
||||
ev.type=InputEvent::SCREEN_DRAG;
|
||||
ev.screen_drag=drag_event;
|
||||
|
||||
main_loop->input_event(ev);
|
||||
}
|
||||
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_BUTTON: {
|
||||
|
||||
int c = _combine_device(p_event.joy_button.button_index,p_event.device);
|
||||
|
||||
if (p_event.joy_button.pressed)
|
||||
joy_buttons_pressed.insert(c);
|
||||
else
|
||||
joy_buttons_pressed.erase(c);
|
||||
} break;
|
||||
case InputEvent::JOYSTICK_MOTION: {
|
||||
set_joy_axis(p_event.device, p_event.joy_motion.axis, p_event.joy_motion.axis_value);
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
if (main_loop)
|
||||
main_loop->input_event(p_event);
|
||||
|
||||
}
|
||||
|
||||
void InputDefault::set_joy_axis(int p_device,int p_axis,float p_value) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
int c = _combine_device(p_axis,p_device);
|
||||
joy_axis[c]=p_value;
|
||||
}
|
||||
|
||||
void InputDefault::set_accelerometer(const Vector3& p_accel) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
accelerometer=p_accel;
|
||||
|
||||
}
|
||||
|
||||
void InputDefault::set_main_loop(MainLoop *p_main_loop) {
|
||||
main_loop=p_main_loop;
|
||||
|
||||
}
|
||||
|
||||
void InputDefault::set_mouse_pos(const Point2& p_posf) {
|
||||
|
||||
mouse_speed_track.update(p_posf-mouse_pos);
|
||||
mouse_pos=p_posf;
|
||||
}
|
||||
|
||||
Point2 InputDefault::get_mouse_pos() const {
|
||||
|
||||
return mouse_pos;
|
||||
}
|
||||
Point2 InputDefault::get_mouse_speed() const {
|
||||
|
||||
return mouse_speed_track.speed;
|
||||
}
|
||||
|
||||
int InputDefault::get_mouse_button_mask() const {
|
||||
|
||||
return OS::get_singleton()->get_mouse_button_state();
|
||||
}
|
||||
|
||||
void InputDefault::warp_mouse_pos(const Vector2& p_to) {
|
||||
|
||||
OS::get_singleton()->warp_mouse_pos(p_to);
|
||||
}
|
||||
|
||||
|
||||
void InputDefault::iteration(float p_step) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void InputDefault::action_press(const StringName& p_action) {
|
||||
|
||||
if (custom_action_press.has(p_action)) {
|
||||
|
||||
custom_action_press[p_action]++;
|
||||
} else {
|
||||
custom_action_press[p_action]=1;
|
||||
}
|
||||
}
|
||||
|
||||
void InputDefault::action_release(const StringName& p_action){
|
||||
|
||||
ERR_FAIL_COND(!custom_action_press.has(p_action));
|
||||
custom_action_press[p_action]--;
|
||||
if (custom_action_press[p_action]==0) {
|
||||
custom_action_press.erase(p_action);
|
||||
}
|
||||
}
|
||||
|
||||
void InputDefault::set_emulate_touch(bool p_emulate) {
|
||||
|
||||
emulate_touch=p_emulate;
|
||||
}
|
||||
|
||||
bool InputDefault::is_emulating_touchscreen() const {
|
||||
|
||||
return emulate_touch;
|
||||
}
|
||||
|
||||
InputDefault::InputDefault() {
|
||||
|
||||
mouse_button_mask=0;
|
||||
emulate_touch=false;
|
||||
main_loop=NULL;
|
||||
}
|
||||
|
|
|
@ -80,82 +80,13 @@ public:
|
|||
|
||||
virtual bool is_emulating_touchscreen() const=0;
|
||||
|
||||
virtual void set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_hotspot=Vector2())=0;
|
||||
virtual void set_mouse_in_window(bool p_in_window)=0;
|
||||
|
||||
Input();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Input::MouseMode);
|
||||
|
||||
class InputDefault : public Input {
|
||||
|
||||
OBJ_TYPE( InputDefault, Input );
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
int mouse_button_mask;
|
||||
Set<int> keys_pressed;
|
||||
Set<int> joy_buttons_pressed;
|
||||
Map<int,float> joy_axis;
|
||||
Map<StringName,int> custom_action_press;
|
||||
Map<int, String> joy_names;
|
||||
Vector3 accelerometer;
|
||||
Vector2 mouse_pos;
|
||||
MainLoop *main_loop;
|
||||
|
||||
bool emulate_touch;
|
||||
|
||||
struct SpeedTrack {
|
||||
|
||||
uint64_t last_tick;
|
||||
Vector2 speed;
|
||||
Vector2 accum;
|
||||
float accum_t;
|
||||
float min_ref_frame;
|
||||
float max_ref_frame;
|
||||
|
||||
void update(const Vector2& p_delta_p);
|
||||
void reset();
|
||||
SpeedTrack();
|
||||
};
|
||||
|
||||
SpeedTrack mouse_speed_track;
|
||||
|
||||
public:
|
||||
|
||||
virtual bool is_key_pressed(int p_scancode);
|
||||
virtual bool is_mouse_button_pressed(int p_button);
|
||||
virtual bool is_joy_button_pressed(int p_device, int p_button);
|
||||
virtual bool is_action_pressed(const StringName& p_action);
|
||||
|
||||
virtual float get_joy_axis(int p_device,int p_axis);
|
||||
String get_joy_name(int p_idx);
|
||||
void joy_connection_changed(int p_idx, bool p_connected, String p_name);
|
||||
|
||||
virtual Vector3 get_accelerometer();
|
||||
|
||||
virtual Point2 get_mouse_pos() const;
|
||||
virtual Point2 get_mouse_speed() const;
|
||||
virtual int get_mouse_button_mask() const;
|
||||
|
||||
virtual void warp_mouse_pos(const Vector2& p_to);
|
||||
|
||||
|
||||
void parse_input_event(const InputEvent& p_event);
|
||||
void set_accelerometer(const Vector3& p_accel);
|
||||
void set_joy_axis(int p_device,int p_axis,float p_value);
|
||||
|
||||
void set_main_loop(MainLoop *main_loop);
|
||||
void set_mouse_pos(const Point2& p_posf);
|
||||
|
||||
void action_press(const StringName& p_action);
|
||||
void action_release(const StringName& p_action);
|
||||
|
||||
void iteration(float p_step);
|
||||
|
||||
void set_emulate_touch(bool p_emulate);
|
||||
virtual bool is_emulating_touchscreen() const;
|
||||
|
||||
InputDefault();
|
||||
|
||||
};
|
||||
|
||||
#endif // INPUT_H
|
||||
|
|
|
@ -45,7 +45,8 @@ void MainLoop::_bind_methods() {
|
|||
BIND_VMETHOD( MethodInfo("_idle",PropertyInfo(Variant::REAL,"delta")) );
|
||||
BIND_VMETHOD( MethodInfo("_finalize") );
|
||||
|
||||
|
||||
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
|
||||
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
|
||||
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
|
||||
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
|
||||
BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
|
||||
|
|
|
@ -47,6 +47,8 @@ protected:
|
|||
public:
|
||||
|
||||
enum {
|
||||
NOTIFICATION_WM_MOUSE_ENTER = 3,
|
||||
NOTIFICATION_WM_MOUSE_EXIT = 4,
|
||||
NOTIFICATION_WM_FOCUS_IN = 5,
|
||||
NOTIFICATION_WM_FOCUS_OUT = 6,
|
||||
NOTIFICATION_WM_QUIT_REQUEST = 7,
|
||||
|
|
|
@ -3119,8 +3119,8 @@ String String::xml_escape(bool p_escape_quotes) const {
|
|||
|
||||
String str=*this;
|
||||
str=str.replace("&","&");
|
||||
str=str.replace("<",">");
|
||||
str=str.replace(">","<");
|
||||
str=str.replace("<","<");
|
||||
str=str.replace(">",">");
|
||||
if (p_escape_quotes) {
|
||||
str=str.replace("'","'");
|
||||
str=str.replace("\"",""");
|
||||
|
@ -3172,12 +3172,12 @@ static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src,int p_src_len,Char
|
|||
} else if (p_src_len>=4 && p_src[1]=='g' && p_src[2]=='t' && p_src[3]==';') {
|
||||
|
||||
if (p_dst)
|
||||
*p_dst='<';
|
||||
*p_dst='>';
|
||||
eat=4;
|
||||
} else if (p_src_len>=4 && p_src[1]=='l' && p_src[2]=='t' && p_src[3]==';') {
|
||||
|
||||
if (p_dst)
|
||||
*p_dst='>';
|
||||
*p_dst='<';
|
||||
eat=4;
|
||||
} else if (p_src_len>=5 && p_src[1]=='a' && p_src[2]=='m' && p_src[3]=='p' && p_src[4]==';') {
|
||||
|
||||
|
|
6328
doc/base/classes.xml
6328
doc/base/classes.xml
File diff suppressed because it is too large
Load Diff
|
@ -31,10 +31,12 @@ SConscript("rtaudio/SCsub");
|
|||
SConscript("nedmalloc/SCsub");
|
||||
SConscript("nrex/SCsub");
|
||||
SConscript("chibi/SCsub");
|
||||
if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"):
|
||||
if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes" or env["opus"]=="yes"):
|
||||
SConscript("ogg/SCsub");
|
||||
if (env["vorbis"]=="yes"):
|
||||
SConscript("vorbis/SCsub");
|
||||
if (env["opus"]=="yes"):
|
||||
SConscript('opus/SCsub');
|
||||
if (env["tools"]=="yes"):
|
||||
SConscript("convex_decomp/SCsub");
|
||||
|
||||
|
|
|
@ -4160,7 +4160,6 @@ void RasterizerGLES2::begin_frame() {
|
|||
time_delta=time-last_time;
|
||||
last_time=time;
|
||||
frame++;
|
||||
clear_viewport(Color(1,0,0.5));
|
||||
|
||||
_rinfo.vertex_count=0;
|
||||
_rinfo.object_count=0;
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
Import('env')
|
||||
|
||||
opus_sources = [
|
||||
"opus/audio_stream_opus.cpp",
|
||||
]
|
||||
|
||||
opus_sources_silk=[]
|
||||
|
||||
opus_sources_lib = [
|
||||
"opus/celt/bands.c",
|
||||
"opus/celt/celt_lpc.c",
|
||||
"opus/celt/entenc.c",
|
||||
"opus/celt/mdct.c",
|
||||
"opus/celt/quant_bands.c",
|
||||
"opus/celt/celt.c",
|
||||
"opus/celt/cwrs.c",
|
||||
"opus/celt/kiss_fft.c",
|
||||
"opus/celt/modes.c",
|
||||
"opus/celt/rate.c",
|
||||
"opus/celt/celt_decoder.c",
|
||||
"opus/celt/entcode.c",
|
||||
"opus/celt/laplace.c",
|
||||
#opus/celt/opus_custom_demo.c",
|
||||
"opus/celt/vq.c",
|
||||
"opus/celt/celt_encoder.c",
|
||||
"opus/celt/entdec.c",
|
||||
"opus/celt/mathops.c",
|
||||
"opus/celt/pitch.c",
|
||||
"opus/silk/A2NLSF.c",
|
||||
"opus/silk/decoder_set_fs.c",
|
||||
"opus/silk/NLSF_stabilize.c",
|
||||
"opus/silk/sigm_Q15.c",
|
||||
"opus/silk/ana_filt_bank_1.c",
|
||||
"opus/silk/enc_API.c",
|
||||
"opus/silk/NLSF_unpack.c",
|
||||
"opus/silk/sort.c",
|
||||
"opus/silk/biquad_alt.c",
|
||||
"opus/silk/encode_indices.c",
|
||||
"opus/silk/NLSF_VQ.c",
|
||||
"opus/silk/stereo_decode_pred.c",
|
||||
"opus/silk/bwexpander_32.c",
|
||||
"opus/silk/encode_pulses.c",
|
||||
"opus/silk/NLSF_VQ_weights_laroia.c",
|
||||
"opus/silk/stereo_encode_pred.c",
|
||||
"opus/silk/bwexpander.c",
|
||||
"opus/silk/gain_quant.c",
|
||||
"opus/silk/NSQ.c",
|
||||
"opus/silk/stereo_find_predictor.c",
|
||||
"opus/silk/check_control_input.c",
|
||||
"opus/silk/HP_variable_cutoff.c",
|
||||
"opus/silk/NSQ_del_dec.c",
|
||||
"opus/silk/stereo_LR_to_MS.c",
|
||||
"opus/silk/CNG.c",
|
||||
"opus/silk/init_decoder.c",
|
||||
"opus/silk/pitch_est_tables.c",
|
||||
"opus/silk/stereo_MS_to_LR.c",
|
||||
"opus/silk/code_signs.c",
|
||||
"opus/silk/init_encoder.c",
|
||||
"opus/silk/PLC.c",
|
||||
"opus/silk/stereo_quant_pred.c",
|
||||
"opus/silk/control_audio_bandwidth.c",
|
||||
"opus/silk/inner_prod_aligned.c",
|
||||
"opus/silk/process_NLSFs.c",
|
||||
"opus/silk/sum_sqr_shift.c",
|
||||
"opus/silk/control_codec.c",
|
||||
"opus/silk/interpolate.c",
|
||||
"opus/silk/quant_LTP_gains.c",
|
||||
"opus/silk/table_LSF_cos.c",
|
||||
"opus/silk/control_SNR.c",
|
||||
"opus/silk/lin2log.c",
|
||||
"opus/silk/resampler.c",
|
||||
"opus/silk/tables_gain.c",
|
||||
"opus/silk/debug.c",
|
||||
"opus/silk/log2lin.c",
|
||||
"opus/silk/resampler_down2_3.c",
|
||||
"opus/silk/tables_LTP.c",
|
||||
"opus/silk/dec_API.c",
|
||||
"opus/silk/LPC_analysis_filter.c",
|
||||
"opus/silk/resampler_down2.c",
|
||||
"opus/silk/tables_NLSF_CB_NB_MB.c",
|
||||
"opus/silk/decode_core.c",
|
||||
"opus/silk/LPC_inv_pred_gain.c",
|
||||
"opus/silk/resampler_private_AR2.c",
|
||||
"opus/silk/tables_NLSF_CB_WB.c",
|
||||
"opus/silk/decode_frame.c",
|
||||
"opus/silk/LP_variable_cutoff.c",
|
||||
"opus/silk/resampler_private_down_FIR.c",
|
||||
"opus/silk/tables_other.c",
|
||||
"opus/silk/decode_indices.c",
|
||||
"opus/silk/NLSF2A.c",
|
||||
"opus/silk/resampler_private_IIR_FIR.c",
|
||||
"opus/silk/tables_pitch_lag.c",
|
||||
"opus/silk/decode_parameters.c",
|
||||
"opus/silk/NLSF_decode.c",
|
||||
"opus/silk/resampler_private_up2_HQ.c",
|
||||
"opus/silk/tables_pulses_per_block.c",
|
||||
"opus/silk/decode_pitch.c",
|
||||
"opus/silk/NLSF_del_dec_quant.c",
|
||||
"opus/silk/resampler_rom.c",
|
||||
"opus/silk/VAD.c",
|
||||
"opus/silk/decode_pulses.c",
|
||||
"opus/silk/NLSF_encode.c",
|
||||
"opus/silk/shell_coder.c",
|
||||
"opus/silk/VQ_WMat_EC.c",
|
||||
"opus/analysis.c",
|
||||
"opus/internal.c",
|
||||
"opus/opus.c",
|
||||
#"opus/opus_demo.c",
|
||||
"opus/opus_multistream.c",
|
||||
"opus/repacketizer.c",
|
||||
"opus/wincerts.c",
|
||||
"opus/http.c",
|
||||
"opus/mlp.c",
|
||||
#"opus/opus_compare.c",
|
||||
"opus/opus_encoder.c",
|
||||
"opus/opus_multistream_decoder.c",
|
||||
#"opus/repacketizer_demo.c",
|
||||
"opus/info.c",
|
||||
"opus/mlp_data.c",
|
||||
"opus/opus_decoder.c",
|
||||
"opus/opusfile.c",
|
||||
"opus/opus_multistream_encoder.c",
|
||||
"opus/stream.c"
|
||||
]
|
||||
|
||||
if("opus_fixed_point" in env and env.opus_fixed_point=="yes"):
|
||||
env.Append(CPPPATH=["#drivers/opus/silk/fixed"], CFLAGS=["-DOPUS_FIXED_POINT"])
|
||||
opus_sources_silk = [
|
||||
"opus/silk/fixed/apply_sine_window_FIX.c",
|
||||
"opus/silk/fixed/k2a_FIX.c",
|
||||
"opus/silk/fixed/residual_energy16_FIX.c",
|
||||
"opus/silk/fixed/autocorr_FIX.c",
|
||||
"opus/silk/fixed/k2a_Q16_FIX.c",
|
||||
"opus/silk/fixed/residual_energy_FIX.c",
|
||||
"opus/silk/fixed/burg_modified_FIX.c",
|
||||
"opus/silk/fixed/LTP_analysis_filter_FIX.c",
|
||||
"opus/silk/fixed/schur64_FIX.c",
|
||||
"opus/silk/fixed/corrMatrix_FIX.c",
|
||||
"opus/silk/fixed/LTP_scale_ctrl_FIX.c",
|
||||
"opus/silk/fixed/schur_FIX.c",
|
||||
"opus/silk/fixed/encode_frame_FIX.c",
|
||||
"opus/silk/fixed/noise_shape_analysis_FIX.c",
|
||||
"opus/silk/fixed/solve_LS_FIX.c",
|
||||
"opus/silk/fixed/find_LPC_FIX.c",
|
||||
"opus/silk/fixed/pitch_analysis_core_FIX.c",
|
||||
"opus/silk/fixed/vector_ops_FIX.c",
|
||||
"opus/silk/fixed/find_LTP_FIX.c",
|
||||
"opus/silk/fixed/prefilter_FIX.c",
|
||||
"opus/silk/fixed/warped_autocorrelation_FIX.c",
|
||||
"opus/silk/fixed/find_pitch_lags_FIX.c",
|
||||
"opus/silk/fixed/process_gains_FIX.c",
|
||||
"opus/silk/fixed/find_pred_coefs_FIX.c",
|
||||
"opus/silk/fixed/regularize_correlations_FIX.c"
|
||||
]
|
||||
else:
|
||||
env.Append(CPPPATH=["#drivers/opus/silk/float"])
|
||||
opus_sources_silk = [
|
||||
"opus/silk/float/apply_sine_window_FLP.c",
|
||||
"opus/silk/float/inner_product_FLP.c",
|
||||
"opus/silk/float/regularize_correlations_FLP.c",
|
||||
"opus/silk/float/autocorrelation_FLP.c",
|
||||
"opus/silk/float/k2a_FLP.c",
|
||||
"opus/silk/float/residual_energy_FLP.c",
|
||||
"opus/silk/float/burg_modified_FLP.c",
|
||||
"opus/silk/float/levinsondurbin_FLP.c",
|
||||
"opus/silk/float/scale_copy_vector_FLP.c",
|
||||
"opus/silk/float/bwexpander_FLP.c",
|
||||
"opus/silk/float/LPC_analysis_filter_FLP.c",
|
||||
"opus/silk/float/scale_vector_FLP.c",
|
||||
"opus/silk/float/corrMatrix_FLP.c",
|
||||
"opus/silk/float/LPC_inv_pred_gain_FLP.c",
|
||||
"opus/silk/float/schur_FLP.c",
|
||||
"opus/silk/float/encode_frame_FLP.c",
|
||||
"opus/silk/float/LTP_analysis_filter_FLP.c",
|
||||
"opus/silk/float/solve_LS_FLP.c",
|
||||
"opus/silk/float/energy_FLP.c",
|
||||
"opus/silk/float/LTP_scale_ctrl_FLP.c",
|
||||
"opus/silk/float/sort_FLP.c",
|
||||
"opus/silk/float/find_LPC_FLP.c",
|
||||
"opus/silk/float/noise_shape_analysis_FLP.c",
|
||||
"opus/silk/float/warped_autocorrelation_FLP.c",
|
||||
"opus/silk/float/find_LTP_FLP.c",
|
||||
"opus/silk/float/pitch_analysis_core_FLP.c",
|
||||
"opus/silk/float/wrappers_FLP.c",
|
||||
"opus/silk/float/find_pitch_lags_FLP.c",
|
||||
"opus/silk/float/prefilter_FLP.c",
|
||||
"opus/silk/float/find_pred_coefs_FLP.c",
|
||||
"opus/silk/float/process_gains_FLP.c"
|
||||
]
|
||||
|
||||
|
||||
opus_sources_lib+=opus_sources_silk
|
||||
env.drivers_sources+=opus_sources_lib
|
||||
env.drivers_sources+=opus_sources
|
||||
|
||||
env.Append(CPPPATH=["#drivers/opus"])
|
||||
env.Append(CPPPATH=["#drivers/opus/celt","#drivers/opus/silk","#drivers/opus/silk/float"])
|
||||
env.Append(CFLAGS=["-DOPUS_HAVE_CONFIG_H"])
|
||||
|
||||
Export('env')
|
|
@ -0,0 +1,645 @@
|
|||
/* Copyright (c) 2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "kiss_fft.h"
|
||||
#include "celt.h"
|
||||
#include "opus_modes.h"
|
||||
#include "arch.h"
|
||||
#include "quant_bands.h"
|
||||
#include <stdio.h>
|
||||
#include "analysis.h"
|
||||
#include "mlp.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
extern const MLP net;
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
static const float dct_table[128] = {
|
||||
0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
|
||||
0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
|
||||
0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
|
||||
-0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
|
||||
0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
|
||||
-0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
|
||||
0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
|
||||
0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
|
||||
0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
|
||||
0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
|
||||
0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
|
||||
-0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
|
||||
0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
|
||||
-0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
|
||||
0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
|
||||
0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
|
||||
};
|
||||
|
||||
static const float analysis_window[240] = {
|
||||
0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
|
||||
0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
|
||||
0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
|
||||
0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
|
||||
0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
|
||||
0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
|
||||
0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
|
||||
0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
|
||||
0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
|
||||
0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
|
||||
0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
|
||||
0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
|
||||
0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
|
||||
0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
|
||||
0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
|
||||
0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
|
||||
0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
|
||||
0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
|
||||
0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
|
||||
0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
|
||||
0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
|
||||
0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
|
||||
0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
|
||||
0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
|
||||
0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
|
||||
0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
|
||||
0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
|
||||
0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
|
||||
0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
|
||||
0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
|
||||
};
|
||||
|
||||
static const int tbands[NB_TBANDS+1] = {
|
||||
2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
|
||||
};
|
||||
|
||||
static const int extra_bands[NB_TOT_BANDS+1] = {
|
||||
1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
|
||||
};
|
||||
|
||||
/*static const float tweight[NB_TBANDS+1] = {
|
||||
.3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
|
||||
};*/
|
||||
|
||||
#define NB_TONAL_SKIP_BANDS 9
|
||||
|
||||
#define cA 0.43157974f
|
||||
#define cB 0.67848403f
|
||||
#define cC 0.08595542f
|
||||
#define cE ((float)M_PI/2)
|
||||
static OPUS_INLINE float fast_atan2f(float y, float x) {
|
||||
float x2, y2;
|
||||
/* Should avoid underflow on the values we'll get */
|
||||
if (ABS16(x)+ABS16(y)<1e-9f)
|
||||
{
|
||||
x*=1e12f;
|
||||
y*=1e12f;
|
||||
}
|
||||
x2 = x*x;
|
||||
y2 = y*y;
|
||||
if(x2<y2){
|
||||
float den = (y2 + cB*x2) * (y2 + cC*x2);
|
||||
if (den!=0)
|
||||
return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE);
|
||||
else
|
||||
return (y<0 ? -cE : cE);
|
||||
}else{
|
||||
float den = (x2 + cB*y2) * (x2 + cC*y2);
|
||||
if (den!=0)
|
||||
return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
|
||||
else
|
||||
return (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
|
||||
}
|
||||
}
|
||||
|
||||
void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len)
|
||||
{
|
||||
int pos;
|
||||
int curr_lookahead;
|
||||
float psum;
|
||||
int i;
|
||||
|
||||
pos = tonal->read_pos;
|
||||
curr_lookahead = tonal->write_pos-tonal->read_pos;
|
||||
if (curr_lookahead<0)
|
||||
curr_lookahead += DETECT_SIZE;
|
||||
|
||||
if (len > 480 && pos != tonal->write_pos)
|
||||
{
|
||||
pos++;
|
||||
if (pos==DETECT_SIZE)
|
||||
pos=0;
|
||||
}
|
||||
if (pos == tonal->write_pos)
|
||||
pos--;
|
||||
if (pos<0)
|
||||
pos = DETECT_SIZE-1;
|
||||
OPUS_COPY(info_out, &tonal->info[pos], 1);
|
||||
tonal->read_subframe += len/120;
|
||||
while (tonal->read_subframe>=4)
|
||||
{
|
||||
tonal->read_subframe -= 4;
|
||||
tonal->read_pos++;
|
||||
}
|
||||
if (tonal->read_pos>=DETECT_SIZE)
|
||||
tonal->read_pos-=DETECT_SIZE;
|
||||
|
||||
/* Compensate for the delay in the features themselves.
|
||||
FIXME: Need a better estimate the 10 I just made up */
|
||||
curr_lookahead = IMAX(curr_lookahead-10, 0);
|
||||
|
||||
psum=0;
|
||||
/* Summing the probability of transition patterns that involve music at
|
||||
time (DETECT_SIZE-curr_lookahead-1) */
|
||||
for (i=0;i<DETECT_SIZE-curr_lookahead;i++)
|
||||
psum += tonal->pmusic[i];
|
||||
for (;i<DETECT_SIZE;i++)
|
||||
psum += tonal->pspeech[i];
|
||||
psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence;
|
||||
/*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/
|
||||
|
||||
info_out->music_prob = psum;
|
||||
}
|
||||
|
||||
void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix)
|
||||
{
|
||||
int i, b;
|
||||
const kiss_fft_state *kfft;
|
||||
VARDECL(kiss_fft_cpx, in);
|
||||
VARDECL(kiss_fft_cpx, out);
|
||||
int N = 480, N2=240;
|
||||
float * OPUS_RESTRICT A = tonal->angle;
|
||||
float * OPUS_RESTRICT dA = tonal->d_angle;
|
||||
float * OPUS_RESTRICT d2A = tonal->d2_angle;
|
||||
VARDECL(float, tonality);
|
||||
VARDECL(float, noisiness);
|
||||
float band_tonality[NB_TBANDS];
|
||||
float logE[NB_TBANDS];
|
||||
float BFCC[8];
|
||||
float features[25];
|
||||
float frame_tonality;
|
||||
float max_frame_tonality;
|
||||
/*float tw_sum=0;*/
|
||||
float frame_noisiness;
|
||||
const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI);
|
||||
float slope=0;
|
||||
float frame_stationarity;
|
||||
float relativeE;
|
||||
float frame_probs[2];
|
||||
float alpha, alphaE, alphaE2;
|
||||
float frame_loudness;
|
||||
float bandwidth_mask;
|
||||
int bandwidth=0;
|
||||
float maxE = 0;
|
||||
float noise_floor;
|
||||
int remaining;
|
||||
AnalysisInfo *info;
|
||||
SAVE_STACK;
|
||||
|
||||
tonal->last_transition++;
|
||||
alpha = 1.f/IMIN(20, 1+tonal->count);
|
||||
alphaE = 1.f/IMIN(50, 1+tonal->count);
|
||||
alphaE2 = 1.f/IMIN(1000, 1+tonal->count);
|
||||
|
||||
if (tonal->count<4)
|
||||
tonal->music_prob = .5;
|
||||
kfft = celt_mode->mdct.kfft[0];
|
||||
if (tonal->count==0)
|
||||
tonal->mem_fill = 240;
|
||||
downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C);
|
||||
if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
|
||||
{
|
||||
tonal->mem_fill += len;
|
||||
/* Don't have enough to update the analysis */
|
||||
RESTORE_STACK;
|
||||
return;
|
||||
}
|
||||
info = &tonal->info[tonal->write_pos++];
|
||||
if (tonal->write_pos>=DETECT_SIZE)
|
||||
tonal->write_pos-=DETECT_SIZE;
|
||||
|
||||
ALLOC(in, 480, kiss_fft_cpx);
|
||||
ALLOC(out, 480, kiss_fft_cpx);
|
||||
ALLOC(tonality, 240, float);
|
||||
ALLOC(noisiness, 240, float);
|
||||
for (i=0;i<N2;i++)
|
||||
{
|
||||
float w = analysis_window[i];
|
||||
in[i].r = (kiss_fft_scalar)(w*tonal->inmem[i]);
|
||||
in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]);
|
||||
in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]);
|
||||
in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]);
|
||||
}
|
||||
OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
|
||||
remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
|
||||
downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C);
|
||||
tonal->mem_fill = 240 + remaining;
|
||||
opus_fft(kfft, in, out);
|
||||
|
||||
for (i=1;i<N2;i++)
|
||||
{
|
||||
float X1r, X2r, X1i, X2i;
|
||||
float angle, d_angle, d2_angle;
|
||||
float angle2, d_angle2, d2_angle2;
|
||||
float mod1, mod2, avg_mod;
|
||||
X1r = (float)out[i].r+out[N-i].r;
|
||||
X1i = (float)out[i].i-out[N-i].i;
|
||||
X2r = (float)out[i].i+out[N-i].i;
|
||||
X2i = (float)out[N-i].r-out[i].r;
|
||||
|
||||
angle = (float)(.5f/M_PI)*fast_atan2f(X1i, X1r);
|
||||
d_angle = angle - A[i];
|
||||
d2_angle = d_angle - dA[i];
|
||||
|
||||
angle2 = (float)(.5f/M_PI)*fast_atan2f(X2i, X2r);
|
||||
d_angle2 = angle2 - angle;
|
||||
d2_angle2 = d_angle2 - d_angle;
|
||||
|
||||
mod1 = d2_angle - (float)floor(.5+d2_angle);
|
||||
noisiness[i] = ABS16(mod1);
|
||||
mod1 *= mod1;
|
||||
mod1 *= mod1;
|
||||
|
||||
mod2 = d2_angle2 - (float)floor(.5+d2_angle2);
|
||||
noisiness[i] += ABS16(mod2);
|
||||
mod2 *= mod2;
|
||||
mod2 *= mod2;
|
||||
|
||||
avg_mod = .25f*(d2A[i]+2.f*mod1+mod2);
|
||||
tonality[i] = 1.f/(1.f+40.f*16.f*pi4*avg_mod)-.015f;
|
||||
|
||||
A[i] = angle2;
|
||||
dA[i] = d_angle2;
|
||||
d2A[i] = mod2;
|
||||
}
|
||||
|
||||
frame_tonality = 0;
|
||||
max_frame_tonality = 0;
|
||||
/*tw_sum = 0;*/
|
||||
info->activity = 0;
|
||||
frame_noisiness = 0;
|
||||
frame_stationarity = 0;
|
||||
if (!tonal->count)
|
||||
{
|
||||
for (b=0;b<NB_TBANDS;b++)
|
||||
{
|
||||
tonal->lowE[b] = 1e10;
|
||||
tonal->highE[b] = -1e10;
|
||||
}
|
||||
}
|
||||
relativeE = 0;
|
||||
frame_loudness = 0;
|
||||
for (b=0;b<NB_TBANDS;b++)
|
||||
{
|
||||
float E=0, tE=0, nE=0;
|
||||
float L1, L2;
|
||||
float stationarity;
|
||||
for (i=tbands[b];i<tbands[b+1];i++)
|
||||
{
|
||||
float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
|
||||
+ out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
/* FIXME: It's probably best to change the BFCC filter initial state instead */
|
||||
binE *= 5.55e-17f;
|
||||
#endif
|
||||
E += binE;
|
||||
tE += binE*tonality[i];
|
||||
nE += binE*2.f*(.5f-noisiness[i]);
|
||||
}
|
||||
tonal->E[tonal->E_count][b] = E;
|
||||
frame_noisiness += nE/(1e-15f+E);
|
||||
|
||||
frame_loudness += (float)sqrt(E+1e-10f);
|
||||
logE[b] = (float)log(E+1e-10f);
|
||||
tonal->lowE[b] = MIN32(logE[b], tonal->lowE[b]+.01f);
|
||||
tonal->highE[b] = MAX32(logE[b], tonal->highE[b]-.1f);
|
||||
if (tonal->highE[b] < tonal->lowE[b]+1.f)
|
||||
{
|
||||
tonal->highE[b]+=.5f;
|
||||
tonal->lowE[b]-=.5f;
|
||||
}
|
||||
relativeE += (logE[b]-tonal->lowE[b])/(1e-15f+tonal->highE[b]-tonal->lowE[b]);
|
||||
|
||||
L1=L2=0;
|
||||
for (i=0;i<NB_FRAMES;i++)
|
||||
{
|
||||
L1 += (float)sqrt(tonal->E[i][b]);
|
||||
L2 += tonal->E[i][b];
|
||||
}
|
||||
|
||||
stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2));
|
||||
stationarity *= stationarity;
|
||||
stationarity *= stationarity;
|
||||
frame_stationarity += stationarity;
|
||||
/*band_tonality[b] = tE/(1e-15+E)*/;
|
||||
band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]);
|
||||
#if 0
|
||||
if (b>=NB_TONAL_SKIP_BANDS)
|
||||
{
|
||||
frame_tonality += tweight[b]*band_tonality[b];
|
||||
tw_sum += tweight[b];
|
||||
}
|
||||
#else
|
||||
frame_tonality += band_tonality[b];
|
||||
if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS)
|
||||
frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS];
|
||||
#endif
|
||||
max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality);
|
||||
slope += band_tonality[b]*(b-8);
|
||||
/*printf("%f %f ", band_tonality[b], stationarity);*/
|
||||
tonal->prev_band_tonality[b] = band_tonality[b];
|
||||
}
|
||||
|
||||
bandwidth_mask = 0;
|
||||
bandwidth = 0;
|
||||
maxE = 0;
|
||||
noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8)));
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
noise_floor *= 1<<(15+SIG_SHIFT);
|
||||
#endif
|
||||
noise_floor *= noise_floor;
|
||||
for (b=0;b<NB_TOT_BANDS;b++)
|
||||
{
|
||||
float E=0;
|
||||
int band_start, band_end;
|
||||
/* Keep a margin of 300 Hz for aliasing */
|
||||
band_start = extra_bands[b];
|
||||
band_end = extra_bands[b+1];
|
||||
for (i=band_start;i<band_end;i++)
|
||||
{
|
||||
float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
|
||||
+ out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
|
||||
E += binE;
|
||||
}
|
||||
maxE = MAX32(maxE, E);
|
||||
tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
|
||||
E = MAX32(E, tonal->meanE[b]);
|
||||
/* Use a simple follower with 13 dB/Bark slope for spreading function */
|
||||
bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
|
||||
/* Consider the band "active" only if all these conditions are met:
|
||||
1) less than 10 dB below the simple follower
|
||||
2) less than 90 dB below the peak band (maximal masking possible considering
|
||||
both the ATH and the loudness-dependent slope of the spreading function)
|
||||
3) above the PCM quantization noise floor
|
||||
*/
|
||||
if (E>.1*bandwidth_mask && E*1e9f > maxE && E > noise_floor*(band_end-band_start))
|
||||
bandwidth = b;
|
||||
}
|
||||
if (tonal->count<=2)
|
||||
bandwidth = 20;
|
||||
frame_loudness = 20*(float)log10(frame_loudness);
|
||||
tonal->Etracker = MAX32(tonal->Etracker-.03f, frame_loudness);
|
||||
tonal->lowECount *= (1-alphaE);
|
||||
if (frame_loudness < tonal->Etracker-30)
|
||||
tonal->lowECount += alphaE;
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
float sum=0;
|
||||
for (b=0;b<16;b++)
|
||||
sum += dct_table[i*16+b]*logE[b];
|
||||
BFCC[i] = sum;
|
||||
}
|
||||
|
||||
frame_stationarity /= NB_TBANDS;
|
||||
relativeE /= NB_TBANDS;
|
||||
if (tonal->count<10)
|
||||
relativeE = .5;
|
||||
frame_noisiness /= NB_TBANDS;
|
||||
#if 1
|
||||
info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
|
||||
#else
|
||||
info->activity = .5*(1+frame_noisiness-frame_stationarity);
|
||||
#endif
|
||||
frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS));
|
||||
frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f);
|
||||
tonal->prev_tonality = frame_tonality;
|
||||
|
||||
slope /= 8*8;
|
||||
info->tonality_slope = slope;
|
||||
|
||||
tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
|
||||
tonal->count++;
|
||||
info->tonality = frame_tonality;
|
||||
|
||||
for (i=0;i<4;i++)
|
||||
features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i];
|
||||
|
||||
for (i=0;i<4;i++)
|
||||
tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i];
|
||||
|
||||
for (i=0;i<4;i++)
|
||||
features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]);
|
||||
for (i=0;i<3;i++)
|
||||
features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8];
|
||||
|
||||
if (tonal->count > 5)
|
||||
{
|
||||
for (i=0;i<9;i++)
|
||||
tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i];
|
||||
}
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
tonal->mem[i+24] = tonal->mem[i+16];
|
||||
tonal->mem[i+16] = tonal->mem[i+8];
|
||||
tonal->mem[i+8] = tonal->mem[i];
|
||||
tonal->mem[i] = BFCC[i];
|
||||
}
|
||||
for (i=0;i<9;i++)
|
||||
features[11+i] = (float)sqrt(tonal->std[i]);
|
||||
features[20] = info->tonality;
|
||||
features[21] = info->activity;
|
||||
features[22] = frame_stationarity;
|
||||
features[23] = info->tonality_slope;
|
||||
features[24] = tonal->lowECount;
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
mlp_process(&net, features, frame_probs);
|
||||
frame_probs[0] = .5f*(frame_probs[0]+1);
|
||||
/* Curve fitting between the MLP probability and the actual probability */
|
||||
frame_probs[0] = .01f + 1.21f*frame_probs[0]*frame_probs[0] - .23f*(float)pow(frame_probs[0], 10);
|
||||
/* Probability of active audio (as opposed to silence) */
|
||||
frame_probs[1] = .5f*frame_probs[1]+.5f;
|
||||
/* Consider that silence has a 50-50 probability. */
|
||||
frame_probs[0] = frame_probs[1]*frame_probs[0] + (1-frame_probs[1])*.5f;
|
||||
|
||||
/*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
|
||||
{
|
||||
/* Probability of state transition */
|
||||
float tau;
|
||||
/* Represents independence of the MLP probabilities, where
|
||||
beta=1 means fully independent. */
|
||||
float beta;
|
||||
/* Denormalized probability of speech (p0) and music (p1) after update */
|
||||
float p0, p1;
|
||||
/* Probabilities for "all speech" and "all music" */
|
||||
float s0, m0;
|
||||
/* Probability sum for renormalisation */
|
||||
float psum;
|
||||
/* Instantaneous probability of speech and music, with beta pre-applied. */
|
||||
float speech0;
|
||||
float music0;
|
||||
|
||||
/* One transition every 3 minutes of active audio */
|
||||
tau = .00005f*frame_probs[1];
|
||||
beta = .05f;
|
||||
if (1) {
|
||||
/* Adapt beta based on how "unexpected" the new prob is */
|
||||
float p, q;
|
||||
p = MAX16(.05f,MIN16(.95f,frame_probs[0]));
|
||||
q = MAX16(.05f,MIN16(.95f,tonal->music_prob));
|
||||
beta = .01f+.05f*ABS16(p-q)/(p*(1-q)+q*(1-p));
|
||||
}
|
||||
/* p0 and p1 are the probabilities of speech and music at this frame
|
||||
using only information from previous frame and applying the
|
||||
state transition model */
|
||||
p0 = (1-tonal->music_prob)*(1-tau) + tonal->music_prob *tau;
|
||||
p1 = tonal->music_prob *(1-tau) + (1-tonal->music_prob)*tau;
|
||||
/* We apply the current probability with exponent beta to work around
|
||||
the fact that the probability estimates aren't independent. */
|
||||
p0 *= (float)pow(1-frame_probs[0], beta);
|
||||
p1 *= (float)pow(frame_probs[0], beta);
|
||||
/* Normalise the probabilities to get the Marokv probability of music. */
|
||||
tonal->music_prob = p1/(p0+p1);
|
||||
info->music_prob = tonal->music_prob;
|
||||
|
||||
/* This chunk of code deals with delayed decision. */
|
||||
psum=1e-20f;
|
||||
/* Instantaneous probability of speech and music, with beta pre-applied. */
|
||||
speech0 = (float)pow(1-frame_probs[0], beta);
|
||||
music0 = (float)pow(frame_probs[0], beta);
|
||||
if (tonal->count==1)
|
||||
{
|
||||
tonal->pspeech[0]=.5;
|
||||
tonal->pmusic [0]=.5;
|
||||
}
|
||||
/* Updated probability of having only speech (s0) or only music (m0),
|
||||
before considering the new observation. */
|
||||
s0 = tonal->pspeech[0] + tonal->pspeech[1];
|
||||
m0 = tonal->pmusic [0] + tonal->pmusic [1];
|
||||
/* Updates s0 and m0 with instantaneous probability. */
|
||||
tonal->pspeech[0] = s0*(1-tau)*speech0;
|
||||
tonal->pmusic [0] = m0*(1-tau)*music0;
|
||||
/* Propagate the transition probabilities */
|
||||
for (i=1;i<DETECT_SIZE-1;i++)
|
||||
{
|
||||
tonal->pspeech[i] = tonal->pspeech[i+1]*speech0;
|
||||
tonal->pmusic [i] = tonal->pmusic [i+1]*music0;
|
||||
}
|
||||
/* Probability that the latest frame is speech, when all the previous ones were music. */
|
||||
tonal->pspeech[DETECT_SIZE-1] = m0*tau*speech0;
|
||||
/* Probability that the latest frame is music, when all the previous ones were speech. */
|
||||
tonal->pmusic [DETECT_SIZE-1] = s0*tau*music0;
|
||||
|
||||
/* Renormalise probabilities to 1 */
|
||||
for (i=0;i<DETECT_SIZE;i++)
|
||||
psum += tonal->pspeech[i] + tonal->pmusic[i];
|
||||
psum = 1.f/psum;
|
||||
for (i=0;i<DETECT_SIZE;i++)
|
||||
{
|
||||
tonal->pspeech[i] *= psum;
|
||||
tonal->pmusic [i] *= psum;
|
||||
}
|
||||
psum = tonal->pmusic[0];
|
||||
for (i=1;i<DETECT_SIZE;i++)
|
||||
psum += tonal->pspeech[i];
|
||||
|
||||
/* Estimate our confidence in the speech/music decisions */
|
||||
if (frame_probs[1]>.75)
|
||||
{
|
||||
if (tonal->music_prob>.9)
|
||||
{
|
||||
float adapt;
|
||||
adapt = 1.f/(++tonal->music_confidence_count);
|
||||
tonal->music_confidence_count = IMIN(tonal->music_confidence_count, 500);
|
||||
tonal->music_confidence += adapt*MAX16(-.2f,frame_probs[0]-tonal->music_confidence);
|
||||
}
|
||||
if (tonal->music_prob<.1)
|
||||
{
|
||||
float adapt;
|
||||
adapt = 1.f/(++tonal->speech_confidence_count);
|
||||
tonal->speech_confidence_count = IMIN(tonal->speech_confidence_count, 500);
|
||||
tonal->speech_confidence += adapt*MIN16(.2f,frame_probs[0]-tonal->speech_confidence);
|
||||
}
|
||||
} else {
|
||||
if (tonal->music_confidence_count==0)
|
||||
tonal->music_confidence = .9f;
|
||||
if (tonal->speech_confidence_count==0)
|
||||
tonal->speech_confidence = .1f;
|
||||
}
|
||||
}
|
||||
if (tonal->last_music != (tonal->music_prob>.5f))
|
||||
tonal->last_transition=0;
|
||||
tonal->last_music = tonal->music_prob>.5f;
|
||||
#else
|
||||
info->music_prob = 0;
|
||||
#endif
|
||||
/*for (i=0;i<25;i++)
|
||||
printf("%f ", features[i]);
|
||||
printf("\n");*/
|
||||
|
||||
info->bandwidth = bandwidth;
|
||||
/*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
|
||||
info->noisiness = frame_noisiness;
|
||||
info->valid = 1;
|
||||
if (info_out!=NULL)
|
||||
OPUS_COPY(info_out, info, 1);
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
|
||||
int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
|
||||
int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
|
||||
{
|
||||
int offset;
|
||||
int pcm_len;
|
||||
|
||||
if (analysis_pcm != NULL)
|
||||
{
|
||||
/* Avoid overflow/wrap-around of the analysis buffer */
|
||||
analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/100, analysis_frame_size);
|
||||
|
||||
pcm_len = analysis_frame_size - analysis->analysis_offset;
|
||||
offset = analysis->analysis_offset;
|
||||
do {
|
||||
tonality_analysis(analysis, NULL, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
|
||||
offset += 480;
|
||||
pcm_len -= 480;
|
||||
} while (pcm_len>0);
|
||||
analysis->analysis_offset = analysis_frame_size;
|
||||
|
||||
analysis->analysis_offset -= frame_size;
|
||||
}
|
||||
|
||||
analysis_info->valid = 0;
|
||||
tonality_get_info(analysis, analysis_info, frame_size);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/* Copyright (c) 2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ANALYSIS_H
|
||||
#define ANALYSIS_H
|
||||
|
||||
#include "celt.h"
|
||||
#include "opus_private.h"
|
||||
|
||||
#define NB_FRAMES 8
|
||||
#define NB_TBANDS 18
|
||||
#define NB_TOT_BANDS 21
|
||||
#define ANALYSIS_BUF_SIZE 720 /* 15 ms at 48 kHz */
|
||||
|
||||
#define DETECT_SIZE 200
|
||||
|
||||
typedef struct {
|
||||
float angle[240];
|
||||
float d_angle[240];
|
||||
float d2_angle[240];
|
||||
opus_val32 inmem[ANALYSIS_BUF_SIZE];
|
||||
int mem_fill; /* number of usable samples in the buffer */
|
||||
float prev_band_tonality[NB_TBANDS];
|
||||
float prev_tonality;
|
||||
float E[NB_FRAMES][NB_TBANDS];
|
||||
float lowE[NB_TBANDS];
|
||||
float highE[NB_TBANDS];
|
||||
float meanE[NB_TOT_BANDS];
|
||||
float mem[32];
|
||||
float cmean[8];
|
||||
float std[9];
|
||||
float music_prob;
|
||||
float Etracker;
|
||||
float lowECount;
|
||||
int E_count;
|
||||
int last_music;
|
||||
int last_transition;
|
||||
int count;
|
||||
float subframe_mem[3];
|
||||
int analysis_offset;
|
||||
/** Probability of having speech for time i to DETECT_SIZE-1 (and music before).
|
||||
pspeech[0] is the probability that all frames in the window are speech. */
|
||||
float pspeech[DETECT_SIZE];
|
||||
/** Probability of having music for time i to DETECT_SIZE-1 (and speech before).
|
||||
pmusic[0] is the probability that all frames in the window are music. */
|
||||
float pmusic[DETECT_SIZE];
|
||||
float speech_confidence;
|
||||
float music_confidence;
|
||||
int speech_confidence_count;
|
||||
int music_confidence_count;
|
||||
int write_pos;
|
||||
int read_pos;
|
||||
int read_subframe;
|
||||
AnalysisInfo info[DETECT_SIZE];
|
||||
} TonalityAnalysisState;
|
||||
|
||||
void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info,
|
||||
const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix);
|
||||
|
||||
void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
|
||||
|
||||
void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
|
||||
int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
|
||||
int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,376 @@
|
|||
/*************************************************************************/
|
||||
/* audio_stream_opus.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Author: George Marques <george@gmarqu.es> */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "audio_stream_opus.h"
|
||||
|
||||
const float AudioStreamPlaybackOpus::osrate=48000.0f;
|
||||
|
||||
int AudioStreamPlaybackOpus::_op_read_func(void *_stream, unsigned char *_ptr, int _nbytes) {
|
||||
FileAccess *fa=(FileAccess*)_stream;
|
||||
|
||||
if(fa->eof_reached())
|
||||
return 0;
|
||||
|
||||
uint8_t *dst = (uint8_t*)_ptr;
|
||||
|
||||
int read = fa->get_buffer(dst, _nbytes);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, int _whence){
|
||||
|
||||
#ifdef SEEK_SET
|
||||
FileAccess *fa=(FileAccess*)_stream;
|
||||
|
||||
switch (_whence) {
|
||||
case SEEK_SET: {
|
||||
fa->seek(_offset);
|
||||
} break;
|
||||
case SEEK_CUR: {
|
||||
fa->seek(fa->get_pos()+_offset);
|
||||
} break;
|
||||
case SEEK_END: {
|
||||
fa->seek_end(_offset);
|
||||
} break;
|
||||
default: {
|
||||
ERR_PRINT("BUG, wtf was whence set to?\n");
|
||||
}
|
||||
}
|
||||
int ret=fa->eof_reached()?-1:0;
|
||||
return ret;
|
||||
#else
|
||||
return -1; // no seeking
|
||||
#endif
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::_op_close_func(void *_stream) {
|
||||
if (!_stream)
|
||||
return 0;
|
||||
FileAccess *fa=(FileAccess*)_stream;
|
||||
if (fa->is_open())
|
||||
fa->close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) {
|
||||
FileAccess *_fa = (FileAccess*)_stream;
|
||||
return (opus_int64)_fa->get_pos();
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::_clear_stream() {
|
||||
if(!stream_loaded)
|
||||
return;
|
||||
|
||||
op_free(opus_file);
|
||||
_close_file();
|
||||
|
||||
stream_loaded=false;
|
||||
stream_channels=1;
|
||||
playing=false;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::_close_file() {
|
||||
if (f) {
|
||||
memdelete(f);
|
||||
f=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Error AudioStreamPlaybackOpus::_load_stream() {
|
||||
|
||||
ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED);
|
||||
|
||||
_clear_stream();
|
||||
if (file=="")
|
||||
return ERR_INVALID_DATA;
|
||||
|
||||
Error err;
|
||||
f=FileAccess::open(file,FileAccess::READ,&err);
|
||||
|
||||
if (err) {
|
||||
ERR_FAIL_COND_V( err, err );
|
||||
}
|
||||
|
||||
int _err = 0;
|
||||
|
||||
opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);
|
||||
|
||||
switch (_err) {
|
||||
case OP_EREAD: { // - Can't read the file.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_FILE_CANT_READ );
|
||||
} break;
|
||||
case OP_EVERSION: // - Unrecognized version number.
|
||||
case OP_ENOTFORMAT: // - Stream is not Opus data.
|
||||
case OP_EIMPL : { // - Stream used non-implemented feature.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
|
||||
} break;
|
||||
case OP_EBADLINK: // - Failed to find old data after seeking.
|
||||
case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
|
||||
case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_FILE_CORRUPT );
|
||||
} break;
|
||||
case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_BUG );
|
||||
} break;
|
||||
}
|
||||
repeats=0;
|
||||
stream_loaded=true;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackOpus::AudioStreamPlaybackOpus() {
|
||||
loops=false;
|
||||
playing=false;
|
||||
f = NULL;
|
||||
stream_loaded=false;
|
||||
stream_valid=false;
|
||||
repeats=0;
|
||||
paused=true;
|
||||
stream_channels=0;
|
||||
current_section=0;
|
||||
length=0;
|
||||
loop_restart_time=0;
|
||||
pre_skip=0;
|
||||
|
||||
_op_callbacks.read = _op_read_func;
|
||||
_op_callbacks.seek = _op_seek_func;
|
||||
_op_callbacks.tell = _op_tell_func;
|
||||
_op_callbacks.close = _op_close_func;
|
||||
}
|
||||
|
||||
Error AudioStreamPlaybackOpus::set_file(const String &p_file) {
|
||||
file=p_file;
|
||||
stream_valid=false;
|
||||
Error err;
|
||||
f=FileAccess::open(file,FileAccess::READ,&err);
|
||||
|
||||
if (err) {
|
||||
ERR_FAIL_COND_V( err, err );
|
||||
}
|
||||
|
||||
int _err;
|
||||
|
||||
opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);
|
||||
|
||||
switch (_err) {
|
||||
case OP_EREAD: { // - Can't read the file.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_FILE_CANT_READ );
|
||||
} break;
|
||||
case OP_EVERSION: // - Unrecognized version number.
|
||||
case OP_ENOTFORMAT: // - Stream is not Opus data.
|
||||
case OP_EIMPL : { // - Stream used non-implemented feature.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
|
||||
} break;
|
||||
case OP_EBADLINK: // - Failed to find old data after seeking.
|
||||
case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
|
||||
case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_FILE_CORRUPT );
|
||||
} break;
|
||||
case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
|
||||
memdelete(f); f=NULL;
|
||||
ERR_FAIL_V( ERR_BUG );
|
||||
} break;
|
||||
}
|
||||
|
||||
const OpusHead *oinfo = op_head(opus_file,-1);
|
||||
|
||||
stream_channels=oinfo->channel_count;
|
||||
pre_skip=oinfo->pre_skip;
|
||||
frames_mixed=pre_skip;
|
||||
ogg_int64_t len = op_pcm_total(opus_file,-1);
|
||||
if(len < 0) {
|
||||
length = 0;
|
||||
} else {
|
||||
length=(len/osrate);
|
||||
}
|
||||
|
||||
op_free(opus_file);
|
||||
memdelete(f);
|
||||
f=NULL;
|
||||
stream_valid=true;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::play(float p_from) {
|
||||
if (playing)
|
||||
stop();
|
||||
|
||||
if (_load_stream()!=OK)
|
||||
return;
|
||||
|
||||
frames_mixed=pre_skip;
|
||||
playing=true;
|
||||
if (p_from>0) {
|
||||
seek_pos(p_from);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::stop() {
|
||||
_clear_stream();
|
||||
playing=false;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::seek_pos(float p_time) {
|
||||
if(!playing) return;
|
||||
ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate);
|
||||
bool ok = op_pcm_seek(opus_file,pcm_offset)==0;
|
||||
if(!ok) {
|
||||
ERR_PRINT("Seek time over stream size.");
|
||||
return;
|
||||
}
|
||||
frames_mixed=osrate*p_time;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::mix(int16_t* p_bufer,int p_frames) {
|
||||
if (!playing)
|
||||
return 0;
|
||||
|
||||
int total=p_frames;
|
||||
|
||||
while (true) {
|
||||
|
||||
int todo = p_frames;
|
||||
|
||||
if (todo==0 || todo<MIN_MIX) {
|
||||
break;
|
||||
}
|
||||
|
||||
int ret=op_read(opus_file,(opus_int16*)p_bufer,todo*stream_channels,¤t_section);
|
||||
if (ret<0) {
|
||||
playing = false;
|
||||
ERR_EXPLAIN("Error reading Opus File: "+file);
|
||||
ERR_BREAK(ret<0);
|
||||
} else if (ret==0) { // end of song, reload?
|
||||
op_free(opus_file);
|
||||
|
||||
_close_file();
|
||||
|
||||
f=FileAccess::open(file,FileAccess::READ);
|
||||
|
||||
int errv = 0;
|
||||
opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&errv);
|
||||
if (errv!=0) {
|
||||
playing=false;
|
||||
break; // :(
|
||||
}
|
||||
|
||||
if (!has_loop()) {
|
||||
playing=false;
|
||||
repeats=1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (loop_restart_time) {
|
||||
bool ok = op_pcm_seek(opus_file, (loop_restart_time*osrate)+pre_skip)==0;
|
||||
if (!ok) {
|
||||
playing=false;
|
||||
ERR_PRINT("loop restart time rejected")
|
||||
}
|
||||
|
||||
frames_mixed=(loop_restart_time*osrate)+pre_skip;
|
||||
} else {
|
||||
frames_mixed=pre_skip;
|
||||
}
|
||||
repeats++;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
stream_channels=op_head(opus_file,current_section)->channel_count;
|
||||
|
||||
frames_mixed+=ret;
|
||||
|
||||
p_bufer+=ret*stream_channels;
|
||||
p_frames-=ret;
|
||||
|
||||
}
|
||||
|
||||
return total-p_frames;
|
||||
}
|
||||
|
||||
float AudioStreamPlaybackOpus::get_length() const {
|
||||
if(!stream_loaded) {
|
||||
if(const_cast<AudioStreamPlaybackOpus*>(this)->_load_stream() != OK)
|
||||
return 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
float AudioStreamPlaybackOpus::get_pos() const {
|
||||
|
||||
int32_t frames = int32_t(frames_mixed);
|
||||
if (frames < 0)
|
||||
frames=0;
|
||||
return double(frames) / osrate;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::get_minimum_buffer_size() const {
|
||||
return MIN_MIX;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() {
|
||||
_clear_stream();
|
||||
}
|
||||
|
||||
RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String& p_original_path, Error *r_error) {
|
||||
if (r_error)
|
||||
*r_error=OK;
|
||||
|
||||
AudioStreamOpus *opus_stream = memnew(AudioStreamOpus);
|
||||
opus_stream->set_file(p_path);
|
||||
return Ref<AudioStreamOpus>(opus_stream);
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderAudioStreamOpus::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
||||
p_extensions->push_back("opus");
|
||||
}
|
||||
String ResourceFormatLoaderAudioStreamOpus::get_resource_type(const String &p_path) const {
|
||||
|
||||
if (p_path.extension().to_lower()=="opus")
|
||||
return "AudioStreamOpus";
|
||||
return "";
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderAudioStreamOpus::handles_type(const String& p_type) const {
|
||||
return (p_type=="AudioStream" || p_type=="AudioStreamOpus");
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*************************************************************************/
|
||||
/* audio_stream_opus.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Author: George Marques <george@gmarqu.es> */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef AUDIO_STREAM_OPUS_H
|
||||
#define AUDIO_STREAM_OPUS_H
|
||||
|
||||
#include "scene/resources/audio_stream.h"
|
||||
#include "opus/opusfile.h"
|
||||
#include "opus/internal.h"
|
||||
#include "os/file_access.h"
|
||||
#include "io/resource_loader.h"
|
||||
|
||||
class AudioStreamPlaybackOpus : public AudioStreamPlayback {
|
||||
|
||||
OBJ_TYPE(AudioStreamPlaybackOpus,AudioStreamPlayback)
|
||||
|
||||
enum {
|
||||
MIN_MIX=1024
|
||||
};
|
||||
|
||||
FileAccess *f;
|
||||
|
||||
OpusFileCallbacks _op_callbacks;
|
||||
float length;
|
||||
static int _op_read_func(void *_stream, unsigned char *_ptr, int _nbytes);
|
||||
static int _op_seek_func(void *_stream, opus_int64 _offset, int _whence);
|
||||
static int _op_close_func(void *_stream);
|
||||
static opus_int64 _op_tell_func(void *_stream);
|
||||
static const float osrate;
|
||||
|
||||
String file;
|
||||
int64_t frames_mixed;
|
||||
|
||||
bool stream_loaded;
|
||||
volatile bool playing;
|
||||
OggOpusFile *opus_file;
|
||||
int stream_channels;
|
||||
int current_section;
|
||||
int pre_skip;
|
||||
|
||||
bool paused;
|
||||
bool loops;
|
||||
int repeats;
|
||||
|
||||
Error _load_stream();
|
||||
void _clear_stream();
|
||||
void _close_file();
|
||||
|
||||
bool stream_valid;
|
||||
float loop_restart_time;
|
||||
|
||||
public:
|
||||
Error set_file(const String& p_file);
|
||||
|
||||
virtual void play(float p_from=0);
|
||||
virtual void stop();
|
||||
virtual bool is_playing() const { return playing; }
|
||||
|
||||
virtual void set_loop_restart_time(float p_time) { loop_restart_time=p_time; }
|
||||
|
||||
virtual void set_paused(bool p_paused) { paused=p_paused; }
|
||||
virtual bool is_paused() const { return paused; }
|
||||
|
||||
virtual void set_loop(bool p_enable) { loops=p_enable; }
|
||||
virtual bool has_loop() const {return loops; }
|
||||
|
||||
virtual float get_length() const;
|
||||
|
||||
virtual String get_stream_name() const { return ""; }
|
||||
|
||||
virtual int get_loop_count() const { return repeats; }
|
||||
|
||||
virtual float get_pos() const;
|
||||
virtual void seek_pos(float p_time);
|
||||
|
||||
virtual int get_channels() const { return stream_channels; }
|
||||
virtual int get_mix_rate() const { return osrate; }
|
||||
|
||||
virtual int get_minimum_buffer_size() const;
|
||||
|
||||
virtual int mix(int16_t* p_bufer,int p_frames);
|
||||
|
||||
AudioStreamPlaybackOpus();
|
||||
~AudioStreamPlaybackOpus();
|
||||
};
|
||||
|
||||
|
||||
class AudioStreamOpus: public AudioStream {
|
||||
|
||||
OBJ_TYPE(AudioStreamOpus,AudioStream)
|
||||
|
||||
String file;
|
||||
public:
|
||||
|
||||
Ref<AudioStreamPlayback> instance_playback() {
|
||||
Ref<AudioStreamPlaybackOpus> pb = memnew( AudioStreamPlaybackOpus );
|
||||
pb->set_file(file);
|
||||
return pb;
|
||||
}
|
||||
|
||||
void set_file(const String& p_file) { file=p_file; }
|
||||
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderAudioStreamOpus: public ResourceFormatLoader {
|
||||
public:
|
||||
virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
virtual bool handles_type(const String& p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
};
|
||||
|
||||
#endif // AUDIO_STREAM_OPUS_H
|
|
@ -0,0 +1,183 @@
|
|||
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.*/
|
||||
|
||||
#ifndef KISS_FFT_GUTS_H
|
||||
#define KISS_FFT_GUTS_H
|
||||
|
||||
#define MIN(a,b) ((a)<(b) ? (a):(b))
|
||||
#define MAX(a,b) ((a)>(b) ? (a):(b))
|
||||
|
||||
/* kiss_fft.h
|
||||
defines kiss_fft_scalar as either short or a float type
|
||||
and defines
|
||||
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
|
||||
#include "kiss_fft.h"
|
||||
|
||||
/*
|
||||
Explanation of macros dealing with complex math:
|
||||
|
||||
C_MUL(m,a,b) : m = a*b
|
||||
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
|
||||
C_SUB( res, a,b) : res = a - b
|
||||
C_SUBFROM( res , a) : res -= a
|
||||
C_ADDTO( res , a) : res += a
|
||||
* */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
#include "arch.h"
|
||||
|
||||
|
||||
#define SAMP_MAX 2147483647
|
||||
#define TWID_MAX 32767
|
||||
#define TRIG_UPSCALE 1
|
||||
|
||||
#define SAMP_MIN -SAMP_MAX
|
||||
|
||||
|
||||
# define S_MUL(a,b) MULT16_32_Q15(b, a)
|
||||
|
||||
# define C_MUL(m,a,b) \
|
||||
do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
|
||||
|
||||
# define C_MULC(m,a,b) \
|
||||
do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
|
||||
|
||||
# define C_MUL4(m,a,b) \
|
||||
do{ (m).r = SHR32(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \
|
||||
(m).i = SHR32(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0)
|
||||
|
||||
# define C_MULBYSCALAR( c, s ) \
|
||||
do{ (c).r = S_MUL( (c).r , s ) ;\
|
||||
(c).i = S_MUL( (c).i , s ) ; }while(0)
|
||||
|
||||
# define DIVSCALAR(x,k) \
|
||||
(x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 )
|
||||
|
||||
# define C_FIXDIV(c,div) \
|
||||
do { DIVSCALAR( (c).r , div); \
|
||||
DIVSCALAR( (c).i , div); }while (0)
|
||||
|
||||
#define C_ADD( res, a,b)\
|
||||
do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \
|
||||
}while(0)
|
||||
#define C_SUB( res, a,b)\
|
||||
do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \
|
||||
}while(0)
|
||||
#define C_ADDTO( res , a)\
|
||||
do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\
|
||||
}while(0)
|
||||
|
||||
#define C_SUBFROM( res , a)\
|
||||
do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \
|
||||
}while(0)
|
||||
|
||||
#if defined(OPUS_ARM_INLINE_ASM)
|
||||
#include "arm/kiss_fft_armv4.h"
|
||||
#endif
|
||||
|
||||
#if defined(OPUS_ARM_INLINE_EDSP)
|
||||
#include "arm/kiss_fft_armv5e.h"
|
||||
#endif
|
||||
|
||||
#else /* not OPUS_FIXED_POINT*/
|
||||
|
||||
# define S_MUL(a,b) ( (a)*(b) )
|
||||
#define C_MUL(m,a,b) \
|
||||
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
||||
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
|
||||
#define C_MULC(m,a,b) \
|
||||
do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
|
||||
(m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
|
||||
|
||||
#define C_MUL4(m,a,b) C_MUL(m,a,b)
|
||||
|
||||
# define C_FIXDIV(c,div) /* NOOP */
|
||||
# define C_MULBYSCALAR( c, s ) \
|
||||
do{ (c).r *= (s);\
|
||||
(c).i *= (s); }while(0)
|
||||
#endif
|
||||
|
||||
#ifndef CHECK_OVERFLOW_OP
|
||||
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
|
||||
#endif
|
||||
|
||||
#ifndef C_ADD
|
||||
#define C_ADD( res, a,b)\
|
||||
do { \
|
||||
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
|
||||
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
|
||||
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
|
||||
}while(0)
|
||||
#define C_SUB( res, a,b)\
|
||||
do { \
|
||||
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
|
||||
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
|
||||
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
|
||||
}while(0)
|
||||
#define C_ADDTO( res , a)\
|
||||
do { \
|
||||
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
|
||||
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
|
||||
(res).r += (a).r; (res).i += (a).i;\
|
||||
}while(0)
|
||||
|
||||
#define C_SUBFROM( res , a)\
|
||||
do {\
|
||||
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
|
||||
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
|
||||
(res).r -= (a).r; (res).i -= (a).i; \
|
||||
}while(0)
|
||||
#endif /* C_ADD defined */
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
|
||||
# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))
|
||||
# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase))
|
||||
# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase))
|
||||
# define HALF_OF(x) ((x)>>1)
|
||||
#elif defined(USE_SIMD)
|
||||
# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
|
||||
# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
|
||||
# define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
|
||||
#else
|
||||
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
|
||||
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
|
||||
# define HALF_OF(x) ((x)*.5f)
|
||||
#endif
|
||||
|
||||
#define kf_cexp(x,phase) \
|
||||
do{ \
|
||||
(x)->r = KISS_FFT_COS(phase);\
|
||||
(x)->i = KISS_FFT_SIN(phase);\
|
||||
}while(0)
|
||||
|
||||
#define kf_cexp2(x,phase) \
|
||||
do{ \
|
||||
(x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
|
||||
(x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
|
||||
}while(0)
|
||||
|
||||
#endif /* KISS_FFT_GUTS_H */
|
|
@ -0,0 +1,214 @@
|
|||
/* Copyright (c) 2003-2008 Jean-Marc Valin
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file arch.h
|
||||
@brief Various architecture definitions for CELT
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ARCH_H
|
||||
#define ARCH_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
# if !defined(__GNUC_PREREQ)
|
||||
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||
# define __GNUC_PREREQ(_maj,_min) \
|
||||
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||
# else
|
||||
# define __GNUC_PREREQ(_maj,_min) 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#define CELT_SIG_SCALE 32768.f
|
||||
|
||||
#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
|
||||
#ifdef ENABLE_ASSERTIONS
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noreturn))
|
||||
#endif
|
||||
static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
|
||||
{
|
||||
fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
|
||||
abort();
|
||||
}
|
||||
#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
|
||||
#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
|
||||
#else
|
||||
#define celt_assert(cond)
|
||||
#define celt_assert2(cond, message)
|
||||
#endif
|
||||
|
||||
#define IMUL32(a,b) ((a)*(b))
|
||||
|
||||
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
|
||||
#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
|
||||
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */
|
||||
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
|
||||
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */
|
||||
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||
#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */
|
||||
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */
|
||||
#define UADD32(a,b) ((a)+(b))
|
||||
#define USUB32(a,b) ((a)-(b))
|
||||
|
||||
#define PRINT_MIPS(file)
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
|
||||
typedef opus_int16 opus_val16;
|
||||
typedef opus_int32 opus_val32;
|
||||
|
||||
typedef opus_val32 celt_sig;
|
||||
typedef opus_val16 celt_norm;
|
||||
typedef opus_val32 celt_ener;
|
||||
|
||||
#define Q15ONE 32767
|
||||
|
||||
#define SIG_SHIFT 12
|
||||
|
||||
#define NORM_SCALING 16384
|
||||
|
||||
#define DB_SHIFT 10
|
||||
|
||||
#define EPSILON 1
|
||||
#define VERY_SMALL 0
|
||||
#define VERY_LARGE16 ((opus_val16)32767)
|
||||
#define Q15_ONE ((opus_val16)32767)
|
||||
|
||||
#define SCALEIN(a) (a)
|
||||
#define SCALEOUT(a) (a)
|
||||
|
||||
#ifdef FIXED_DEBUG
|
||||
#include "fixed_debug.h"
|
||||
#else
|
||||
|
||||
#include "fixed_generic.h"
|
||||
|
||||
#ifdef OPUS_ARM_INLINE_EDSP
|
||||
#include "arm/fixed_armv5e.h"
|
||||
#elif defined (OPUS_ARM_INLINE_ASM)
|
||||
#include "arm/fixed_armv4.h"
|
||||
#elif defined (BFIN_ASM)
|
||||
#include "fixed_bfin.h"
|
||||
#elif defined (TI_C5X_ASM)
|
||||
#include "fixed_c5x.h"
|
||||
#elif defined (TI_C6X_ASM)
|
||||
#include "fixed_c6x.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#else /* OPUS_FIXED_POINT */
|
||||
|
||||
typedef float opus_val16;
|
||||
typedef float opus_val32;
|
||||
|
||||
typedef float celt_sig;
|
||||
typedef float celt_norm;
|
||||
typedef float celt_ener;
|
||||
|
||||
#define Q15ONE 1.0f
|
||||
|
||||
#define NORM_SCALING 1.f
|
||||
|
||||
#define EPSILON 1e-15f
|
||||
#define VERY_SMALL 1e-30f
|
||||
#define VERY_LARGE16 1e15f
|
||||
#define Q15_ONE ((opus_val16)1.f)
|
||||
|
||||
#define QCONST16(x,bits) (x)
|
||||
#define QCONST32(x,bits) (x)
|
||||
|
||||
#define NEG16(x) (-(x))
|
||||
#define NEG32(x) (-(x))
|
||||
#define EXTRACT16(x) (x)
|
||||
#define EXTEND32(x) (x)
|
||||
#define SHR16(a,shift) (a)
|
||||
#define SHL16(a,shift) (a)
|
||||
#define SHR32(a,shift) (a)
|
||||
#define SHL32(a,shift) (a)
|
||||
#define PSHR32(a,shift) (a)
|
||||
#define VSHR32(a,shift) (a)
|
||||
|
||||
#define PSHR(a,shift) (a)
|
||||
#define SHR(a,shift) (a)
|
||||
#define SHL(a,shift) (a)
|
||||
#define SATURATE(x,a) (x)
|
||||
#define SATURATE16(x) (x)
|
||||
|
||||
#define ROUND16(a,shift) (a)
|
||||
#define HALF16(x) (.5f*(x))
|
||||
#define HALF32(x) (.5f*(x))
|
||||
|
||||
#define ADD16(a,b) ((a)+(b))
|
||||
#define SUB16(a,b) ((a)-(b))
|
||||
#define ADD32(a,b) ((a)+(b))
|
||||
#define SUB32(a,b) ((a)-(b))
|
||||
#define MULT16_16_16(a,b) ((a)*(b))
|
||||
#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b))
|
||||
#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b))
|
||||
|
||||
#define MULT16_32_Q15(a,b) ((a)*(b))
|
||||
#define MULT16_32_Q16(a,b) ((a)*(b))
|
||||
|
||||
#define MULT32_32_Q31(a,b) ((a)*(b))
|
||||
|
||||
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
|
||||
|
||||
#define MULT16_16_Q11_32(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q11(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q13(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q14(a,b) ((a)*(b))
|
||||
#define MULT16_16_Q15(a,b) ((a)*(b))
|
||||
#define MULT16_16_P15(a,b) ((a)*(b))
|
||||
#define MULT16_16_P13(a,b) ((a)*(b))
|
||||
#define MULT16_16_P14(a,b) ((a)*(b))
|
||||
#define MULT16_32_P16(a,b) ((a)*(b))
|
||||
|
||||
#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b))
|
||||
#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b))
|
||||
|
||||
#define SCALEIN(a) ((a)*CELT_SIG_SCALE)
|
||||
#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE))
|
||||
|
||||
#endif /* !OPUS_FIXED_POINT */
|
||||
|
||||
#ifndef GLOBAL_STACK_SIZE
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
#define GLOBAL_STACK_SIZE 100000
|
||||
#else
|
||||
#define GLOBAL_STACK_SIZE 100000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_H */
|
|
@ -0,0 +1,316 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
my $bigend; # little/big endian
|
||||
my $nxstack;
|
||||
|
||||
$nxstack = 0;
|
||||
|
||||
eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
|
||||
if $running_under_some_shell;
|
||||
|
||||
while ($ARGV[0] =~ /^-/) {
|
||||
$_ = shift;
|
||||
last if /^--/;
|
||||
if (/^-n/) {
|
||||
$nflag++;
|
||||
next;
|
||||
}
|
||||
die "I don't recognize this switch: $_\\n";
|
||||
}
|
||||
$printit++ unless $nflag;
|
||||
|
||||
$\ = "\n"; # automatically add newline on print
|
||||
$n=0;
|
||||
|
||||
$thumb = 0; # ARM mode by default, not Thumb.
|
||||
@proc_stack = ();
|
||||
|
||||
LINE:
|
||||
while (<>) {
|
||||
|
||||
# For ADRLs we need to add a new line after the substituted one.
|
||||
$addPadding = 0;
|
||||
|
||||
# First, we do not dare to touch *anything* inside double quotes, do we?
|
||||
# Second, if you want a dollar character in the string,
|
||||
# insert two of them -- that's how ARM C and assembler treat strings.
|
||||
s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next };
|
||||
s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next };
|
||||
s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next };
|
||||
# If there's nothing on a line but a comment, don't try to apply any further
|
||||
# substitutions (this is a cheap hack to avoid mucking up the license header)
|
||||
s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next };
|
||||
# If substituted -- leave immediately !
|
||||
|
||||
s/@/,:/;
|
||||
s/;/@/;
|
||||
while ( /@.*'/ ) {
|
||||
s/(@.*)'/$1/g;
|
||||
}
|
||||
s/\{FALSE\}/0/g;
|
||||
s/\{TRUE\}/1/g;
|
||||
s/\{(\w\w\w\w+)\}/$1/g;
|
||||
s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
|
||||
s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
|
||||
s/\bIMPORT\b/.extern/;
|
||||
s/\bEXPORT\b/.global/;
|
||||
s/^(\s+)\[/$1IF/;
|
||||
s/^(\s+)\|/$1ELSE/;
|
||||
s/^(\s+)\]/$1ENDIF/;
|
||||
s/IF *:DEF:/ .ifdef/;
|
||||
s/IF *:LNOT: *:DEF:/ .ifndef/;
|
||||
s/ELSE/ .else/;
|
||||
s/ENDIF/ .endif/;
|
||||
|
||||
if( /\bIF\b/ ) {
|
||||
s/\bIF\b/ .if/;
|
||||
s/=/==/;
|
||||
}
|
||||
if ( $n == 2) {
|
||||
s/\$/\\/g;
|
||||
}
|
||||
if ($n == 1) {
|
||||
s/\$//g;
|
||||
s/label//g;
|
||||
$n = 2;
|
||||
}
|
||||
if ( /MACRO/ ) {
|
||||
s/MACRO *\n/.macro/;
|
||||
$n=1;
|
||||
}
|
||||
if ( /\bMEND\b/ ) {
|
||||
s/\bMEND\b/.endm/;
|
||||
$n=0;
|
||||
}
|
||||
|
||||
# ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
|
||||
#
|
||||
if ( /\bAREA\b/ ) {
|
||||
my $align;
|
||||
$align = "2";
|
||||
if ( /ALIGN=(\d+)/ ) {
|
||||
$align = $1;
|
||||
}
|
||||
if ( /CODE/ ) {
|
||||
$nxstack = 1;
|
||||
}
|
||||
s/^(.+)CODE(.+)READONLY(.*)/ .text/;
|
||||
s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/;
|
||||
s/^(.+)\|\|\.data\|\|(.+)/ .data/;
|
||||
s/^(.+)\|\|\.bss\|\|(.+)/ .bss/;
|
||||
s/$/; .p2align $align/;
|
||||
# Enable NEON instructions but don't produce a binary that requires
|
||||
# ARMv7. RVCT does not have equivalent directives, so we just do this
|
||||
# for all CODE areas.
|
||||
if ( /.text/ ) {
|
||||
# Separating .arch, .fpu, etc., by semicolons does not work (gas
|
||||
# thinks the semicolon is part of the arch name, even when there's
|
||||
# whitespace separating them). Sadly this means our line numbers
|
||||
# won't match the original source file (we could use the .line
|
||||
# directive, which is documented to be obsolete, but then gdb will
|
||||
# show the wrong line in the translated source file).
|
||||
s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/;
|
||||
}
|
||||
}
|
||||
|
||||
s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3||
|
||||
s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2||
|
||||
s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2||
|
||||
s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
|
||||
s/^(\s+)\%(\s)/ .space $1/;
|
||||
|
||||
s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123
|
||||
s/\bCODE32\b/.code 32/ && do {$thumb = 0};
|
||||
s/\bCODE16\b/.code 16/ && do {$thumb = 1};
|
||||
if (/\bPROC\b/)
|
||||
{
|
||||
my $prefix;
|
||||
my $proc;
|
||||
/^([A-Za-z_\.]\w+)\b/;
|
||||
$proc = $1;
|
||||
$prefix = "";
|
||||
if ($proc)
|
||||
{
|
||||
$prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc);
|
||||
push(@proc_stack, $proc);
|
||||
s/^[A-Za-z_\.]\w+/$&:/;
|
||||
}
|
||||
$prefix = $prefix."\t.thumb_func; " if ($thumb);
|
||||
s/\bPROC\b/@ $&/;
|
||||
$_ = $prefix.$_;
|
||||
}
|
||||
s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
|
||||
s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
|
||||
if (/\bENDP\b/)
|
||||
{
|
||||
my $proc;
|
||||
s/\bENDP\b/@ $&/;
|
||||
$proc = pop(@proc_stack);
|
||||
$_ = "\t.size $proc, .-$proc".$_ if ($proc);
|
||||
}
|
||||
s/\bSUBT\b/@ $&/;
|
||||
s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25
|
||||
s/\bKEEP\b/@ $&/;
|
||||
s/\bEXPORTAS\b/@ $&/;
|
||||
s/\|\|(.)+\bEQU\b/@ $&/;
|
||||
s/\|\|([\w\$]+)\|\|/$1/;
|
||||
s/\bENTRY\b/@ $&/;
|
||||
s/\bASSERT\b/@ $&/;
|
||||
s/\bGBLL\b/@ $&/;
|
||||
s/\bGBLA\b/@ $&/;
|
||||
s/^\W+OPT\b/@ $&/;
|
||||
s/:OR:/|/g;
|
||||
s/:SHL:/<</g;
|
||||
s/:SHR:/>>/g;
|
||||
s/:AND:/&/g;
|
||||
s/:LAND:/&&/g;
|
||||
s/CPSR/cpsr/;
|
||||
s/SPSR/spsr/;
|
||||
s/ALIGN$/.balign 4/;
|
||||
s/ALIGN\s+([0-9x]+)$/.balign $1/;
|
||||
s/psr_cxsf/psr_all/;
|
||||
s/LTORG/.ltorg/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
|
||||
|
||||
# {PC} + 0xdeadfeed --> . + 0xdeadfeed
|
||||
s/\{PC\} \+/ \. +/;
|
||||
|
||||
# Single hex constant on the line !
|
||||
#
|
||||
# >>> NOTE <<<
|
||||
# Double-precision floats in gcc are always mixed-endian, which means
|
||||
# bytes in two words are little-endian, but words are big-endian.
|
||||
# So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
|
||||
# and 0xfeed0000 at high address.
|
||||
#
|
||||
s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
|
||||
# Only decimal constants on the line, no hex !
|
||||
s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
|
||||
|
||||
# Single hex constant on the line !
|
||||
# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
|
||||
# Only decimal constants on the line, no hex !
|
||||
# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
|
||||
s/\bDCFS[ \t]+0x/.word 0x/;
|
||||
s/\bDCFS\b/.float/;
|
||||
|
||||
s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
|
||||
s/\bDCD\b/.word/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
|
||||
s/\bDCW\b/.short/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
|
||||
s/\bDCB\b/.byte/;
|
||||
s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
|
||||
s/^[A-Za-z_\.]\w+/$&:/;
|
||||
s/^(\d+)/$1:/;
|
||||
s/\%(\d+)/$1b_or_f/;
|
||||
s/\%[Bb](\d+)/$1b/;
|
||||
s/\%[Ff](\d+)/$1f/;
|
||||
s/\%[Ff][Tt](\d+)/$1f/;
|
||||
s/&([\dA-Fa-f]+)/0x$1/;
|
||||
if ( /\b2_[01]+\b/ ) {
|
||||
s/\b2_([01]+)\b/conv$1&&&&/g;
|
||||
while ( /[01][01][01][01]&&&&/ ) {
|
||||
s/0000&&&&/&&&&0/g;
|
||||
s/0001&&&&/&&&&1/g;
|
||||
s/0010&&&&/&&&&2/g;
|
||||
s/0011&&&&/&&&&3/g;
|
||||
s/0100&&&&/&&&&4/g;
|
||||
s/0101&&&&/&&&&5/g;
|
||||
s/0110&&&&/&&&&6/g;
|
||||
s/0111&&&&/&&&&7/g;
|
||||
s/1000&&&&/&&&&8/g;
|
||||
s/1001&&&&/&&&&9/g;
|
||||
s/1010&&&&/&&&&A/g;
|
||||
s/1011&&&&/&&&&B/g;
|
||||
s/1100&&&&/&&&&C/g;
|
||||
s/1101&&&&/&&&&D/g;
|
||||
s/1110&&&&/&&&&E/g;
|
||||
s/1111&&&&/&&&&F/g;
|
||||
}
|
||||
s/000&&&&/&&&&0/g;
|
||||
s/001&&&&/&&&&1/g;
|
||||
s/010&&&&/&&&&2/g;
|
||||
s/011&&&&/&&&&3/g;
|
||||
s/100&&&&/&&&&4/g;
|
||||
s/101&&&&/&&&&5/g;
|
||||
s/110&&&&/&&&&6/g;
|
||||
s/111&&&&/&&&&7/g;
|
||||
s/00&&&&/&&&&0/g;
|
||||
s/01&&&&/&&&&1/g;
|
||||
s/10&&&&/&&&&2/g;
|
||||
s/11&&&&/&&&&3/g;
|
||||
s/0&&&&/&&&&0/g;
|
||||
s/1&&&&/&&&&1/g;
|
||||
s/conv&&&&/0x/g;
|
||||
}
|
||||
|
||||
if ( /commandline/)
|
||||
{
|
||||
if( /-bigend/)
|
||||
{
|
||||
$bigend=1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( /\bDCDU\b/ )
|
||||
{
|
||||
my $cmd=$_;
|
||||
my $value;
|
||||
my $prefix;
|
||||
my $w1;
|
||||
my $w2;
|
||||
my $w3;
|
||||
my $w4;
|
||||
|
||||
s/\s+DCDU\b/@ $&/;
|
||||
|
||||
$cmd =~ /\bDCDU\b\s+0x(\d+)/;
|
||||
$value = $1;
|
||||
$value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
|
||||
$w1 = $1;
|
||||
$w2 = $2;
|
||||
$w3 = $3;
|
||||
$w4 = $4;
|
||||
|
||||
if( $bigend ne "")
|
||||
{
|
||||
# big endian
|
||||
$prefix = "\t.byte\t0x".$w1.";".
|
||||
"\t.byte\t0x".$w2.";".
|
||||
"\t.byte\t0x".$w3.";".
|
||||
"\t.byte\t0x".$w4."; ";
|
||||
}
|
||||
else
|
||||
{
|
||||
# little endian
|
||||
$prefix = "\t.byte\t0x".$w4.";".
|
||||
"\t.byte\t0x".$w3.";".
|
||||
"\t.byte\t0x".$w2.";".
|
||||
"\t.byte\t0x".$w1."; ";
|
||||
}
|
||||
$_=$prefix.$_;
|
||||
}
|
||||
|
||||
if ( /\badrl\b/i )
|
||||
{
|
||||
s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
|
||||
$addPadding = 1;
|
||||
}
|
||||
s/\bEND\b/@ END/;
|
||||
} continue {
|
||||
printf ("%s", $_) if $printit;
|
||||
if ($addPadding != 0)
|
||||
{
|
||||
printf (" mov r0,r0\n");
|
||||
$addPadding = 0;
|
||||
}
|
||||
}
|
||||
#If we had a code section, mark that this object doesn't need an executable
|
||||
# stack.
|
||||
if ($nxstack) {
|
||||
printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n");
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation
|
||||
* Copyright (c) 2013 Parrot */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "pitch.h"
|
||||
|
||||
#if defined(OPUS_HAVE_RTCD)
|
||||
|
||||
# if defined(OPUS_FIXED_POINT)
|
||||
opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
||||
const opus_val16 *, opus_val32 *, int , int) = {
|
||||
celt_pitch_xcorr_c, /* ARMv4 */
|
||||
MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */
|
||||
MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */
|
||||
MAY_HAVE_NEON(celt_pitch_xcorr) /* NEON */
|
||||
};
|
||||
# else
|
||||
# error "Floating-point implementation is not supported by ARM asm yet." \
|
||||
"Reconfigure with --disable-rtcd or send patches."
|
||||
# endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,174 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation
|
||||
* Copyright (c) 2013 Parrot */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Original code from libtheora modified to suit to Opus */
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#ifdef OPUS_HAVE_RTCD
|
||||
|
||||
#include "armcpu.h"
|
||||
#include "cpu_support.h"
|
||||
#include "os_support.h"
|
||||
#include "opus_types.h"
|
||||
|
||||
#define OPUS_CPU_ARM_V4 (1)
|
||||
#define OPUS_CPU_ARM_EDSP (1<<1)
|
||||
#define OPUS_CPU_ARM_MEDIA (1<<2)
|
||||
#define OPUS_CPU_ARM_NEON (1<<3)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_EXTRA_LEAN
|
||||
# include <windows.h>
|
||||
|
||||
static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
|
||||
opus_uint32 flags;
|
||||
flags=0;
|
||||
/* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
|
||||
* instructions via their assembled hex code.
|
||||
* All of these instructions should be essentially nops. */
|
||||
# if defined(OPUS_ARM_MAY_HAVE_EDSP)
|
||||
__try{
|
||||
/*PLD [r13]*/
|
||||
__emit(0xF5DDF000);
|
||||
flags|=OPUS_CPU_ARM_EDSP;
|
||||
}
|
||||
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||
/*Ignore exception.*/
|
||||
}
|
||||
# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
|
||||
__try{
|
||||
/*SHADD8 r3,r3,r3*/
|
||||
__emit(0xE6333F93);
|
||||
flags|=OPUS_CPU_ARM_MEDIA;
|
||||
}
|
||||
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||
/*Ignore exception.*/
|
||||
}
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON)
|
||||
__try{
|
||||
/*VORR q0,q0,q0*/
|
||||
__emit(0xF2200150);
|
||||
flags|=OPUS_CPU_ARM_NEON;
|
||||
}
|
||||
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||
/*Ignore exception.*/
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
/* Linux based */
|
||||
opus_uint32 opus_cpu_capabilities(void)
|
||||
{
|
||||
opus_uint32 flags = 0;
|
||||
FILE *cpuinfo;
|
||||
|
||||
/* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
|
||||
* Android */
|
||||
cpuinfo = fopen("/proc/cpuinfo", "r");
|
||||
|
||||
if(cpuinfo != NULL)
|
||||
{
|
||||
/* 512 should be enough for anybody (it's even enough for all the flags that
|
||||
* x86 has accumulated... so far). */
|
||||
char buf[512];
|
||||
|
||||
while(fgets(buf, 512, cpuinfo) != NULL)
|
||||
{
|
||||
# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_NEON)
|
||||
/* Search for edsp and neon flag */
|
||||
if(memcmp(buf, "Features", 8) == 0)
|
||||
{
|
||||
char *p;
|
||||
# if defined(OPUS_ARM_MAY_HAVE_EDSP)
|
||||
p = strstr(buf, " edsp");
|
||||
if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
|
||||
flags |= OPUS_CPU_ARM_EDSP;
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON)
|
||||
p = strstr(buf, " neon");
|
||||
if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
|
||||
flags |= OPUS_CPU_ARM_NEON;
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
|
||||
/* Search for media capabilities (>= ARMv6) */
|
||||
if(memcmp(buf, "CPU architecture:", 17) == 0)
|
||||
{
|
||||
int version;
|
||||
version = atoi(buf+17);
|
||||
|
||||
if(version >= 6)
|
||||
flags |= OPUS_CPU_ARM_MEDIA;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
fclose(cpuinfo);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
#else
|
||||
/* The feature registers which can tell us what the processor supports are
|
||||
* accessible in priveleged modes only, so we can't have a general user-space
|
||||
* detection method like on x86.*/
|
||||
# error "Configured to use ARM asm but no CPU detection method available for " \
|
||||
"your platform. Reconfigure with --disable-rtcd (or send patches)."
|
||||
#endif
|
||||
|
||||
int opus_select_arch(void)
|
||||
{
|
||||
opus_uint32 flags = opus_cpu_capabilities();
|
||||
int arch = 0;
|
||||
|
||||
if(!(flags & OPUS_CPU_ARM_EDSP))
|
||||
return arch;
|
||||
arch++;
|
||||
|
||||
if(!(flags & OPUS_CPU_ARM_MEDIA))
|
||||
return arch;
|
||||
arch++;
|
||||
|
||||
if(!(flags & OPUS_CPU_ARM_NEON))
|
||||
return arch;
|
||||
arch++;
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,71 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation
|
||||
* Copyright (c) 2013 Parrot */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !defined(ARMCPU_H)
|
||||
# define ARMCPU_H
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_EDSP)
|
||||
# define MAY_HAVE_EDSP(name) name ## _edsp
|
||||
# else
|
||||
# define MAY_HAVE_EDSP(name) name ## _c
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
|
||||
# define MAY_HAVE_MEDIA(name) name ## _media
|
||||
# else
|
||||
# define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name)
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON)
|
||||
# define MAY_HAVE_NEON(name) name ## _neon
|
||||
# else
|
||||
# define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name)
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_PRESUME_EDSP)
|
||||
# define PRESUME_EDSP(name) name ## _edsp
|
||||
# else
|
||||
# define PRESUME_EDSP(name) name ## _c
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_PRESUME_MEDIA)
|
||||
# define PRESUME_MEDIA(name) name ## _media
|
||||
# else
|
||||
# define PRESUME_MEDIA(name) PRESUME_EDSP(name)
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_PRESUME_NEON)
|
||||
# define PRESUME_NEON(name) name ## _neon
|
||||
# else
|
||||
# define PRESUME_NEON(name) PRESUME_MEDIA(name)
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_HAVE_RTCD)
|
||||
int opus_select_arch(void);
|
||||
# endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (C) 2013 Mozilla Corporation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
; Set the following to 1 if we have EDSP instructions
|
||||
; (LDRD/STRD, etc., ARMv5E and later).
|
||||
OPUS_ARM_MAY_HAVE_EDSP *
|
||||
|
||||
; Set the following to 1 if we have ARMv6 media instructions.
|
||||
OPUS_ARM_MAY_HAVE_MEDIA *
|
||||
|
||||
; Set the following to 1 if we have NEON (some ARMv7)
|
||||
OPUS_ARM_MAY_HAVE_NEON *
|
||||
|
||||
END
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (C) 2013 Mozilla Corporation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
; Set the following to 1 if we have EDSP instructions
|
||||
; (LDRD/STRD, etc., ARMv5E and later).
|
||||
OPUS_ARM_MAY_HAVE_EDSP * @OPUS_ARM_MAY_HAVE_EDSP@
|
||||
|
||||
; Set the following to 1 if we have ARMv6 media instructions.
|
||||
OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@
|
||||
|
||||
; Set the following to 1 if we have NEON (some ARMv7)
|
||||
OPUS_ARM_MAY_HAVE_NEON * @OPUS_ARM_MAY_HAVE_NEON@
|
||||
|
||||
END
|
|
@ -0,0 +1,545 @@
|
|||
; Copyright (c) 2007-2008 CSIRO
|
||||
; Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
; Copyright (c) 2013 Parrot
|
||||
; Written by Aurélien Zanelli
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions
|
||||
; are met:
|
||||
;
|
||||
; - Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
;
|
||||
; - Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
GET celt/arm/armopts.s
|
||||
|
||||
IF OPUS_ARM_MAY_HAVE_EDSP
|
||||
EXPORT celt_pitch_xcorr_edsp
|
||||
ENDIF
|
||||
|
||||
IF OPUS_ARM_MAY_HAVE_NEON
|
||||
EXPORT celt_pitch_xcorr_neon
|
||||
ENDIF
|
||||
|
||||
IF OPUS_ARM_MAY_HAVE_NEON
|
||||
|
||||
; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3
|
||||
xcorr_kernel_neon PROC
|
||||
; input:
|
||||
; r3 = int len
|
||||
; r4 = opus_val16 *x
|
||||
; r5 = opus_val16 *y
|
||||
; q0 = opus_val32 sum[4]
|
||||
; output:
|
||||
; q0 = opus_val32 sum[4]
|
||||
; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15
|
||||
; internal usage:
|
||||
; r12 = int j
|
||||
; d3 = y_3|y_2|y_1|y_0
|
||||
; q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4
|
||||
; q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0
|
||||
; q8 = scratch
|
||||
;
|
||||
; Load y[0...3]
|
||||
; This requires len>0 to always be valid (which we assert in the C code).
|
||||
VLD1.16 {d5}, [r5]!
|
||||
SUBS r12, r3, #8
|
||||
BLE xcorr_kernel_neon_process4
|
||||
; Process 8 samples at a time.
|
||||
; This loop loads one y value more than we actually need. Therefore we have to
|
||||
; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid
|
||||
; reading past the end of the array.
|
||||
xcorr_kernel_neon_process8
|
||||
; This loop has 19 total instructions (10 cycles to issue, minimum), with
|
||||
; - 2 cycles of ARM insrtuctions,
|
||||
; - 10 cycles of load/store/byte permute instructions, and
|
||||
; - 9 cycles of data processing instructions.
|
||||
; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the
|
||||
; latter two categories, meaning the whole loop should run in 10 cycles per
|
||||
; iteration, barring cache misses.
|
||||
;
|
||||
; Load x[0...7]
|
||||
VLD1.16 {d6, d7}, [r4]!
|
||||
; Unlike VMOV, VAND is a data processsing instruction (and doesn't get
|
||||
; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1.
|
||||
VAND d3, d5, d5
|
||||
SUBS r12, r12, #8
|
||||
; Load y[4...11]
|
||||
VLD1.16 {d4, d5}, [r5]!
|
||||
VMLAL.S16 q0, d3, d6[0]
|
||||
VEXT.16 d16, d3, d4, #1
|
||||
VMLAL.S16 q0, d4, d7[0]
|
||||
VEXT.16 d17, d4, d5, #1
|
||||
VMLAL.S16 q0, d16, d6[1]
|
||||
VEXT.16 d16, d3, d4, #2
|
||||
VMLAL.S16 q0, d17, d7[1]
|
||||
VEXT.16 d17, d4, d5, #2
|
||||
VMLAL.S16 q0, d16, d6[2]
|
||||
VEXT.16 d16, d3, d4, #3
|
||||
VMLAL.S16 q0, d17, d7[2]
|
||||
VEXT.16 d17, d4, d5, #3
|
||||
VMLAL.S16 q0, d16, d6[3]
|
||||
VMLAL.S16 q0, d17, d7[3]
|
||||
BGT xcorr_kernel_neon_process8
|
||||
; Process 4 samples here if we have > 4 left (still reading one extra y value).
|
||||
xcorr_kernel_neon_process4
|
||||
ADDS r12, r12, #4
|
||||
BLE xcorr_kernel_neon_process2
|
||||
; Load x[0...3]
|
||||
VLD1.16 d6, [r4]!
|
||||
; Use VAND since it's a data processing instruction again.
|
||||
VAND d4, d5, d5
|
||||
SUB r12, r12, #4
|
||||
; Load y[4...7]
|
||||
VLD1.16 d5, [r5]!
|
||||
VMLAL.S16 q0, d4, d6[0]
|
||||
VEXT.16 d16, d4, d5, #1
|
||||
VMLAL.S16 q0, d16, d6[1]
|
||||
VEXT.16 d16, d4, d5, #2
|
||||
VMLAL.S16 q0, d16, d6[2]
|
||||
VEXT.16 d16, d4, d5, #3
|
||||
VMLAL.S16 q0, d16, d6[3]
|
||||
; Process 2 samples here if we have > 2 left (still reading one extra y value).
|
||||
xcorr_kernel_neon_process2
|
||||
ADDS r12, r12, #2
|
||||
BLE xcorr_kernel_neon_process1
|
||||
; Load x[0...1]
|
||||
VLD2.16 {d6[],d7[]}, [r4]!
|
||||
; Use VAND since it's a data processing instruction again.
|
||||
VAND d4, d5, d5
|
||||
SUB r12, r12, #2
|
||||
; Load y[4...5]
|
||||
VLD1.32 {d5[]}, [r5]!
|
||||
VMLAL.S16 q0, d4, d6
|
||||
VEXT.16 d16, d4, d5, #1
|
||||
; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI
|
||||
; instead of VEXT, since it's a data-processing instruction.
|
||||
VSRI.64 d5, d4, #32
|
||||
VMLAL.S16 q0, d16, d7
|
||||
; Process 1 sample using the extra y value we loaded above.
|
||||
xcorr_kernel_neon_process1
|
||||
; Load next *x
|
||||
VLD1.16 {d6[]}, [r4]!
|
||||
ADDS r12, r12, #1
|
||||
; y[0...3] are left in d5 from prior iteration(s) (if any)
|
||||
VMLAL.S16 q0, d5, d6
|
||||
MOVLE pc, lr
|
||||
; Now process 1 last sample, not reading ahead.
|
||||
; Load last *y
|
||||
VLD1.16 {d4[]}, [r5]!
|
||||
VSRI.64 d4, d5, #16
|
||||
; Load last *x
|
||||
VLD1.16 {d6[]}, [r4]!
|
||||
VMLAL.S16 q0, d4, d6
|
||||
MOV pc, lr
|
||||
ENDP
|
||||
|
||||
; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
|
||||
; opus_val32 *xcorr, int len, int max_pitch)
|
||||
celt_pitch_xcorr_neon PROC
|
||||
; input:
|
||||
; r0 = opus_val16 *_x
|
||||
; r1 = opus_val16 *_y
|
||||
; r2 = opus_val32 *xcorr
|
||||
; r3 = int len
|
||||
; output:
|
||||
; r0 = int maxcorr
|
||||
; internal usage:
|
||||
; r4 = opus_val16 *x (for xcorr_kernel_neon())
|
||||
; r5 = opus_val16 *y (for xcorr_kernel_neon())
|
||||
; r6 = int max_pitch
|
||||
; r12 = int j
|
||||
; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon())
|
||||
STMFD sp!, {r4-r6, lr}
|
||||
LDR r6, [sp, #16]
|
||||
VMOV.S32 q15, #1
|
||||
; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
|
||||
SUBS r6, r6, #4
|
||||
BLT celt_pitch_xcorr_neon_process4_done
|
||||
celt_pitch_xcorr_neon_process4
|
||||
; xcorr_kernel_neon parameters:
|
||||
; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0}
|
||||
MOV r4, r0
|
||||
MOV r5, r1
|
||||
VEOR q0, q0, q0
|
||||
; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3.
|
||||
; So we don't save/restore any other registers.
|
||||
BL xcorr_kernel_neon
|
||||
SUBS r6, r6, #4
|
||||
VST1.32 {q0}, [r2]!
|
||||
; _y += 4
|
||||
ADD r1, r1, #8
|
||||
VMAX.S32 q15, q15, q0
|
||||
; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
|
||||
BGE celt_pitch_xcorr_neon_process4
|
||||
; We have less than 4 sums left to compute.
|
||||
celt_pitch_xcorr_neon_process4_done
|
||||
ADDS r6, r6, #4
|
||||
; Reduce maxcorr to a single value
|
||||
VMAX.S32 d30, d30, d31
|
||||
VPMAX.S32 d30, d30, d30
|
||||
; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done
|
||||
BLE celt_pitch_xcorr_neon_done
|
||||
; Now compute each remaining sum one at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining
|
||||
MOV r4, r0
|
||||
MOV r5, r1
|
||||
VMOV.I32 q0, #0
|
||||
SUBS r12, r3, #8
|
||||
BLT celt_pitch_xcorr_neon_process_remaining4
|
||||
; Sum terms 8 at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining_loop8
|
||||
; Load x[0...7]
|
||||
VLD1.16 {q1}, [r4]!
|
||||
; Load y[0...7]
|
||||
VLD1.16 {q2}, [r5]!
|
||||
SUBS r12, r12, #8
|
||||
VMLAL.S16 q0, d4, d2
|
||||
VMLAL.S16 q0, d5, d3
|
||||
BGE celt_pitch_xcorr_neon_process_remaining_loop8
|
||||
; Sum terms 4 at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining4
|
||||
ADDS r12, r12, #4
|
||||
BLT celt_pitch_xcorr_neon_process_remaining4_done
|
||||
; Load x[0...3]
|
||||
VLD1.16 {d2}, [r4]!
|
||||
; Load y[0...3]
|
||||
VLD1.16 {d3}, [r5]!
|
||||
SUB r12, r12, #4
|
||||
VMLAL.S16 q0, d3, d2
|
||||
celt_pitch_xcorr_neon_process_remaining4_done
|
||||
; Reduce the sum to a single value.
|
||||
VADD.S32 d0, d0, d1
|
||||
VPADDL.S32 d0, d0
|
||||
ADDS r12, r12, #4
|
||||
BLE celt_pitch_xcorr_neon_process_remaining_loop_done
|
||||
; Sum terms 1 at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining_loop1
|
||||
VLD1.16 {d2[]}, [r4]!
|
||||
VLD1.16 {d3[]}, [r5]!
|
||||
SUBS r12, r12, #1
|
||||
VMLAL.S16 q0, d2, d3
|
||||
BGT celt_pitch_xcorr_neon_process_remaining_loop1
|
||||
celt_pitch_xcorr_neon_process_remaining_loop_done
|
||||
VST1.32 {d0[0]}, [r2]!
|
||||
VMAX.S32 d30, d30, d0
|
||||
SUBS r6, r6, #1
|
||||
; _y++
|
||||
ADD r1, r1, #2
|
||||
; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining
|
||||
BGT celt_pitch_xcorr_neon_process_remaining
|
||||
celt_pitch_xcorr_neon_done
|
||||
VMOV.32 r0, d30[0]
|
||||
LDMFD sp!, {r4-r6, pc}
|
||||
ENDP
|
||||
|
||||
ENDIF
|
||||
|
||||
IF OPUS_ARM_MAY_HAVE_EDSP
|
||||
|
||||
; This will get used on ARMv7 devices without NEON, so it has been optimized
|
||||
; to take advantage of dual-issuing where possible.
|
||||
xcorr_kernel_edsp PROC
|
||||
; input:
|
||||
; r3 = int len
|
||||
; r4 = opus_val16 *_x (must be 32-bit aligned)
|
||||
; r5 = opus_val16 *_y (must be 32-bit aligned)
|
||||
; r6...r9 = opus_val32 sum[4]
|
||||
; output:
|
||||
; r6...r9 = opus_val32 sum[4]
|
||||
; preserved: r0-r5
|
||||
; internal usage
|
||||
; r2 = int j
|
||||
; r12,r14 = opus_val16 x[4]
|
||||
; r10,r11 = opus_val16 y[4]
|
||||
STMFD sp!, {r2,r4,r5,lr}
|
||||
LDR r10, [r5], #4 ; Load y[0...1]
|
||||
SUBS r2, r3, #4 ; j = len-4
|
||||
LDR r11, [r5], #4 ; Load y[2...3]
|
||||
BLE xcorr_kernel_edsp_process4_done
|
||||
LDR r12, [r4], #4 ; Load x[0...1]
|
||||
; Stall
|
||||
xcorr_kernel_edsp_process4
|
||||
; The multiplies must issue from pipeline 0, and can't dual-issue with each
|
||||
; other. Every other instruction here dual-issues with a multiply, and is
|
||||
; thus "free". There should be no stalls in the body of the loop.
|
||||
SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_0,y_0)
|
||||
LDR r14, [r4], #4 ; Load x[2...3]
|
||||
SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x_0,y_1)
|
||||
SUBS r2, r2, #4 ; j-=4
|
||||
SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_0,y_2)
|
||||
SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x_0,y_3)
|
||||
SMLATT r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_1,y_1)
|
||||
LDR r10, [r5], #4 ; Load y[4...5]
|
||||
SMLATB r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],x_1,y_2)
|
||||
SMLATT r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_1,y_3)
|
||||
SMLATB r9, r12, r10, r9 ; sum[3] = MAC16_16(sum[3],x_1,y_4)
|
||||
LDRGT r12, [r4], #4 ; Load x[0...1]
|
||||
SMLABB r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_2,y_2)
|
||||
SMLABT r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x_2,y_3)
|
||||
SMLABB r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_2,y_4)
|
||||
SMLABT r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x_2,y_5)
|
||||
SMLATT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_3,y_3)
|
||||
LDR r11, [r5], #4 ; Load y[6...7]
|
||||
SMLATB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],x_3,y_4)
|
||||
SMLATT r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_3,y_5)
|
||||
SMLATB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],x_3,y_6)
|
||||
BGT xcorr_kernel_edsp_process4
|
||||
xcorr_kernel_edsp_process4_done
|
||||
ADDS r2, r2, #4
|
||||
BLE xcorr_kernel_edsp_done
|
||||
LDRH r12, [r4], #2 ; r12 = *x++
|
||||
SUBS r2, r2, #1 ; j--
|
||||
; Stall
|
||||
SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_0)
|
||||
LDRGTH r14, [r4], #2 ; r14 = *x++
|
||||
SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x,y_1)
|
||||
SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_2)
|
||||
SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x,y_3)
|
||||
BLE xcorr_kernel_edsp_done
|
||||
SMLABT r6, r14, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_1)
|
||||
SUBS r2, r2, #1 ; j--
|
||||
SMLABB r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x,y_2)
|
||||
LDRH r10, [r5], #2 ; r10 = y_4 = *y++
|
||||
SMLABT r8, r14, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_3)
|
||||
LDRGTH r12, [r4], #2 ; r12 = *x++
|
||||
SMLABB r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x,y_4)
|
||||
BLE xcorr_kernel_edsp_done
|
||||
SMLABB r6, r12, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_2)
|
||||
CMP r2, #1 ; j--
|
||||
SMLABT r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_3)
|
||||
LDRH r2, [r5], #2 ; r2 = y_5 = *y++
|
||||
SMLABB r8, r12, r10, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_4)
|
||||
LDRGTH r14, [r4] ; r14 = *x
|
||||
SMLABB r9, r12, r2, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_5)
|
||||
BLE xcorr_kernel_edsp_done
|
||||
SMLABT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_3)
|
||||
LDRH r11, [r5] ; r11 = y_6 = *y
|
||||
SMLABB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_4)
|
||||
SMLABB r8, r14, r2, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_5)
|
||||
SMLABB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_6)
|
||||
xcorr_kernel_edsp_done
|
||||
LDMFD sp!, {r2,r4,r5,pc}
|
||||
ENDP
|
||||
|
||||
celt_pitch_xcorr_edsp PROC
|
||||
; input:
|
||||
; r0 = opus_val16 *_x (must be 32-bit aligned)
|
||||
; r1 = opus_val16 *_y (only needs to be 16-bit aligned)
|
||||
; r2 = opus_val32 *xcorr
|
||||
; r3 = int len
|
||||
; output:
|
||||
; r0 = maxcorr
|
||||
; internal usage
|
||||
; r4 = opus_val16 *x
|
||||
; r5 = opus_val16 *y
|
||||
; r6 = opus_val32 sum0
|
||||
; r7 = opus_val32 sum1
|
||||
; r8 = opus_val32 sum2
|
||||
; r9 = opus_val32 sum3
|
||||
; r1 = int max_pitch
|
||||
; r12 = int j
|
||||
STMFD sp!, {r4-r11, lr}
|
||||
MOV r5, r1
|
||||
LDR r1, [sp, #36]
|
||||
MOV r4, r0
|
||||
TST r5, #3
|
||||
; maxcorr = 1
|
||||
MOV r0, #1
|
||||
BEQ celt_pitch_xcorr_edsp_process1u_done
|
||||
; Compute one sum at the start to make y 32-bit aligned.
|
||||
SUBS r12, r3, #4
|
||||
; r14 = sum = 0
|
||||
MOV r14, #0
|
||||
LDRH r8, [r5], #2
|
||||
BLE celt_pitch_xcorr_edsp_process1u_loop4_done
|
||||
LDR r6, [r4], #4
|
||||
MOV r8, r8, LSL #16
|
||||
celt_pitch_xcorr_edsp_process1u_loop4
|
||||
LDR r9, [r5], #4
|
||||
SMLABT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
|
||||
LDR r7, [r4], #4
|
||||
SMLATB r14, r6, r9, r14 ; sum = MAC16_16(sum, x_1, y_1)
|
||||
LDR r8, [r5], #4
|
||||
SMLABT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2)
|
||||
SUBS r12, r12, #4 ; j-=4
|
||||
SMLATB r14, r7, r8, r14 ; sum = MAC16_16(sum, x_3, y_3)
|
||||
LDRGT r6, [r4], #4
|
||||
BGT celt_pitch_xcorr_edsp_process1u_loop4
|
||||
MOV r8, r8, LSR #16
|
||||
celt_pitch_xcorr_edsp_process1u_loop4_done
|
||||
ADDS r12, r12, #4
|
||||
celt_pitch_xcorr_edsp_process1u_loop1
|
||||
LDRGEH r6, [r4], #2
|
||||
; Stall
|
||||
SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y)
|
||||
SUBGES r12, r12, #1
|
||||
LDRGTH r8, [r5], #2
|
||||
BGT celt_pitch_xcorr_edsp_process1u_loop1
|
||||
; Restore _x
|
||||
SUB r4, r4, r3, LSL #1
|
||||
; Restore and advance _y
|
||||
SUB r5, r5, r3, LSL #1
|
||||
; maxcorr = max(maxcorr, sum)
|
||||
CMP r0, r14
|
||||
ADD r5, r5, #2
|
||||
MOVLT r0, r14
|
||||
SUBS r1, r1, #1
|
||||
; xcorr[i] = sum
|
||||
STR r14, [r2], #4
|
||||
BLE celt_pitch_xcorr_edsp_done
|
||||
celt_pitch_xcorr_edsp_process1u_done
|
||||
; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2
|
||||
SUBS r1, r1, #4
|
||||
BLT celt_pitch_xcorr_edsp_process2
|
||||
celt_pitch_xcorr_edsp_process4
|
||||
; xcorr_kernel_edsp parameters:
|
||||
; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0}
|
||||
MOV r6, #0
|
||||
MOV r7, #0
|
||||
MOV r8, #0
|
||||
MOV r9, #0
|
||||
BL xcorr_kernel_edsp ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len)
|
||||
; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3)
|
||||
CMP r0, r6
|
||||
; _y+=4
|
||||
ADD r5, r5, #8
|
||||
MOVLT r0, r6
|
||||
CMP r0, r7
|
||||
MOVLT r0, r7
|
||||
CMP r0, r8
|
||||
MOVLT r0, r8
|
||||
CMP r0, r9
|
||||
MOVLT r0, r9
|
||||
STMIA r2!, {r6-r9}
|
||||
SUBS r1, r1, #4
|
||||
BGE celt_pitch_xcorr_edsp_process4
|
||||
celt_pitch_xcorr_edsp_process2
|
||||
ADDS r1, r1, #2
|
||||
BLT celt_pitch_xcorr_edsp_process1a
|
||||
SUBS r12, r3, #4
|
||||
; {r10, r11} = {sum0, sum1} = {0, 0}
|
||||
MOV r10, #0
|
||||
MOV r11, #0
|
||||
LDR r8, [r5], #4
|
||||
BLE celt_pitch_xcorr_edsp_process2_loop_done
|
||||
LDR r6, [r4], #4
|
||||
LDR r9, [r5], #4
|
||||
celt_pitch_xcorr_edsp_process2_loop4
|
||||
SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
|
||||
LDR r7, [r4], #4
|
||||
SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
|
||||
SUBS r12, r12, #4 ; j-=4
|
||||
SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1)
|
||||
LDR r8, [r5], #4
|
||||
SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2)
|
||||
LDRGT r6, [r4], #4
|
||||
SMLABB r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_2, y_2)
|
||||
SMLABT r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_2, y_3)
|
||||
SMLATT r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_3, y_3)
|
||||
LDRGT r9, [r5], #4
|
||||
SMLATB r11, r7, r8, r11 ; sum1 = MAC16_16(sum1, x_3, y_4)
|
||||
BGT celt_pitch_xcorr_edsp_process2_loop4
|
||||
celt_pitch_xcorr_edsp_process2_loop_done
|
||||
ADDS r12, r12, #2
|
||||
BLE celt_pitch_xcorr_edsp_process2_1
|
||||
LDR r6, [r4], #4
|
||||
; Stall
|
||||
SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
|
||||
LDR r9, [r5], #4
|
||||
SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
|
||||
SUB r12, r12, #2
|
||||
SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1)
|
||||
MOV r8, r9
|
||||
SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2)
|
||||
celt_pitch_xcorr_edsp_process2_1
|
||||
LDRH r6, [r4], #2
|
||||
ADDS r12, r12, #1
|
||||
; Stall
|
||||
SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
|
||||
LDRGTH r7, [r4], #2
|
||||
SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
|
||||
BLE celt_pitch_xcorr_edsp_process2_done
|
||||
LDRH r9, [r5], #2
|
||||
SMLABT r10, r7, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_1)
|
||||
SMLABB r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_0, y_2)
|
||||
celt_pitch_xcorr_edsp_process2_done
|
||||
; Restore _x
|
||||
SUB r4, r4, r3, LSL #1
|
||||
; Restore and advance _y
|
||||
SUB r5, r5, r3, LSL #1
|
||||
; maxcorr = max(maxcorr, sum0)
|
||||
CMP r0, r10
|
||||
ADD r5, r5, #2
|
||||
MOVLT r0, r10
|
||||
SUB r1, r1, #2
|
||||
; maxcorr = max(maxcorr, sum1)
|
||||
CMP r0, r11
|
||||
; xcorr[i] = sum
|
||||
STR r10, [r2], #4
|
||||
MOVLT r0, r11
|
||||
STR r11, [r2], #4
|
||||
celt_pitch_xcorr_edsp_process1a
|
||||
ADDS r1, r1, #1
|
||||
BLT celt_pitch_xcorr_edsp_done
|
||||
SUBS r12, r3, #4
|
||||
; r14 = sum = 0
|
||||
MOV r14, #0
|
||||
BLT celt_pitch_xcorr_edsp_process1a_loop_done
|
||||
LDR r6, [r4], #4
|
||||
LDR r8, [r5], #4
|
||||
LDR r7, [r4], #4
|
||||
LDR r9, [r5], #4
|
||||
celt_pitch_xcorr_edsp_process1a_loop4
|
||||
SMLABB r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
|
||||
SUBS r12, r12, #4 ; j-=4
|
||||
SMLATT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1)
|
||||
LDRGE r6, [r4], #4
|
||||
SMLABB r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2)
|
||||
LDRGE r8, [r5], #4
|
||||
SMLATT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_3, y_3)
|
||||
LDRGE r7, [r4], #4
|
||||
LDRGE r9, [r5], #4
|
||||
BGE celt_pitch_xcorr_edsp_process1a_loop4
|
||||
celt_pitch_xcorr_edsp_process1a_loop_done
|
||||
ADDS r12, r12, #2
|
||||
LDRGE r6, [r4], #4
|
||||
LDRGE r8, [r5], #4
|
||||
; Stall
|
||||
SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
|
||||
SUBGE r12, r12, #2
|
||||
SMLATTGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1)
|
||||
ADDS r12, r12, #1
|
||||
LDRGEH r6, [r4], #2
|
||||
LDRGEH r8, [r5], #2
|
||||
; Stall
|
||||
SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y)
|
||||
; maxcorr = max(maxcorr, sum)
|
||||
CMP r0, r14
|
||||
; xcorr[i] = sum
|
||||
STR r14, [r2], #4
|
||||
MOVLT r0, r14
|
||||
celt_pitch_xcorr_edsp_done
|
||||
LDMFD sp!, {r4-r11, pc}
|
||||
ENDP
|
||||
|
||||
ENDIF
|
||||
|
||||
END
|
|
@ -0,0 +1,76 @@
|
|||
/* Copyright (C) 2013 Xiph.Org Foundation and contributors */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_ARMv4_H
|
||||
#define FIXED_ARMv4_H
|
||||
|
||||
/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
|
||||
#undef MULT16_32_Q16
|
||||
static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b)
|
||||
{
|
||||
unsigned rd_lo;
|
||||
int rd_hi;
|
||||
__asm__(
|
||||
"#MULT16_32_Q16\n\t"
|
||||
"smull %0, %1, %2, %3\n\t"
|
||||
: "=&r"(rd_lo), "=&r"(rd_hi)
|
||||
: "%r"(b),"r"(a<<16)
|
||||
);
|
||||
return rd_hi;
|
||||
}
|
||||
#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b))
|
||||
|
||||
|
||||
/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
|
||||
#undef MULT16_32_Q15
|
||||
static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b)
|
||||
{
|
||||
unsigned rd_lo;
|
||||
int rd_hi;
|
||||
__asm__(
|
||||
"#MULT16_32_Q15\n\t"
|
||||
"smull %0, %1, %2, %3\n\t"
|
||||
: "=&r"(rd_lo), "=&r"(rd_hi)
|
||||
: "%r"(b), "r"(a<<16)
|
||||
);
|
||||
/*We intentionally don't OR in the high bit of rd_lo for speed.*/
|
||||
return rd_hi<<1;
|
||||
}
|
||||
#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b))
|
||||
|
||||
|
||||
/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
|
||||
b must fit in 31 bits.
|
||||
Result fits in 32 bits. */
|
||||
#undef MAC16_32_Q15
|
||||
#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b))
|
||||
|
||||
|
||||
/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
|
||||
#undef MULT32_32_Q31
|
||||
#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,116 @@
|
|||
/* Copyright (C) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (C) 2003-2008 Jean-Marc Valin
|
||||
Copyright (C) 2007-2008 CSIRO
|
||||
Copyright (C) 2013 Parrot */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_ARMv5E_H
|
||||
#define FIXED_ARMv5E_H
|
||||
|
||||
#include "fixed_armv4.h"
|
||||
|
||||
/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
|
||||
#undef MULT16_32_Q16
|
||||
static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b)
|
||||
{
|
||||
int res;
|
||||
__asm__(
|
||||
"#MULT16_32_Q16\n\t"
|
||||
"smulwb %0, %1, %2\n\t"
|
||||
: "=r"(res)
|
||||
: "r"(b),"r"(a)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b))
|
||||
|
||||
|
||||
/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
|
||||
#undef MULT16_32_Q15
|
||||
static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b)
|
||||
{
|
||||
int res;
|
||||
__asm__(
|
||||
"#MULT16_32_Q15\n\t"
|
||||
"smulwb %0, %1, %2\n\t"
|
||||
: "=r"(res)
|
||||
: "r"(b), "r"(a)
|
||||
);
|
||||
return res<<1;
|
||||
}
|
||||
#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b))
|
||||
|
||||
|
||||
/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
|
||||
b must fit in 31 bits.
|
||||
Result fits in 32 bits. */
|
||||
#undef MAC16_32_Q15
|
||||
static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a,
|
||||
opus_val32 b)
|
||||
{
|
||||
int res;
|
||||
__asm__(
|
||||
"#MAC16_32_Q15\n\t"
|
||||
"smlawb %0, %1, %2, %3;\n"
|
||||
: "=r"(res)
|
||||
: "r"(b<<1), "r"(a), "r"(c)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b))
|
||||
|
||||
/** 16x16 multiply-add where the result fits in 32 bits */
|
||||
#undef MAC16_16
|
||||
static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a,
|
||||
opus_val16 b)
|
||||
{
|
||||
int res;
|
||||
__asm__(
|
||||
"#MAC16_16\n\t"
|
||||
"smlabb %0, %1, %2, %3;\n"
|
||||
: "=r"(res)
|
||||
: "r"(a), "r"(b), "r"(c)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b))
|
||||
|
||||
/** 16x16 multiplication where the result fits in 32 bits */
|
||||
#undef MULT16_16
|
||||
static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b)
|
||||
{
|
||||
int res;
|
||||
__asm__(
|
||||
"#MULT16_16\n\t"
|
||||
"smulbb %0, %1, %2;\n"
|
||||
: "=r"(res)
|
||||
: "r"(a), "r"(b)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
#define MULT16_16(a, b) (MULT16_16_armv5e(a, b))
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.*/
|
||||
|
||||
#ifndef KISS_FFT_ARMv4_H
|
||||
#define KISS_FFT_ARMv4_H
|
||||
|
||||
#if !defined(KISS_FFT_GUTS_H)
|
||||
#error "This file should only be included from _kiss_fft_guts.h"
|
||||
#endif
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
|
||||
#undef C_MUL
|
||||
#define C_MUL(m,a,b) \
|
||||
do{ \
|
||||
int br__; \
|
||||
int bi__; \
|
||||
int tt__; \
|
||||
__asm__ __volatile__( \
|
||||
"#C_MUL\n\t" \
|
||||
"ldrsh %[br], [%[bp], #0]\n\t" \
|
||||
"ldm %[ap], {r0,r1}\n\t" \
|
||||
"ldrsh %[bi], [%[bp], #2]\n\t" \
|
||||
"smull %[tt], %[mi], r1, %[br]\n\t" \
|
||||
"smlal %[tt], %[mi], r0, %[bi]\n\t" \
|
||||
"rsb %[bi], %[bi], #0\n\t" \
|
||||
"smull %[br], %[mr], r0, %[br]\n\t" \
|
||||
"mov %[tt], %[tt], lsr #15\n\t" \
|
||||
"smlal %[br], %[mr], r1, %[bi]\n\t" \
|
||||
"orr %[mi], %[tt], %[mi], lsl #17\n\t" \
|
||||
"mov %[br], %[br], lsr #15\n\t" \
|
||||
"orr %[mr], %[br], %[mr], lsl #17\n\t" \
|
||||
: [mr]"=r"((m).r), [mi]"=r"((m).i), \
|
||||
[br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
|
||||
: [ap]"r"(&(a)), [bp]"r"(&(b)) \
|
||||
: "r0", "r1" \
|
||||
); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#undef C_MUL4
|
||||
#define C_MUL4(m,a,b) \
|
||||
do{ \
|
||||
int br__; \
|
||||
int bi__; \
|
||||
int tt__; \
|
||||
__asm__ __volatile__( \
|
||||
"#C_MUL4\n\t" \
|
||||
"ldrsh %[br], [%[bp], #0]\n\t" \
|
||||
"ldm %[ap], {r0,r1}\n\t" \
|
||||
"ldrsh %[bi], [%[bp], #2]\n\t" \
|
||||
"smull %[tt], %[mi], r1, %[br]\n\t" \
|
||||
"smlal %[tt], %[mi], r0, %[bi]\n\t" \
|
||||
"rsb %[bi], %[bi], #0\n\t" \
|
||||
"smull %[br], %[mr], r0, %[br]\n\t" \
|
||||
"mov %[tt], %[tt], lsr #17\n\t" \
|
||||
"smlal %[br], %[mr], r1, %[bi]\n\t" \
|
||||
"orr %[mi], %[tt], %[mi], lsl #15\n\t" \
|
||||
"mov %[br], %[br], lsr #17\n\t" \
|
||||
"orr %[mr], %[br], %[mr], lsl #15\n\t" \
|
||||
: [mr]"=r"((m).r), [mi]"=r"((m).i), \
|
||||
[br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
|
||||
: [ap]"r"(&(a)), [bp]"r"(&(b)) \
|
||||
: "r0", "r1" \
|
||||
); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#undef C_MULC
|
||||
#define C_MULC(m,a,b) \
|
||||
do{ \
|
||||
int br__; \
|
||||
int bi__; \
|
||||
int tt__; \
|
||||
__asm__ __volatile__( \
|
||||
"#C_MULC\n\t" \
|
||||
"ldrsh %[br], [%[bp], #0]\n\t" \
|
||||
"ldm %[ap], {r0,r1}\n\t" \
|
||||
"ldrsh %[bi], [%[bp], #2]\n\t" \
|
||||
"smull %[tt], %[mr], r0, %[br]\n\t" \
|
||||
"smlal %[tt], %[mr], r1, %[bi]\n\t" \
|
||||
"rsb %[bi], %[bi], #0\n\t" \
|
||||
"smull %[br], %[mi], r1, %[br]\n\t" \
|
||||
"mov %[tt], %[tt], lsr #15\n\t" \
|
||||
"smlal %[br], %[mi], r0, %[bi]\n\t" \
|
||||
"orr %[mr], %[tt], %[mr], lsl #17\n\t" \
|
||||
"mov %[br], %[br], lsr #15\n\t" \
|
||||
"orr %[mi], %[br], %[mi], lsl #17\n\t" \
|
||||
: [mr]"=r"((m).r), [mi]"=r"((m).i), \
|
||||
[br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
|
||||
: [ap]"r"(&(a)), [bp]"r"(&(b)) \
|
||||
: "r0", "r1" \
|
||||
); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#endif /* OPUS_FIXED_POINT */
|
||||
|
||||
#endif /* KISS_FFT_ARMv4_H */
|
|
@ -0,0 +1,118 @@
|
|||
/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.*/
|
||||
|
||||
#ifndef KISS_FFT_ARMv5E_H
|
||||
#define KISS_FFT_ARMv5E_H
|
||||
|
||||
#if !defined(KISS_FFT_GUTS_H)
|
||||
#error "This file should only be included from _kiss_fft_guts.h"
|
||||
#endif
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
|
||||
#if defined(__thumb__)||defined(__thumb2__)
|
||||
#define LDRD_CONS "Q"
|
||||
#else
|
||||
#define LDRD_CONS "Uq"
|
||||
#endif
|
||||
|
||||
#undef C_MUL
|
||||
#define C_MUL(m,a,b) \
|
||||
do{ \
|
||||
int mr1__; \
|
||||
int mr2__; \
|
||||
int mi__; \
|
||||
long long aval__; \
|
||||
int bval__; \
|
||||
__asm__( \
|
||||
"#C_MUL\n\t" \
|
||||
"ldrd %[aval], %H[aval], %[ap]\n\t" \
|
||||
"ldr %[bval], %[bp]\n\t" \
|
||||
"smulwb %[mi], %H[aval], %[bval]\n\t" \
|
||||
"smulwb %[mr1], %[aval], %[bval]\n\t" \
|
||||
"smulwt %[mr2], %H[aval], %[bval]\n\t" \
|
||||
"smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
|
||||
: [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
|
||||
[aval]"=&r"(aval__), [bval]"=r"(bval__) \
|
||||
: [ap]LDRD_CONS(a), [bp]"m"(b) \
|
||||
); \
|
||||
(m).r = SHL32(SUB32(mr1__, mr2__), 1); \
|
||||
(m).i = SHL32(mi__, 1); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#undef C_MUL4
|
||||
#define C_MUL4(m,a,b) \
|
||||
do{ \
|
||||
int mr1__; \
|
||||
int mr2__; \
|
||||
int mi__; \
|
||||
long long aval__; \
|
||||
int bval__; \
|
||||
__asm__( \
|
||||
"#C_MUL4\n\t" \
|
||||
"ldrd %[aval], %H[aval], %[ap]\n\t" \
|
||||
"ldr %[bval], %[bp]\n\t" \
|
||||
"smulwb %[mi], %H[aval], %[bval]\n\t" \
|
||||
"smulwb %[mr1], %[aval], %[bval]\n\t" \
|
||||
"smulwt %[mr2], %H[aval], %[bval]\n\t" \
|
||||
"smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
|
||||
: [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
|
||||
[aval]"=&r"(aval__), [bval]"=r"(bval__) \
|
||||
: [ap]LDRD_CONS(a), [bp]"m"(b) \
|
||||
); \
|
||||
(m).r = SHR32(SUB32(mr1__, mr2__), 1); \
|
||||
(m).i = SHR32(mi__, 1); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#undef C_MULC
|
||||
#define C_MULC(m,a,b) \
|
||||
do{ \
|
||||
int mr__; \
|
||||
int mi1__; \
|
||||
int mi2__; \
|
||||
long long aval__; \
|
||||
int bval__; \
|
||||
__asm__( \
|
||||
"#C_MULC\n\t" \
|
||||
"ldrd %[aval], %H[aval], %[ap]\n\t" \
|
||||
"ldr %[bval], %[bp]\n\t" \
|
||||
"smulwb %[mr], %[aval], %[bval]\n\t" \
|
||||
"smulwb %[mi1], %H[aval], %[bval]\n\t" \
|
||||
"smulwt %[mi2], %[aval], %[bval]\n\t" \
|
||||
"smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \
|
||||
: [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \
|
||||
[aval]"=&r"(aval__), [bval]"=r"(bval__) \
|
||||
: [ap]LDRD_CONS(a), [bp]"m"(b) \
|
||||
); \
|
||||
(m).r = SHL32(mr__, 1); \
|
||||
(m).i = SHL32(SUB32(mi1__, mi2__), 1); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#endif /* OPUS_FIXED_POINT */
|
||||
|
||||
#endif /* KISS_FFT_GUTS_H */
|
|
@ -0,0 +1,57 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation
|
||||
* Copyright (c) 2013 Parrot */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !defined(PITCH_ARM_H)
|
||||
# define PITCH_ARM_H
|
||||
|
||||
# include "armcpu.h"
|
||||
|
||||
# if defined(OPUS_FIXED_POINT)
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON)
|
||||
opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
|
||||
# define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr)
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_EDSP)
|
||||
opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
# endif
|
||||
|
||||
# if !defined(OPUS_HAVE_RTCD)
|
||||
# define OVERRIDE_PITCH_XCORR (1)
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((void)(arch),PRESUME_NEON(celt_pitch_xcorr)(_x, _y, xcorr, len, max_pitch))
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,114 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2008-2009 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BANDS_H
|
||||
#define BANDS_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "opus_modes.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
#include "rate.h"
|
||||
|
||||
/** Compute the amplitude (sqrt energy) in each of the bands
|
||||
* @param m Mode data
|
||||
* @param X Spectrum
|
||||
* @param bandE Square root of the energy for each band (returned)
|
||||
*/
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int M);
|
||||
|
||||
/*void compute_noise_energies(const CELTMode *m, const celt_sig *X, const opus_val16 *tonality, celt_ener *bandE);*/
|
||||
|
||||
/** Normalise each band of X such that the energy in each band is
|
||||
equal to 1
|
||||
* @param m Mode data
|
||||
* @param X Spectrum (returned normalised)
|
||||
* @param bandE Square root of the energy for each band
|
||||
*/
|
||||
void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M);
|
||||
|
||||
/** Denormalise each band of X to restore full amplitude
|
||||
* @param m Mode data
|
||||
* @param X Spectrum (returned de-normalised)
|
||||
* @param bandE Square root of the energy for each band
|
||||
*/
|
||||
void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
|
||||
celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandE, int start, int end, int C, int M);
|
||||
|
||||
#define SPREAD_NONE (0)
|
||||
#define SPREAD_LIGHT (1)
|
||||
#define SPREAD_NORMAL (2)
|
||||
#define SPREAD_AGGRESSIVE (3)
|
||||
|
||||
int spreading_decision(const CELTMode *m, celt_norm *X, int *average,
|
||||
int last_decision, int *hf_average, int *tapset_decision, int update_hf,
|
||||
int end, int C, int M);
|
||||
|
||||
#ifdef MEASURE_NORM_MSE
|
||||
void measure_norm_mse(const CELTMode *m, float *X, float *X0, float *bandE, float *bandE0, int M, int N, int C);
|
||||
#endif
|
||||
|
||||
void haar1(celt_norm *X, int N0, int stride);
|
||||
|
||||
/** Quantisation/encoding of the residual spectrum
|
||||
* @param encode flag that indicates whether we're encoding (1) or decoding (0)
|
||||
* @param m Mode data
|
||||
* @param start First band to process
|
||||
* @param end Last band to process + 1
|
||||
* @param X Residual (normalised)
|
||||
* @param Y Residual (normalised) for second channel (or NULL for mono)
|
||||
* @param collapse_masks Anti-collapse tracking mask
|
||||
* @param bandE Square root of the energy for each band
|
||||
* @param pulses Bit allocation (per band) for PVQ
|
||||
* @param shortBlocks Zero for long blocks, non-zero for short blocks
|
||||
* @param spread Amount of spreading to use
|
||||
* @param dual_stereo Zero for MS stereo, non-zero for dual stereo
|
||||
* @param intensity First band to use intensity stereo
|
||||
* @param tf_res Time-frequency resolution change
|
||||
* @param total_bits Total number of bits that can be used for the frame (including the ones already spent)
|
||||
* @param balance Number of unallocated bits
|
||||
* @param en Entropy coder state
|
||||
* @param LM log2() of the number of 2.5 subframes in the frame
|
||||
* @param codedBands Last band to receive bits + 1
|
||||
* @param seed Random generator seed
|
||||
*/
|
||||
void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
||||
celt_norm * X, celt_norm * Y, unsigned char *collapse_masks, const celt_ener *bandE, int *pulses,
|
||||
int shortBlocks, int spread, int dual_stereo, int intensity, int *tf_res,
|
||||
opus_int32 total_bits, opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed);
|
||||
|
||||
void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_masks, int LM, int C, int size,
|
||||
int start, int end, opus_val16 *logE, opus_val16 *prev1logE,
|
||||
opus_val16 *prev2logE, int *pulses, opus_uint32 seed);
|
||||
|
||||
opus_uint32 celt_lcg_rand(opus_uint32 seed);
|
||||
|
||||
int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev);
|
||||
|
||||
#endif /* BANDS_H */
|
|
@ -0,0 +1,223 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2010 Xiph.Org Foundation
|
||||
Copyright (c) 2008 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
|
||||
#include "os_support.h"
|
||||
#include "mdct.h"
|
||||
#include <math.h>
|
||||
#include "celt.h"
|
||||
#include "pitch.h"
|
||||
#include "bands.h"
|
||||
#include "opus_modes.h"
|
||||
#include "entcode.h"
|
||||
#include "quant_bands.h"
|
||||
#include "rate.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "mathops.h"
|
||||
#include "float_cast.h"
|
||||
#include <stdarg.h>
|
||||
#include "celt_lpc.h"
|
||||
#include "vq.h"
|
||||
|
||||
#ifndef PACKAGE_VERSION
|
||||
#define PACKAGE_VERSION "unknown"
|
||||
#endif
|
||||
|
||||
|
||||
int resampling_factor(opus_int32 rate)
|
||||
{
|
||||
int ret;
|
||||
switch (rate)
|
||||
{
|
||||
case 48000:
|
||||
ret = 1;
|
||||
break;
|
||||
case 24000:
|
||||
ret = 2;
|
||||
break;
|
||||
case 16000:
|
||||
ret = 3;
|
||||
break;
|
||||
case 12000:
|
||||
ret = 4;
|
||||
break;
|
||||
case 8000:
|
||||
ret = 6;
|
||||
break;
|
||||
default:
|
||||
#ifndef CUSTOM_MODES
|
||||
celt_assert(0);
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef OVERRIDE_COMB_FILTER_CONST
|
||||
static void comb_filter_const(opus_val32 *y, opus_val32 *x, int T, int N,
|
||||
opus_val16 g10, opus_val16 g11, opus_val16 g12)
|
||||
{
|
||||
opus_val32 x0, x1, x2, x3, x4;
|
||||
int i;
|
||||
x4 = x[-T-2];
|
||||
x3 = x[-T-1];
|
||||
x2 = x[-T];
|
||||
x1 = x[-T+1];
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
x0=x[i-T+2];
|
||||
y[i] = x[i]
|
||||
+ MULT16_32_Q15(g10,x2)
|
||||
+ MULT16_32_Q15(g11,ADD32(x1,x3))
|
||||
+ MULT16_32_Q15(g12,ADD32(x0,x4));
|
||||
x4=x3;
|
||||
x3=x2;
|
||||
x2=x1;
|
||||
x1=x0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
|
||||
opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
|
||||
const opus_val16 *window, int overlap)
|
||||
{
|
||||
int i;
|
||||
/* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
|
||||
opus_val16 g00, g01, g02, g10, g11, g12;
|
||||
opus_val32 x0, x1, x2, x3, x4;
|
||||
static const opus_val16 gains[3][3] = {
|
||||
{QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)},
|
||||
{QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)},
|
||||
{QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}};
|
||||
|
||||
if (g0==0 && g1==0)
|
||||
{
|
||||
/* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
|
||||
if (x!=y)
|
||||
OPUS_MOVE(y, x, N);
|
||||
return;
|
||||
}
|
||||
g00 = MULT16_16_Q15(g0, gains[tapset0][0]);
|
||||
g01 = MULT16_16_Q15(g0, gains[tapset0][1]);
|
||||
g02 = MULT16_16_Q15(g0, gains[tapset0][2]);
|
||||
g10 = MULT16_16_Q15(g1, gains[tapset1][0]);
|
||||
g11 = MULT16_16_Q15(g1, gains[tapset1][1]);
|
||||
g12 = MULT16_16_Q15(g1, gains[tapset1][2]);
|
||||
x1 = x[-T1+1];
|
||||
x2 = x[-T1 ];
|
||||
x3 = x[-T1-1];
|
||||
x4 = x[-T1-2];
|
||||
for (i=0;i<overlap;i++)
|
||||
{
|
||||
opus_val16 f;
|
||||
x0=x[i-T1+2];
|
||||
f = MULT16_16_Q15(window[i],window[i]);
|
||||
y[i] = x[i]
|
||||
+ MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g00),x[i-T0])
|
||||
+ MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g01),ADD32(x[i-T0+1],x[i-T0-1]))
|
||||
+ MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g02),ADD32(x[i-T0+2],x[i-T0-2]))
|
||||
+ MULT16_32_Q15(MULT16_16_Q15(f,g10),x2)
|
||||
+ MULT16_32_Q15(MULT16_16_Q15(f,g11),ADD32(x1,x3))
|
||||
+ MULT16_32_Q15(MULT16_16_Q15(f,g12),ADD32(x0,x4));
|
||||
x4=x3;
|
||||
x3=x2;
|
||||
x2=x1;
|
||||
x1=x0;
|
||||
|
||||
}
|
||||
if (g1==0)
|
||||
{
|
||||
/* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
|
||||
if (x!=y)
|
||||
OPUS_MOVE(y+overlap, x+overlap, N-overlap);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compute the part with the constant filter. */
|
||||
comb_filter_const(y+i, x+i, T1, N-i, g10, g11, g12);
|
||||
}
|
||||
|
||||
const signed char tf_select_table[4][8] = {
|
||||
{0, -1, 0, -1, 0,-1, 0,-1},
|
||||
{0, -1, 0, -2, 1, 0, 1,-1},
|
||||
{0, -2, 0, -3, 2, 0, 1,-1},
|
||||
{0, -2, 0, -3, 3, 0, 1,-1},
|
||||
};
|
||||
|
||||
|
||||
void init_caps(const CELTMode *m,int *cap,int LM,int C)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<m->nbEBands;i++)
|
||||
{
|
||||
int N;
|
||||
N=(m->eBands[i+1]-m->eBands[i])<<LM;
|
||||
cap[i] = (m->cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *opus_strerror(int error)
|
||||
{
|
||||
static const char * const error_strings[8] = {
|
||||
"success",
|
||||
"invalid argument",
|
||||
"buffer too small",
|
||||
"internal error",
|
||||
"corrupted stream",
|
||||
"request not implemented",
|
||||
"invalid state",
|
||||
"memory allocation failed"
|
||||
};
|
||||
if (error > 0 || error < -7)
|
||||
return "unknown error";
|
||||
else
|
||||
return error_strings[-error];
|
||||
}
|
||||
|
||||
const char *opus_get_version_string(void)
|
||||
{
|
||||
return "libopus " PACKAGE_VERSION
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
"-fixed"
|
||||
#endif
|
||||
#ifdef FUZZING
|
||||
"-fuzzing"
|
||||
#endif
|
||||
;
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2008 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/**
|
||||
@file celt.h
|
||||
@brief Contains all the functions for encoding and decoding audio
|
||||
*/
|
||||
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CELT_H
|
||||
#define CELT_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
#include "opus_custom.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
#include "arch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CELTEncoder OpusCustomEncoder
|
||||
#define CELTDecoder OpusCustomDecoder
|
||||
#define CELTMode OpusCustomMode
|
||||
|
||||
typedef struct {
|
||||
int valid;
|
||||
float tonality;
|
||||
float tonality_slope;
|
||||
float noisiness;
|
||||
float activity;
|
||||
float music_prob;
|
||||
int bandwidth;
|
||||
}AnalysisInfo;
|
||||
|
||||
#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr)))
|
||||
|
||||
#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr)))
|
||||
|
||||
/* Encoder/decoder Requests */
|
||||
|
||||
/* Expose this option again when variable framesize actually works */
|
||||
#define OPUS_FRAMESIZE_VARIABLE 5010 /**< Optimize the frame size dynamically */
|
||||
|
||||
|
||||
#define CELT_SET_PREDICTION_REQUEST 10002
|
||||
/** Controls the use of interframe prediction.
|
||||
0=Independent frames
|
||||
1=Short term interframe prediction allowed
|
||||
2=Long term prediction allowed
|
||||
*/
|
||||
#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define CELT_SET_INPUT_CLIPPING_REQUEST 10004
|
||||
#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007
|
||||
#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
#define CELT_SET_CHANNELS_REQUEST 10008
|
||||
#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x)
|
||||
|
||||
|
||||
/* Internal */
|
||||
#define CELT_SET_START_BAND_REQUEST 10010
|
||||
#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define CELT_SET_END_BAND_REQUEST 10012
|
||||
#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define CELT_GET_MODE_REQUEST 10015
|
||||
/** Get the CELTMode used by an encoder or decoder */
|
||||
#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x)
|
||||
|
||||
#define CELT_SET_SIGNALLING_REQUEST 10016
|
||||
#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define CELT_SET_TONALITY_REQUEST 10018
|
||||
#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x)
|
||||
#define CELT_SET_TONALITY_SLOPE_REQUEST 10020
|
||||
#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define CELT_SET_ANALYSIS_REQUEST 10022
|
||||
#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x)
|
||||
|
||||
#define OPUS_SET_LFE_REQUEST 10024
|
||||
#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x)
|
||||
|
||||
#define OPUS_SET_ENERGY_MASK_REQUEST 10026
|
||||
#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x)
|
||||
|
||||
/* Encoder stuff */
|
||||
|
||||
int celt_encoder_get_size(int channels);
|
||||
|
||||
int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
|
||||
|
||||
int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
|
||||
int arch);
|
||||
|
||||
|
||||
|
||||
/* Decoder stuff */
|
||||
|
||||
int celt_decoder_get_size(int channels);
|
||||
|
||||
|
||||
int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels);
|
||||
|
||||
int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec);
|
||||
|
||||
#define celt_encoder_ctl opus_custom_encoder_ctl
|
||||
#define celt_decoder_ctl opus_custom_decoder_ctl
|
||||
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
#define OPUS_CUSTOM_NOSTATIC
|
||||
#else
|
||||
#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE
|
||||
#endif
|
||||
|
||||
static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0};
|
||||
/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */
|
||||
static const unsigned char spread_icdf[4] = {25, 23, 2, 0};
|
||||
|
||||
static const unsigned char tapset_icdf[3]={2,1,0};
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
static const unsigned char toOpusTable[20] = {
|
||||
0xE0, 0xE8, 0xF0, 0xF8,
|
||||
0xC0, 0xC8, 0xD0, 0xD8,
|
||||
0xA0, 0xA8, 0xB0, 0xB8,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x88, 0x90, 0x98,
|
||||
};
|
||||
|
||||
static const unsigned char fromOpusTable[16] = {
|
||||
0x80, 0x88, 0x90, 0x98,
|
||||
0x40, 0x48, 0x50, 0x58,
|
||||
0x20, 0x28, 0x30, 0x38,
|
||||
0x00, 0x08, 0x10, 0x18
|
||||
};
|
||||
|
||||
static OPUS_INLINE int toOpus(unsigned char c)
|
||||
{
|
||||
int ret=0;
|
||||
if (c<0xA0)
|
||||
ret = toOpusTable[c>>3];
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
else
|
||||
return ret|(c&0x7);
|
||||
}
|
||||
|
||||
static OPUS_INLINE int fromOpus(unsigned char c)
|
||||
{
|
||||
if (c<0x80)
|
||||
return -1;
|
||||
else
|
||||
return fromOpusTable[(c>>3)-16] | (c&0x7);
|
||||
}
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
#define COMBFILTER_MAXPERIOD 1024
|
||||
#define COMBFILTER_MINPERIOD 15
|
||||
|
||||
extern const signed char tf_select_table[4][8];
|
||||
|
||||
int resampling_factor(opus_int32 rate);
|
||||
|
||||
void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
|
||||
int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip);
|
||||
|
||||
void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
|
||||
opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
|
||||
const opus_val16 *window, int overlap);
|
||||
|
||||
void init_caps(const CELTMode *m,int *cap,int LM,int C);
|
||||
|
||||
#ifdef RESYNTH
|
||||
void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem, celt_sig * OPUS_RESTRICT scratch);
|
||||
|
||||
void compute_inv_mdcts(const CELTMode *mode, int shortBlocks, celt_sig *X,
|
||||
celt_sig * OPUS_RESTRICT out_mem[], int C, int LM);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CELT_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,309 @@
|
|||
/* Copyright (c) 2009-2010 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "celt_lpc.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "mathops.h"
|
||||
#include "pitch.h"
|
||||
|
||||
void _celt_lpc(
|
||||
opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */
|
||||
const opus_val32 *ac, /* in: [0...p] autocorrelation values */
|
||||
int p
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
opus_val32 r;
|
||||
opus_val32 error = ac[0];
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32 lpc[LPC_ORDER];
|
||||
#else
|
||||
float *lpc = _lpc;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < p; i++)
|
||||
lpc[i] = 0;
|
||||
if (ac[0] != 0)
|
||||
{
|
||||
for (i = 0; i < p; i++) {
|
||||
/* Sum up this iteration's reflection coefficient */
|
||||
opus_val32 rr = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
rr += MULT32_32_Q31(lpc[j],ac[i - j]);
|
||||
rr += SHR32(ac[i + 1],3);
|
||||
r = -frac_div32(SHL32(rr,3), error);
|
||||
/* Update LPC coefficients and total error */
|
||||
lpc[i] = SHR32(r,3);
|
||||
for (j = 0; j < (i+1)>>1; j++)
|
||||
{
|
||||
opus_val32 tmp1, tmp2;
|
||||
tmp1 = lpc[j];
|
||||
tmp2 = lpc[i-1-j];
|
||||
lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2);
|
||||
lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
|
||||
}
|
||||
|
||||
error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
|
||||
/* Bail out once we get 30 dB gain */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
if (error<SHR32(ac[0],10))
|
||||
break;
|
||||
#else
|
||||
if (error<.001f*ac[0])
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
for (i=0;i<p;i++)
|
||||
_lpc[i] = ROUND16(lpc[i],16);
|
||||
#endif
|
||||
}
|
||||
|
||||
void celt_fir(const opus_val16 *_x,
|
||||
const opus_val16 *num,
|
||||
opus_val16 *_y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem)
|
||||
{
|
||||
int i,j;
|
||||
VARDECL(opus_val16, rnum);
|
||||
VARDECL(opus_val16, x);
|
||||
SAVE_STACK;
|
||||
|
||||
ALLOC(rnum, ord, opus_val16);
|
||||
ALLOC(x, N+ord, opus_val16);
|
||||
for(i=0;i<ord;i++)
|
||||
rnum[i] = num[ord-i-1];
|
||||
for(i=0;i<ord;i++)
|
||||
x[i] = mem[ord-i-1];
|
||||
for (i=0;i<N;i++)
|
||||
x[i+ord]=_x[i];
|
||||
for(i=0;i<ord;i++)
|
||||
mem[i] = _x[N-i-1];
|
||||
#ifdef SMALL_FOOTPRINT
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
|
||||
for (j=0;j<ord;j++)
|
||||
{
|
||||
sum = MAC16_16(sum,rnum[j],x[i+j]);
|
||||
}
|
||||
_y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
|
||||
}
|
||||
#else
|
||||
for (i=0;i<N-3;i+=4)
|
||||
{
|
||||
opus_val32 sum[4]={0,0,0,0};
|
||||
xcorr_kernel(rnum, x+i, sum, ord);
|
||||
_y[i ] = SATURATE16(ADD32(EXTEND32(_x[i ]), PSHR32(sum[0], SIG_SHIFT)));
|
||||
_y[i+1] = SATURATE16(ADD32(EXTEND32(_x[i+1]), PSHR32(sum[1], SIG_SHIFT)));
|
||||
_y[i+2] = SATURATE16(ADD32(EXTEND32(_x[i+2]), PSHR32(sum[2], SIG_SHIFT)));
|
||||
_y[i+3] = SATURATE16(ADD32(EXTEND32(_x[i+3]), PSHR32(sum[3], SIG_SHIFT)));
|
||||
}
|
||||
for (;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = 0;
|
||||
for (j=0;j<ord;j++)
|
||||
sum = MAC16_16(sum,rnum[j],x[i+j]);
|
||||
_y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
|
||||
}
|
||||
#endif
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
void celt_iir(const opus_val32 *_x,
|
||||
const opus_val16 *den,
|
||||
opus_val32 *_y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem)
|
||||
{
|
||||
#ifdef SMALL_FOOTPRINT
|
||||
int i,j;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = _x[i];
|
||||
for (j=0;j<ord;j++)
|
||||
{
|
||||
sum -= MULT16_16(den[j],mem[j]);
|
||||
}
|
||||
for (j=ord-1;j>=1;j--)
|
||||
{
|
||||
mem[j]=mem[j-1];
|
||||
}
|
||||
mem[0] = ROUND16(sum,SIG_SHIFT);
|
||||
_y[i] = sum;
|
||||
}
|
||||
#else
|
||||
int i,j;
|
||||
VARDECL(opus_val16, rden);
|
||||
VARDECL(opus_val16, y);
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert((ord&3)==0);
|
||||
ALLOC(rden, ord, opus_val16);
|
||||
ALLOC(y, N+ord, opus_val16);
|
||||
for(i=0;i<ord;i++)
|
||||
rden[i] = den[ord-i-1];
|
||||
for(i=0;i<ord;i++)
|
||||
y[i] = -mem[ord-i-1];
|
||||
for(;i<N+ord;i++)
|
||||
y[i]=0;
|
||||
for (i=0;i<N-3;i+=4)
|
||||
{
|
||||
/* Unroll by 4 as if it were an FIR filter */
|
||||
opus_val32 sum[4];
|
||||
sum[0]=_x[i];
|
||||
sum[1]=_x[i+1];
|
||||
sum[2]=_x[i+2];
|
||||
sum[3]=_x[i+3];
|
||||
xcorr_kernel(rden, y+i, sum, ord);
|
||||
|
||||
/* Patch up the result to compensate for the fact that this is an IIR */
|
||||
y[i+ord ] = -ROUND16(sum[0],SIG_SHIFT);
|
||||
_y[i ] = sum[0];
|
||||
sum[1] = MAC16_16(sum[1], y[i+ord ], den[0]);
|
||||
y[i+ord+1] = -ROUND16(sum[1],SIG_SHIFT);
|
||||
_y[i+1] = sum[1];
|
||||
sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]);
|
||||
sum[2] = MAC16_16(sum[2], y[i+ord ], den[1]);
|
||||
y[i+ord+2] = -ROUND16(sum[2],SIG_SHIFT);
|
||||
_y[i+2] = sum[2];
|
||||
|
||||
sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]);
|
||||
sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]);
|
||||
sum[3] = MAC16_16(sum[3], y[i+ord ], den[2]);
|
||||
y[i+ord+3] = -ROUND16(sum[3],SIG_SHIFT);
|
||||
_y[i+3] = sum[3];
|
||||
}
|
||||
for (;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = _x[i];
|
||||
for (j=0;j<ord;j++)
|
||||
sum -= MULT16_16(rden[j],y[i+j]);
|
||||
y[i+ord] = ROUND16(sum,SIG_SHIFT);
|
||||
_y[i] = sum;
|
||||
}
|
||||
for(i=0;i<ord;i++)
|
||||
mem[i] = _y[N-i-1];
|
||||
RESTORE_STACK;
|
||||
#endif
|
||||
}
|
||||
|
||||
int _celt_autocorr(
|
||||
const opus_val16 *x, /* in: [0...n-1] samples x */
|
||||
opus_val32 *ac, /* out: [0...lag-1] ac values */
|
||||
const opus_val16 *window,
|
||||
int overlap,
|
||||
int lag,
|
||||
int n,
|
||||
int arch
|
||||
)
|
||||
{
|
||||
opus_val32 d;
|
||||
int i, k;
|
||||
int fastN=n-lag;
|
||||
int shift;
|
||||
const opus_val16 *xptr;
|
||||
VARDECL(opus_val16, xx);
|
||||
SAVE_STACK;
|
||||
ALLOC(xx, n, opus_val16);
|
||||
celt_assert(n>0);
|
||||
celt_assert(overlap>=0);
|
||||
if (overlap == 0)
|
||||
{
|
||||
xptr = x;
|
||||
} else {
|
||||
for (i=0;i<n;i++)
|
||||
xx[i] = x[i];
|
||||
for (i=0;i<overlap;i++)
|
||||
{
|
||||
xx[i] = MULT16_16_Q15(x[i],window[i]);
|
||||
xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
|
||||
}
|
||||
xptr = xx;
|
||||
}
|
||||
shift=0;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
{
|
||||
opus_val32 ac0;
|
||||
ac0 = 1+(n<<7);
|
||||
if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
|
||||
for(i=(n&1);i<n;i+=2)
|
||||
{
|
||||
ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
|
||||
ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
|
||||
}
|
||||
|
||||
shift = celt_ilog2(ac0)-30+10;
|
||||
shift = (shift)/2;
|
||||
if (shift>0)
|
||||
{
|
||||
for(i=0;i<n;i++)
|
||||
xx[i] = PSHR32(xptr[i], shift);
|
||||
xptr = xx;
|
||||
} else
|
||||
shift = 0;
|
||||
}
|
||||
#endif
|
||||
celt_pitch_xcorr(xptr, xptr, ac, fastN, lag+1, arch);
|
||||
for (k=0;k<=lag;k++)
|
||||
{
|
||||
for (i = k+fastN, d = 0; i < n; i++)
|
||||
d = MAC16_16(d, xptr[i], xptr[i-k]);
|
||||
ac[k] += d;
|
||||
}
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
shift = 2*shift;
|
||||
if (shift<=0)
|
||||
ac[0] += SHL32((opus_int32)1, -shift);
|
||||
if (ac[0] < 268435456)
|
||||
{
|
||||
int shift2 = 29 - EC_ILOG(ac[0]);
|
||||
for (i=0;i<=lag;i++)
|
||||
ac[i] = SHL32(ac[i], shift2);
|
||||
shift -= shift2;
|
||||
} else if (ac[0] >= 536870912)
|
||||
{
|
||||
int shift2=1;
|
||||
if (ac[0] >= 1073741824)
|
||||
shift2++;
|
||||
for (i=0;i<=lag;i++)
|
||||
ac[i] = SHR32(ac[i], shift2);
|
||||
shift += shift2;
|
||||
}
|
||||
#endif
|
||||
|
||||
RESTORE_STACK;
|
||||
return shift;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/* Copyright (c) 2009-2010 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PLC_H
|
||||
#define PLC_H
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
#define LPC_ORDER 24
|
||||
|
||||
void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p);
|
||||
|
||||
void celt_fir(const opus_val16 *x,
|
||||
const opus_val16 *num,
|
||||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem);
|
||||
|
||||
void celt_iir(const opus_val32 *x,
|
||||
const opus_val16 *den,
|
||||
opus_val32 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem);
|
||||
|
||||
int _celt_autocorr(const opus_val16 *x, opus_val32 *ac,
|
||||
const opus_val16 *window, int overlap, int lag, int n, int arch);
|
||||
|
||||
#endif /* PLC_H */
|
|
@ -0,0 +1,54 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation
|
||||
* Copyright (c) 2013 Parrot */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CPU_SUPPORT_H
|
||||
#define CPU_SUPPORT_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#if defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_ASM)
|
||||
#include "arm/armcpu.h"
|
||||
|
||||
/* We currently support 4 ARM variants:
|
||||
* arch[0] -> ARMv4
|
||||
* arch[1] -> ARMv5E
|
||||
* arch[2] -> ARMv6
|
||||
* arch[3] -> NEON
|
||||
*/
|
||||
#define OPUS_ARCHMASK 3
|
||||
|
||||
#else
|
||||
#define OPUS_ARCHMASK 0
|
||||
|
||||
static OPUS_INLINE int opus_select_arch(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,697 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2007-2009 Timothy B. Terriberry
|
||||
Written by Timothy B. Terriberry and Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "os_support.h"
|
||||
#include "cwrs.h"
|
||||
#include "mathops.h"
|
||||
#include "arch.h"
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
|
||||
/*Guaranteed to return a conservatively large estimate of the binary logarithm
|
||||
with frac bits of fractional precision.
|
||||
Tested for all possible 32-bit inputs with frac=4, where the maximum
|
||||
overestimation is 0.06254243 bits.*/
|
||||
int log2_frac(opus_uint32 val, int frac)
|
||||
{
|
||||
int l;
|
||||
l=EC_ILOG(val);
|
||||
if(val&(val-1)){
|
||||
/*This is (val>>l-16), but guaranteed to round up, even if adding a bias
|
||||
before the shift would cause overflow (e.g., for 0xFFFFxxxx).
|
||||
Doesn't work for val=0, but that case fails the test above.*/
|
||||
if(l>16)val=((val-1)>>(l-16))+1;
|
||||
else val<<=16-l;
|
||||
l=(l-1)<<frac;
|
||||
/*Note that we always need one iteration, since the rounding up above means
|
||||
that we might need to adjust the integer part of the logarithm.*/
|
||||
do{
|
||||
int b;
|
||||
b=(int)(val>>16);
|
||||
l+=b<<frac;
|
||||
val=(val+b)>>b;
|
||||
val=(val*val+0x7FFF)>>15;
|
||||
}
|
||||
while(frac-->0);
|
||||
/*If val is not exactly 0x8000, then we have to round up the remainder.*/
|
||||
return l+(val>0x8000);
|
||||
}
|
||||
/*Exact powers of two require no rounding.*/
|
||||
else return (l-1)<<frac;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Although derived separately, the pulse vector coding scheme is equivalent to
|
||||
a Pyramid Vector Quantizer \cite{Fis86}.
|
||||
Some additional notes about an early version appear at
|
||||
http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering
|
||||
and the definitions of some terms have evolved since that was written.
|
||||
|
||||
The conversion from a pulse vector to an integer index (encoding) and back
|
||||
(decoding) is governed by two related functions, V(N,K) and U(N,K).
|
||||
|
||||
V(N,K) = the number of combinations, with replacement, of N items, taken K
|
||||
at a time, when a sign bit is added to each item taken at least once (i.e.,
|
||||
the number of N-dimensional unit pulse vectors with K pulses).
|
||||
One way to compute this is via
|
||||
V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1,
|
||||
where choose() is the binomial function.
|
||||
A table of values for N<10 and K<10 looks like:
|
||||
V[10][10] = {
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{1, 2, 2, 2, 2, 2, 2, 2, 2, 2},
|
||||
{1, 4, 8, 12, 16, 20, 24, 28, 32, 36},
|
||||
{1, 6, 18, 38, 66, 102, 146, 198, 258, 326},
|
||||
{1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992},
|
||||
{1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290},
|
||||
{1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436},
|
||||
{1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598},
|
||||
{1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688},
|
||||
{1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146}
|
||||
};
|
||||
|
||||
U(N,K) = the number of such combinations wherein N-1 objects are taken at
|
||||
most K-1 at a time.
|
||||
This is given by
|
||||
U(N,K) = sum(k=0...K-1,V(N-1,k))
|
||||
= K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0.
|
||||
The latter expression also makes clear that U(N,K) is half the number of such
|
||||
combinations wherein the first object is taken at least once.
|
||||
Although it may not be clear from either of these definitions, U(N,K) is the
|
||||
natural function to work with when enumerating the pulse vector codebooks,
|
||||
not V(N,K).
|
||||
U(N,K) is not well-defined for N=0, but with the extension
|
||||
U(0,K) = K>0 ? 0 : 1,
|
||||
the function becomes symmetric: U(N,K) = U(K,N), with a similar table:
|
||||
U[10][10] = {
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{0, 1, 3, 5, 7, 9, 11, 13, 15, 17},
|
||||
{0, 1, 5, 13, 25, 41, 61, 85, 113, 145},
|
||||
{0, 1, 7, 25, 63, 129, 231, 377, 575, 833},
|
||||
{0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649},
|
||||
{0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073},
|
||||
{0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081},
|
||||
{0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545},
|
||||
{0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729}
|
||||
};
|
||||
|
||||
With this extension, V(N,K) may be written in terms of U(N,K):
|
||||
V(N,K) = U(N,K) + U(N,K+1)
|
||||
for all N>=0, K>=0.
|
||||
Thus U(N,K+1) represents the number of combinations where the first element
|
||||
is positive or zero, and U(N,K) represents the number of combinations where
|
||||
it is negative.
|
||||
With a large enough table of U(N,K) values, we could write O(N) encoding
|
||||
and O(min(N*log(K),N+K)) decoding routines, but such a table would be
|
||||
prohibitively large for small embedded devices (K may be as large as 32767
|
||||
for small N, and N may be as large as 200).
|
||||
|
||||
Both functions obey the same recurrence relation:
|
||||
V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1),
|
||||
U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1),
|
||||
for all N>0, K>0, with different initial conditions at N=0 or K=0.
|
||||
This allows us to construct a row of one of the tables above given the
|
||||
previous row or the next row.
|
||||
Thus we can derive O(NK) encoding and decoding routines with O(K) memory
|
||||
using only addition and subtraction.
|
||||
|
||||
When encoding, we build up from the U(2,K) row and work our way forwards.
|
||||
When decoding, we need to start at the U(N,K) row and work our way backwards,
|
||||
which requires a means of computing U(N,K).
|
||||
U(N,K) may be computed from two previous values with the same N:
|
||||
U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2)
|
||||
for all N>1, and since U(N,K) is symmetric, a similar relation holds for two
|
||||
previous values with the same K:
|
||||
U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K)
|
||||
for all K>1.
|
||||
This allows us to construct an arbitrary row of the U(N,K) table by starting
|
||||
with the first two values, which are constants.
|
||||
This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K)
|
||||
multiplications.
|
||||
Similar relations can be derived for V(N,K), but are not used here.
|
||||
|
||||
For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree
|
||||
polynomial for fixed N.
|
||||
The first few are
|
||||
U(1,K) = 1,
|
||||
U(2,K) = 2*K-1,
|
||||
U(3,K) = (2*K-2)*K+1,
|
||||
U(4,K) = (((4*K-6)*K+8)*K-3)/3,
|
||||
U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3,
|
||||
and
|
||||
V(1,K) = 2,
|
||||
V(2,K) = 4*K,
|
||||
V(3,K) = 4*K*K+2,
|
||||
V(4,K) = 8*(K*K+2)*K/3,
|
||||
V(5,K) = ((4*K*K+20)*K*K+6)/3,
|
||||
for all K>0.
|
||||
This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for
|
||||
small N (and indeed decoding is also O(N) for N<3).
|
||||
|
||||
@ARTICLE{Fis86,
|
||||
author="Thomas R. Fischer",
|
||||
title="A Pyramid Vector Quantizer",
|
||||
journal="IEEE Transactions on Information Theory",
|
||||
volume="IT-32",
|
||||
number=4,
|
||||
pages="568--583",
|
||||
month=Jul,
|
||||
year=1986
|
||||
}*/
|
||||
|
||||
#if !defined(SMALL_FOOTPRINT)
|
||||
|
||||
/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/
|
||||
# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)])
|
||||
/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N
|
||||
with K pulses allocated to it.*/
|
||||
# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1))
|
||||
|
||||
/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)).
|
||||
Thus, the number of entries in row I is the larger of the maximum number of
|
||||
pulses we will ever allocate for a given N=I (K=128, or however many fit in
|
||||
32 bits, whichever is smaller), plus one, and the maximum N for which
|
||||
K=I-1 pulses fit in 32 bits.
|
||||
The largest band size in an Opus Custom mode is 208.
|
||||
Otherwise, we can limit things to the set of N which can be achieved by
|
||||
splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48,
|
||||
44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/
|
||||
#if defined(CUSTOM_MODES)
|
||||
static const opus_uint32 CELT_PVQ_U_DATA[1488]={
|
||||
#else
|
||||
static const opus_uint32 CELT_PVQ_U_DATA[1272]={
|
||||
#endif
|
||||
/*N=0, K=0...176:*/
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...208:*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
#endif
|
||||
/*N=1, K=1...176:*/
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...208:*/
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
#endif
|
||||
/*N=2, K=2...176:*/
|
||||
3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41,
|
||||
43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
|
||||
81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113,
|
||||
115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143,
|
||||
145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
|
||||
175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
|
||||
205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233,
|
||||
235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263,
|
||||
265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293,
|
||||
295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323,
|
||||
325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...208:*/
|
||||
353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381,
|
||||
383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411,
|
||||
413, 415,
|
||||
#endif
|
||||
/*N=3, K=3...176:*/
|
||||
13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613,
|
||||
685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861,
|
||||
1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785,
|
||||
3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385,
|
||||
6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661,
|
||||
9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961,
|
||||
13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745,
|
||||
17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013,
|
||||
21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765,
|
||||
26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001,
|
||||
31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721,
|
||||
37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925,
|
||||
43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613,
|
||||
50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785,
|
||||
57461, 58141, 58825, 59513, 60205, 60901, 61601,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...208:*/
|
||||
62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565,
|
||||
70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013,
|
||||
78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113,
|
||||
#endif
|
||||
/*N=4, K=4...176:*/
|
||||
63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017,
|
||||
7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775,
|
||||
30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153,
|
||||
82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193,
|
||||
161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575,
|
||||
267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217,
|
||||
410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951,
|
||||
597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609,
|
||||
833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023,
|
||||
1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407,
|
||||
1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759,
|
||||
1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175,
|
||||
2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751,
|
||||
2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583,
|
||||
3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767,
|
||||
3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399,
|
||||
4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575,
|
||||
5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391,
|
||||
6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943,
|
||||
7085049, 7207551,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...208:*/
|
||||
7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783,
|
||||
8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967,
|
||||
9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199,
|
||||
10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177,
|
||||
11912575,
|
||||
#endif
|
||||
/*N=5, K=5...176:*/
|
||||
321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041,
|
||||
50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401,
|
||||
330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241,
|
||||
1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241,
|
||||
2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801,
|
||||
4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849,
|
||||
8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849,
|
||||
13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809,
|
||||
20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881,
|
||||
29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641,
|
||||
40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081,
|
||||
55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609,
|
||||
73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049,
|
||||
95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641,
|
||||
122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041,
|
||||
155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321,
|
||||
193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969,
|
||||
238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889,
|
||||
290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401,
|
||||
351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241,
|
||||
420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561,
|
||||
500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929,
|
||||
590359041, 604167209, 618216201, 632508801,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...208:*/
|
||||
647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241,
|
||||
755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161,
|
||||
878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329,
|
||||
1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041,
|
||||
1143412929, 1166053121, 1189027881, 1212340489, 1235994241,
|
||||
#endif
|
||||
/*N=6, K=6...96:*/
|
||||
1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047,
|
||||
335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409,
|
||||
2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793,
|
||||
11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455,
|
||||
29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189,
|
||||
64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651,
|
||||
128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185,
|
||||
235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647,
|
||||
402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229,
|
||||
655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283,
|
||||
1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135,
|
||||
1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187,
|
||||
2011371957, 2120032959,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...109:*/
|
||||
2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U,
|
||||
3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U,
|
||||
4012305913U,
|
||||
#endif
|
||||
/*N=7, K=7...54*/
|
||||
8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777,
|
||||
1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233,
|
||||
19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013,
|
||||
88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805,
|
||||
292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433,
|
||||
793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821,
|
||||
1667010073, 1870535785, 2094367717,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...60:*/
|
||||
2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U,
|
||||
#endif
|
||||
/*N=8, K=8...37*/
|
||||
48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767,
|
||||
9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017,
|
||||
104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351,
|
||||
638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615,
|
||||
2229491905U,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...40:*/
|
||||
2691463695U, 3233240945U, 3866006015U,
|
||||
#endif
|
||||
/*N=9, K=9...28:*/
|
||||
265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777,
|
||||
39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145,
|
||||
628496897, 872893441, 1196924561, 1621925137, 2173806145U,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...29:*/
|
||||
2883810113U,
|
||||
#endif
|
||||
/*N=10, K=10...24:*/
|
||||
1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073,
|
||||
254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U,
|
||||
3375210671U,
|
||||
/*N=11, K=11...19:*/
|
||||
8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585,
|
||||
948062325, 1616336765,
|
||||
#if defined(CUSTOM_MODES)
|
||||
/*...20:*/
|
||||
2684641785U,
|
||||
#endif
|
||||
/*N=12, K=12...18:*/
|
||||
45046719, 103274625, 224298231, 464387817, 921406335, 1759885185,
|
||||
3248227095U,
|
||||
/*N=13, K=13...16:*/
|
||||
251595969, 579168825, 1267854873, 2653649025U,
|
||||
/*N=14, K=14:*/
|
||||
1409933619
|
||||
};
|
||||
|
||||
#if defined(CUSTOM_MODES)
|
||||
static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
|
||||
CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415,
|
||||
CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030,
|
||||
CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389,
|
||||
CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455,
|
||||
CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473
|
||||
};
|
||||
#else
|
||||
static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
|
||||
CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351,
|
||||
CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870,
|
||||
CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178,
|
||||
CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240,
|
||||
CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CUSTOM_MODES)
|
||||
void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
|
||||
int k;
|
||||
/*_maxk==0 => there's nothing to do.*/
|
||||
celt_assert(_maxk>0);
|
||||
_bits[0]=0;
|
||||
for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac);
|
||||
}
|
||||
#endif
|
||||
|
||||
static opus_uint32 icwrs(int _n,const int *_y){
|
||||
opus_uint32 i;
|
||||
int j;
|
||||
int k;
|
||||
celt_assert(_n>=2);
|
||||
j=_n-1;
|
||||
i=_y[j]<0;
|
||||
k=abs(_y[j]);
|
||||
do{
|
||||
j--;
|
||||
i+=CELT_PVQ_U(_n-j,k);
|
||||
k+=abs(_y[j]);
|
||||
if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1);
|
||||
}
|
||||
while(j>0);
|
||||
return i;
|
||||
}
|
||||
|
||||
void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
|
||||
celt_assert(_k>0);
|
||||
ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k));
|
||||
}
|
||||
|
||||
static void cwrsi(int _n,int _k,opus_uint32 _i,int *_y){
|
||||
opus_uint32 p;
|
||||
int s;
|
||||
int k0;
|
||||
celt_assert(_k>0);
|
||||
celt_assert(_n>1);
|
||||
while(_n>2){
|
||||
opus_uint32 q;
|
||||
/*Lots of pulses case:*/
|
||||
if(_k>=_n){
|
||||
const opus_uint32 *row;
|
||||
row=CELT_PVQ_U_ROW[_n];
|
||||
/*Are the pulses in this dimension negative?*/
|
||||
p=row[_k+1];
|
||||
s=-(_i>=p);
|
||||
_i-=p&s;
|
||||
/*Count how many pulses were placed in this dimension.*/
|
||||
k0=_k;
|
||||
q=row[_n];
|
||||
if(q>_i){
|
||||
celt_assert(p>q);
|
||||
_k=_n;
|
||||
do p=CELT_PVQ_U_ROW[--_k][_n];
|
||||
while(p>_i);
|
||||
}
|
||||
else for(p=row[_k];p>_i;p=row[_k])_k--;
|
||||
_i-=p;
|
||||
*_y++=(k0-_k+s)^s;
|
||||
}
|
||||
/*Lots of dimensions case:*/
|
||||
else{
|
||||
/*Are there any pulses in this dimension at all?*/
|
||||
p=CELT_PVQ_U_ROW[_k][_n];
|
||||
q=CELT_PVQ_U_ROW[_k+1][_n];
|
||||
if(p<=_i&&_i<q){
|
||||
_i-=p;
|
||||
*_y++=0;
|
||||
}
|
||||
else{
|
||||
/*Are the pulses in this dimension negative?*/
|
||||
s=-(_i>=q);
|
||||
_i-=q&s;
|
||||
/*Count how many pulses were placed in this dimension.*/
|
||||
k0=_k;
|
||||
do p=CELT_PVQ_U_ROW[--_k][_n];
|
||||
while(p>_i);
|
||||
_i-=p;
|
||||
*_y++=(k0-_k+s)^s;
|
||||
}
|
||||
}
|
||||
_n--;
|
||||
}
|
||||
/*_n==2*/
|
||||
p=2*_k+1;
|
||||
s=-(_i>=p);
|
||||
_i-=p&s;
|
||||
k0=_k;
|
||||
_k=(_i+1)>>1;
|
||||
if(_k)_i-=2*_k-1;
|
||||
*_y++=(k0-_k+s)^s;
|
||||
/*_n==1*/
|
||||
s=-(int)_i;
|
||||
*_y=(_k+s)^s;
|
||||
}
|
||||
|
||||
void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
|
||||
cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y);
|
||||
}
|
||||
|
||||
#else /* SMALL_FOOTPRINT */
|
||||
|
||||
/*Computes the next row/column of any recurrence that obeys the relation
|
||||
u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1].
|
||||
_ui0 is the base case for the new row/column.*/
|
||||
static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){
|
||||
opus_uint32 ui1;
|
||||
unsigned j;
|
||||
/*This do-while will overrun the array if we don't have storage for at least
|
||||
2 values.*/
|
||||
j=1; do {
|
||||
ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0);
|
||||
_ui[j-1]=_ui0;
|
||||
_ui0=ui1;
|
||||
} while (++j<_len);
|
||||
_ui[j-1]=_ui0;
|
||||
}
|
||||
|
||||
/*Computes the previous row/column of any recurrence that obeys the relation
|
||||
u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1].
|
||||
_ui0 is the base case for the new row/column.*/
|
||||
static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){
|
||||
opus_uint32 ui1;
|
||||
unsigned j;
|
||||
/*This do-while will overrun the array if we don't have storage for at least
|
||||
2 values.*/
|
||||
j=1; do {
|
||||
ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0);
|
||||
_ui[j-1]=_ui0;
|
||||
_ui0=ui1;
|
||||
} while (++j<_n);
|
||||
_ui[j-1]=_ui0;
|
||||
}
|
||||
|
||||
/*Compute V(_n,_k), as well as U(_n,0..._k+1).
|
||||
_u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/
|
||||
static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){
|
||||
opus_uint32 um2;
|
||||
unsigned len;
|
||||
unsigned k;
|
||||
len=_k+2;
|
||||
/*We require storage at least 3 values (e.g., _k>0).*/
|
||||
celt_assert(len>=3);
|
||||
_u[0]=0;
|
||||
_u[1]=um2=1;
|
||||
/*If _n==0, _u[0] should be 1 and the rest should be 0.*/
|
||||
/*If _n==1, _u[i] should be 1 for i>1.*/
|
||||
celt_assert(_n>=2);
|
||||
/*If _k==0, the following do-while loop will overflow the buffer.*/
|
||||
celt_assert(_k>0);
|
||||
k=2;
|
||||
do _u[k]=(k<<1)-1;
|
||||
while(++k<len);
|
||||
for(k=2;k<_n;k++)unext(_u+1,_k+1,1);
|
||||
return _u[_k]+_u[_k+1];
|
||||
}
|
||||
|
||||
/*Returns the _i'th combination of _k elements chosen from a set of size _n
|
||||
with associated sign bits.
|
||||
_y: Returns the vector of pulses.
|
||||
_u: Must contain entries [0..._k+1] of row _n of U() on input.
|
||||
Its contents will be destructively modified.*/
|
||||
static void cwrsi(int _n,int _k,opus_uint32 _i,int *_y,opus_uint32 *_u){
|
||||
int j;
|
||||
celt_assert(_n>0);
|
||||
j=0;
|
||||
do{
|
||||
opus_uint32 p;
|
||||
int s;
|
||||
int yj;
|
||||
p=_u[_k+1];
|
||||
s=-(_i>=p);
|
||||
_i-=p&s;
|
||||
yj=_k;
|
||||
p=_u[_k];
|
||||
while(p>_i)p=_u[--_k];
|
||||
_i-=p;
|
||||
yj-=_k;
|
||||
_y[j]=(yj+s)^s;
|
||||
uprev(_u,_k+2,0);
|
||||
}
|
||||
while(++j<_n);
|
||||
}
|
||||
|
||||
/*Returns the index of the given combination of K elements chosen from a set
|
||||
of size 1 with associated sign bits.
|
||||
_y: The vector of pulses, whose sum of absolute values is K.
|
||||
_k: Returns K.*/
|
||||
static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){
|
||||
*_k=abs(_y[0]);
|
||||
return _y[0]<0;
|
||||
}
|
||||
|
||||
/*Returns the index of the given combination of K elements chosen from a set
|
||||
of size _n with associated sign bits.
|
||||
_y: The vector of pulses, whose sum of absolute values must be _k.
|
||||
_nc: Returns V(_n,_k).*/
|
||||
static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y,
|
||||
opus_uint32 *_u){
|
||||
opus_uint32 i;
|
||||
int j;
|
||||
int k;
|
||||
/*We can't unroll the first two iterations of the loop unless _n>=2.*/
|
||||
celt_assert(_n>=2);
|
||||
_u[0]=0;
|
||||
for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1;
|
||||
i=icwrs1(_y+_n-1,&k);
|
||||
j=_n-2;
|
||||
i+=_u[k];
|
||||
k+=abs(_y[j]);
|
||||
if(_y[j]<0)i+=_u[k+1];
|
||||
while(j-->0){
|
||||
unext(_u,_k+2,0);
|
||||
i+=_u[k];
|
||||
k+=abs(_y[j]);
|
||||
if(_y[j]<0)i+=_u[k+1];
|
||||
}
|
||||
*_nc=_u[k]+_u[k+1];
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
|
||||
int k;
|
||||
/*_maxk==0 => there's nothing to do.*/
|
||||
celt_assert(_maxk>0);
|
||||
_bits[0]=0;
|
||||
if (_n==1)
|
||||
{
|
||||
for (k=1;k<=_maxk;k++)
|
||||
_bits[k] = 1<<_frac;
|
||||
}
|
||||
else {
|
||||
VARDECL(opus_uint32,u);
|
||||
SAVE_STACK;
|
||||
ALLOC(u,_maxk+2U,opus_uint32);
|
||||
ncwrs_urow(_n,_maxk,u);
|
||||
for(k=1;k<=_maxk;k++)
|
||||
_bits[k]=log2_frac(u[k]+u[k+1],_frac);
|
||||
RESTORE_STACK;
|
||||
}
|
||||
}
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
|
||||
opus_uint32 i;
|
||||
VARDECL(opus_uint32,u);
|
||||
opus_uint32 nc;
|
||||
SAVE_STACK;
|
||||
celt_assert(_k>0);
|
||||
ALLOC(u,_k+2U,opus_uint32);
|
||||
i=icwrs(_n,_k,&nc,_y,u);
|
||||
ec_enc_uint(_enc,i,nc);
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
|
||||
VARDECL(opus_uint32,u);
|
||||
SAVE_STACK;
|
||||
celt_assert(_k>0);
|
||||
ALLOC(u,_k+2U,opus_uint32);
|
||||
cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u);
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
#endif /* SMALL_FOOTPRINT */
|
|
@ -0,0 +1,48 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2007-2009 Timothy B. Terriberry
|
||||
Written by Timothy B. Terriberry and Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CWRS_H
|
||||
#define CWRS_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
int log2_frac(opus_uint32 val, int frac);
|
||||
#endif
|
||||
|
||||
void get_required_bits(opus_int16 *bits, int N, int K, int frac);
|
||||
|
||||
void encode_pulses(const int *_y, int N, int K, ec_enc *enc);
|
||||
|
||||
void decode_pulses(int *_y, int N, int K, ec_dec *dec);
|
||||
|
||||
#endif /* CWRS_H */
|
|
@ -0,0 +1,87 @@
|
|||
/* Copyright (c) 2003-2008 Timothy B. Terriberry
|
||||
Copyright (c) 2008 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*Some common macros for potential platform-specific optimization.*/
|
||||
#include "opus_types.h"
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include "arch.h"
|
||||
#if !defined(_ecintrin_H)
|
||||
# define _ecintrin_H (1)
|
||||
|
||||
/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly
|
||||
versions of these functions which can substantially improve performance.
|
||||
We define macros for them to allow easy incorporation of these non-ANSI
|
||||
features.*/
|
||||
|
||||
/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if
|
||||
given an appropriate architecture, but the branchless bit-twiddling versions
|
||||
are just as fast, and do not require any special target architecture.
|
||||
Earlier gcc versions (3.x) compiled both code to the same assembly
|
||||
instructions, because of the way they represented ((_b)>(_a)) internally.*/
|
||||
# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a))))
|
||||
|
||||
/*Count leading zeros.
|
||||
This macro should only be used for implementing ec_ilog(), if it is defined.
|
||||
All other code should use EC_ILOG() instead.*/
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
# include <intrin.h>
|
||||
/*In _DEBUG mode this is not an intrinsic by default.*/
|
||||
# pragma intrinsic(_BitScanReverse)
|
||||
|
||||
static __inline int ec_bsr(unsigned long _x){
|
||||
unsigned long ret;
|
||||
_BitScanReverse(&ret,_x);
|
||||
return (int)ret;
|
||||
}
|
||||
# define EC_CLZ0 (1)
|
||||
# define EC_CLZ(_x) (-ec_bsr(_x))
|
||||
#elif defined(ENABLE_TI_DSPLIB)
|
||||
# include "dsplib.h"
|
||||
# define EC_CLZ0 (31)
|
||||
# define EC_CLZ(_x) (_lnorm(_x))
|
||||
#elif __GNUC_PREREQ(3,4)
|
||||
# if INT_MAX>=2147483647
|
||||
# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT)
|
||||
# define EC_CLZ(_x) (__builtin_clz(_x))
|
||||
# elif LONG_MAX>=2147483647L
|
||||
# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT)
|
||||
# define EC_CLZ(_x) (__builtin_clzl(_x))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(EC_CLZ)
|
||||
/*Note that __builtin_clz is not defined when _x==0, according to the gcc
|
||||
documentation (and that of the BSR instruction that implements it on x86).
|
||||
The majority of the time we can never pass it zero.
|
||||
When we need to, it can be special cased.*/
|
||||
# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x))
|
||||
#else
|
||||
int ec_ilog(opus_uint32 _v);
|
||||
# define EC_ILOG(_x) (ec_ilog(_x))
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,93 @@
|
|||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "entcode.h"
|
||||
#include "arch.h"
|
||||
|
||||
#if !defined(EC_CLZ)
|
||||
/*This is a fallback for systems where we don't know how to access
|
||||
a BSR or CLZ instruction (see ecintrin.h).
|
||||
If you are optimizing Opus on a new platform and it has a native CLZ or
|
||||
BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be
|
||||
an easy performance win.*/
|
||||
int ec_ilog(opus_uint32 _v){
|
||||
/*On a Pentium M, this branchless version tested as the fastest on
|
||||
1,000,000,000 random 32-bit integers, edging out a similar version with
|
||||
branches, and a 256-entry LUT version.*/
|
||||
int ret;
|
||||
int m;
|
||||
ret=!!_v;
|
||||
m=!!(_v&0xFFFF0000)<<4;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
m=!!(_v&0xFF00)<<3;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
m=!!(_v&0xF0)<<2;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
m=!!(_v&0xC)<<1;
|
||||
_v>>=m;
|
||||
ret|=m;
|
||||
ret+=!!(_v&0x2);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
opus_uint32 ec_tell_frac(ec_ctx *_this){
|
||||
opus_uint32 nbits;
|
||||
opus_uint32 r;
|
||||
int l;
|
||||
int i;
|
||||
/*To handle the non-integral number of bits still left in the encoder/decoder
|
||||
state, we compute the worst-case number of bits of val that must be
|
||||
encoded to ensure that the value is inside the range for any possible
|
||||
subsequent bits.
|
||||
The computation here is independent of val itself (the decoder does not
|
||||
even track that value), even though the real number of bits used after
|
||||
ec_enc_done() may be 1 smaller if rng is a power of two and the
|
||||
corresponding trailing bits of val are all zeros.
|
||||
If we did try to track that special case, then coding a value with a
|
||||
probability of 1/(1<<n) might sometimes appear to use more than n bits.
|
||||
This may help explain the surprising result that a newly initialized
|
||||
encoder or decoder claims to have used 1 bit.*/
|
||||
nbits=_this->nbits_total<<BITRES;
|
||||
l=EC_ILOG(_this->rng);
|
||||
r=_this->rng>>(l-16);
|
||||
for(i=BITRES;i-->0;){
|
||||
int b;
|
||||
r=r*r>>15;
|
||||
b=(int)(r>>16);
|
||||
l=l<<1|b;
|
||||
r>>=b;
|
||||
}
|
||||
return nbits-l;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
Copyright (c) 2008-2009 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#if !defined(_entcode_H)
|
||||
# define _entcode_H (1)
|
||||
# include <limits.h>
|
||||
# include <stddef.h>
|
||||
# include "ecintrin.h"
|
||||
|
||||
/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a
|
||||
larger type, you can speed up the decoder by using it here.*/
|
||||
typedef opus_uint32 ec_window;
|
||||
typedef struct ec_ctx ec_ctx;
|
||||
typedef struct ec_ctx ec_enc;
|
||||
typedef struct ec_ctx ec_dec;
|
||||
|
||||
# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT)
|
||||
|
||||
/*The number of bits to use for the range-coded part of unsigned integers.*/
|
||||
# define EC_UINT_BITS (8)
|
||||
|
||||
/*The resolution of fractional-precision bit usage measurements, i.e.,
|
||||
3 => 1/8th bits.*/
|
||||
# define BITRES 3
|
||||
|
||||
/*The entropy encoder/decoder context.
|
||||
We use the same structure for both, so that common functions like ec_tell()
|
||||
can be used on either one.*/
|
||||
struct ec_ctx{
|
||||
/*Buffered input/output.*/
|
||||
unsigned char *buf;
|
||||
/*The size of the buffer.*/
|
||||
opus_uint32 storage;
|
||||
/*The offset at which the last byte containing raw bits was read/written.*/
|
||||
opus_uint32 end_offs;
|
||||
/*Bits that will be read from/written at the end.*/
|
||||
ec_window end_window;
|
||||
/*Number of valid bits in end_window.*/
|
||||
int nend_bits;
|
||||
/*The total number of whole bits read/written.
|
||||
This does not include partial bits currently in the range coder.*/
|
||||
int nbits_total;
|
||||
/*The offset at which the next range coder byte will be read/written.*/
|
||||
opus_uint32 offs;
|
||||
/*The number of values in the current range.*/
|
||||
opus_uint32 rng;
|
||||
/*In the decoder: the difference between the top of the current range and
|
||||
the input value, minus one.
|
||||
In the encoder: the low end of the current range.*/
|
||||
opus_uint32 val;
|
||||
/*In the decoder: the saved normalization factor from ec_decode().
|
||||
In the encoder: the number of oustanding carry propagating symbols.*/
|
||||
opus_uint32 ext;
|
||||
/*A buffered input/output symbol, awaiting carry propagation.*/
|
||||
int rem;
|
||||
/*Nonzero if an error occurred.*/
|
||||
int error;
|
||||
};
|
||||
|
||||
static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){
|
||||
return _this->offs;
|
||||
}
|
||||
|
||||
static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){
|
||||
return _this->buf;
|
||||
}
|
||||
|
||||
static OPUS_INLINE int ec_get_error(ec_ctx *_this){
|
||||
return _this->error;
|
||||
}
|
||||
|
||||
/*Returns the number of bits "used" by the encoded or decoded symbols so far.
|
||||
This same number can be computed in either the encoder or the decoder, and is
|
||||
suitable for making coding decisions.
|
||||
Return: The number of bits.
|
||||
This will always be slightly larger than the exact value (e.g., all
|
||||
rounding error is in the positive direction).*/
|
||||
static OPUS_INLINE int ec_tell(ec_ctx *_this){
|
||||
return _this->nbits_total-EC_ILOG(_this->rng);
|
||||
}
|
||||
|
||||
/*Returns the number of bits "used" by the encoded or decoded symbols so far.
|
||||
This same number can be computed in either the encoder or the decoder, and is
|
||||
suitable for making coding decisions.
|
||||
Return: The number of bits scaled by 2**BITRES.
|
||||
This will always be slightly larger than the exact value (e.g., all
|
||||
rounding error is in the positive direction).*/
|
||||
opus_uint32 ec_tell_frac(ec_ctx *_this);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,245 @@
|
|||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
Copyright (c) 2008-2009 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "os_support.h"
|
||||
#include "arch.h"
|
||||
#include "entdec.h"
|
||||
#include "mfrngcod.h"
|
||||
|
||||
/*A range decoder.
|
||||
This is an entropy decoder based upon \cite{Mar79}, which is itself a
|
||||
rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}.
|
||||
It is very similar to arithmetic encoding, except that encoding is done with
|
||||
digits in any base, instead of with bits, and so it is faster when using
|
||||
larger bases (i.e.: a byte).
|
||||
The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$
|
||||
is the base, longer than the theoretical optimum, but to my knowledge there
|
||||
is no published justification for this claim.
|
||||
This only seems true when using near-infinite precision arithmetic so that
|
||||
the process is carried out with no rounding errors.
|
||||
|
||||
An excellent description of implementation details is available at
|
||||
http://www.arturocampos.com/ac_range.html
|
||||
A recent work \cite{MNW98} which proposes several changes to arithmetic
|
||||
encoding for efficiency actually re-discovers many of the principles
|
||||
behind range encoding, and presents a good theoretical analysis of them.
|
||||
|
||||
End of stream is handled by writing out the smallest number of bits that
|
||||
ensures that the stream will be correctly decoded regardless of the value of
|
||||
any subsequent bits.
|
||||
ec_tell() can be used to determine how many bits were needed to decode
|
||||
all the symbols thus far; other data can be packed in the remaining bits of
|
||||
the input buffer.
|
||||
@PHDTHESIS{Pas76,
|
||||
author="Richard Clark Pasco",
|
||||
title="Source coding algorithms for fast data compression",
|
||||
school="Dept. of Electrical Engineering, Stanford University",
|
||||
address="Stanford, CA",
|
||||
month=May,
|
||||
year=1976
|
||||
}
|
||||
@INPROCEEDINGS{Mar79,
|
||||
author="Martin, G.N.N.",
|
||||
title="Range encoding: an algorithm for removing redundancy from a digitised
|
||||
message",
|
||||
booktitle="Video & Data Recording Conference",
|
||||
year=1979,
|
||||
address="Southampton",
|
||||
month=Jul
|
||||
}
|
||||
@ARTICLE{MNW98,
|
||||
author="Alistair Moffat and Radford Neal and Ian H. Witten",
|
||||
title="Arithmetic Coding Revisited",
|
||||
journal="{ACM} Transactions on Information Systems",
|
||||
year=1998,
|
||||
volume=16,
|
||||
number=3,
|
||||
pages="256--294",
|
||||
month=Jul,
|
||||
URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf"
|
||||
}*/
|
||||
|
||||
static int ec_read_byte(ec_dec *_this){
|
||||
return _this->offs<_this->storage?_this->buf[_this->offs++]:0;
|
||||
}
|
||||
|
||||
static int ec_read_byte_from_end(ec_dec *_this){
|
||||
return _this->end_offs<_this->storage?
|
||||
_this->buf[_this->storage-++(_this->end_offs)]:0;
|
||||
}
|
||||
|
||||
/*Normalizes the contents of val and rng so that rng lies entirely in the
|
||||
high-order symbol.*/
|
||||
static void ec_dec_normalize(ec_dec *_this){
|
||||
/*If the range is too small, rescale it and input some bits.*/
|
||||
while(_this->rng<=EC_CODE_BOT){
|
||||
int sym;
|
||||
_this->nbits_total+=EC_SYM_BITS;
|
||||
_this->rng<<=EC_SYM_BITS;
|
||||
/*Use up the remaining bits from our last symbol.*/
|
||||
sym=_this->rem;
|
||||
/*Read the next value from the input.*/
|
||||
_this->rem=ec_read_byte(_this);
|
||||
/*Take the rest of the bits we need from this new symbol.*/
|
||||
sym=(sym<<EC_SYM_BITS|_this->rem)>>(EC_SYM_BITS-EC_CODE_EXTRA);
|
||||
/*And subtract them from val, capped to be less than EC_CODE_TOP.*/
|
||||
_this->val=((_this->val<<EC_SYM_BITS)+(EC_SYM_MAX&~sym))&(EC_CODE_TOP-1);
|
||||
}
|
||||
}
|
||||
|
||||
void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage){
|
||||
_this->buf=_buf;
|
||||
_this->storage=_storage;
|
||||
_this->end_offs=0;
|
||||
_this->end_window=0;
|
||||
_this->nend_bits=0;
|
||||
/*This is the offset from which ec_tell() will subtract partial bits.
|
||||
The final value after the ec_dec_normalize() call will be the same as in
|
||||
the encoder, but we have to compensate for the bits that are added there.*/
|
||||
_this->nbits_total=EC_CODE_BITS+1
|
||||
-((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS;
|
||||
_this->offs=0;
|
||||
_this->rng=1U<<EC_CODE_EXTRA;
|
||||
_this->rem=ec_read_byte(_this);
|
||||
_this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA));
|
||||
_this->error=0;
|
||||
/*Normalize the interval.*/
|
||||
ec_dec_normalize(_this);
|
||||
}
|
||||
|
||||
unsigned ec_decode(ec_dec *_this,unsigned _ft){
|
||||
unsigned s;
|
||||
_this->ext=_this->rng/_ft;
|
||||
s=(unsigned)(_this->val/_this->ext);
|
||||
return _ft-EC_MINI(s+1,_ft);
|
||||
}
|
||||
|
||||
unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){
|
||||
unsigned s;
|
||||
_this->ext=_this->rng>>_bits;
|
||||
s=(unsigned)(_this->val/_this->ext);
|
||||
return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits);
|
||||
}
|
||||
|
||||
void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){
|
||||
opus_uint32 s;
|
||||
s=IMUL32(_this->ext,_ft-_fh);
|
||||
_this->val-=s;
|
||||
_this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s;
|
||||
ec_dec_normalize(_this);
|
||||
}
|
||||
|
||||
/*The probability of having a "one" is 1/(1<<_logp).*/
|
||||
int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){
|
||||
opus_uint32 r;
|
||||
opus_uint32 d;
|
||||
opus_uint32 s;
|
||||
int ret;
|
||||
r=_this->rng;
|
||||
d=_this->val;
|
||||
s=r>>_logp;
|
||||
ret=d<s;
|
||||
if(!ret)_this->val=d-s;
|
||||
_this->rng=ret?s:r-s;
|
||||
ec_dec_normalize(_this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){
|
||||
opus_uint32 r;
|
||||
opus_uint32 d;
|
||||
opus_uint32 s;
|
||||
opus_uint32 t;
|
||||
int ret;
|
||||
s=_this->rng;
|
||||
d=_this->val;
|
||||
r=s>>_ftb;
|
||||
ret=-1;
|
||||
do{
|
||||
t=s;
|
||||
s=IMUL32(r,_icdf[++ret]);
|
||||
}
|
||||
while(d<s);
|
||||
_this->val=d-s;
|
||||
_this->rng=t-s;
|
||||
ec_dec_normalize(_this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){
|
||||
unsigned ft;
|
||||
unsigned s;
|
||||
int ftb;
|
||||
/*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
|
||||
celt_assert(_ft>1);
|
||||
_ft--;
|
||||
ftb=EC_ILOG(_ft);
|
||||
if(ftb>EC_UINT_BITS){
|
||||
opus_uint32 t;
|
||||
ftb-=EC_UINT_BITS;
|
||||
ft=(unsigned)(_ft>>ftb)+1;
|
||||
s=ec_decode(_this,ft);
|
||||
ec_dec_update(_this,s,s+1,ft);
|
||||
t=(opus_uint32)s<<ftb|ec_dec_bits(_this,ftb);
|
||||
if(t<=_ft)return t;
|
||||
_this->error=1;
|
||||
return _ft;
|
||||
}
|
||||
else{
|
||||
_ft++;
|
||||
s=ec_decode(_this,(unsigned)_ft);
|
||||
ec_dec_update(_this,s,s+1,(unsigned)_ft);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){
|
||||
ec_window window;
|
||||
int available;
|
||||
opus_uint32 ret;
|
||||
window=_this->end_window;
|
||||
available=_this->nend_bits;
|
||||
if((unsigned)available<_bits){
|
||||
do{
|
||||
window|=(ec_window)ec_read_byte_from_end(_this)<<available;
|
||||
available+=EC_SYM_BITS;
|
||||
}
|
||||
while(available<=EC_WINDOW_SIZE-EC_SYM_BITS);
|
||||
}
|
||||
ret=(opus_uint32)window&(((opus_uint32)1<<_bits)-1U);
|
||||
window>>=_bits;
|
||||
available-=_bits;
|
||||
_this->end_window=window;
|
||||
_this->nend_bits=available;
|
||||
_this->nbits_total+=_bits;
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
Copyright (c) 2008-2009 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !defined(_entdec_H)
|
||||
# define _entdec_H (1)
|
||||
# include <limits.h>
|
||||
# include "entcode.h"
|
||||
|
||||
/*Initializes the decoder.
|
||||
_buf: The input buffer to use.
|
||||
Return: 0 on success, or a negative value on error.*/
|
||||
void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage);
|
||||
|
||||
/*Calculates the cumulative frequency for the next symbol.
|
||||
This can then be fed into the probability model to determine what that
|
||||
symbol is, and the additional frequency information required to advance to
|
||||
the next symbol.
|
||||
This function cannot be called more than once without a corresponding call to
|
||||
ec_dec_update(), or decoding will not proceed correctly.
|
||||
_ft: The total frequency of the symbols in the alphabet the next symbol was
|
||||
encoded with.
|
||||
Return: A cumulative frequency representing the encoded symbol.
|
||||
If the cumulative frequency of all the symbols before the one that
|
||||
was encoded was fl, and the cumulative frequency of all the symbols
|
||||
up to and including the one encoded is fh, then the returned value
|
||||
will fall in the range [fl,fh).*/
|
||||
unsigned ec_decode(ec_dec *_this,unsigned _ft);
|
||||
|
||||
/*Equivalent to ec_decode() with _ft==1<<_bits.*/
|
||||
unsigned ec_decode_bin(ec_dec *_this,unsigned _bits);
|
||||
|
||||
/*Advance the decoder past the next symbol using the frequency information the
|
||||
symbol was encoded with.
|
||||
Exactly one call to ec_decode() must have been made so that all necessary
|
||||
intermediate calculations are performed.
|
||||
_fl: The cumulative frequency of all symbols that come before the symbol
|
||||
decoded.
|
||||
_fh: The cumulative frequency of all symbols up to and including the symbol
|
||||
decoded.
|
||||
Together with _fl, this defines the range [_fl,_fh) in which the value
|
||||
returned above must fall.
|
||||
_ft: The total frequency of the symbols in the alphabet the symbol decoded
|
||||
was encoded in.
|
||||
This must be the same as passed to the preceding call to ec_decode().*/
|
||||
void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft);
|
||||
|
||||
/* Decode a bit that has a 1/(1<<_logp) probability of being a one */
|
||||
int ec_dec_bit_logp(ec_dec *_this,unsigned _logp);
|
||||
|
||||
/*Decodes a symbol given an "inverse" CDF table.
|
||||
No call to ec_dec_update() is necessary after this call.
|
||||
_icdf: The "inverse" CDF, such that symbol s falls in the range
|
||||
[s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb.
|
||||
The values must be monotonically non-increasing, and the last value
|
||||
must be 0.
|
||||
_ftb: The number of bits of precision in the cumulative distribution.
|
||||
Return: The decoded symbol s.*/
|
||||
int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb);
|
||||
|
||||
/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream.
|
||||
The bits must have been encoded with ec_enc_uint().
|
||||
No call to ec_dec_update() is necessary after this call.
|
||||
_ft: The number of integers that can be decoded (one more than the max).
|
||||
This must be at least one, and no more than 2**32-1.
|
||||
Return: The decoded bits.*/
|
||||
opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft);
|
||||
|
||||
/*Extracts a sequence of raw bits from the stream.
|
||||
The bits must have been encoded with ec_enc_bits().
|
||||
No call to ec_dec_update() is necessary after this call.
|
||||
_ftb: The number of bits to extract.
|
||||
This must be between 0 and 25, inclusive.
|
||||
Return: The decoded bits.*/
|
||||
opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,294 @@
|
|||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
Copyright (c) 2008-2009 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(OPUS_HAVE_CONFIG_H)
|
||||
# include "opus_config.h"
|
||||
#endif
|
||||
#include "os_support.h"
|
||||
#include "arch.h"
|
||||
#include "entenc.h"
|
||||
#include "mfrngcod.h"
|
||||
|
||||
/*A range encoder.
|
||||
See entdec.c and the references for implementation details \cite{Mar79,MNW98}.
|
||||
|
||||
@INPROCEEDINGS{Mar79,
|
||||
author="Martin, G.N.N.",
|
||||
title="Range encoding: an algorithm for removing redundancy from a digitised
|
||||
message",
|
||||
booktitle="Video \& Data Recording Conference",
|
||||
year=1979,
|
||||
address="Southampton",
|
||||
month=Jul
|
||||
}
|
||||
@ARTICLE{MNW98,
|
||||
author="Alistair Moffat and Radford Neal and Ian H. Witten",
|
||||
title="Arithmetic Coding Revisited",
|
||||
journal="{ACM} Transactions on Information Systems",
|
||||
year=1998,
|
||||
volume=16,
|
||||
number=3,
|
||||
pages="256--294",
|
||||
month=Jul,
|
||||
URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf"
|
||||
}*/
|
||||
|
||||
static int ec_write_byte(ec_enc *_this,unsigned _value){
|
||||
if(_this->offs+_this->end_offs>=_this->storage)return -1;
|
||||
_this->buf[_this->offs++]=(unsigned char)_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){
|
||||
if(_this->offs+_this->end_offs>=_this->storage)return -1;
|
||||
_this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Outputs a symbol, with a carry bit.
|
||||
If there is a potential to propagate a carry over several symbols, they are
|
||||
buffered until it can be determined whether or not an actual carry will
|
||||
occur.
|
||||
If the counter for the buffered symbols overflows, then the stream becomes
|
||||
undecodable.
|
||||
This gives a theoretical limit of a few billion symbols in a single packet on
|
||||
32-bit systems.
|
||||
The alternative is to truncate the range in order to force a carry, but
|
||||
requires similar carry tracking in the decoder, needlessly slowing it down.*/
|
||||
static void ec_enc_carry_out(ec_enc *_this,int _c){
|
||||
if(_c!=EC_SYM_MAX){
|
||||
/*No further carry propagation possible, flush buffer.*/
|
||||
int carry;
|
||||
carry=_c>>EC_SYM_BITS;
|
||||
/*Don't output a byte on the first write.
|
||||
This compare should be taken care of by branch-prediction thereafter.*/
|
||||
if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry);
|
||||
if(_this->ext>0){
|
||||
unsigned sym;
|
||||
sym=(EC_SYM_MAX+carry)&EC_SYM_MAX;
|
||||
do _this->error|=ec_write_byte(_this,sym);
|
||||
while(--(_this->ext)>0);
|
||||
}
|
||||
_this->rem=_c&EC_SYM_MAX;
|
||||
}
|
||||
else _this->ext++;
|
||||
}
|
||||
|
||||
static void ec_enc_normalize(ec_enc *_this){
|
||||
/*If the range is too small, output some bits and rescale it.*/
|
||||
while(_this->rng<=EC_CODE_BOT){
|
||||
ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT));
|
||||
/*Move the next-to-high-order symbol into the high-order position.*/
|
||||
_this->val=(_this->val<<EC_SYM_BITS)&(EC_CODE_TOP-1);
|
||||
_this->rng<<=EC_SYM_BITS;
|
||||
_this->nbits_total+=EC_SYM_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){
|
||||
_this->buf=_buf;
|
||||
_this->end_offs=0;
|
||||
_this->end_window=0;
|
||||
_this->nend_bits=0;
|
||||
/*This is the offset from which ec_tell() will subtract partial bits.*/
|
||||
_this->nbits_total=EC_CODE_BITS+1;
|
||||
_this->offs=0;
|
||||
_this->rng=EC_CODE_TOP;
|
||||
_this->rem=-1;
|
||||
_this->val=0;
|
||||
_this->ext=0;
|
||||
_this->storage=_size;
|
||||
_this->error=0;
|
||||
}
|
||||
|
||||
void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){
|
||||
opus_uint32 r;
|
||||
r=_this->rng/_ft;
|
||||
if(_fl>0){
|
||||
_this->val+=_this->rng-IMUL32(r,(_ft-_fl));
|
||||
_this->rng=IMUL32(r,(_fh-_fl));
|
||||
}
|
||||
else _this->rng-=IMUL32(r,(_ft-_fh));
|
||||
ec_enc_normalize(_this);
|
||||
}
|
||||
|
||||
void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){
|
||||
opus_uint32 r;
|
||||
r=_this->rng>>_bits;
|
||||
if(_fl>0){
|
||||
_this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl));
|
||||
_this->rng=IMUL32(r,(_fh-_fl));
|
||||
}
|
||||
else _this->rng-=IMUL32(r,((1U<<_bits)-_fh));
|
||||
ec_enc_normalize(_this);
|
||||
}
|
||||
|
||||
/*The probability of having a "one" is 1/(1<<_logp).*/
|
||||
void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){
|
||||
opus_uint32 r;
|
||||
opus_uint32 s;
|
||||
opus_uint32 l;
|
||||
r=_this->rng;
|
||||
l=_this->val;
|
||||
s=r>>_logp;
|
||||
r-=s;
|
||||
if(_val)_this->val=l+r;
|
||||
_this->rng=_val?s:r;
|
||||
ec_enc_normalize(_this);
|
||||
}
|
||||
|
||||
void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){
|
||||
opus_uint32 r;
|
||||
r=_this->rng>>_ftb;
|
||||
if(_s>0){
|
||||
_this->val+=_this->rng-IMUL32(r,_icdf[_s-1]);
|
||||
_this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]);
|
||||
}
|
||||
else _this->rng-=IMUL32(r,_icdf[_s]);
|
||||
ec_enc_normalize(_this);
|
||||
}
|
||||
|
||||
void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){
|
||||
unsigned ft;
|
||||
unsigned fl;
|
||||
int ftb;
|
||||
/*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
|
||||
celt_assert(_ft>1);
|
||||
_ft--;
|
||||
ftb=EC_ILOG(_ft);
|
||||
if(ftb>EC_UINT_BITS){
|
||||
ftb-=EC_UINT_BITS;
|
||||
ft=(_ft>>ftb)+1;
|
||||
fl=(unsigned)(_fl>>ftb);
|
||||
ec_encode(_this,fl,fl+1,ft);
|
||||
ec_enc_bits(_this,_fl&(((opus_uint32)1<<ftb)-1U),ftb);
|
||||
}
|
||||
else ec_encode(_this,_fl,_fl+1,_ft+1);
|
||||
}
|
||||
|
||||
void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _bits){
|
||||
ec_window window;
|
||||
int used;
|
||||
window=_this->end_window;
|
||||
used=_this->nend_bits;
|
||||
celt_assert(_bits>0);
|
||||
if(used+_bits>EC_WINDOW_SIZE){
|
||||
do{
|
||||
_this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
|
||||
window>>=EC_SYM_BITS;
|
||||
used-=EC_SYM_BITS;
|
||||
}
|
||||
while(used>=EC_SYM_BITS);
|
||||
}
|
||||
window|=(ec_window)_fl<<used;
|
||||
used+=_bits;
|
||||
_this->end_window=window;
|
||||
_this->nend_bits=used;
|
||||
_this->nbits_total+=_bits;
|
||||
}
|
||||
|
||||
void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){
|
||||
int shift;
|
||||
unsigned mask;
|
||||
celt_assert(_nbits<=EC_SYM_BITS);
|
||||
shift=EC_SYM_BITS-_nbits;
|
||||
mask=((1<<_nbits)-1)<<shift;
|
||||
if(_this->offs>0){
|
||||
/*The first byte has been finalized.*/
|
||||
_this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<<shift);
|
||||
}
|
||||
else if(_this->rem>=0){
|
||||
/*The first byte is still awaiting carry propagation.*/
|
||||
_this->rem=(_this->rem&~mask)|_val<<shift;
|
||||
}
|
||||
else if(_this->rng<=(EC_CODE_TOP>>_nbits)){
|
||||
/*The renormalization loop has never been run.*/
|
||||
_this->val=(_this->val&~((opus_uint32)mask<<EC_CODE_SHIFT))|
|
||||
(opus_uint32)_val<<(EC_CODE_SHIFT+shift);
|
||||
}
|
||||
/*The encoder hasn't even encoded _nbits of data yet.*/
|
||||
else _this->error=-1;
|
||||
}
|
||||
|
||||
void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){
|
||||
celt_assert(_this->offs+_this->end_offs<=_size);
|
||||
OPUS_MOVE(_this->buf+_size-_this->end_offs,
|
||||
_this->buf+_this->storage-_this->end_offs,_this->end_offs);
|
||||
_this->storage=_size;
|
||||
}
|
||||
|
||||
void ec_enc_done(ec_enc *_this){
|
||||
ec_window window;
|
||||
int used;
|
||||
opus_uint32 msk;
|
||||
opus_uint32 end;
|
||||
int l;
|
||||
/*We output the minimum number of bits that ensures that the symbols encoded
|
||||
thus far will be decoded correctly regardless of the bits that follow.*/
|
||||
l=EC_CODE_BITS-EC_ILOG(_this->rng);
|
||||
msk=(EC_CODE_TOP-1)>>l;
|
||||
end=(_this->val+msk)&~msk;
|
||||
if((end|msk)>=_this->val+_this->rng){
|
||||
l++;
|
||||
msk>>=1;
|
||||
end=(_this->val+msk)&~msk;
|
||||
}
|
||||
while(l>0){
|
||||
ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT));
|
||||
end=(end<<EC_SYM_BITS)&(EC_CODE_TOP-1);
|
||||
l-=EC_SYM_BITS;
|
||||
}
|
||||
/*If we have a buffered byte flush it into the output buffer.*/
|
||||
if(_this->rem>=0||_this->ext>0)ec_enc_carry_out(_this,0);
|
||||
/*If we have buffered extra bits, flush them as well.*/
|
||||
window=_this->end_window;
|
||||
used=_this->nend_bits;
|
||||
while(used>=EC_SYM_BITS){
|
||||
_this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
|
||||
window>>=EC_SYM_BITS;
|
||||
used-=EC_SYM_BITS;
|
||||
}
|
||||
/*Clear any excess space and add any remaining extra bits to the last byte.*/
|
||||
if(!_this->error){
|
||||
OPUS_CLEAR(_this->buf+_this->offs,
|
||||
_this->storage-_this->offs-_this->end_offs);
|
||||
if(used>0){
|
||||
/*If there's no range coder data at all, give up.*/
|
||||
if(_this->end_offs>=_this->storage)_this->error=-1;
|
||||
else{
|
||||
l=-l;
|
||||
/*If we've busted, don't add too many extra bits to the last byte; it
|
||||
would corrupt the range coder data, and that's more important.*/
|
||||
if(_this->offs+_this->end_offs>=_this->storage&&l<used){
|
||||
window&=(1<<l)-1;
|
||||
_this->error=-1;
|
||||
}
|
||||
_this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
Copyright (c) 2008-2009 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !defined(_entenc_H)
|
||||
# define _entenc_H (1)
|
||||
# include <stddef.h>
|
||||
# include "entcode.h"
|
||||
|
||||
/*Initializes the encoder.
|
||||
_buf: The buffer to store output bytes in.
|
||||
_size: The size of the buffer, in chars.*/
|
||||
void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size);
|
||||
/*Encodes a symbol given its frequency information.
|
||||
The frequency information must be discernable by the decoder, assuming it
|
||||
has read only the previous symbols from the stream.
|
||||
It is allowable to change the frequency information, or even the entire
|
||||
source alphabet, so long as the decoder can tell from the context of the
|
||||
previously encoded information that it is supposed to do so as well.
|
||||
_fl: The cumulative frequency of all symbols that come before the one to be
|
||||
encoded.
|
||||
_fh: The cumulative frequency of all symbols up to and including the one to
|
||||
be encoded.
|
||||
Together with _fl, this defines the range [_fl,_fh) in which the
|
||||
decoded value will fall.
|
||||
_ft: The sum of the frequencies of all the symbols*/
|
||||
void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft);
|
||||
|
||||
/*Equivalent to ec_encode() with _ft==1<<_bits.*/
|
||||
void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits);
|
||||
|
||||
/* Encode a bit that has a 1/(1<<_logp) probability of being a one */
|
||||
void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp);
|
||||
|
||||
/*Encodes a symbol given an "inverse" CDF table.
|
||||
_s: The index of the symbol to encode.
|
||||
_icdf: The "inverse" CDF, such that symbol _s falls in the range
|
||||
[_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb.
|
||||
The values must be monotonically non-increasing, and the last value
|
||||
must be 0.
|
||||
_ftb: The number of bits of precision in the cumulative distribution.*/
|
||||
void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb);
|
||||
|
||||
/*Encodes a raw unsigned integer in the stream.
|
||||
_fl: The integer to encode.
|
||||
_ft: The number of integers that can be encoded (one more than the max).
|
||||
This must be at least one, and no more than 2**32-1.*/
|
||||
void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft);
|
||||
|
||||
/*Encodes a sequence of raw bits in the stream.
|
||||
_fl: The bits to encode.
|
||||
_ftb: The number of bits to encode.
|
||||
This must be between 1 and 25, inclusive.*/
|
||||
void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb);
|
||||
|
||||
/*Overwrites a few bits at the very start of an existing stream, after they
|
||||
have already been encoded.
|
||||
This makes it possible to have a few flags up front, where it is easy for
|
||||
decoders to access them without parsing the whole stream, even if their
|
||||
values are not determined until late in the encoding process, without having
|
||||
to buffer all the intermediate symbols in the encoder.
|
||||
In order for this to work, at least _nbits bits must have already been
|
||||
encoded using probabilities that are an exact power of two.
|
||||
The encoder can verify the number of encoded bits is sufficient, but cannot
|
||||
check this latter condition.
|
||||
_val: The bits to encode (in the least _nbits significant bits).
|
||||
They will be decoded in order from most-significant to least.
|
||||
_nbits: The number of bits to overwrite.
|
||||
This must be no more than 8.*/
|
||||
void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits);
|
||||
|
||||
/*Compacts the data to fit in the target size.
|
||||
This moves up the raw bits at the end of the current buffer so they are at
|
||||
the end of the new buffer size.
|
||||
The caller must ensure that the amount of data that's already been written
|
||||
will fit in the new size.
|
||||
_size: The number of bytes in the new buffer.
|
||||
This must be large enough to contain the bits already written, and
|
||||
must be no larger than the existing size.*/
|
||||
void ec_enc_shrink(ec_enc *_this,opus_uint32 _size);
|
||||
|
||||
/*Indicates that there are no more symbols to encode.
|
||||
All reamining output bytes are flushed to the output buffer.
|
||||
ec_enc_init() must be called before the encoder can be used again.*/
|
||||
void ec_enc_done(ec_enc *_this);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,773 @@
|
|||
/* Copyright (C) 2003-2008 Jean-Marc Valin
|
||||
Copyright (C) 2007-2012 Xiph.Org Foundation */
|
||||
/**
|
||||
@file fixed_debug.h
|
||||
@brief Fixed-point operations with debugging
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_DEBUG_H
|
||||
#define FIXED_DEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "opus_defines.h"
|
||||
|
||||
#ifdef CELT_C
|
||||
OPUS_EXPORT opus_int64 celt_mips=0;
|
||||
#else
|
||||
extern opus_int64 celt_mips;
|
||||
#endif
|
||||
|
||||
#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
|
||||
#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15))
|
||||
|
||||
/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
|
||||
#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16))
|
||||
|
||||
#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16)
|
||||
|
||||
#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
|
||||
#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
|
||||
|
||||
#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
|
||||
#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
|
||||
#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1))
|
||||
|
||||
#define SHR(a,b) SHR32(a,b)
|
||||
#define PSHR(a,b) PSHR32(a,b)
|
||||
|
||||
static OPUS_INLINE short NEG16(int x)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(x))
|
||||
{
|
||||
fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = -x;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
static OPUS_INLINE int NEG32(opus_int64 x)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_INT(x))
|
||||
{
|
||||
fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = -x;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short EXTRACT16_(int x, char *file, int line)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(x))
|
||||
{
|
||||
fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = x;
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int EXTEND32_(int x, char *file, int line)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(x))
|
||||
{
|
||||
fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = x;
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
|
||||
{
|
||||
fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a>>shift;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
|
||||
{
|
||||
fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a<<shift;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
static OPUS_INLINE int SHR32(opus_int64 a, int shift)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
|
||||
{
|
||||
fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a>>shift;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
|
||||
{
|
||||
fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a<<shift;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "SHL32: output is not int: %lld<<%d = %lld in %s: line %d\n", a, shift, res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((opus_val32)(1)<<((shift))>>1))),shift))
|
||||
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
|
||||
|
||||
#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
|
||||
#define HALF16(x) (SHR16(x,1))
|
||||
#define HALF32(x) (SHR32(x,1))
|
||||
|
||||
//#define SHR(a,shift) ((a) >> (shift))
|
||||
//#define SHL(a,shift) ((a) << (shift))
|
||||
|
||||
#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short ADD16_(int a, int b, char *file, int line)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a+b;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short SUB16_(int a, int b, char *file, int line)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a-b;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
||||
{
|
||||
fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a+b;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
||||
{
|
||||
fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a-b;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
#undef UADD32
|
||||
#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line)
|
||||
{
|
||||
opus_uint64 res;
|
||||
if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
|
||||
{
|
||||
fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a+b;
|
||||
if (!VERIFY_UINT(res))
|
||||
{
|
||||
fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
#undef USUB32
|
||||
#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line)
|
||||
{
|
||||
opus_uint64 res;
|
||||
if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
|
||||
{
|
||||
fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
if (a<b)
|
||||
{
|
||||
fprintf (stderr, "USUB32: inputs underflow: %llu < %llu in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a-b;
|
||||
if (!VERIFY_UINT(res))
|
||||
{
|
||||
fprintf (stderr, "USUB32: output is not uint32: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* result fits in 16 bits */
|
||||
static OPUS_INLINE short MULT16_16_16(int a, int b)
|
||||
{
|
||||
int res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a*b;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int MULT16_16_(int a, int b, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips++;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
|
||||
|
||||
#define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int MULT16_32_QX_(int a, opus_int64 b, int Q, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
if (ABS32(b)>=((opus_val32)(1)<<(15+Q)))
|
||||
{
|
||||
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = (((opus_int64)a)*(opus_int64)b) >> Q;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
if (Q==15)
|
||||
celt_mips+=3;
|
||||
else
|
||||
celt_mips+=4;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
if (ABS32(b)>=((opus_int64)(1)<<(15+Q)))
|
||||
{
|
||||
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<<Q)>>1))>> Q;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
if (Q==15)
|
||||
celt_mips+=4;
|
||||
else
|
||||
celt_mips+=5;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
|
||||
#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b))))
|
||||
|
||||
static OPUS_INLINE int SATURATE(int a, int b)
|
||||
{
|
||||
if (a>b)
|
||||
a=b;
|
||||
if (a<-b)
|
||||
a = -b;
|
||||
celt_mips+=3;
|
||||
return a;
|
||||
}
|
||||
|
||||
static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a)
|
||||
{
|
||||
celt_mips+=3;
|
||||
if (a>32767)
|
||||
return 32767;
|
||||
else if (a<-32768)
|
||||
return -32768;
|
||||
else return a;
|
||||
}
|
||||
|
||||
static OPUS_INLINE int MULT16_16_Q11_32(int a, int b)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res >>= 11;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=3;
|
||||
return res;
|
||||
}
|
||||
static OPUS_INLINE short MULT16_16_Q13(int a, int b)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res >>= 13;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=3;
|
||||
return res;
|
||||
}
|
||||
static OPUS_INLINE short MULT16_16_Q14(int a, int b)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res >>= 14;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=3;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res >>= 15;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=1;
|
||||
return res;
|
||||
}
|
||||
|
||||
static OPUS_INLINE short MULT16_16_P13(int a, int b)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res += 4096;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res >>= 13;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=4;
|
||||
return res;
|
||||
}
|
||||
static OPUS_INLINE short MULT16_16_P14(int a, int b)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res += 8192;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res >>= 14;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=4;
|
||||
return res;
|
||||
}
|
||||
static OPUS_INLINE short MULT16_16_P15(int a, int b)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = ((opus_int64)a)*b;
|
||||
res += 16384;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res >>= 15;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__)
|
||||
|
||||
static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (b==0)
|
||||
{
|
||||
fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
|
||||
{
|
||||
fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a/b;
|
||||
if (!VERIFY_SHORT(res))
|
||||
{
|
||||
fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
|
||||
if (res>32767)
|
||||
res = 32767;
|
||||
if (res<-32768)
|
||||
res = -32768;
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=35;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line)
|
||||
{
|
||||
opus_int64 res;
|
||||
if (b==0)
|
||||
{
|
||||
fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
||||
{
|
||||
fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
res = a/b;
|
||||
if (!VERIFY_INT(res))
|
||||
{
|
||||
fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||
#ifdef FIXED_DEBUG_ASSERT
|
||||
celt_assert(0);
|
||||
#endif
|
||||
}
|
||||
celt_mips+=70;
|
||||
return res;
|
||||
}
|
||||
|
||||
#undef PRINT_MIPS
|
||||
#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,134 @@
|
|||
/* Copyright (C) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (C) 2003-2008 Jean-Marc Valin
|
||||
Copyright (C) 2007-2008 CSIRO */
|
||||
/**
|
||||
@file fixed_generic.h
|
||||
@brief Generic fixed-point operations
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_GENERIC_H
|
||||
#define FIXED_GENERIC_H
|
||||
|
||||
/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */
|
||||
#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
|
||||
|
||||
/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
|
||||
#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
|
||||
|
||||
/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */
|
||||
#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
|
||||
|
||||
/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
|
||||
#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15))
|
||||
|
||||
/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
|
||||
#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15))
|
||||
|
||||
/** Compile-time conversion of float constant to 16-bit value */
|
||||
#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
|
||||
|
||||
/** Compile-time conversion of float constant to 32-bit value */
|
||||
#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
|
||||
|
||||
/** Negate a 16-bit value */
|
||||
#define NEG16(x) (-(x))
|
||||
/** Negate a 32-bit value */
|
||||
#define NEG32(x) (-(x))
|
||||
|
||||
/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */
|
||||
#define EXTRACT16(x) ((opus_val16)(x))
|
||||
/** Change a 16-bit value into a 32-bit value */
|
||||
#define EXTEND32(x) ((opus_val32)(x))
|
||||
|
||||
/** Arithmetic shift-right of a 16-bit value */
|
||||
#define SHR16(a,shift) ((a) >> (shift))
|
||||
/** Arithmetic shift-left of a 16-bit value */
|
||||
#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift)))
|
||||
/** Arithmetic shift-right of a 32-bit value */
|
||||
#define SHR32(a,shift) ((a) >> (shift))
|
||||
/** Arithmetic shift-left of a 32-bit value */
|
||||
#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift)))
|
||||
|
||||
/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */
|
||||
#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
|
||||
/** 32-bit arithmetic shift right where the argument can be negative */
|
||||
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
|
||||
|
||||
/** "RAW" macros, should not be used outside of this header file */
|
||||
#define SHR(a,shift) ((a) >> (shift))
|
||||
#define SHL(a,shift) SHL32(a,shift)
|
||||
#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
|
||||
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||
|
||||
#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x)))
|
||||
|
||||
/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */
|
||||
#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a))))
|
||||
/** Divide by two */
|
||||
#define HALF16(x) (SHR16(x,1))
|
||||
#define HALF32(x) (SHR32(x,1))
|
||||
|
||||
/** Add two 16-bit values */
|
||||
#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b)))
|
||||
/** Subtract two 16-bit values */
|
||||
#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b))
|
||||
/** Add two 32-bit values */
|
||||
#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b))
|
||||
/** Subtract two 32-bit values */
|
||||
#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b))
|
||||
|
||||
/** 16x16 multiplication where the result fits in 16 bits */
|
||||
#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b))))
|
||||
|
||||
/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */
|
||||
/** 16x16 multiplication where the result fits in 32 bits */
|
||||
#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b)))
|
||||
|
||||
/** 16x16 multiply-add where the result fits in 32 bits */
|
||||
#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
|
||||
/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
|
||||
b must fit in 31 bits.
|
||||
Result fits in 32 bits. */
|
||||
#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
|
||||
|
||||
#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
|
||||
#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11))
|
||||
#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
|
||||
#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
|
||||
#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
|
||||
|
||||
#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
|
||||
#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
|
||||
#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
|
||||
|
||||
/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */
|
||||
#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b))))
|
||||
|
||||
/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */
|
||||
#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b)))
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/* Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com> */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Version 1.1 */
|
||||
|
||||
#ifndef FLOAT_CAST_H
|
||||
#define FLOAT_CAST_H
|
||||
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
/*============================================================================
|
||||
** On Intel Pentium processors (especially PIII and probably P4), converting
|
||||
** from float to int is very slow. To meet the C specs, the code produced by
|
||||
** most C compilers targeting Pentium needs to change the FPU rounding mode
|
||||
** before the float to int conversion is performed.
|
||||
**
|
||||
** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
|
||||
** is this flushing of the pipeline which is so slow.
|
||||
**
|
||||
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
|
||||
** llrint and llrintf which fix this problem as a side effect.
|
||||
**
|
||||
** On Unix-like systems, the configure process should have detected the
|
||||
** presence of these functions. If they weren't found we have to replace them
|
||||
** here with a standard C cast.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The C99 prototypes for lrint and lrintf are as follows:
|
||||
**
|
||||
** long int lrintf (float x) ;
|
||||
** long int lrint (double x) ;
|
||||
*/
|
||||
|
||||
/* The presence of the required functions are detected during the configure
|
||||
** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
|
||||
** the config.h file.
|
||||
*/
|
||||
|
||||
#if (HAVE_LRINTF)
|
||||
|
||||
/* These defines enable functionality introduced with the 1999 ISO C
|
||||
** standard. They must be defined before the inclusion of math.h to
|
||||
** engage them. If optimisation is enabled, these functions will be
|
||||
** inlined. With optimisation switched off, you have to link in the
|
||||
** maths library using -lm.
|
||||
*/
|
||||
|
||||
#define _ISOC9X_SOURCE 1
|
||||
#define _ISOC99_SOURCE 1
|
||||
|
||||
#define __USE_ISOC9X 1
|
||||
#define __USE_ISOC99 1
|
||||
|
||||
#include <math.h>
|
||||
#define float2int(x) lrintf(x)
|
||||
|
||||
#elif (defined(HAVE_LRINT))
|
||||
|
||||
#define _ISOC9X_SOURCE 1
|
||||
#define _ISOC99_SOURCE 1
|
||||
|
||||
#define __USE_ISOC9X 1
|
||||
#define __USE_ISOC99 1
|
||||
|
||||
#include <math.h>
|
||||
#define float2int(x) lrint(x)
|
||||
|
||||
#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined (WIN64) || defined (_WIN64))
|
||||
#include <xmmintrin.h>
|
||||
|
||||
__inline long int float2int(float value)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_load_ss(&value));
|
||||
}
|
||||
#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined (WIN32) || defined (_WIN32))
|
||||
#include <math.h>
|
||||
|
||||
/* Win32 doesn't seem to have these functions.
|
||||
** Therefore implement OPUS_INLINE versions of these functions here.
|
||||
*/
|
||||
|
||||
__inline long int
|
||||
float2int (float flt)
|
||||
{ int intgr;
|
||||
|
||||
_asm
|
||||
{ fld flt
|
||||
fistp intgr
|
||||
} ;
|
||||
|
||||
return intgr ;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
||||
/* supported by gcc in C99 mode, but not by all other compilers */
|
||||
#warning "Don't have the functions lrint() and lrintf ()."
|
||||
#warning "Replacing these functions with a standard C cast."
|
||||
#endif /* __STDC_VERSION__ >= 199901L */
|
||||
#include <math.h>
|
||||
#define float2int(flt) ((int)(floor(.5+flt)))
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
static OPUS_INLINE opus_int16 FLOAT2INT16(float x)
|
||||
{
|
||||
x = x*CELT_SIG_SCALE;
|
||||
x = MAX32(x, -32768);
|
||||
x = MIN32(x, 32767);
|
||||
return (opus_int16)float2int(x);
|
||||
}
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
||||
#endif /* FLOAT_CAST_H */
|
|
@ -0,0 +1,719 @@
|
|||
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||
Lots of modifications by Jean-Marc Valin
|
||||
Copyright (c) 2005-2007, Xiph.Org Foundation
|
||||
Copyright (c) 2008, Xiph.Org Foundation, CSIRO
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.*/
|
||||
|
||||
/* This code is originally from Mark Borgerding's KISS-FFT but has been
|
||||
heavily modified to better suit Opus */
|
||||
|
||||
#ifndef SKIP_CONFIG_H
|
||||
# ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "_kiss_fft_guts.h"
|
||||
#include "arch.h"
|
||||
#include "os_support.h"
|
||||
#include "mathops.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
/* The guts header contains all the multiplication and addition macros that are defined for
|
||||
complex numbers. It also delares the kf_ internal functions.
|
||||
*/
|
||||
|
||||
static void kf_bfly2(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
kiss_fft_cpx * Fout2;
|
||||
const kiss_twiddle_cpx * tw1;
|
||||
int i,j;
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
Fout2 = Fout + m;
|
||||
tw1 = st->twiddles;
|
||||
for(j=0;j<m;j++)
|
||||
{
|
||||
kiss_fft_cpx t;
|
||||
Fout->r = SHR32(Fout->r, 1);Fout->i = SHR32(Fout->i, 1);
|
||||
Fout2->r = SHR32(Fout2->r, 1);Fout2->i = SHR32(Fout2->i, 1);
|
||||
C_MUL (t, *Fout2 , *tw1);
|
||||
tw1 += fstride;
|
||||
C_SUB( *Fout2 , *Fout , t );
|
||||
C_ADDTO( *Fout , t );
|
||||
++Fout2;
|
||||
++Fout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ki_bfly2(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
kiss_fft_cpx * Fout2;
|
||||
const kiss_twiddle_cpx * tw1;
|
||||
kiss_fft_cpx t;
|
||||
int i,j;
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
Fout2 = Fout + m;
|
||||
tw1 = st->twiddles;
|
||||
for(j=0;j<m;j++)
|
||||
{
|
||||
C_MULC (t, *Fout2 , *tw1);
|
||||
tw1 += fstride;
|
||||
C_SUB( *Fout2 , *Fout , t );
|
||||
C_ADDTO( *Fout , t );
|
||||
++Fout2;
|
||||
++Fout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kf_bfly4(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
const kiss_twiddle_cpx *tw1,*tw2,*tw3;
|
||||
kiss_fft_cpx scratch[6];
|
||||
const size_t m2=2*m;
|
||||
const size_t m3=3*m;
|
||||
int i, j;
|
||||
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
tw3 = tw2 = tw1 = st->twiddles;
|
||||
for (j=0;j<m;j++)
|
||||
{
|
||||
C_MUL4(scratch[0],Fout[m] , *tw1 );
|
||||
C_MUL4(scratch[1],Fout[m2] , *tw2 );
|
||||
C_MUL4(scratch[2],Fout[m3] , *tw3 );
|
||||
|
||||
Fout->r = PSHR32(Fout->r, 2);
|
||||
Fout->i = PSHR32(Fout->i, 2);
|
||||
C_SUB( scratch[5] , *Fout, scratch[1] );
|
||||
C_ADDTO(*Fout, scratch[1]);
|
||||
C_ADD( scratch[3] , scratch[0] , scratch[2] );
|
||||
C_SUB( scratch[4] , scratch[0] , scratch[2] );
|
||||
C_SUB( Fout[m2], *Fout, scratch[3] );
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
tw3 += fstride*3;
|
||||
C_ADDTO( *Fout , scratch[3] );
|
||||
|
||||
Fout[m].r = scratch[5].r + scratch[4].i;
|
||||
Fout[m].i = scratch[5].i - scratch[4].r;
|
||||
Fout[m3].r = scratch[5].r - scratch[4].i;
|
||||
Fout[m3].i = scratch[5].i + scratch[4].r;
|
||||
++Fout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ki_bfly4(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
const kiss_twiddle_cpx *tw1,*tw2,*tw3;
|
||||
kiss_fft_cpx scratch[6];
|
||||
const size_t m2=2*m;
|
||||
const size_t m3=3*m;
|
||||
int i, j;
|
||||
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
tw3 = tw2 = tw1 = st->twiddles;
|
||||
for (j=0;j<m;j++)
|
||||
{
|
||||
C_MULC(scratch[0],Fout[m] , *tw1 );
|
||||
C_MULC(scratch[1],Fout[m2] , *tw2 );
|
||||
C_MULC(scratch[2],Fout[m3] , *tw3 );
|
||||
|
||||
C_SUB( scratch[5] , *Fout, scratch[1] );
|
||||
C_ADDTO(*Fout, scratch[1]);
|
||||
C_ADD( scratch[3] , scratch[0] , scratch[2] );
|
||||
C_SUB( scratch[4] , scratch[0] , scratch[2] );
|
||||
C_SUB( Fout[m2], *Fout, scratch[3] );
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
tw3 += fstride*3;
|
||||
C_ADDTO( *Fout , scratch[3] );
|
||||
|
||||
Fout[m].r = scratch[5].r - scratch[4].i;
|
||||
Fout[m].i = scratch[5].i + scratch[4].r;
|
||||
Fout[m3].r = scratch[5].r + scratch[4].i;
|
||||
Fout[m3].i = scratch[5].i - scratch[4].r;
|
||||
++Fout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
|
||||
static void kf_bfly3(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
int i;
|
||||
size_t k;
|
||||
const size_t m2 = 2*m;
|
||||
const kiss_twiddle_cpx *tw1,*tw2;
|
||||
kiss_fft_cpx scratch[5];
|
||||
kiss_twiddle_cpx epi3;
|
||||
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
epi3 = st->twiddles[fstride*m];
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
tw1=tw2=st->twiddles;
|
||||
k=m;
|
||||
do {
|
||||
C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
|
||||
|
||||
C_MUL(scratch[1],Fout[m] , *tw1);
|
||||
C_MUL(scratch[2],Fout[m2] , *tw2);
|
||||
|
||||
C_ADD(scratch[3],scratch[1],scratch[2]);
|
||||
C_SUB(scratch[0],scratch[1],scratch[2]);
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
|
||||
Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
|
||||
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
|
||||
|
||||
C_MULBYSCALAR( scratch[0] , epi3.i );
|
||||
|
||||
C_ADDTO(*Fout,scratch[3]);
|
||||
|
||||
Fout[m2].r = Fout[m].r + scratch[0].i;
|
||||
Fout[m2].i = Fout[m].i - scratch[0].r;
|
||||
|
||||
Fout[m].r -= scratch[0].i;
|
||||
Fout[m].i += scratch[0].r;
|
||||
|
||||
++Fout;
|
||||
} while(--k);
|
||||
}
|
||||
}
|
||||
|
||||
static void ki_bfly3(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
int i, k;
|
||||
const size_t m2 = 2*m;
|
||||
const kiss_twiddle_cpx *tw1,*tw2;
|
||||
kiss_fft_cpx scratch[5];
|
||||
kiss_twiddle_cpx epi3;
|
||||
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
epi3 = st->twiddles[fstride*m];
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
tw1=tw2=st->twiddles;
|
||||
k=m;
|
||||
do{
|
||||
|
||||
C_MULC(scratch[1],Fout[m] , *tw1);
|
||||
C_MULC(scratch[2],Fout[m2] , *tw2);
|
||||
|
||||
C_ADD(scratch[3],scratch[1],scratch[2]);
|
||||
C_SUB(scratch[0],scratch[1],scratch[2]);
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
|
||||
Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
|
||||
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
|
||||
|
||||
C_MULBYSCALAR( scratch[0] , -epi3.i );
|
||||
|
||||
C_ADDTO(*Fout,scratch[3]);
|
||||
|
||||
Fout[m2].r = Fout[m].r + scratch[0].i;
|
||||
Fout[m2].i = Fout[m].i - scratch[0].r;
|
||||
|
||||
Fout[m].r -= scratch[0].i;
|
||||
Fout[m].i += scratch[0].r;
|
||||
|
||||
++Fout;
|
||||
}while(--k);
|
||||
}
|
||||
}
|
||||
|
||||
static void kf_bfly5(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
|
||||
int i, u;
|
||||
kiss_fft_cpx scratch[13];
|
||||
const kiss_twiddle_cpx * twiddles = st->twiddles;
|
||||
const kiss_twiddle_cpx *tw;
|
||||
kiss_twiddle_cpx ya,yb;
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
|
||||
ya = twiddles[fstride*m];
|
||||
yb = twiddles[fstride*2*m];
|
||||
tw=st->twiddles;
|
||||
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
Fout0=Fout;
|
||||
Fout1=Fout0+m;
|
||||
Fout2=Fout0+2*m;
|
||||
Fout3=Fout0+3*m;
|
||||
Fout4=Fout0+4*m;
|
||||
|
||||
for ( u=0; u<m; ++u ) {
|
||||
C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
|
||||
scratch[0] = *Fout0;
|
||||
|
||||
C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
|
||||
C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
|
||||
C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
|
||||
C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
|
||||
|
||||
C_ADD( scratch[7],scratch[1],scratch[4]);
|
||||
C_SUB( scratch[10],scratch[1],scratch[4]);
|
||||
C_ADD( scratch[8],scratch[2],scratch[3]);
|
||||
C_SUB( scratch[9],scratch[2],scratch[3]);
|
||||
|
||||
Fout0->r += scratch[7].r + scratch[8].r;
|
||||
Fout0->i += scratch[7].i + scratch[8].i;
|
||||
|
||||
scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
|
||||
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
|
||||
|
||||
scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
|
||||
scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
|
||||
|
||||
C_SUB(*Fout1,scratch[5],scratch[6]);
|
||||
C_ADD(*Fout4,scratch[5],scratch[6]);
|
||||
|
||||
scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
|
||||
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
|
||||
scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
|
||||
scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
|
||||
|
||||
C_ADD(*Fout2,scratch[11],scratch[12]);
|
||||
C_SUB(*Fout3,scratch[11],scratch[12]);
|
||||
|
||||
++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ki_bfly5(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_state *st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
|
||||
int i, u;
|
||||
kiss_fft_cpx scratch[13];
|
||||
const kiss_twiddle_cpx * twiddles = st->twiddles;
|
||||
const kiss_twiddle_cpx *tw;
|
||||
kiss_twiddle_cpx ya,yb;
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
|
||||
ya = twiddles[fstride*m];
|
||||
yb = twiddles[fstride*2*m];
|
||||
tw=st->twiddles;
|
||||
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
Fout0=Fout;
|
||||
Fout1=Fout0+m;
|
||||
Fout2=Fout0+2*m;
|
||||
Fout3=Fout0+3*m;
|
||||
Fout4=Fout0+4*m;
|
||||
|
||||
for ( u=0; u<m; ++u ) {
|
||||
scratch[0] = *Fout0;
|
||||
|
||||
C_MULC(scratch[1] ,*Fout1, tw[u*fstride]);
|
||||
C_MULC(scratch[2] ,*Fout2, tw[2*u*fstride]);
|
||||
C_MULC(scratch[3] ,*Fout3, tw[3*u*fstride]);
|
||||
C_MULC(scratch[4] ,*Fout4, tw[4*u*fstride]);
|
||||
|
||||
C_ADD( scratch[7],scratch[1],scratch[4]);
|
||||
C_SUB( scratch[10],scratch[1],scratch[4]);
|
||||
C_ADD( scratch[8],scratch[2],scratch[3]);
|
||||
C_SUB( scratch[9],scratch[2],scratch[3]);
|
||||
|
||||
Fout0->r += scratch[7].r + scratch[8].r;
|
||||
Fout0->i += scratch[7].i + scratch[8].i;
|
||||
|
||||
scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
|
||||
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
|
||||
|
||||
scratch[6].r = -S_MUL(scratch[10].i,ya.i) - S_MUL(scratch[9].i,yb.i);
|
||||
scratch[6].i = S_MUL(scratch[10].r,ya.i) + S_MUL(scratch[9].r,yb.i);
|
||||
|
||||
C_SUB(*Fout1,scratch[5],scratch[6]);
|
||||
C_ADD(*Fout4,scratch[5],scratch[6]);
|
||||
|
||||
scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
|
||||
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
|
||||
scratch[12].r = S_MUL(scratch[10].i,yb.i) - S_MUL(scratch[9].i,ya.i);
|
||||
scratch[12].i = -S_MUL(scratch[10].r,yb.i) + S_MUL(scratch[9].r,ya.i);
|
||||
|
||||
C_ADD(*Fout2,scratch[11],scratch[12]);
|
||||
C_SUB(*Fout3,scratch[11],scratch[12]);
|
||||
|
||||
++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
|
||||
static
|
||||
void compute_bitrev_table(
|
||||
int Fout,
|
||||
opus_int16 *f,
|
||||
const size_t fstride,
|
||||
int in_stride,
|
||||
opus_int16 * factors,
|
||||
const kiss_fft_state *st
|
||||
)
|
||||
{
|
||||
const int p=*factors++; /* the radix */
|
||||
const int m=*factors++; /* stage's fft length/p */
|
||||
|
||||
/*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
|
||||
if (m==1)
|
||||
{
|
||||
int j;
|
||||
for (j=0;j<p;j++)
|
||||
{
|
||||
*f = Fout+j;
|
||||
f += fstride*in_stride;
|
||||
}
|
||||
} else {
|
||||
int j;
|
||||
for (j=0;j<p;j++)
|
||||
{
|
||||
compute_bitrev_table( Fout , f, fstride*p, in_stride, factors,st);
|
||||
f += fstride*in_stride;
|
||||
Fout += m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* facbuf is populated by p1,m1,p2,m2, ...
|
||||
where
|
||||
p[i] * m[i] = m[i-1]
|
||||
m0 = n */
|
||||
static
|
||||
int kf_factor(int n,opus_int16 * facbuf)
|
||||
{
|
||||
int p=4;
|
||||
|
||||
/*factor out powers of 4, powers of 2, then any remaining primes */
|
||||
do {
|
||||
while (n % p) {
|
||||
switch (p) {
|
||||
case 4: p = 2; break;
|
||||
case 2: p = 3; break;
|
||||
default: p += 2; break;
|
||||
}
|
||||
if (p>32000 || (opus_int32)p*(opus_int32)p > n)
|
||||
p = n; /* no more factors, skip to end */
|
||||
}
|
||||
n /= p;
|
||||
#ifdef RADIX_TWO_ONLY
|
||||
if (p!=2 && p != 4)
|
||||
#else
|
||||
if (p>5)
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*facbuf++ = p;
|
||||
*facbuf++ = n;
|
||||
} while (n > 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft)
|
||||
{
|
||||
int i;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
for (i=0;i<nfft;++i) {
|
||||
opus_val32 phase = -i;
|
||||
kf_cexp2(twiddles+i, DIV32(SHL32(phase,17),nfft));
|
||||
}
|
||||
#else
|
||||
for (i=0;i<nfft;++i) {
|
||||
const double pi=3.14159265358979323846264338327;
|
||||
double phase = ( -2*pi /nfft ) * i;
|
||||
kf_cexp(twiddles+i, phase );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Allocates all necessary storage space for the fft and ifft.
|
||||
* The return value is a contiguous block of memory. As such,
|
||||
* It can be freed with free().
|
||||
* */
|
||||
kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base)
|
||||
{
|
||||
kiss_fft_state *st=NULL;
|
||||
size_t memneeded = sizeof(struct kiss_fft_state); /* twiddle factors*/
|
||||
|
||||
if ( lenmem==NULL ) {
|
||||
st = ( kiss_fft_state*)KISS_FFT_MALLOC( memneeded );
|
||||
}else{
|
||||
if (mem != NULL && *lenmem >= memneeded)
|
||||
st = (kiss_fft_state*)mem;
|
||||
*lenmem = memneeded;
|
||||
}
|
||||
if (st) {
|
||||
opus_int16 *bitrev;
|
||||
kiss_twiddle_cpx *twiddles;
|
||||
|
||||
st->nfft=nfft;
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
st->scale = 1.f/nfft;
|
||||
#endif
|
||||
if (base != NULL)
|
||||
{
|
||||
st->twiddles = base->twiddles;
|
||||
st->shift = 0;
|
||||
while (nfft<<st->shift != base->nfft && st->shift < 32)
|
||||
st->shift++;
|
||||
if (st->shift>=32)
|
||||
goto fail;
|
||||
} else {
|
||||
st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft);
|
||||
compute_twiddles(twiddles, nfft);
|
||||
st->shift = -1;
|
||||
}
|
||||
if (!kf_factor(nfft,st->factors))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* bitrev */
|
||||
st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft);
|
||||
if (st->bitrev==NULL)
|
||||
goto fail;
|
||||
compute_bitrev_table(0, bitrev, 1,1, st->factors,st);
|
||||
}
|
||||
return st;
|
||||
fail:
|
||||
opus_fft_free(st);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem )
|
||||
{
|
||||
return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL);
|
||||
}
|
||||
|
||||
void opus_fft_free(const kiss_fft_state *cfg)
|
||||
{
|
||||
if (cfg)
|
||||
{
|
||||
opus_free((opus_int16*)cfg->bitrev);
|
||||
if (cfg->shift < 0)
|
||||
opus_free((kiss_twiddle_cpx*)cfg->twiddles);
|
||||
opus_free((kiss_fft_state*)cfg);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
void opus_fft(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
|
||||
{
|
||||
int m2, m;
|
||||
int p;
|
||||
int L;
|
||||
int fstride[MAXFACTORS];
|
||||
int i;
|
||||
int shift;
|
||||
|
||||
/* st->shift can be -1 */
|
||||
shift = st->shift>0 ? st->shift : 0;
|
||||
|
||||
celt_assert2 (fin != fout, "In-place FFT not supported");
|
||||
/* Bit-reverse the input */
|
||||
for (i=0;i<st->nfft;i++)
|
||||
{
|
||||
fout[st->bitrev[i]] = fin[i];
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
fout[st->bitrev[i]].r *= st->scale;
|
||||
fout[st->bitrev[i]].i *= st->scale;
|
||||
#endif
|
||||
}
|
||||
|
||||
fstride[0] = 1;
|
||||
L=0;
|
||||
do {
|
||||
p = st->factors[2*L];
|
||||
m = st->factors[2*L+1];
|
||||
fstride[L+1] = fstride[L]*p;
|
||||
L++;
|
||||
} while(m!=1);
|
||||
m = st->factors[2*L-1];
|
||||
for (i=L-1;i>=0;i--)
|
||||
{
|
||||
if (i!=0)
|
||||
m2 = st->factors[2*i-1];
|
||||
else
|
||||
m2 = 1;
|
||||
switch (st->factors[2*i])
|
||||
{
|
||||
case 2:
|
||||
kf_bfly2(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
case 4:
|
||||
kf_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
case 3:
|
||||
kf_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
case 5:
|
||||
kf_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
m = m2;
|
||||
}
|
||||
}
|
||||
|
||||
void opus_ifft(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
|
||||
{
|
||||
int m2, m;
|
||||
int p;
|
||||
int L;
|
||||
int fstride[MAXFACTORS];
|
||||
int i;
|
||||
int shift;
|
||||
|
||||
/* st->shift can be -1 */
|
||||
shift = st->shift>0 ? st->shift : 0;
|
||||
celt_assert2 (fin != fout, "In-place FFT not supported");
|
||||
/* Bit-reverse the input */
|
||||
for (i=0;i<st->nfft;i++)
|
||||
fout[st->bitrev[i]] = fin[i];
|
||||
|
||||
fstride[0] = 1;
|
||||
L=0;
|
||||
do {
|
||||
p = st->factors[2*L];
|
||||
m = st->factors[2*L+1];
|
||||
fstride[L+1] = fstride[L]*p;
|
||||
L++;
|
||||
} while(m!=1);
|
||||
m = st->factors[2*L-1];
|
||||
for (i=L-1;i>=0;i--)
|
||||
{
|
||||
if (i!=0)
|
||||
m2 = st->factors[2*i-1];
|
||||
else
|
||||
m2 = 1;
|
||||
switch (st->factors[2*i])
|
||||
{
|
||||
case 2:
|
||||
ki_bfly2(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
case 4:
|
||||
ki_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
case 3:
|
||||
ki_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
case 5:
|
||||
ki_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
m = m2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*Copyright (c) 2003-2004, Mark Borgerding
|
||||
Lots of modifications by Jean-Marc Valin
|
||||
Copyright (c) 2005-2007, Xiph.Org Foundation
|
||||
Copyright (c) 2008, Xiph.Org Foundation, CSIRO
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.*/
|
||||
|
||||
#ifndef KISS_FFT_H
|
||||
#define KISS_FFT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "arch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIMD
|
||||
# include <xmmintrin.h>
|
||||
# define kiss_fft_scalar __m128
|
||||
#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
|
||||
#else
|
||||
#define KISS_FFT_MALLOC opus_alloc
|
||||
#endif
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
#include "arch.h"
|
||||
|
||||
# define kiss_fft_scalar opus_int32
|
||||
# define kiss_twiddle_scalar opus_int16
|
||||
|
||||
|
||||
#else
|
||||
# ifndef kiss_fft_scalar
|
||||
/* default is float */
|
||||
# define kiss_fft_scalar float
|
||||
# define kiss_twiddle_scalar float
|
||||
# define KF_SUFFIX _celt_single
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kiss_fft_scalar r;
|
||||
kiss_fft_scalar i;
|
||||
}kiss_fft_cpx;
|
||||
|
||||
typedef struct {
|
||||
kiss_twiddle_scalar r;
|
||||
kiss_twiddle_scalar i;
|
||||
}kiss_twiddle_cpx;
|
||||
|
||||
#define MAXFACTORS 8
|
||||
/* e.g. an fft of length 128 has 4 factors
|
||||
as far as kissfft is concerned
|
||||
4*4*4*2
|
||||
*/
|
||||
|
||||
typedef struct kiss_fft_state{
|
||||
int nfft;
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
kiss_fft_scalar scale;
|
||||
#endif
|
||||
int shift;
|
||||
opus_int16 factors[2*MAXFACTORS];
|
||||
const opus_int16 *bitrev;
|
||||
const kiss_twiddle_cpx *twiddles;
|
||||
} kiss_fft_state;
|
||||
|
||||
/*typedef struct kiss_fft_state* kiss_fft_cfg;*/
|
||||
|
||||
/**
|
||||
* opus_fft_alloc
|
||||
*
|
||||
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
|
||||
*
|
||||
* typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL);
|
||||
*
|
||||
* The return value from fft_alloc is a cfg buffer used internally
|
||||
* by the fft routine or NULL.
|
||||
*
|
||||
* If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc.
|
||||
* The returned value should be free()d when done to avoid memory leaks.
|
||||
*
|
||||
* The state can be placed in a user supplied buffer 'mem':
|
||||
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
|
||||
* then the function places the cfg in mem and the size used in *lenmem
|
||||
* and returns mem.
|
||||
*
|
||||
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
|
||||
* then the function returns NULL and places the minimum cfg
|
||||
* buffer size in *lenmem.
|
||||
* */
|
||||
|
||||
kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base);
|
||||
|
||||
kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem);
|
||||
|
||||
/**
|
||||
* opus_fft(cfg,in_out_buf)
|
||||
*
|
||||
* Perform an FFT on a complex input buffer.
|
||||
* for a forward FFT,
|
||||
* fin should be f[0] , f[1] , ... ,f[nfft-1]
|
||||
* fout will be F[0] , F[1] , ... ,F[nfft-1]
|
||||
* Note that each element is complex and can be accessed like
|
||||
f[k].r and f[k].i
|
||||
* */
|
||||
void opus_fft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||
void opus_ifft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||
|
||||
void opus_fft_free(const kiss_fft_state *cfg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,134 @@
|
|||
/* Copyright (c) 2007 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "laplace.h"
|
||||
#include "mathops.h"
|
||||
|
||||
/* The minimum probability of an energy delta (out of 32768). */
|
||||
#define LAPLACE_LOG_MINP (0)
|
||||
#define LAPLACE_MINP (1<<LAPLACE_LOG_MINP)
|
||||
/* The minimum number of guaranteed representable energy deltas (in one
|
||||
direction). */
|
||||
#define LAPLACE_NMIN (16)
|
||||
|
||||
/* When called, decay is positive and at most 11456. */
|
||||
static unsigned ec_laplace_get_freq1(unsigned fs0, int decay)
|
||||
{
|
||||
unsigned ft;
|
||||
ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN) - fs0;
|
||||
return ft*(opus_int32)(16384-decay)>>15;
|
||||
}
|
||||
|
||||
void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay)
|
||||
{
|
||||
unsigned fl;
|
||||
int val = *value;
|
||||
fl = 0;
|
||||
if (val)
|
||||
{
|
||||
int s;
|
||||
int i;
|
||||
s = -(val<0);
|
||||
val = (val+s)^s;
|
||||
fl = fs;
|
||||
fs = ec_laplace_get_freq1(fs, decay);
|
||||
/* Search the decaying part of the PDF.*/
|
||||
for (i=1; fs > 0 && i < val; i++)
|
||||
{
|
||||
fs *= 2;
|
||||
fl += fs+2*LAPLACE_MINP;
|
||||
fs = (fs*(opus_int32)decay)>>15;
|
||||
}
|
||||
/* Everything beyond that has probability LAPLACE_MINP. */
|
||||
if (!fs)
|
||||
{
|
||||
int di;
|
||||
int ndi_max;
|
||||
ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP;
|
||||
ndi_max = (ndi_max-s)>>1;
|
||||
di = IMIN(val - i, ndi_max - 1);
|
||||
fl += (2*di+1+s)*LAPLACE_MINP;
|
||||
fs = IMIN(LAPLACE_MINP, 32768-fl);
|
||||
*value = (i+di+s)^s;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs += LAPLACE_MINP;
|
||||
fl += fs&~s;
|
||||
}
|
||||
celt_assert(fl+fs<=32768);
|
||||
celt_assert(fs>0);
|
||||
}
|
||||
ec_encode_bin(enc, fl, fl+fs, 15);
|
||||
}
|
||||
|
||||
int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay)
|
||||
{
|
||||
int val=0;
|
||||
unsigned fl;
|
||||
unsigned fm;
|
||||
fm = ec_decode_bin(dec, 15);
|
||||
fl = 0;
|
||||
if (fm >= fs)
|
||||
{
|
||||
val++;
|
||||
fl = fs;
|
||||
fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP;
|
||||
/* Search the decaying part of the PDF.*/
|
||||
while(fs > LAPLACE_MINP && fm >= fl+2*fs)
|
||||
{
|
||||
fs *= 2;
|
||||
fl += fs;
|
||||
fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15;
|
||||
fs += LAPLACE_MINP;
|
||||
val++;
|
||||
}
|
||||
/* Everything beyond that has probability LAPLACE_MINP. */
|
||||
if (fs <= LAPLACE_MINP)
|
||||
{
|
||||
int di;
|
||||
di = (fm-fl)>>(LAPLACE_LOG_MINP+1);
|
||||
val += di;
|
||||
fl += 2*di*LAPLACE_MINP;
|
||||
}
|
||||
if (fm < fl+fs)
|
||||
val = -val;
|
||||
else
|
||||
fl += fs;
|
||||
}
|
||||
celt_assert(fl<32768);
|
||||
celt_assert(fs>0);
|
||||
celt_assert(fl<=fm);
|
||||
celt_assert(fm<IMIN(fl+fs,32768));
|
||||
ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
|
||||
return val;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* Copyright (c) 2007 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
|
||||
/** Encode a value that is assumed to be the realisation of a
|
||||
Laplace-distributed random process
|
||||
@param enc Entropy encoder state
|
||||
@param value Value to encode
|
||||
@param fs Probability of 0, multiplied by 32768
|
||||
@param decay Probability of the value +/- 1, multiplied by 16384
|
||||
*/
|
||||
void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay);
|
||||
|
||||
/** Decode a value that is assumed to be the realisation of a
|
||||
Laplace-distributed random process
|
||||
@param dec Entropy decoder state
|
||||
@param fs Probability of 0, multiplied by 32768
|
||||
@param decay Probability of the value +/- 1, multiplied by 16384
|
||||
@return Value decoded
|
||||
*/
|
||||
int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay);
|
|
@ -0,0 +1,208 @@
|
|||
/* Copyright (c) 2002-2008 Jean-Marc Valin
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file mathops.h
|
||||
@brief Various math functions
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "mathops.h"
|
||||
|
||||
/*Compute floor(sqrt(_val)) with exact arithmetic.
|
||||
This has been tested on all possible 32-bit inputs.*/
|
||||
unsigned isqrt32(opus_uint32 _val){
|
||||
unsigned b;
|
||||
unsigned g;
|
||||
int bshift;
|
||||
/*Uses the second method from
|
||||
http://www.azillionmonkeys.com/qed/sqroot.html
|
||||
The main idea is to search for the largest binary digit b such that
|
||||
(g+b)*(g+b) <= _val, and add it to the solution g.*/
|
||||
g=0;
|
||||
bshift=(EC_ILOG(_val)-1)>>1;
|
||||
b=1U<<bshift;
|
||||
do{
|
||||
opus_uint32 t;
|
||||
t=(((opus_uint32)g<<1)+b)<<bshift;
|
||||
if(t<=_val){
|
||||
g+=b;
|
||||
_val-=t;
|
||||
}
|
||||
b>>=1;
|
||||
bshift--;
|
||||
}
|
||||
while(bshift>=0);
|
||||
return g;
|
||||
}
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
|
||||
opus_val32 frac_div32(opus_val32 a, opus_val32 b)
|
||||
{
|
||||
opus_val16 rcp;
|
||||
opus_val32 result, rem;
|
||||
int shift = celt_ilog2(b)-29;
|
||||
a = VSHR32(a,shift);
|
||||
b = VSHR32(b,shift);
|
||||
/* 16-bit reciprocal */
|
||||
rcp = ROUND16(celt_rcp(ROUND16(b,16)),3);
|
||||
result = MULT16_32_Q15(rcp, a);
|
||||
rem = PSHR32(a,2)-MULT32_32_Q31(result, b);
|
||||
result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2));
|
||||
if (result >= 536870912) /* 2^29 */
|
||||
return 2147483647; /* 2^31 - 1 */
|
||||
else if (result <= -536870912) /* -2^29 */
|
||||
return -2147483647; /* -2^31 */
|
||||
else
|
||||
return SHL32(result, 2);
|
||||
}
|
||||
|
||||
/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */
|
||||
opus_val16 celt_rsqrt_norm(opus_val32 x)
|
||||
{
|
||||
opus_val16 n;
|
||||
opus_val16 r;
|
||||
opus_val16 r2;
|
||||
opus_val16 y;
|
||||
/* Range of n is [-16384,32767] ([-0.5,1) in Q15). */
|
||||
n = x-32768;
|
||||
/* Get a rough initial guess for the root.
|
||||
The optimal minimax quadratic approximation (using relative error) is
|
||||
r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485).
|
||||
Coefficients here, and the final result r, are Q14.*/
|
||||
r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713))));
|
||||
/* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14.
|
||||
We can compute the result from n and r using Q15 multiplies with some
|
||||
adjustment, carefully done to avoid overflow.
|
||||
Range of y is [-1564,1594]. */
|
||||
r2 = MULT16_16_Q15(r, r);
|
||||
y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1);
|
||||
/* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5).
|
||||
This yields the Q14 reciprocal square root of the Q16 x, with a maximum
|
||||
relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a
|
||||
peak absolute error of 2.26591/16384. */
|
||||
return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y,
|
||||
SUB16(MULT16_16_Q15(y, 12288), 16384))));
|
||||
}
|
||||
|
||||
/** Sqrt approximation (QX input, QX/2 output) */
|
||||
opus_val32 celt_sqrt(opus_val32 x)
|
||||
{
|
||||
int k;
|
||||
opus_val16 n;
|
||||
opus_val32 rt;
|
||||
static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664};
|
||||
if (x==0)
|
||||
return 0;
|
||||
else if (x>=1073741824)
|
||||
return 32767;
|
||||
k = (celt_ilog2(x)>>1)-7;
|
||||
x = VSHR32(x, 2*k);
|
||||
n = x-32768;
|
||||
rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
|
||||
MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
|
||||
rt = VSHR32(rt,7-k);
|
||||
return rt;
|
||||
}
|
||||
|
||||
#define L1 32767
|
||||
#define L2 -7651
|
||||
#define L3 8277
|
||||
#define L4 -626
|
||||
|
||||
static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x)
|
||||
{
|
||||
opus_val16 x2;
|
||||
|
||||
x2 = MULT16_16_P15(x,x);
|
||||
return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2
|
||||
))))))));
|
||||
}
|
||||
|
||||
#undef L1
|
||||
#undef L2
|
||||
#undef L3
|
||||
#undef L4
|
||||
|
||||
opus_val16 celt_cos_norm(opus_val32 x)
|
||||
{
|
||||
x = x&0x0001ffff;
|
||||
if (x>SHL32(EXTEND32(1), 16))
|
||||
x = SUB32(SHL32(EXTEND32(1), 17),x);
|
||||
if (x&0x00007fff)
|
||||
{
|
||||
if (x<SHL32(EXTEND32(1), 15))
|
||||
{
|
||||
return _celt_cos_pi_2(EXTRACT16(x));
|
||||
} else {
|
||||
return NEG32(_celt_cos_pi_2(EXTRACT16(65536-x)));
|
||||
}
|
||||
} else {
|
||||
if (x&0x0000ffff)
|
||||
return 0;
|
||||
else if (x&0x0001ffff)
|
||||
return -32767;
|
||||
else
|
||||
return 32767;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reciprocal approximation (Q15 input, Q16 output) */
|
||||
opus_val32 celt_rcp(opus_val32 x)
|
||||
{
|
||||
int i;
|
||||
opus_val16 n;
|
||||
opus_val16 r;
|
||||
celt_assert2(x>0, "celt_rcp() only defined for positive values");
|
||||
i = celt_ilog2(x);
|
||||
/* n is Q15 with range [0,1). */
|
||||
n = VSHR32(x,i-15)-32768;
|
||||
/* Start with a linear approximation:
|
||||
r = 1.8823529411764706-0.9411764705882353*n.
|
||||
The coefficients and the result are Q14 in the range [15420,30840].*/
|
||||
r = ADD16(30840, MULT16_16_Q15(-15420, n));
|
||||
/* Perform two Newton iterations:
|
||||
r -= r*((r*n)-1.Q15)
|
||||
= r*((r*n)+(r-1.Q15)). */
|
||||
r = SUB16(r, MULT16_16_Q15(r,
|
||||
ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))));
|
||||
/* We subtract an extra 1 in the second iteration to avoid overflow; it also
|
||||
neatly compensates for truncation error in the rest of the process. */
|
||||
r = SUB16(r, ADD16(1, MULT16_16_Q15(r,
|
||||
ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))));
|
||||
/* r is now the Q15 solution to 2/(n+1), with a maximum relative error
|
||||
of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute
|
||||
error of 1.24665/32768. */
|
||||
return VSHR32(EXTEND32(r),i-16);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,258 @@
|
|||
/* Copyright (c) 2002-2008 Jean-Marc Valin
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file mathops.h
|
||||
@brief Various math functions
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MATHOPS_H
|
||||
#define MATHOPS_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "entcode.h"
|
||||
#include "os_support.h"
|
||||
|
||||
/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */
|
||||
#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15)
|
||||
|
||||
unsigned isqrt32(opus_uint32 _val);
|
||||
|
||||
#ifndef OVERRIDE_CELT_MAXABS16
|
||||
static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len)
|
||||
{
|
||||
int i;
|
||||
opus_val16 maxval = 0;
|
||||
opus_val16 minval = 0;
|
||||
for (i=0;i<len;i++)
|
||||
{
|
||||
maxval = MAX16(maxval, x[i]);
|
||||
minval = MIN16(minval, x[i]);
|
||||
}
|
||||
return MAX32(EXTEND32(maxval),-EXTEND32(minval));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OVERRIDE_CELT_MAXABS32
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len)
|
||||
{
|
||||
int i;
|
||||
opus_val32 maxval = 0;
|
||||
opus_val32 minval = 0;
|
||||
for (i=0;i<len;i++)
|
||||
{
|
||||
maxval = MAX32(maxval, x[i]);
|
||||
minval = MIN32(minval, x[i]);
|
||||
}
|
||||
return MAX32(maxval, -minval);
|
||||
}
|
||||
#else
|
||||
#define celt_maxabs32(x,len) celt_maxabs16(x,len)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
|
||||
#define PI 3.141592653f
|
||||
#define celt_sqrt(x) ((float)sqrt(x))
|
||||
#define celt_rsqrt(x) (1.f/celt_sqrt(x))
|
||||
#define celt_rsqrt_norm(x) (celt_rsqrt(x))
|
||||
#define celt_cos_norm(x) ((float)cos((.5f*PI)*(x)))
|
||||
#define celt_rcp(x) (1.f/(x))
|
||||
#define celt_div(a,b) ((a)/(b))
|
||||
#define frac_div32(a,b) ((float)(a)/(b))
|
||||
|
||||
#ifdef FLOAT_APPROX
|
||||
|
||||
/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127
|
||||
denorm, +/- inf and NaN are *not* handled */
|
||||
|
||||
/** Base-2 log approximation (log2(x)). */
|
||||
static OPUS_INLINE float celt_log2(float x)
|
||||
{
|
||||
int integer;
|
||||
float frac;
|
||||
union {
|
||||
float f;
|
||||
opus_uint32 i;
|
||||
} in;
|
||||
in.f = x;
|
||||
integer = (in.i>>23)-127;
|
||||
in.i -= integer<<23;
|
||||
frac = in.f - 1.5f;
|
||||
frac = -0.41445418f + frac*(0.95909232f
|
||||
+ frac*(-0.33951290f + frac*0.16541097f));
|
||||
return 1+integer+frac;
|
||||
}
|
||||
|
||||
/** Base-2 exponential approximation (2^x). */
|
||||
static OPUS_INLINE float celt_exp2(float x)
|
||||
{
|
||||
int integer;
|
||||
float frac;
|
||||
union {
|
||||
float f;
|
||||
opus_uint32 i;
|
||||
} res;
|
||||
integer = floor(x);
|
||||
if (integer < -50)
|
||||
return 0;
|
||||
frac = x-integer;
|
||||
/* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */
|
||||
res.f = 0.99992522f + frac * (0.69583354f
|
||||
+ frac * (0.22606716f + 0.078024523f*frac));
|
||||
res.i = (res.i + (integer<<23)) & 0x7fffffff;
|
||||
return res.f;
|
||||
}
|
||||
|
||||
#else
|
||||
#define celt_log2(x) ((float)(1.442695040888963387*log(x)))
|
||||
#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x)))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
|
||||
#include "os_support.h"
|
||||
|
||||
#ifndef OVERRIDE_CELT_ILOG2
|
||||
/** Integer log in base2. Undefined for zero and negative numbers */
|
||||
static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x)
|
||||
{
|
||||
celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers");
|
||||
return EC_ILOG(x)-1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** Integer log in base2. Defined for zero, but not for negative numbers */
|
||||
static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x)
|
||||
{
|
||||
return x <= 0 ? 0 : celt_ilog2(x);
|
||||
}
|
||||
|
||||
opus_val16 celt_rsqrt_norm(opus_val32 x);
|
||||
|
||||
opus_val32 celt_sqrt(opus_val32 x);
|
||||
|
||||
opus_val16 celt_cos_norm(opus_val32 x);
|
||||
|
||||
/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */
|
||||
static OPUS_INLINE opus_val16 celt_log2(opus_val32 x)
|
||||
{
|
||||
int i;
|
||||
opus_val16 n, frac;
|
||||
/* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605,
|
||||
0.15530808010959576, -0.08556153059057618 */
|
||||
static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401};
|
||||
if (x==0)
|
||||
return -32767;
|
||||
i = celt_ilog2(x);
|
||||
n = VSHR32(x,i-15)-32768-16384;
|
||||
frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4]))))))));
|
||||
return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
K0 = 1
|
||||
K1 = log(2)
|
||||
K2 = 3-4*log(2)
|
||||
K3 = 3*log(2) - 2
|
||||
*/
|
||||
#define D0 16383
|
||||
#define D1 22804
|
||||
#define D2 14819
|
||||
#define D3 10204
|
||||
|
||||
static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x)
|
||||
{
|
||||
opus_val16 frac;
|
||||
frac = SHL16(x, 4);
|
||||
return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac))))));
|
||||
}
|
||||
/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */
|
||||
static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x)
|
||||
{
|
||||
int integer;
|
||||
opus_val16 frac;
|
||||
integer = SHR16(x,10);
|
||||
if (integer>14)
|
||||
return 0x7f000000;
|
||||
else if (integer < -15)
|
||||
return 0;
|
||||
frac = celt_exp2_frac(x-SHL16(integer,10));
|
||||
return VSHR32(EXTEND32(frac), -integer-2);
|
||||
}
|
||||
|
||||
opus_val32 celt_rcp(opus_val32 x);
|
||||
|
||||
#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b))
|
||||
|
||||
opus_val32 frac_div32(opus_val32 a, opus_val32 b);
|
||||
|
||||
#define M1 32767
|
||||
#define M2 -21
|
||||
#define M3 -11943
|
||||
#define M4 4936
|
||||
|
||||
/* Atan approximation using a 4th order polynomial. Input is in Q15 format
|
||||
and normalized by pi/4. Output is in Q15 format */
|
||||
static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x)
|
||||
{
|
||||
return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
|
||||
}
|
||||
|
||||
#undef M1
|
||||
#undef M2
|
||||
#undef M3
|
||||
#undef M4
|
||||
|
||||
/* atan2() approximation valid for positive input values */
|
||||
static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x)
|
||||
{
|
||||
if (y < x)
|
||||
{
|
||||
opus_val32 arg;
|
||||
arg = celt_div(SHL32(EXTEND32(y),15),x);
|
||||
if (arg >= 32767)
|
||||
arg = 32767;
|
||||
return SHR16(celt_atan01(EXTRACT16(arg)),1);
|
||||
} else {
|
||||
opus_val32 arg;
|
||||
arg = celt_div(SHL32(EXTEND32(x),15),y);
|
||||
if (arg >= 32767)
|
||||
arg = 32767;
|
||||
return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* OPUS_FIXED_POINT */
|
||||
#endif /* MATHOPS_H */
|
|
@ -0,0 +1,311 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2008 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This is a simple MDCT implementation that uses a N/4 complex FFT
|
||||
to do most of the work. It should be relatively straightforward to
|
||||
plug in pretty much and FFT here.
|
||||
|
||||
This replaces the Vorbis FFT (and uses the exact same API), which
|
||||
was a bit too messy and that was ending up duplicating code
|
||||
(might as well use the same FFT everywhere).
|
||||
|
||||
The algorithm is similar to (and inspired from) Fabrice Bellard's
|
||||
MDCT implementation in FFMPEG, but has differences in signs, ordering
|
||||
and scaling in many places.
|
||||
*/
|
||||
|
||||
#ifndef SKIP_CONFIG_H
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "mdct.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "_kiss_fft_guts.h"
|
||||
#include <math.h>
|
||||
#include "os_support.h"
|
||||
#include "mathops.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
|
||||
int clt_mdct_init(celt_mdct_lookup *l,int N, int maxshift)
|
||||
{
|
||||
int i;
|
||||
int N4;
|
||||
kiss_twiddle_scalar *trig;
|
||||
#if defined(OPUS_FIXED_POINT)
|
||||
int N2=N>>1;
|
||||
#endif
|
||||
l->n = N;
|
||||
N4 = N>>2;
|
||||
l->maxshift = maxshift;
|
||||
for (i=0;i<=maxshift;i++)
|
||||
{
|
||||
if (i==0)
|
||||
l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0);
|
||||
else
|
||||
l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0]);
|
||||
#ifndef ENABLE_TI_DSPLIB55
|
||||
if (l->kfft[i]==NULL)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N4+1)*sizeof(kiss_twiddle_scalar));
|
||||
if (l->trig==NULL)
|
||||
return 0;
|
||||
/* We have enough points that sine isn't necessary */
|
||||
#if defined(OPUS_FIXED_POINT)
|
||||
for (i=0;i<=N4;i++)
|
||||
trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2),N));
|
||||
#else
|
||||
for (i=0;i<=N4;i++)
|
||||
trig[i] = (kiss_twiddle_scalar)cos(2*PI*i/N);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
void clt_mdct_clear(celt_mdct_lookup *l)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<=l->maxshift;i++)
|
||||
opus_fft_free(l->kfft[i]);
|
||||
opus_free((kiss_twiddle_scalar*)l->trig);
|
||||
}
|
||||
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
/* Forward MDCT trashes the input array */
|
||||
void clt_mdct_forward(const celt_mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
|
||||
const opus_val16 *window, int overlap, int shift, int stride)
|
||||
{
|
||||
int i;
|
||||
int N, N2, N4;
|
||||
kiss_twiddle_scalar sine;
|
||||
VARDECL(kiss_fft_scalar, f);
|
||||
VARDECL(kiss_fft_scalar, f2);
|
||||
SAVE_STACK;
|
||||
N = l->n;
|
||||
N >>= shift;
|
||||
N2 = N>>1;
|
||||
N4 = N>>2;
|
||||
ALLOC(f, N2, kiss_fft_scalar);
|
||||
ALLOC(f2, N2, kiss_fft_scalar);
|
||||
/* sin(x) ~= x here */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N;
|
||||
#else
|
||||
sine = (kiss_twiddle_scalar)2*PI*(.125f)/N;
|
||||
#endif
|
||||
|
||||
/* Consider the input to be composed of four blocks: [a, b, c, d] */
|
||||
/* Window, shuffle, fold */
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
|
||||
const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp = f;
|
||||
const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
|
||||
const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
|
||||
for(i=0;i<((overlap+3)>>2);i++)
|
||||
{
|
||||
/* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
|
||||
*yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
|
||||
*yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]);
|
||||
xp1+=2;
|
||||
xp2-=2;
|
||||
wp1+=2;
|
||||
wp2-=2;
|
||||
}
|
||||
wp1 = window;
|
||||
wp2 = window+overlap-1;
|
||||
for(;i<N4-((overlap+3)>>2);i++)
|
||||
{
|
||||
/* Real part arranged as a-bR, Imag part arranged as -c-dR */
|
||||
*yp++ = *xp2;
|
||||
*yp++ = *xp1;
|
||||
xp1+=2;
|
||||
xp2-=2;
|
||||
}
|
||||
for(;i<N4;i++)
|
||||
{
|
||||
/* Real part arranged as a-bR, Imag part arranged as -c-dR */
|
||||
*yp++ = -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
|
||||
*yp++ = MULT16_32_Q15(*wp2, *xp1) + MULT16_32_Q15(*wp1, xp2[N2]);
|
||||
xp1+=2;
|
||||
xp2-=2;
|
||||
wp1+=2;
|
||||
wp2-=2;
|
||||
}
|
||||
}
|
||||
/* Pre-rotation */
|
||||
{
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp = f;
|
||||
const kiss_twiddle_scalar *t = &l->trig[0];
|
||||
for(i=0;i<N4;i++)
|
||||
{
|
||||
kiss_fft_scalar re, im, yr, yi;
|
||||
re = yp[0];
|
||||
im = yp[1];
|
||||
yr = -S_MUL(re,t[i<<shift]) - S_MUL(im,t[(N4-i)<<shift]);
|
||||
yi = -S_MUL(im,t[i<<shift]) + S_MUL(re,t[(N4-i)<<shift]);
|
||||
/* works because the cos is nearly one */
|
||||
*yp++ = yr + S_MUL(yi,sine);
|
||||
*yp++ = yi - S_MUL(yr,sine);
|
||||
}
|
||||
}
|
||||
|
||||
/* N/4 complex FFT, down-scales by 4/N */
|
||||
opus_fft(l->kfft[shift], (kiss_fft_cpx *)f, (kiss_fft_cpx *)f2);
|
||||
|
||||
/* Post-rotate */
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
const kiss_fft_scalar * OPUS_RESTRICT fp = f2;
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
|
||||
const kiss_twiddle_scalar *t = &l->trig[0];
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
for(i=0;i<N4;i++)
|
||||
{
|
||||
kiss_fft_scalar yr, yi;
|
||||
yr = S_MUL(fp[1],t[(N4-i)<<shift]) + S_MUL(fp[0],t[i<<shift]);
|
||||
yi = S_MUL(fp[0],t[(N4-i)<<shift]) - S_MUL(fp[1],t[i<<shift]);
|
||||
/* works because the cos is nearly one */
|
||||
*yp1 = yr - S_MUL(yi,sine);
|
||||
*yp2 = yi + S_MUL(yr,sine);;
|
||||
fp += 2;
|
||||
yp1 += 2*stride;
|
||||
yp2 -= 2*stride;
|
||||
}
|
||||
}
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
void clt_mdct_backward(const celt_mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
|
||||
const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride)
|
||||
{
|
||||
int i;
|
||||
int N, N2, N4;
|
||||
kiss_twiddle_scalar sine;
|
||||
VARDECL(kiss_fft_scalar, f2);
|
||||
SAVE_STACK;
|
||||
N = l->n;
|
||||
N >>= shift;
|
||||
N2 = N>>1;
|
||||
N4 = N>>2;
|
||||
ALLOC(f2, N2, kiss_fft_scalar);
|
||||
/* sin(x) ~= x here */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N;
|
||||
#else
|
||||
sine = (kiss_twiddle_scalar)2*PI*(.125f)/N;
|
||||
#endif
|
||||
|
||||
/* Pre-rotate */
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
|
||||
const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp = f2;
|
||||
const kiss_twiddle_scalar *t = &l->trig[0];
|
||||
for(i=0;i<N4;i++)
|
||||
{
|
||||
kiss_fft_scalar yr, yi;
|
||||
yr = -S_MUL(*xp2, t[i<<shift]) + S_MUL(*xp1,t[(N4-i)<<shift]);
|
||||
yi = -S_MUL(*xp2, t[(N4-i)<<shift]) - S_MUL(*xp1,t[i<<shift]);
|
||||
/* works because the cos is nearly one */
|
||||
*yp++ = yr - S_MUL(yi,sine);
|
||||
*yp++ = yi + S_MUL(yr,sine);
|
||||
xp1+=2*stride;
|
||||
xp2-=2*stride;
|
||||
}
|
||||
}
|
||||
|
||||
/* Inverse N/4 complex FFT. This one should *not* downscale even in fixed-point */
|
||||
opus_ifft(l->kfft[shift], (kiss_fft_cpx *)f2, (kiss_fft_cpx *)(out+(overlap>>1)));
|
||||
|
||||
/* Post-rotate and de-shuffle from both ends of the buffer at once to make
|
||||
it in-place. */
|
||||
{
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1);
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2;
|
||||
const kiss_twiddle_scalar *t = &l->trig[0];
|
||||
/* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
|
||||
middle pair will be computed twice. */
|
||||
for(i=0;i<(N4+1)>>1;i++)
|
||||
{
|
||||
kiss_fft_scalar re, im, yr, yi;
|
||||
kiss_twiddle_scalar t0, t1;
|
||||
re = yp0[0];
|
||||
im = yp0[1];
|
||||
t0 = t[i<<shift];
|
||||
t1 = t[(N4-i)<<shift];
|
||||
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
|
||||
yr = S_MUL(re,t0) - S_MUL(im,t1);
|
||||
yi = S_MUL(im,t0) + S_MUL(re,t1);
|
||||
re = yp1[0];
|
||||
im = yp1[1];
|
||||
/* works because the cos is nearly one */
|
||||
yp0[0] = -(yr - S_MUL(yi,sine));
|
||||
yp1[1] = yi + S_MUL(yr,sine);
|
||||
|
||||
t0 = t[(N4-i-1)<<shift];
|
||||
t1 = t[(i+1)<<shift];
|
||||
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
|
||||
yr = S_MUL(re,t0) - S_MUL(im,t1);
|
||||
yi = S_MUL(im,t0) + S_MUL(re,t1);
|
||||
/* works because the cos is nearly one */
|
||||
yp1[0] = -(yr - S_MUL(yi,sine));
|
||||
yp0[1] = yi + S_MUL(yr,sine);
|
||||
yp0 += 2;
|
||||
yp1 -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mirror on both sides for TDAC */
|
||||
{
|
||||
kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
|
||||
kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
|
||||
const opus_val16 * OPUS_RESTRICT wp1 = window;
|
||||
const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
|
||||
|
||||
for(i = 0; i < overlap/2; i++)
|
||||
{
|
||||
kiss_fft_scalar x1, x2;
|
||||
x1 = *xp1;
|
||||
x2 = *yp1;
|
||||
*yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
|
||||
*xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
|
||||
wp1++;
|
||||
wp2--;
|
||||
}
|
||||
}
|
||||
RESTORE_STACK;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2008 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This is a simple MDCT implementation that uses a N/4 complex FFT
|
||||
to do most of the work. It should be relatively straightforward to
|
||||
plug in pretty much and FFT here.
|
||||
|
||||
This replaces the Vorbis FFT (and uses the exact same API), which
|
||||
was a bit too messy and that was ending up duplicating code
|
||||
(might as well use the same FFT everywhere).
|
||||
|
||||
The algorithm is similar to (and inspired from) Fabrice Bellard's
|
||||
MDCT implementation in FFMPEG, but has differences in signs, ordering
|
||||
and scaling in many places.
|
||||
*/
|
||||
|
||||
#ifndef MDCT_H
|
||||
#define MDCT_H
|
||||
|
||||
#include "opus_defines.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "arch.h"
|
||||
|
||||
typedef struct {
|
||||
int n;
|
||||
int maxshift;
|
||||
const kiss_fft_state *kfft[4];
|
||||
const kiss_twiddle_scalar * OPUS_RESTRICT trig;
|
||||
} celt_mdct_lookup;
|
||||
|
||||
int clt_mdct_init(celt_mdct_lookup *l,int N, int maxshift);
|
||||
void clt_mdct_clear(celt_mdct_lookup *l);
|
||||
|
||||
/** Compute a forward MDCT and scale by 4/N, trashes the input array */
|
||||
void clt_mdct_forward(const celt_mdct_lookup *l, kiss_fft_scalar *in,
|
||||
kiss_fft_scalar * OPUS_RESTRICT out,
|
||||
const opus_val16 *window, int overlap, int shift, int stride);
|
||||
|
||||
/** Compute a backward MDCT (no scaling) and performs weighted overlap-add
|
||||
(scales implicitly by 1/2) */
|
||||
void clt_mdct_backward(const celt_mdct_lookup *l, kiss_fft_scalar *in,
|
||||
kiss_fft_scalar * OPUS_RESTRICT out,
|
||||
const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
/* Copyright (c) 2001-2008 Timothy B. Terriberry
|
||||
Copyright (c) 2008-2009 Xiph.Org Foundation */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !defined(_mfrngcode_H)
|
||||
# define _mfrngcode_H (1)
|
||||
# include "entcode.h"
|
||||
|
||||
/*Constants used by the entropy encoder/decoder.*/
|
||||
|
||||
/*The number of bits to output at a time.*/
|
||||
# define EC_SYM_BITS (8)
|
||||
/*The total number of bits in each of the state registers.*/
|
||||
# define EC_CODE_BITS (32)
|
||||
/*The maximum symbol value.*/
|
||||
# define EC_SYM_MAX ((1U<<EC_SYM_BITS)-1)
|
||||
/*Bits to shift by to move a symbol into the high-order position.*/
|
||||
# define EC_CODE_SHIFT (EC_CODE_BITS-EC_SYM_BITS-1)
|
||||
/*Carry bit of the high-order range symbol.*/
|
||||
# define EC_CODE_TOP (((opus_uint32)1U)<<(EC_CODE_BITS-1))
|
||||
/*Low-order bit of the high-order range symbol.*/
|
||||
# define EC_CODE_BOT (EC_CODE_TOP>>EC_SYM_BITS)
|
||||
/*The number of bits available for the last, partial symbol in the code field.*/
|
||||
# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1)
|
||||
#endif
|
|
@ -0,0 +1,438 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2008 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "celt.h"
|
||||
#include "opus_modes.h"
|
||||
#include "rate.h"
|
||||
#include "os_support.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "quant_bands.h"
|
||||
|
||||
static const opus_int16 eband5ms[] = {
|
||||
/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
|
||||
};
|
||||
|
||||
/* Alternate tuning (partially derived from Vorbis) */
|
||||
#define BITALLOC_SIZE 11
|
||||
/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */
|
||||
static const unsigned char band_allocation[] = {
|
||||
/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0,
|
||||
118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0,
|
||||
126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0,
|
||||
134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1,
|
||||
144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1,
|
||||
152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1,
|
||||
162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1,
|
||||
172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20,
|
||||
200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104,
|
||||
};
|
||||
|
||||
#ifndef CUSTOM_MODES_ONLY
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
#include "static_modes_fixed.h"
|
||||
#else
|
||||
#include "static_modes_float.h"
|
||||
#endif
|
||||
#endif /* CUSTOM_MODES_ONLY */
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
|
||||
/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth
|
||||
Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */
|
||||
#define BARK_BANDS 25
|
||||
static const opus_int16 bark_freq[BARK_BANDS+1] = {
|
||||
0, 100, 200, 300, 400,
|
||||
510, 630, 770, 920, 1080,
|
||||
1270, 1480, 1720, 2000, 2320,
|
||||
2700, 3150, 3700, 4400, 5300,
|
||||
6400, 7700, 9500, 12000, 15500,
|
||||
20000};
|
||||
|
||||
static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands)
|
||||
{
|
||||
opus_int16 *eBands;
|
||||
int i, j, lin, low, high, nBark, offset=0;
|
||||
|
||||
/* All modes that have 2.5 ms short blocks use the same definition */
|
||||
if (Fs == 400*(opus_int32)frame_size)
|
||||
{
|
||||
*nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
|
||||
eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1));
|
||||
for (i=0;i<*nbEBands+1;i++)
|
||||
eBands[i] = eband5ms[i];
|
||||
return eBands;
|
||||
}
|
||||
/* Find the number of critical bands supported by our sampling rate */
|
||||
for (nBark=1;nBark<BARK_BANDS;nBark++)
|
||||
if (bark_freq[nBark+1]*2 >= Fs)
|
||||
break;
|
||||
|
||||
/* Find where the linear part ends (i.e. where the spacing is more than min_width */
|
||||
for (lin=0;lin<nBark;lin++)
|
||||
if (bark_freq[lin+1]-bark_freq[lin] >= res)
|
||||
break;
|
||||
|
||||
low = (bark_freq[lin]+res/2)/res;
|
||||
high = nBark-lin;
|
||||
*nbEBands = low+high;
|
||||
eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2));
|
||||
|
||||
if (eBands==NULL)
|
||||
return NULL;
|
||||
|
||||
/* Linear spacing (min_width) */
|
||||
for (i=0;i<low;i++)
|
||||
eBands[i] = i;
|
||||
if (low>0)
|
||||
offset = eBands[low-1]*res - bark_freq[lin-1];
|
||||
/* Spacing follows critical bands */
|
||||
for (i=0;i<high;i++)
|
||||
{
|
||||
int target = bark_freq[lin+i];
|
||||
/* Round to an even value */
|
||||
eBands[i+low] = (target+offset/2+res)/(2*res)*2;
|
||||
offset = eBands[i+low]*res - target;
|
||||
}
|
||||
/* Enforce the minimum spacing at the boundary */
|
||||
for (i=0;i<*nbEBands;i++)
|
||||
if (eBands[i] < i)
|
||||
eBands[i] = i;
|
||||
/* Round to an even value */
|
||||
eBands[*nbEBands] = (bark_freq[nBark]+res)/(2*res)*2;
|
||||
if (eBands[*nbEBands] > frame_size)
|
||||
eBands[*nbEBands] = frame_size;
|
||||
for (i=1;i<*nbEBands-1;i++)
|
||||
{
|
||||
if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1])
|
||||
{
|
||||
eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2;
|
||||
}
|
||||
}
|
||||
/* Remove any empty bands. */
|
||||
for (i=j=0;i<*nbEBands;i++)
|
||||
if(eBands[i+1]>eBands[j])
|
||||
eBands[++j]=eBands[i+1];
|
||||
*nbEBands=j;
|
||||
|
||||
for (i=1;i<*nbEBands;i++)
|
||||
{
|
||||
/* Every band must be smaller than the last band. */
|
||||
celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]);
|
||||
/* Each band must be no larger than twice the size of the previous one. */
|
||||
celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1]));
|
||||
}
|
||||
|
||||
return eBands;
|
||||
}
|
||||
|
||||
static void compute_allocation_table(CELTMode *mode)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char *allocVectors;
|
||||
int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
|
||||
|
||||
mode->nbAllocVectors = BITALLOC_SIZE;
|
||||
allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands));
|
||||
if (allocVectors==NULL)
|
||||
return;
|
||||
|
||||
/* Check for standard mode */
|
||||
if (mode->Fs == 400*(opus_int32)mode->shortMdctSize)
|
||||
{
|
||||
for (i=0;i<BITALLOC_SIZE*mode->nbEBands;i++)
|
||||
allocVectors[i] = band_allocation[i];
|
||||
mode->allocVectors = allocVectors;
|
||||
return;
|
||||
}
|
||||
/* If not the standard mode, interpolate */
|
||||
/* Compute per-codec-band allocation from per-critical-band matrix */
|
||||
for (i=0;i<BITALLOC_SIZE;i++)
|
||||
{
|
||||
for (j=0;j<mode->nbEBands;j++)
|
||||
{
|
||||
int k;
|
||||
for (k=0;k<maxBands;k++)
|
||||
{
|
||||
if (400*(opus_int32)eband5ms[k] > mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize)
|
||||
break;
|
||||
}
|
||||
if (k>maxBands-1)
|
||||
allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1];
|
||||
else {
|
||||
opus_int32 a0, a1;
|
||||
a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1];
|
||||
a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize;
|
||||
allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1]
|
||||
+ a1*band_allocation[i*maxBands+k])/(a0+a1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*printf ("\n");
|
||||
for (i=0;i<BITALLOC_SIZE;i++)
|
||||
{
|
||||
for (j=0;j<mode->nbEBands;j++)
|
||||
printf ("%d ", allocVectors[i*mode->nbEBands+j]);
|
||||
printf ("\n");
|
||||
}
|
||||
exit(0);*/
|
||||
|
||||
mode->allocVectors = allocVectors;
|
||||
}
|
||||
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error)
|
||||
{
|
||||
int i;
|
||||
#ifdef CUSTOM_MODES
|
||||
CELTMode *mode=NULL;
|
||||
int res;
|
||||
opus_val16 *window;
|
||||
opus_int16 *logN;
|
||||
int LM;
|
||||
ALLOC_STACK;
|
||||
#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA)
|
||||
if (global_stack==NULL)
|
||||
goto failure;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CUSTOM_MODES_ONLY
|
||||
for (i=0;i<TOTAL_MODES;i++)
|
||||
{
|
||||
int j;
|
||||
for (j=0;j<4;j++)
|
||||
{
|
||||
if (Fs == static_mode_list[i]->Fs &&
|
||||
(frame_size<<j) == static_mode_list[i]->shortMdctSize*static_mode_list[i]->nbShortMdcts)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_OK;
|
||||
return (CELTMode*)static_mode_list[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CUSTOM_MODES_ONLY */
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
if (error)
|
||||
*error = OPUS_BAD_ARG;
|
||||
return NULL;
|
||||
#else
|
||||
|
||||
/* The good thing here is that permutation of the arguments will automatically be invalid */
|
||||
|
||||
if (Fs < 8000 || Fs > 96000)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_BAD_ARG;
|
||||
return NULL;
|
||||
}
|
||||
if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_BAD_ARG;
|
||||
return NULL;
|
||||
}
|
||||
/* Frames of less than 1ms are not supported. */
|
||||
if ((opus_int32)frame_size*1000 < Fs)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_BAD_ARG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0)
|
||||
{
|
||||
LM = 3;
|
||||
} else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0)
|
||||
{
|
||||
LM = 2;
|
||||
} else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0)
|
||||
{
|
||||
LM = 1;
|
||||
} else
|
||||
{
|
||||
LM = 0;
|
||||
}
|
||||
|
||||
/* Shorts longer than 3.3ms are not supported. */
|
||||
if ((opus_int32)(frame_size>>LM)*300 > Fs)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_BAD_ARG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mode = opus_alloc(sizeof(CELTMode));
|
||||
if (mode==NULL)
|
||||
goto failure;
|
||||
mode->Fs = Fs;
|
||||
|
||||
/* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis
|
||||
is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should
|
||||
approximate that. */
|
||||
if(Fs < 12000) /* 8 kHz */
|
||||
{
|
||||
mode->preemph[0] = QCONST16(0.3500061035f, 15);
|
||||
mode->preemph[1] = -QCONST16(0.1799926758f, 15);
|
||||
mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */
|
||||
mode->preemph[3] = QCONST16(3.6765136719f, 13);
|
||||
} else if(Fs < 24000) /* 16 kHz */
|
||||
{
|
||||
mode->preemph[0] = QCONST16(0.6000061035f, 15);
|
||||
mode->preemph[1] = -QCONST16(0.1799926758f, 15);
|
||||
mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */
|
||||
mode->preemph[3] = QCONST16(2.2598876953f, 13);
|
||||
} else if(Fs < 40000) /* 32 kHz */
|
||||
{
|
||||
mode->preemph[0] = QCONST16(0.7799987793f, 15);
|
||||
mode->preemph[1] = -QCONST16(0.1000061035f, 15);
|
||||
mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */
|
||||
mode->preemph[3] = QCONST16(1.3333740234f, 13);
|
||||
} else /* 48 kHz */
|
||||
{
|
||||
mode->preemph[0] = QCONST16(0.8500061035f, 15);
|
||||
mode->preemph[1] = QCONST16(0.0f, 15);
|
||||
mode->preemph[2] = QCONST16(1.f, SIG_SHIFT);
|
||||
mode->preemph[3] = QCONST16(1.f, 13);
|
||||
}
|
||||
|
||||
mode->maxLM = LM;
|
||||
mode->nbShortMdcts = 1<<LM;
|
||||
mode->shortMdctSize = frame_size/mode->nbShortMdcts;
|
||||
res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize);
|
||||
|
||||
mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands);
|
||||
if (mode->eBands==NULL)
|
||||
goto failure;
|
||||
#if !defined(SMALL_FOOTPRINT)
|
||||
/* Make sure we don't allocate a band larger than our PVQ table.
|
||||
208 should be enough, but let's be paranoid. */
|
||||
if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])<<LM >
|
||||
208) {
|
||||
goto failure;
|
||||
}
|
||||
#endif
|
||||
|
||||
mode->effEBands = mode->nbEBands;
|
||||
while (mode->eBands[mode->effEBands] > mode->shortMdctSize)
|
||||
mode->effEBands--;
|
||||
|
||||
/* Overlap must be divisible by 4 */
|
||||
mode->overlap = ((mode->shortMdctSize>>2)<<2);
|
||||
|
||||
compute_allocation_table(mode);
|
||||
if (mode->allocVectors==NULL)
|
||||
goto failure;
|
||||
|
||||
window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16));
|
||||
if (window==NULL)
|
||||
goto failure;
|
||||
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
for (i=0;i<mode->overlap;i++)
|
||||
window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap));
|
||||
#else
|
||||
for (i=0;i<mode->overlap;i++)
|
||||
window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap))));
|
||||
#endif
|
||||
mode->window = window;
|
||||
|
||||
logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16));
|
||||
if (logN==NULL)
|
||||
goto failure;
|
||||
|
||||
for (i=0;i<mode->nbEBands;i++)
|
||||
logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES);
|
||||
mode->logN = logN;
|
||||
|
||||
compute_pulse_cache(mode, mode->maxLM);
|
||||
|
||||
if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts,
|
||||
mode->maxLM) == 0)
|
||||
goto failure;
|
||||
|
||||
if (error)
|
||||
*error = OPUS_OK;
|
||||
|
||||
return mode;
|
||||
failure:
|
||||
if (error)
|
||||
*error = OPUS_ALLOC_FAIL;
|
||||
if (mode!=NULL)
|
||||
opus_custom_mode_destroy(mode);
|
||||
return NULL;
|
||||
#endif /* !CUSTOM_MODES */
|
||||
}
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
void opus_custom_mode_destroy(CELTMode *mode)
|
||||
{
|
||||
if (mode == NULL)
|
||||
return;
|
||||
#ifndef CUSTOM_MODES_ONLY
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<TOTAL_MODES;i++)
|
||||
{
|
||||
if (mode == static_mode_list[i])
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CUSTOM_MODES_ONLY */
|
||||
opus_free((opus_int16*)mode->eBands);
|
||||
opus_free((opus_int16*)mode->allocVectors);
|
||||
|
||||
opus_free((opus_val16*)mode->window);
|
||||
opus_free((opus_int16*)mode->logN);
|
||||
|
||||
opus_free((opus_int16*)mode->cache.index);
|
||||
opus_free((unsigned char*)mode->cache.bits);
|
||||
opus_free((unsigned char*)mode->cache.caps);
|
||||
clt_mdct_clear(&mode->mdct);
|
||||
|
||||
opus_free((CELTMode *)mode);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,210 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "opus_custom.h"
|
||||
#include "arch.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_PACKET 1275
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
char *inFile, *outFile;
|
||||
FILE *fin, *fout;
|
||||
OpusCustomMode *mode=NULL;
|
||||
OpusCustomEncoder *enc;
|
||||
OpusCustomDecoder *dec;
|
||||
int len;
|
||||
opus_int32 frame_size, channels, rate;
|
||||
int bytes_per_packet;
|
||||
unsigned char data[MAX_PACKET];
|
||||
int complexity;
|
||||
#if !(defined (OPUS_FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
|
||||
int i;
|
||||
double rmsd = 0;
|
||||
#endif
|
||||
int count = 0;
|
||||
opus_int32 skip;
|
||||
opus_int16 *in, *out;
|
||||
if (argc != 9 && argc != 8 && argc != 7)
|
||||
{
|
||||
fprintf (stderr, "Usage: test_opus_custom <rate> <channels> <frame size> "
|
||||
" <bytes per packet> [<complexity> [packet loss rate]] "
|
||||
"<input> <output>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rate = (opus_int32)atol(argv[1]);
|
||||
channels = atoi(argv[2]);
|
||||
frame_size = atoi(argv[3]);
|
||||
mode = opus_custom_mode_create(rate, frame_size, NULL);
|
||||
if (mode == NULL)
|
||||
{
|
||||
fprintf(stderr, "failed to create a mode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytes_per_packet = atoi(argv[4]);
|
||||
if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET)
|
||||
{
|
||||
fprintf (stderr, "bytes per packet must be between 0 and %d\n",
|
||||
MAX_PACKET);
|
||||
return 1;
|
||||
}
|
||||
|
||||
inFile = argv[argc-2];
|
||||
fin = fopen(inFile, "rb");
|
||||
if (!fin)
|
||||
{
|
||||
fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
|
||||
return 1;
|
||||
}
|
||||
outFile = argv[argc-1];
|
||||
fout = fopen(outFile, "wb+");
|
||||
if (!fout)
|
||||
{
|
||||
fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
|
||||
fclose(fin);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enc = opus_custom_encoder_create(mode, channels, &err);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err));
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
return 1;
|
||||
}
|
||||
dec = opus_custom_decoder_create(mode, channels, &err);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err));
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
return 1;
|
||||
}
|
||||
opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip));
|
||||
|
||||
if (argc>7)
|
||||
{
|
||||
complexity=atoi(argv[5]);
|
||||
opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity));
|
||||
}
|
||||
|
||||
in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
|
||||
out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
|
||||
|
||||
while (!feof(fin))
|
||||
{
|
||||
int ret;
|
||||
err = fread(in, sizeof(short), frame_size*channels, fin);
|
||||
if (feof(fin))
|
||||
break;
|
||||
len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet);
|
||||
if (len <= 0)
|
||||
fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len));
|
||||
|
||||
/* This is for simulating bit errors */
|
||||
#if 0
|
||||
int errors = 0;
|
||||
int eid = 0;
|
||||
/* This simulates random bit error */
|
||||
for (i=0;i<len*8;i++)
|
||||
{
|
||||
if (rand()%atoi(argv[8])==0)
|
||||
{
|
||||
if (i<64)
|
||||
{
|
||||
errors++;
|
||||
eid = i;
|
||||
}
|
||||
data[i/8] ^= 1<<(7-(i%8));
|
||||
}
|
||||
}
|
||||
if (errors == 1)
|
||||
data[eid/8] ^= 1<<(7-(eid%8));
|
||||
else if (errors%2 == 1)
|
||||
data[rand()%8] ^= 1<<rand()%8;
|
||||
#endif
|
||||
|
||||
#if 1 /* Set to zero to use the encoder's output instead */
|
||||
/* This is to simulate packet loss */
|
||||
if (argc==9 && rand()%1000<atoi(argv[argc-3]))
|
||||
/*if (errors && (errors%2==0))*/
|
||||
ret = opus_custom_decode(dec, NULL, len, out, frame_size);
|
||||
else
|
||||
ret = opus_custom_decode(dec, data, len, out, frame_size);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "opus_custom_decode() failed: %s\n", opus_strerror(ret));
|
||||
#else
|
||||
for (i=0;i<ret*channels;i++)
|
||||
out[i] = in[i];
|
||||
#endif
|
||||
#if !(defined (OPUS_FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
|
||||
for (i=0;i<ret*channels;i++)
|
||||
{
|
||||
rmsd += (in[i]-out[i])*1.0*(in[i]-out[i]);
|
||||
/*out[i] -= in[i];*/
|
||||
}
|
||||
#endif
|
||||
count++;
|
||||
fwrite(out+skip*channels, sizeof(short), (ret-skip)*channels, fout);
|
||||
skip = 0;
|
||||
}
|
||||
PRINT_MIPS(stderr);
|
||||
|
||||
opus_custom_encoder_destroy(enc);
|
||||
opus_custom_decoder_destroy(dec);
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
opus_custom_mode_destroy(mode);
|
||||
free(in);
|
||||
free(out);
|
||||
#if !(defined (OPUS_FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
|
||||
if (rmsd > 0)
|
||||
{
|
||||
rmsd = sqrt(rmsd/(1.0*frame_size*channels*count));
|
||||
fprintf (stderr, "Error: encoder doesn't match decoder\n");
|
||||
fprintf (stderr, "RMS mismatch is %f\n", rmsd);
|
||||
return 1;
|
||||
} else {
|
||||
fprintf (stderr, "Encoder matches decoder!!\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2008 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef OPUS_MODES_H
|
||||
#define OPUS_MODES_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "celt.h"
|
||||
#include "arch.h"
|
||||
#include "mdct.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
|
||||
#define MAX_PERIOD 1024
|
||||
|
||||
#ifndef OVERLAP
|
||||
#define OVERLAP(mode) ((mode)->overlap)
|
||||
#endif
|
||||
|
||||
#ifndef FRAMESIZE
|
||||
#define FRAMESIZE(mode) ((mode)->mdctSize)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
const opus_int16 *index;
|
||||
const unsigned char *bits;
|
||||
const unsigned char *caps;
|
||||
} PulseCache;
|
||||
|
||||
/** Mode definition (opaque)
|
||||
@brief Mode definition
|
||||
*/
|
||||
struct OpusCustomMode {
|
||||
opus_int32 Fs;
|
||||
int overlap;
|
||||
|
||||
int nbEBands;
|
||||
int effEBands;
|
||||
opus_val16 preemph[4];
|
||||
const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */
|
||||
|
||||
int maxLM;
|
||||
int nbShortMdcts;
|
||||
int shortMdctSize;
|
||||
|
||||
int nbAllocVectors; /**< Number of lines in the matrix below */
|
||||
const unsigned char *allocVectors; /**< Number of bits in each band for several rates */
|
||||
const opus_int16 *logN;
|
||||
|
||||
const opus_val16 *window;
|
||||
celt_mdct_lookup mdct;
|
||||
PulseCache cache;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
/* Copyright (C) 2007 Jean-Marc Valin
|
||||
|
||||
File: os_support.h
|
||||
This is the (tiny) OS abstraction layer. Aside from math.h, this is the
|
||||
only place where system headers are allowed.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef OS_SUPPORT_H
|
||||
#define OS_SUPPORT_H
|
||||
|
||||
#ifdef CUSTOM_SUPPORT
|
||||
# include "custom_support.h"
|
||||
#endif
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */
|
||||
#ifndef OVERRIDE_OPUS_ALLOC
|
||||
static OPUS_INLINE void *opus_alloc (size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */
|
||||
#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH
|
||||
static OPUS_INLINE void *opus_alloc_scratch (size_t size)
|
||||
{
|
||||
/* Scratch space doesn't need to be cleared */
|
||||
return opus_alloc(size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */
|
||||
#ifndef OVERRIDE_OPUS_FREE
|
||||
static OPUS_INLINE void opus_free (void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */
|
||||
#ifndef OVERRIDE_OPUS_COPY
|
||||
#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
|
||||
#endif
|
||||
|
||||
/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term
|
||||
provides compile-time type checking */
|
||||
#ifndef OVERRIDE_OPUS_MOVE
|
||||
#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
|
||||
#endif
|
||||
|
||||
/** Set n elements of dst to zero, starting at address s */
|
||||
#ifndef OVERRIDE_OPUS_CLEAR
|
||||
#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
|
||||
#endif
|
||||
|
||||
/*#ifdef __GNUC__
|
||||
#pragma GCC poison printf sprintf
|
||||
#pragma GCC poison malloc free realloc calloc
|
||||
#endif*/
|
||||
|
||||
#endif /* OS_SUPPORT_H */
|
||||
|
|
@ -0,0 +1,537 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file pitch.c
|
||||
@brief Pitch analysis
|
||||
*/
|
||||
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "pitch.h"
|
||||
#include "os_support.h"
|
||||
#include "opus_modes.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "mathops.h"
|
||||
#include "celt_lpc.h"
|
||||
|
||||
static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
|
||||
int max_pitch, int *best_pitch
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
, int yshift, opus_val32 maxcorr
|
||||
#endif
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
opus_val32 Syy=1;
|
||||
opus_val16 best_num[2];
|
||||
opus_val32 best_den[2];
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
int xshift;
|
||||
|
||||
xshift = celt_ilog2(maxcorr)-14;
|
||||
#endif
|
||||
|
||||
best_num[0] = -1;
|
||||
best_num[1] = -1;
|
||||
best_den[0] = 0;
|
||||
best_den[1] = 0;
|
||||
best_pitch[0] = 0;
|
||||
best_pitch[1] = 1;
|
||||
for (j=0;j<len;j++)
|
||||
Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
|
||||
for (i=0;i<max_pitch;i++)
|
||||
{
|
||||
if (xcorr[i]>0)
|
||||
{
|
||||
opus_val16 num;
|
||||
opus_val32 xcorr16;
|
||||
xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
/* Considering the range of xcorr16, this should avoid both underflows
|
||||
and overflows (inf) when squaring xcorr16 */
|
||||
xcorr16 *= 1e-12f;
|
||||
#endif
|
||||
num = MULT16_16_Q15(xcorr16,xcorr16);
|
||||
if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
|
||||
{
|
||||
if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
|
||||
{
|
||||
best_num[1] = best_num[0];
|
||||
best_den[1] = best_den[0];
|
||||
best_pitch[1] = best_pitch[0];
|
||||
best_num[0] = num;
|
||||
best_den[0] = Syy;
|
||||
best_pitch[0] = i;
|
||||
} else {
|
||||
best_num[1] = num;
|
||||
best_den[1] = Syy;
|
||||
best_pitch[1] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
|
||||
Syy = MAX32(1, Syy);
|
||||
}
|
||||
}
|
||||
|
||||
static void celt_fir5(const opus_val16 *x,
|
||||
const opus_val16 *num,
|
||||
opus_val16 *y,
|
||||
int N,
|
||||
opus_val16 *mem)
|
||||
{
|
||||
int i;
|
||||
opus_val16 num0, num1, num2, num3, num4;
|
||||
opus_val32 mem0, mem1, mem2, mem3, mem4;
|
||||
num0=num[0];
|
||||
num1=num[1];
|
||||
num2=num[2];
|
||||
num3=num[3];
|
||||
num4=num[4];
|
||||
mem0=mem[0];
|
||||
mem1=mem[1];
|
||||
mem2=mem[2];
|
||||
mem3=mem[3];
|
||||
mem4=mem[4];
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
|
||||
sum = MAC16_16(sum,num0,mem0);
|
||||
sum = MAC16_16(sum,num1,mem1);
|
||||
sum = MAC16_16(sum,num2,mem2);
|
||||
sum = MAC16_16(sum,num3,mem3);
|
||||
sum = MAC16_16(sum,num4,mem4);
|
||||
mem4 = mem3;
|
||||
mem3 = mem2;
|
||||
mem2 = mem1;
|
||||
mem1 = mem0;
|
||||
mem0 = x[i];
|
||||
y[i] = ROUND16(sum, SIG_SHIFT);
|
||||
}
|
||||
mem[0]=mem0;
|
||||
mem[1]=mem1;
|
||||
mem[2]=mem2;
|
||||
mem[3]=mem3;
|
||||
mem[4]=mem4;
|
||||
}
|
||||
|
||||
|
||||
void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
|
||||
int len, int C, int arch)
|
||||
{
|
||||
int i;
|
||||
opus_val32 ac[5];
|
||||
opus_val16 tmp=Q15ONE;
|
||||
opus_val16 lpc[4], mem[5]={0,0,0,0,0};
|
||||
opus_val16 lpc2[5];
|
||||
opus_val16 c1 = QCONST16(.8f,15);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
int shift;
|
||||
opus_val32 maxabs = celt_maxabs32(x[0], len);
|
||||
if (C==2)
|
||||
{
|
||||
opus_val32 maxabs_1 = celt_maxabs32(x[1], len);
|
||||
maxabs = MAX32(maxabs, maxabs_1);
|
||||
}
|
||||
if (maxabs<1)
|
||||
maxabs=1;
|
||||
shift = celt_ilog2(maxabs)-10;
|
||||
if (shift<0)
|
||||
shift=0;
|
||||
if (C==2)
|
||||
shift++;
|
||||
#endif
|
||||
for (i=1;i<len>>1;i++)
|
||||
x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift);
|
||||
x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift);
|
||||
if (C==2)
|
||||
{
|
||||
for (i=1;i<len>>1;i++)
|
||||
x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift);
|
||||
x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift);
|
||||
}
|
||||
|
||||
_celt_autocorr(x_lp, ac, NULL, 0,
|
||||
4, len>>1, arch);
|
||||
|
||||
/* Noise floor -40 dB */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
ac[0] += SHR32(ac[0],13);
|
||||
#else
|
||||
ac[0] *= 1.0001f;
|
||||
#endif
|
||||
/* Lag windowing */
|
||||
for (i=1;i<=4;i++)
|
||||
{
|
||||
/*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
|
||||
#else
|
||||
ac[i] -= ac[i]*(.008f*i)*(.008f*i);
|
||||
#endif
|
||||
}
|
||||
|
||||
_celt_lpc(lpc, ac, 4);
|
||||
for (i=0;i<4;i++)
|
||||
{
|
||||
tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
|
||||
lpc[i] = MULT16_16_Q15(lpc[i], tmp);
|
||||
}
|
||||
/* Add a zero */
|
||||
lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
|
||||
lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
|
||||
lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
|
||||
lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
|
||||
lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
|
||||
celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
|
||||
}
|
||||
|
||||
#if 0 /* This is a simple version of the pitch correlation that should work
|
||||
well on DSPs like Blackfin and TI C5x/C6x */
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
celt_pitch_xcorr(opus_val16 *x, opus_val16 *y, opus_val32 *xcorr, int len, int max_pitch)
|
||||
{
|
||||
int i, j;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32 maxcorr=1;
|
||||
#endif
|
||||
for (i=0;i<max_pitch;i++)
|
||||
{
|
||||
opus_val32 sum = 0;
|
||||
for (j=0;j<len;j++)
|
||||
sum = MAC16_16(sum, x[j],y[i+j]);
|
||||
xcorr[i] = sum;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
maxcorr = MAX32(maxcorr, sum);
|
||||
#endif
|
||||
}
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
return maxcorr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, opus_val32 *xcorr, int len, int max_pitch)
|
||||
{
|
||||
int i,j;
|
||||
/*The EDSP version requires that max_pitch is at least 1, and that _x is
|
||||
32-bit aligned.
|
||||
Since it's hard to put asserts in assembly, put them here.*/
|
||||
celt_assert(max_pitch>0);
|
||||
celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32 maxcorr=1;
|
||||
#endif
|
||||
for (i=0;i<max_pitch-3;i+=4)
|
||||
{
|
||||
opus_val32 sum[4]={0,0,0,0};
|
||||
xcorr_kernel(_x, _y+i, sum, len);
|
||||
xcorr[i]=sum[0];
|
||||
xcorr[i+1]=sum[1];
|
||||
xcorr[i+2]=sum[2];
|
||||
xcorr[i+3]=sum[3];
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
sum[0] = MAX32(sum[0], sum[1]);
|
||||
sum[2] = MAX32(sum[2], sum[3]);
|
||||
sum[0] = MAX32(sum[0], sum[2]);
|
||||
maxcorr = MAX32(maxcorr, sum[0]);
|
||||
#endif
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (;i<max_pitch;i++)
|
||||
{
|
||||
opus_val32 sum = 0;
|
||||
for (j=0;j<len;j++)
|
||||
sum = MAC16_16(sum, _x[j],_y[i+j]);
|
||||
xcorr[i] = sum;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
maxcorr = MAX32(maxcorr, sum);
|
||||
#endif
|
||||
}
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
return maxcorr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
|
||||
int len, int max_pitch, int *pitch, int arch)
|
||||
{
|
||||
int i, j;
|
||||
int lag;
|
||||
int best_pitch[2]={0,0};
|
||||
VARDECL(opus_val16, x_lp4);
|
||||
VARDECL(opus_val16, y_lp4);
|
||||
VARDECL(opus_val32, xcorr);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32 maxcorr;
|
||||
opus_val32 xmax, ymax;
|
||||
int shift=0;
|
||||
#endif
|
||||
int offset;
|
||||
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert(len>0);
|
||||
celt_assert(max_pitch>0);
|
||||
lag = len+max_pitch;
|
||||
|
||||
ALLOC(x_lp4, len>>2, opus_val16);
|
||||
ALLOC(y_lp4, lag>>2, opus_val16);
|
||||
ALLOC(xcorr, max_pitch>>1, opus_val32);
|
||||
|
||||
/* Downsample by 2 again */
|
||||
for (j=0;j<len>>2;j++)
|
||||
x_lp4[j] = x_lp[2*j];
|
||||
for (j=0;j<lag>>2;j++)
|
||||
y_lp4[j] = y[2*j];
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
xmax = celt_maxabs16(x_lp4, len>>2);
|
||||
ymax = celt_maxabs16(y_lp4, lag>>2);
|
||||
shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11;
|
||||
if (shift>0)
|
||||
{
|
||||
for (j=0;j<len>>2;j++)
|
||||
x_lp4[j] = SHR16(x_lp4[j], shift);
|
||||
for (j=0;j<lag>>2;j++)
|
||||
y_lp4[j] = SHR16(y_lp4[j], shift);
|
||||
/* Use double the shift for a MAC */
|
||||
shift *= 2;
|
||||
} else {
|
||||
shift = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Coarse search with 4x decimation */
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
maxcorr =
|
||||
#endif
|
||||
celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch);
|
||||
|
||||
find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
, 0, maxcorr
|
||||
#endif
|
||||
);
|
||||
|
||||
/* Finer search with 2x decimation */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
maxcorr=1;
|
||||
#endif
|
||||
for (i=0;i<max_pitch>>1;i++)
|
||||
{
|
||||
opus_val32 sum=0;
|
||||
xcorr[i] = 0;
|
||||
if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
|
||||
continue;
|
||||
for (j=0;j<len>>1;j++)
|
||||
sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
|
||||
xcorr[i] = MAX32(-1, sum);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
maxcorr = MAX32(maxcorr, sum);
|
||||
#endif
|
||||
}
|
||||
find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
, shift+1, maxcorr
|
||||
#endif
|
||||
);
|
||||
|
||||
/* Refine by pseudo-interpolation */
|
||||
if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
|
||||
{
|
||||
opus_val32 a, b, c;
|
||||
a = xcorr[best_pitch[0]-1];
|
||||
b = xcorr[best_pitch[0]];
|
||||
c = xcorr[best_pitch[0]+1];
|
||||
if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
|
||||
offset = 1;
|
||||
else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
|
||||
offset = -1;
|
||||
else
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
*pitch = 2*best_pitch[0]-offset;
|
||||
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
|
||||
opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
|
||||
int N, int *T0_, int prev_period, opus_val16 prev_gain)
|
||||
{
|
||||
int k, i, T, T0;
|
||||
opus_val16 g, g0;
|
||||
opus_val16 pg;
|
||||
opus_val32 xy,xx,yy,xy2;
|
||||
opus_val32 xcorr[3];
|
||||
opus_val32 best_xy, best_yy;
|
||||
int offset;
|
||||
int minperiod0;
|
||||
VARDECL(opus_val32, yy_lookup);
|
||||
SAVE_STACK;
|
||||
|
||||
minperiod0 = minperiod;
|
||||
maxperiod /= 2;
|
||||
minperiod /= 2;
|
||||
*T0_ /= 2;
|
||||
prev_period /= 2;
|
||||
N /= 2;
|
||||
x += maxperiod;
|
||||
if (*T0_>=maxperiod)
|
||||
*T0_=maxperiod-1;
|
||||
|
||||
T = T0 = *T0_;
|
||||
ALLOC(yy_lookup, maxperiod+1, opus_val32);
|
||||
dual_inner_prod(x, x, x-T0, N, &xx, &xy);
|
||||
yy_lookup[0] = xx;
|
||||
yy=xx;
|
||||
for (i=1;i<=maxperiod;i++)
|
||||
{
|
||||
yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
|
||||
yy_lookup[i] = MAX32(0, yy);
|
||||
}
|
||||
yy = yy_lookup[T0];
|
||||
best_xy = xy;
|
||||
best_yy = yy;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
{
|
||||
opus_val32 x2y2;
|
||||
int sh, t;
|
||||
x2y2 = 1+HALF32(MULT32_32_Q31(xx,yy));
|
||||
sh = celt_ilog2(x2y2)>>1;
|
||||
t = VSHR32(x2y2, 2*(sh-7));
|
||||
g = g0 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1);
|
||||
}
|
||||
#else
|
||||
g = g0 = xy/celt_sqrt(1+xx*yy);
|
||||
#endif
|
||||
/* Look for any pitch at T/k */
|
||||
for (k=2;k<=15;k++)
|
||||
{
|
||||
int T1, T1b;
|
||||
opus_val16 g1;
|
||||
opus_val16 cont=0;
|
||||
opus_val16 thresh;
|
||||
T1 = (2*T0+k)/(2*k);
|
||||
if (T1 < minperiod)
|
||||
break;
|
||||
/* Look for another strong correlation at T1b */
|
||||
if (k==2)
|
||||
{
|
||||
if (T1+T0>maxperiod)
|
||||
T1b = T0;
|
||||
else
|
||||
T1b = T0+T1;
|
||||
} else
|
||||
{
|
||||
T1b = (2*second_check[k]*T0+k)/(2*k);
|
||||
}
|
||||
dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2);
|
||||
xy += xy2;
|
||||
yy = yy_lookup[T1] + yy_lookup[T1b];
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
{
|
||||
opus_val32 x2y2;
|
||||
int sh, t;
|
||||
x2y2 = 1+MULT32_32_Q31(xx,yy);
|
||||
sh = celt_ilog2(x2y2)>>1;
|
||||
t = VSHR32(x2y2, 2*(sh-7));
|
||||
g1 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1);
|
||||
}
|
||||
#else
|
||||
g1 = xy/celt_sqrt(1+2.f*xx*1.f*yy);
|
||||
#endif
|
||||
if (abs(T1-prev_period)<=1)
|
||||
cont = prev_gain;
|
||||
else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
|
||||
cont = HALF32(prev_gain);
|
||||
else
|
||||
cont = 0;
|
||||
thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
|
||||
/* Bias against very high pitch (very short period) to avoid false-positives
|
||||
due to short-term correlation */
|
||||
if (T1<3*minperiod)
|
||||
thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
|
||||
else if (T1<2*minperiod)
|
||||
thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
|
||||
if (g1 > thresh)
|
||||
{
|
||||
best_xy = xy;
|
||||
best_yy = yy;
|
||||
T = T1;
|
||||
g = g1;
|
||||
}
|
||||
}
|
||||
best_xy = MAX32(0, best_xy);
|
||||
if (best_yy <= best_xy)
|
||||
pg = Q15ONE;
|
||||
else
|
||||
pg = SHR32(frac_div32(best_xy,best_yy+1),16);
|
||||
|
||||
for (k=0;k<3;k++)
|
||||
{
|
||||
int T1 = T+k-1;
|
||||
xy = 0;
|
||||
for (i=0;i<N;i++)
|
||||
xy = MAC16_16(xy, x[i], x[i-T1]);
|
||||
xcorr[k] = xy;
|
||||
}
|
||||
if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
|
||||
offset = 1;
|
||||
else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
|
||||
offset = -1;
|
||||
else
|
||||
offset = 0;
|
||||
if (pg > g)
|
||||
pg = g;
|
||||
*T0_ = 2*T+offset;
|
||||
|
||||
if (*T0_<minperiod0)
|
||||
*T0_=minperiod0;
|
||||
RESTORE_STACK;
|
||||
return pg;
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file pitch.h
|
||||
@brief Pitch analysis
|
||||
*/
|
||||
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PITCH_H
|
||||
#define PITCH_H
|
||||
|
||||
#include "opus_modes.h"
|
||||
#include "cpu_support.h"
|
||||
|
||||
#if defined(__SSE__) && !defined(OPUS_FIXED_POINT)
|
||||
#include "x86/pitch_sse.h"
|
||||
#endif
|
||||
|
||||
#if defined(OPUS_ARM_ASM) && defined(OPUS_FIXED_POINT)
|
||||
# include "arm/pitch_arm.h"
|
||||
#endif
|
||||
|
||||
void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
|
||||
int len, int C, int arch);
|
||||
|
||||
void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
|
||||
int len, int max_pitch, int *pitch, int arch);
|
||||
|
||||
opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
|
||||
int N, int *T0, int prev_period, opus_val16 prev_gain);
|
||||
|
||||
/* OPT: This is the kernel you really want to optimize. It gets used a lot
|
||||
by the prefilter and by the PLC. */
|
||||
#ifndef OVERRIDE_XCORR_KERNEL
|
||||
static OPUS_INLINE void xcorr_kernel(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
|
||||
{
|
||||
int j;
|
||||
opus_val16 y_0, y_1, y_2, y_3;
|
||||
celt_assert(len>=3);
|
||||
y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
|
||||
y_0=*y++;
|
||||
y_1=*y++;
|
||||
y_2=*y++;
|
||||
for (j=0;j<len-3;j+=4)
|
||||
{
|
||||
opus_val16 tmp;
|
||||
tmp = *x++;
|
||||
y_3=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_0);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_1);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_2);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_3);
|
||||
tmp=*x++;
|
||||
y_0=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_1);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_2);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_3);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_0);
|
||||
tmp=*x++;
|
||||
y_1=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_2);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_3);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_0);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_1);
|
||||
tmp=*x++;
|
||||
y_2=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_3);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_0);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_1);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_2);
|
||||
}
|
||||
if (j++<len)
|
||||
{
|
||||
opus_val16 tmp = *x++;
|
||||
y_3=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_0);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_1);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_2);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_3);
|
||||
}
|
||||
if (j++<len)
|
||||
{
|
||||
opus_val16 tmp=*x++;
|
||||
y_0=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_1);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_2);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_3);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_0);
|
||||
}
|
||||
if (j<len)
|
||||
{
|
||||
opus_val16 tmp=*x++;
|
||||
y_1=*y++;
|
||||
sum[0] = MAC16_16(sum[0],tmp,y_2);
|
||||
sum[1] = MAC16_16(sum[1],tmp,y_3);
|
||||
sum[2] = MAC16_16(sum[2],tmp,y_0);
|
||||
sum[3] = MAC16_16(sum[3],tmp,y_1);
|
||||
}
|
||||
}
|
||||
#endif /* OVERRIDE_XCORR_KERNEL */
|
||||
|
||||
#ifndef OVERRIDE_DUAL_INNER_PROD
|
||||
static OPUS_INLINE void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||
int N, opus_val32 *xy1, opus_val32 *xy2)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy01=0;
|
||||
opus_val32 xy02=0;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
xy01 = MAC16_16(xy01, x[i], y01[i]);
|
||||
xy02 = MAC16_16(xy02, x[i], y02[i]);
|
||||
}
|
||||
*xy1 = xy01;
|
||||
*xy2 = xy02;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
opus_val32
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
|
||||
#if !defined(OVERRIDE_PITCH_XCORR)
|
||||
/*Is run-time CPU detection enabled on this platform?*/
|
||||
# if defined(OPUS_HAVE_RTCD)
|
||||
extern
|
||||
# if defined(OPUS_FIXED_POINT)
|
||||
opus_val32
|
||||
# else
|
||||
void
|
||||
# endif
|
||||
(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
||||
const opus_val16 *, opus_val32 *, int, int);
|
||||
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
|
||||
xcorr, len, max_pitch))
|
||||
# else
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((void)(arch),celt_pitch_xcorr_c(_x, _y, xcorr, len, max_pitch))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,556 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "quant_bands.h"
|
||||
#include "laplace.h"
|
||||
#include <math.h>
|
||||
#include "os_support.h"
|
||||
#include "arch.h"
|
||||
#include "mathops.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "rate.h"
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
/* Mean energy in each band quantized in Q4 */
|
||||
const signed char eMeans[25] = {
|
||||
103,100, 92, 85, 81,
|
||||
77, 72, 70, 78, 75,
|
||||
73, 71, 78, 74, 69,
|
||||
72, 70, 74, 76, 71,
|
||||
60, 60, 60, 60, 60
|
||||
};
|
||||
#else
|
||||
/* Mean energy in each band quantized in Q4 and converted back to float */
|
||||
const opus_val16 eMeans[25] = {
|
||||
6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f,
|
||||
4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f,
|
||||
4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f,
|
||||
4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f,
|
||||
3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f
|
||||
};
|
||||
#endif
|
||||
/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384};
|
||||
static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554};
|
||||
static const opus_val16 beta_intra = 4915;
|
||||
#else
|
||||
static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.};
|
||||
static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.};
|
||||
static const opus_val16 beta_intra = 4915/32768.;
|
||||
#endif
|
||||
|
||||
/*Parameters of the Laplace-like probability models used for the coarse energy.
|
||||
There is one pair of parameters for each frame size, prediction type
|
||||
(inter/intra), and band number.
|
||||
The first number of each pair is the probability of 0, and the second is the
|
||||
decay rate, both in Q8 precision.*/
|
||||
static const unsigned char e_prob_model[4][2][42] = {
|
||||
/*120 sample frames.*/
|
||||
{
|
||||
/*Inter*/
|
||||
{
|
||||
72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128,
|
||||
64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40,
|
||||
114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11
|
||||
},
|
||||
/*Intra*/
|
||||
{
|
||||
24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132,
|
||||
55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66,
|
||||
91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50
|
||||
}
|
||||
},
|
||||
/*240 sample frames.*/
|
||||
{
|
||||
/*Inter*/
|
||||
{
|
||||
83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74,
|
||||
93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18,
|
||||
146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9
|
||||
},
|
||||
/*Intra*/
|
||||
{
|
||||
23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91,
|
||||
73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60,
|
||||
104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45
|
||||
}
|
||||
},
|
||||
/*480 sample frames.*/
|
||||
{
|
||||
/*Inter*/
|
||||
{
|
||||
61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38,
|
||||
112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16,
|
||||
158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10
|
||||
},
|
||||
/*Intra*/
|
||||
{
|
||||
21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73,
|
||||
87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55,
|
||||
112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42
|
||||
}
|
||||
},
|
||||
/*960 sample frames.*/
|
||||
{
|
||||
/*Inter*/
|
||||
{
|
||||
42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36,
|
||||
119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25,
|
||||
154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15
|
||||
},
|
||||
/*Intra*/
|
||||
{
|
||||
22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72,
|
||||
96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52,
|
||||
117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const unsigned char small_energy_icdf[3]={2,1,0};
|
||||
|
||||
static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C)
|
||||
{
|
||||
int c, i;
|
||||
opus_val32 dist = 0;
|
||||
c=0; do {
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
opus_val16 d = SUB16(SHR16(eBands[i+c*len], 3), SHR16(oldEBands[i+c*len], 3));
|
||||
dist = MAC16_16(dist, d,d);
|
||||
}
|
||||
} while (++c<C);
|
||||
return MIN32(200,SHR32(dist,2*DB_SHIFT-6));
|
||||
}
|
||||
|
||||
static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,
|
||||
const opus_val16 *eBands, opus_val16 *oldEBands,
|
||||
opus_int32 budget, opus_int32 tell,
|
||||
const unsigned char *prob_model, opus_val16 *error, ec_enc *enc,
|
||||
int C, int LM, int intra, opus_val16 max_decay, int lfe)
|
||||
{
|
||||
int i, c;
|
||||
int badness = 0;
|
||||
opus_val32 prev[2] = {0,0};
|
||||
opus_val16 coef;
|
||||
opus_val16 beta;
|
||||
|
||||
if (tell+3 <= budget)
|
||||
ec_enc_bit_logp(enc, intra, 3);
|
||||
if (intra)
|
||||
{
|
||||
coef = 0;
|
||||
beta = beta_intra;
|
||||
} else {
|
||||
beta = beta_coef[LM];
|
||||
coef = pred_coef[LM];
|
||||
}
|
||||
|
||||
/* Encode at a fixed coarse resolution */
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
c=0;
|
||||
do {
|
||||
int bits_left;
|
||||
int qi, qi0;
|
||||
opus_val32 q;
|
||||
opus_val16 x;
|
||||
opus_val32 f, tmp;
|
||||
opus_val16 oldE;
|
||||
opus_val16 decay_bound;
|
||||
x = eBands[i+c*m->nbEBands];
|
||||
oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c];
|
||||
/* Rounding to nearest integer here is really important! */
|
||||
qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7);
|
||||
decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT),
|
||||
SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay)));
|
||||
#else
|
||||
f = x-coef*oldE-prev[c];
|
||||
/* Rounding to nearest integer here is really important! */
|
||||
qi = (int)floor(.5f+f);
|
||||
decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay;
|
||||
#endif
|
||||
/* Prevent the energy from going down too quickly (e.g. for bands
|
||||
that have just one bin) */
|
||||
if (qi < 0 && x < decay_bound)
|
||||
{
|
||||
qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT);
|
||||
if (qi > 0)
|
||||
qi = 0;
|
||||
}
|
||||
qi0 = qi;
|
||||
/* If we don't have enough bits to encode all the energy, just assume
|
||||
something safe. */
|
||||
tell = ec_tell(enc);
|
||||
bits_left = budget-tell-3*C*(end-i);
|
||||
if (i!=start && bits_left < 30)
|
||||
{
|
||||
if (bits_left < 24)
|
||||
qi = IMIN(1, qi);
|
||||
if (bits_left < 16)
|
||||
qi = IMAX(-1, qi);
|
||||
}
|
||||
if (lfe && i>=2)
|
||||
qi = IMIN(qi, 0);
|
||||
if (budget-tell >= 15)
|
||||
{
|
||||
int pi;
|
||||
pi = 2*IMIN(i,20);
|
||||
ec_laplace_encode(enc, &qi,
|
||||
prob_model[pi]<<7, prob_model[pi+1]<<6);
|
||||
}
|
||||
else if(budget-tell >= 2)
|
||||
{
|
||||
qi = IMAX(-1, IMIN(qi, 1));
|
||||
ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2);
|
||||
}
|
||||
else if(budget-tell >= 1)
|
||||
{
|
||||
qi = IMIN(0, qi);
|
||||
ec_enc_bit_logp(enc, -qi, 1);
|
||||
}
|
||||
else
|
||||
qi = -1;
|
||||
error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT);
|
||||
badness += abs(qi0-qi);
|
||||
q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
|
||||
|
||||
tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
|
||||
prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
|
||||
} while (++c < C);
|
||||
}
|
||||
return lfe ? 0 : badness;
|
||||
}
|
||||
|
||||
void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
|
||||
const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
|
||||
opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes,
|
||||
int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe)
|
||||
{
|
||||
int intra;
|
||||
opus_val16 max_decay;
|
||||
VARDECL(opus_val16, oldEBands_intra);
|
||||
VARDECL(opus_val16, error_intra);
|
||||
ec_enc enc_start_state;
|
||||
opus_uint32 tell;
|
||||
int badness1=0;
|
||||
opus_int32 intra_bias;
|
||||
opus_val32 new_distortion;
|
||||
SAVE_STACK;
|
||||
|
||||
intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C);
|
||||
intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512));
|
||||
new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C);
|
||||
|
||||
tell = ec_tell(enc);
|
||||
if (tell+3 > budget)
|
||||
two_pass = intra = 0;
|
||||
|
||||
max_decay = QCONST16(16.f,DB_SHIFT);
|
||||
if (end-start>10)
|
||||
{
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3));
|
||||
#else
|
||||
max_decay = MIN32(max_decay, .125f*nbAvailableBytes);
|
||||
#endif
|
||||
}
|
||||
if (lfe)
|
||||
max_decay=3;
|
||||
enc_start_state = *enc;
|
||||
|
||||
ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16);
|
||||
ALLOC(error_intra, C*m->nbEBands, opus_val16);
|
||||
OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands);
|
||||
|
||||
if (two_pass || intra)
|
||||
{
|
||||
badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
|
||||
tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe);
|
||||
}
|
||||
|
||||
if (!intra)
|
||||
{
|
||||
unsigned char *intra_buf;
|
||||
ec_enc enc_intra_state;
|
||||
opus_int32 tell_intra;
|
||||
opus_uint32 nstart_bytes;
|
||||
opus_uint32 nintra_bytes;
|
||||
opus_uint32 save_bytes;
|
||||
int badness2;
|
||||
VARDECL(unsigned char, intra_bits);
|
||||
|
||||
tell_intra = ec_tell_frac(enc);
|
||||
|
||||
enc_intra_state = *enc;
|
||||
|
||||
nstart_bytes = ec_range_bytes(&enc_start_state);
|
||||
nintra_bytes = ec_range_bytes(&enc_intra_state);
|
||||
intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes;
|
||||
save_bytes = nintra_bytes-nstart_bytes;
|
||||
if (save_bytes == 0)
|
||||
save_bytes = ALLOC_NONE;
|
||||
ALLOC(intra_bits, save_bytes, unsigned char);
|
||||
/* Copy bits from intra bit-stream */
|
||||
OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes);
|
||||
|
||||
*enc = enc_start_state;
|
||||
|
||||
badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
|
||||
tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe);
|
||||
|
||||
if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra)))
|
||||
{
|
||||
*enc = enc_intra_state;
|
||||
/* Copy intra bits to bit-stream */
|
||||
OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes);
|
||||
OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
|
||||
OPUS_COPY(error, error_intra, C*m->nbEBands);
|
||||
intra = 1;
|
||||
}
|
||||
} else {
|
||||
OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
|
||||
OPUS_COPY(error, error_intra, C*m->nbEBands);
|
||||
}
|
||||
|
||||
if (intra)
|
||||
*delayedIntra = new_distortion;
|
||||
else
|
||||
*delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra),
|
||||
new_distortion);
|
||||
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
/* Encode finer resolution */
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
opus_int16 frac = 1<<fine_quant[i];
|
||||
if (fine_quant[i] <= 0)
|
||||
continue;
|
||||
c=0;
|
||||
do {
|
||||
int q2;
|
||||
opus_val16 offset;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
/* Has to be without rounding */
|
||||
q2 = (error[i+c*m->nbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]);
|
||||
#else
|
||||
q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac);
|
||||
#endif
|
||||
if (q2 > frac-1)
|
||||
q2 = frac-1;
|
||||
if (q2<0)
|
||||
q2 = 0;
|
||||
ec_enc_bits(enc, q2, fine_quant[i]);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
|
||||
#else
|
||||
offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] += offset;
|
||||
error[i+c*m->nbEBands] -= offset;
|
||||
/*printf ("%f ", error[i] - offset);*/
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
|
||||
void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C)
|
||||
{
|
||||
int i, prio, c;
|
||||
|
||||
/* Use up the remaining bits */
|
||||
for (prio=0;prio<2;prio++)
|
||||
{
|
||||
for (i=start;i<end && bits_left>=C ;i++)
|
||||
{
|
||||
if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
|
||||
continue;
|
||||
c=0;
|
||||
do {
|
||||
int q2;
|
||||
opus_val16 offset;
|
||||
q2 = error[i+c*m->nbEBands]<0 ? 0 : 1;
|
||||
ec_enc_bits(enc, q2, 1);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
|
||||
#else
|
||||
offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] += offset;
|
||||
bits_left--;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM)
|
||||
{
|
||||
const unsigned char *prob_model = e_prob_model[LM][intra];
|
||||
int i, c;
|
||||
opus_val32 prev[2] = {0, 0};
|
||||
opus_val16 coef;
|
||||
opus_val16 beta;
|
||||
opus_int32 budget;
|
||||
opus_int32 tell;
|
||||
|
||||
if (intra)
|
||||
{
|
||||
coef = 0;
|
||||
beta = beta_intra;
|
||||
} else {
|
||||
beta = beta_coef[LM];
|
||||
coef = pred_coef[LM];
|
||||
}
|
||||
|
||||
budget = dec->storage*8;
|
||||
|
||||
/* Decode at a fixed coarse resolution */
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
c=0;
|
||||
do {
|
||||
int qi;
|
||||
opus_val32 q;
|
||||
opus_val32 tmp;
|
||||
/* It would be better to express this invariant as a
|
||||
test on C at function entry, but that isn't enough
|
||||
to make the static analyzer happy. */
|
||||
celt_assert(c<2);
|
||||
tell = ec_tell(dec);
|
||||
if(budget-tell>=15)
|
||||
{
|
||||
int pi;
|
||||
pi = 2*IMIN(i,20);
|
||||
qi = ec_laplace_decode(dec,
|
||||
prob_model[pi]<<7, prob_model[pi+1]<<6);
|
||||
}
|
||||
else if(budget-tell>=2)
|
||||
{
|
||||
qi = ec_dec_icdf(dec, small_energy_icdf, 2);
|
||||
qi = (qi>>1)^-(qi&1);
|
||||
}
|
||||
else if(budget-tell>=1)
|
||||
{
|
||||
qi = -ec_dec_bit_logp(dec, 1);
|
||||
}
|
||||
else
|
||||
qi = -1;
|
||||
q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
|
||||
|
||||
oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
|
||||
tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
|
||||
prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
|
||||
void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C)
|
||||
{
|
||||
int i, c;
|
||||
/* Decode finer resolution */
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
if (fine_quant[i] <= 0)
|
||||
continue;
|
||||
c=0;
|
||||
do {
|
||||
int q2;
|
||||
opus_val16 offset;
|
||||
q2 = ec_dec_bits(dec, fine_quant[i]);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
|
||||
#else
|
||||
offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] += offset;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
|
||||
void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C)
|
||||
{
|
||||
int i, prio, c;
|
||||
|
||||
/* Use up the remaining bits */
|
||||
for (prio=0;prio<2;prio++)
|
||||
{
|
||||
for (i=start;i<end && bits_left>=C ;i++)
|
||||
{
|
||||
if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
|
||||
continue;
|
||||
c=0;
|
||||
do {
|
||||
int q2;
|
||||
opus_val16 offset;
|
||||
q2 = ec_dec_bits(dec, 1);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
|
||||
#else
|
||||
offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] += offset;
|
||||
bits_left--;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void amp2Log2(const CELTMode *m, int effEnd, int end,
|
||||
celt_ener *bandE, opus_val16 *bandLogE, int C)
|
||||
{
|
||||
int c, i;
|
||||
c=0;
|
||||
do {
|
||||
for (i=0;i<effEnd;i++)
|
||||
bandLogE[i+c*m->nbEBands] =
|
||||
celt_log2(SHL32(bandE[i+c*m->nbEBands],2))
|
||||
- SHL16((opus_val16)eMeans[i],6);
|
||||
for (i=effEnd;i<end;i++)
|
||||
bandLogE[c*m->nbEBands+i] = -QCONST16(14.f,DB_SHIFT);
|
||||
} while (++c < C);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef QUANT_BANDS
|
||||
#define QUANT_BANDS
|
||||
|
||||
#include "arch.h"
|
||||
#include "opus_modes.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
#include "mathops.h"
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
extern const signed char eMeans[25];
|
||||
#else
|
||||
extern const opus_val16 eMeans[25];
|
||||
#endif
|
||||
|
||||
void amp2Log2(const CELTMode *m, int effEnd, int end,
|
||||
celt_ener *bandE, opus_val16 *bandLogE, int C);
|
||||
|
||||
void log2Amp(const CELTMode *m, int start, int end,
|
||||
celt_ener *eBands, const opus_val16 *oldEBands, int C);
|
||||
|
||||
void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
|
||||
const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
|
||||
opus_val16 *error, ec_enc *enc, int C, int LM,
|
||||
int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra,
|
||||
int two_pass, int loss_rate, int lfe);
|
||||
|
||||
void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C);
|
||||
|
||||
void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C);
|
||||
|
||||
void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM);
|
||||
|
||||
void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C);
|
||||
|
||||
void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C);
|
||||
|
||||
#endif /* QUANT_BANDS */
|
|
@ -0,0 +1,638 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include "opus_modes.h"
|
||||
#include "cwrs.h"
|
||||
#include "arch.h"
|
||||
#include "os_support.h"
|
||||
|
||||
#include "entcode.h"
|
||||
#include "rate.h"
|
||||
|
||||
static const unsigned char LOG2_FRAC_TABLE[24]={
|
||||
0,
|
||||
8,13,
|
||||
16,19,21,23,
|
||||
24,26,27,28,29,30,31,32,
|
||||
32,33,34,34,35,36,36,37,37
|
||||
};
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
|
||||
/*Determines if V(N,K) fits in a 32-bit unsigned integer.
|
||||
N and K are themselves limited to 15 bits.*/
|
||||
static int fits_in32(int _n, int _k)
|
||||
{
|
||||
static const opus_int16 maxN[15] = {
|
||||
32767, 32767, 32767, 1476, 283, 109, 60, 40,
|
||||
29, 24, 20, 18, 16, 14, 13};
|
||||
static const opus_int16 maxK[15] = {
|
||||
32767, 32767, 32767, 32767, 1172, 238, 95, 53,
|
||||
36, 27, 22, 18, 16, 15, 13};
|
||||
if (_n>=14)
|
||||
{
|
||||
if (_k>=14)
|
||||
return 0;
|
||||
else
|
||||
return _n <= maxN[_k];
|
||||
} else {
|
||||
return _k <= maxK[_n];
|
||||
}
|
||||
}
|
||||
|
||||
void compute_pulse_cache(CELTMode *m, int LM)
|
||||
{
|
||||
int C;
|
||||
int i;
|
||||
int j;
|
||||
int curr=0;
|
||||
int nbEntries=0;
|
||||
int entryN[100], entryK[100], entryI[100];
|
||||
const opus_int16 *eBands = m->eBands;
|
||||
PulseCache *cache = &m->cache;
|
||||
opus_int16 *cindex;
|
||||
unsigned char *bits;
|
||||
unsigned char *cap;
|
||||
|
||||
cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2));
|
||||
cache->index = cindex;
|
||||
|
||||
/* Scan for all unique band sizes */
|
||||
for (i=0;i<=LM+1;i++)
|
||||
{
|
||||
for (j=0;j<m->nbEBands;j++)
|
||||
{
|
||||
int k;
|
||||
int N = (eBands[j+1]-eBands[j])<<i>>1;
|
||||
cindex[i*m->nbEBands+j] = -1;
|
||||
/* Find other bands that have the same size */
|
||||
for (k=0;k<=i;k++)
|
||||
{
|
||||
int n;
|
||||
for (n=0;n<m->nbEBands && (k!=i || n<j);n++)
|
||||
{
|
||||
if (N == (eBands[n+1]-eBands[n])<<k>>1)
|
||||
{
|
||||
cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cache->index[i*m->nbEBands+j] == -1 && N!=0)
|
||||
{
|
||||
int K;
|
||||
entryN[nbEntries] = N;
|
||||
K = 0;
|
||||
while (fits_in32(N,get_pulses(K+1)) && K<MAX_PSEUDO)
|
||||
K++;
|
||||
entryK[nbEntries] = K;
|
||||
cindex[i*m->nbEBands+j] = curr;
|
||||
entryI[nbEntries] = curr;
|
||||
|
||||
curr += K+1;
|
||||
nbEntries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr);
|
||||
cache->bits = bits;
|
||||
cache->size = curr;
|
||||
/* Compute the cache for all unique sizes */
|
||||
for (i=0;i<nbEntries;i++)
|
||||
{
|
||||
unsigned char *ptr = bits+entryI[i];
|
||||
opus_int16 tmp[MAX_PULSES+1];
|
||||
get_required_bits(tmp, entryN[i], get_pulses(entryK[i]), BITRES);
|
||||
for (j=1;j<=entryK[i];j++)
|
||||
ptr[j] = tmp[get_pulses(j)]-1;
|
||||
ptr[0] = entryK[i];
|
||||
}
|
||||
|
||||
/* Compute the maximum rate for each band at which we'll reliably use as
|
||||
many bits as we ask for. */
|
||||
cache->caps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands);
|
||||
for (i=0;i<=LM;i++)
|
||||
{
|
||||
for (C=1;C<=2;C++)
|
||||
{
|
||||
for (j=0;j<m->nbEBands;j++)
|
||||
{
|
||||
int N0;
|
||||
int max_bits;
|
||||
N0 = m->eBands[j+1]-m->eBands[j];
|
||||
/* N=1 bands only have a sign bit and fine bits. */
|
||||
if (N0<<i == 1)
|
||||
max_bits = C*(1+MAX_FINE_BITS)<<BITRES;
|
||||
else
|
||||
{
|
||||
const unsigned char *pcache;
|
||||
opus_int32 num;
|
||||
opus_int32 den;
|
||||
int LM0;
|
||||
int N;
|
||||
int offset;
|
||||
int ndof;
|
||||
int qb;
|
||||
int k;
|
||||
LM0 = 0;
|
||||
/* Even-sized bands bigger than N=2 can be split one more time.
|
||||
As of commit 44203907 all bands >1 are even, including custom modes.*/
|
||||
if (N0 > 2)
|
||||
{
|
||||
N0>>=1;
|
||||
LM0--;
|
||||
}
|
||||
/* N0=1 bands can't be split down to N<2. */
|
||||
else if (N0 <= 1)
|
||||
{
|
||||
LM0=IMIN(i,1);
|
||||
N0<<=LM0;
|
||||
}
|
||||
/* Compute the cost for the lowest-level PVQ of a fully split
|
||||
band. */
|
||||
pcache = bits + cindex[(LM0+1)*m->nbEBands+j];
|
||||
max_bits = pcache[pcache[0]]+1;
|
||||
/* Add in the cost of coding regular splits. */
|
||||
N = N0;
|
||||
for(k=0;k<i-LM0;k++){
|
||||
max_bits <<= 1;
|
||||
/* Offset the number of qtheta bits by log2(N)/2
|
||||
+ QTHETA_OFFSET compared to their "fair share" of
|
||||
total/N */
|
||||
offset = ((m->logN[j]+((LM0+k)<<BITRES))>>1)-QTHETA_OFFSET;
|
||||
/* The number of qtheta bits we'll allocate if the remainder
|
||||
is to be max_bits.
|
||||
The average measured cost for theta is 0.89701 times qb,
|
||||
approximated here as 459/512. */
|
||||
num=459*(opus_int32)((2*N-1)*offset+max_bits);
|
||||
den=((opus_int32)(2*N-1)<<9)-459;
|
||||
qb = IMIN((num+(den>>1))/den, 57);
|
||||
celt_assert(qb >= 0);
|
||||
max_bits += qb;
|
||||
N <<= 1;
|
||||
}
|
||||
/* Add in the cost of a stereo split, if necessary. */
|
||||
if (C==2)
|
||||
{
|
||||
max_bits <<= 1;
|
||||
offset = ((m->logN[j]+(i<<BITRES))>>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET);
|
||||
ndof = 2*N-1-(N==2);
|
||||
/* The average measured cost for theta with the step PDF is
|
||||
0.95164 times qb, approximated here as 487/512. */
|
||||
num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset);
|
||||
den = ((opus_int32)ndof<<9)-(N==2?512:487);
|
||||
qb = IMIN((num+(den>>1))/den, (N==2?64:61));
|
||||
celt_assert(qb >= 0);
|
||||
max_bits += qb;
|
||||
}
|
||||
/* Add the fine bits we'll use. */
|
||||
/* Compensate for the extra DoF in stereo */
|
||||
ndof = C*N + ((C==2 && N>2) ? 1 : 0);
|
||||
/* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET
|
||||
compared to their "fair share" of total/N */
|
||||
offset = ((m->logN[j] + (i<<BITRES))>>1)-FINE_OFFSET;
|
||||
/* N=2 is the only point that doesn't match the curve */
|
||||
if (N==2)
|
||||
offset += 1<<BITRES>>2;
|
||||
/* The number of fine bits we'll allocate if the remainder is
|
||||
to be max_bits. */
|
||||
num = max_bits+ndof*offset;
|
||||
den = (ndof-1)<<BITRES;
|
||||
qb = IMIN((num+(den>>1))/den, MAX_FINE_BITS);
|
||||
celt_assert(qb >= 0);
|
||||
max_bits += C*qb<<BITRES;
|
||||
}
|
||||
max_bits = (4*max_bits/(C*((m->eBands[j+1]-m->eBands[j])<<i)))-64;
|
||||
celt_assert(max_bits >= 0);
|
||||
celt_assert(max_bits < 256);
|
||||
*cap++ = (unsigned char)max_bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
#define ALLOC_STEPS 6
|
||||
|
||||
static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start,
|
||||
const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance,
|
||||
int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits,
|
||||
int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
|
||||
{
|
||||
opus_int32 psum;
|
||||
int lo, hi;
|
||||
int i, j;
|
||||
int logM;
|
||||
int stereo;
|
||||
int codedBands=-1;
|
||||
int alloc_floor;
|
||||
opus_int32 left, percoeff;
|
||||
int done;
|
||||
opus_int32 balance;
|
||||
SAVE_STACK;
|
||||
|
||||
alloc_floor = C<<BITRES;
|
||||
stereo = C>1;
|
||||
|
||||
logM = LM<<BITRES;
|
||||
lo = 0;
|
||||
hi = 1<<ALLOC_STEPS;
|
||||
for (i=0;i<ALLOC_STEPS;i++)
|
||||
{
|
||||
int mid = (lo+hi)>>1;
|
||||
psum = 0;
|
||||
done = 0;
|
||||
for (j=end;j-->start;)
|
||||
{
|
||||
int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS);
|
||||
if (tmp >= thresh[j] || done)
|
||||
{
|
||||
done = 1;
|
||||
/* Don't allocate more than we can actually use */
|
||||
psum += IMIN(tmp, cap[j]);
|
||||
} else {
|
||||
if (tmp >= alloc_floor)
|
||||
psum += alloc_floor;
|
||||
}
|
||||
}
|
||||
if (psum > total)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid;
|
||||
}
|
||||
psum = 0;
|
||||
/*printf ("interp bisection gave %d\n", lo);*/
|
||||
done = 0;
|
||||
for (j=end;j-->start;)
|
||||
{
|
||||
int tmp = bits1[j] + (lo*bits2[j]>>ALLOC_STEPS);
|
||||
if (tmp < thresh[j] && !done)
|
||||
{
|
||||
if (tmp >= alloc_floor)
|
||||
tmp = alloc_floor;
|
||||
else
|
||||
tmp = 0;
|
||||
} else
|
||||
done = 1;
|
||||
/* Don't allocate more than we can actually use */
|
||||
tmp = IMIN(tmp, cap[j]);
|
||||
bits[j] = tmp;
|
||||
psum += tmp;
|
||||
}
|
||||
|
||||
/* Decide which bands to skip, working backwards from the end. */
|
||||
for (codedBands=end;;codedBands--)
|
||||
{
|
||||
int band_width;
|
||||
int band_bits;
|
||||
int rem;
|
||||
j = codedBands-1;
|
||||
/* Never skip the first band, nor a band that has been boosted by
|
||||
dynalloc.
|
||||
In the first case, we'd be coding a bit to signal we're going to waste
|
||||
all the other bits.
|
||||
In the second case, we'd be coding a bit to redistribute all the bits
|
||||
we just signaled should be cocentrated in this band. */
|
||||
if (j<=skip_start)
|
||||
{
|
||||
/* Give the bit we reserved to end skipping back. */
|
||||
total += skip_rsv;
|
||||
break;
|
||||
}
|
||||
/*Figure out how many left-over bits we would be adding to this band.
|
||||
This can include bits we've stolen back from higher, skipped bands.*/
|
||||
left = total-psum;
|
||||
percoeff = left/(m->eBands[codedBands]-m->eBands[start]);
|
||||
left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
|
||||
rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0);
|
||||
band_width = m->eBands[codedBands]-m->eBands[j];
|
||||
band_bits = (int)(bits[j] + percoeff*band_width + rem);
|
||||
/*Only code a skip decision if we're above the threshold for this band.
|
||||
Otherwise it is force-skipped.
|
||||
This ensures that we have enough bits to code the skip flag.*/
|
||||
if (band_bits >= IMAX(thresh[j], alloc_floor+(1<<BITRES)))
|
||||
{
|
||||
if (encode)
|
||||
{
|
||||
/*This if() block is the only part of the allocation function that
|
||||
is not a mandatory part of the bitstream: any bands we choose to
|
||||
skip here must be explicitly signaled.*/
|
||||
/*Choose a threshold with some hysteresis to keep bands from
|
||||
fluctuating in and out.*/
|
||||
#ifdef FUZZING
|
||||
if ((rand()&0x1) == 0)
|
||||
#else
|
||||
if (codedBands<=start+2 || (band_bits > ((j<prev?7:9)*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth))
|
||||
#endif
|
||||
{
|
||||
ec_enc_bit_logp(ec, 1, 1);
|
||||
break;
|
||||
}
|
||||
ec_enc_bit_logp(ec, 0, 1);
|
||||
} else if (ec_dec_bit_logp(ec, 1)) {
|
||||
break;
|
||||
}
|
||||
/*We used a bit to skip this band.*/
|
||||
psum += 1<<BITRES;
|
||||
band_bits -= 1<<BITRES;
|
||||
}
|
||||
/*Reclaim the bits originally allocated to this band.*/
|
||||
psum -= bits[j]+intensity_rsv;
|
||||
if (intensity_rsv > 0)
|
||||
intensity_rsv = LOG2_FRAC_TABLE[j-start];
|
||||
psum += intensity_rsv;
|
||||
if (band_bits >= alloc_floor)
|
||||
{
|
||||
/*If we have enough for a fine energy bit per channel, use it.*/
|
||||
psum += alloc_floor;
|
||||
bits[j] = alloc_floor;
|
||||
} else {
|
||||
/*Otherwise this band gets nothing at all.*/
|
||||
bits[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
celt_assert(codedBands > start);
|
||||
/* Code the intensity and dual stereo parameters. */
|
||||
if (intensity_rsv > 0)
|
||||
{
|
||||
if (encode)
|
||||
{
|
||||
*intensity = IMIN(*intensity, codedBands);
|
||||
ec_enc_uint(ec, *intensity-start, codedBands+1-start);
|
||||
}
|
||||
else
|
||||
*intensity = start+ec_dec_uint(ec, codedBands+1-start);
|
||||
}
|
||||
else
|
||||
*intensity = 0;
|
||||
if (*intensity <= start)
|
||||
{
|
||||
total += dual_stereo_rsv;
|
||||
dual_stereo_rsv = 0;
|
||||
}
|
||||
if (dual_stereo_rsv > 0)
|
||||
{
|
||||
if (encode)
|
||||
ec_enc_bit_logp(ec, *dual_stereo, 1);
|
||||
else
|
||||
*dual_stereo = ec_dec_bit_logp(ec, 1);
|
||||
}
|
||||
else
|
||||
*dual_stereo = 0;
|
||||
|
||||
/* Allocate the remaining bits */
|
||||
left = total-psum;
|
||||
percoeff = left/(m->eBands[codedBands]-m->eBands[start]);
|
||||
left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
|
||||
for (j=start;j<codedBands;j++)
|
||||
bits[j] += ((int)percoeff*(m->eBands[j+1]-m->eBands[j]));
|
||||
for (j=start;j<codedBands;j++)
|
||||
{
|
||||
int tmp = (int)IMIN(left, m->eBands[j+1]-m->eBands[j]);
|
||||
bits[j] += tmp;
|
||||
left -= tmp;
|
||||
}
|
||||
/*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/
|
||||
|
||||
balance = 0;
|
||||
for (j=start;j<codedBands;j++)
|
||||
{
|
||||
int N0, N, den;
|
||||
int offset;
|
||||
int NClogN;
|
||||
opus_int32 excess, bit;
|
||||
|
||||
celt_assert(bits[j] >= 0);
|
||||
N0 = m->eBands[j+1]-m->eBands[j];
|
||||
N=N0<<LM;
|
||||
bit = (opus_int32)bits[j]+balance;
|
||||
|
||||
if (N>1)
|
||||
{
|
||||
excess = MAX32(bit-cap[j],0);
|
||||
bits[j] = bit-excess;
|
||||
|
||||
/* Compensate for the extra DoF in stereo */
|
||||
den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0));
|
||||
|
||||
NClogN = den*(m->logN[j] + logM);
|
||||
|
||||
/* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
|
||||
compared to their "fair share" of total/N */
|
||||
offset = (NClogN>>1)-den*FINE_OFFSET;
|
||||
|
||||
/* N=2 is the only point that doesn't match the curve */
|
||||
if (N==2)
|
||||
offset += den<<BITRES>>2;
|
||||
|
||||
/* Changing the offset for allocating the second and third
|
||||
fine energy bit */
|
||||
if (bits[j] + offset < den*2<<BITRES)
|
||||
offset += NClogN>>2;
|
||||
else if (bits[j] + offset < den*3<<BITRES)
|
||||
offset += NClogN>>3;
|
||||
|
||||
/* Divide with rounding */
|
||||
ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))) / (den<<BITRES));
|
||||
|
||||
/* Make sure not to bust */
|
||||
if (C*ebits[j] > (bits[j]>>BITRES))
|
||||
ebits[j] = bits[j] >> stereo >> BITRES;
|
||||
|
||||
/* More than that is useless because that's about as far as PVQ can go */
|
||||
ebits[j] = IMIN(ebits[j], MAX_FINE_BITS);
|
||||
|
||||
/* If we rounded down or capped this band, make it a candidate for the
|
||||
final fine energy pass */
|
||||
fine_priority[j] = ebits[j]*(den<<BITRES) >= bits[j]+offset;
|
||||
|
||||
/* Remove the allocated fine bits; the rest are assigned to PVQ */
|
||||
bits[j] -= C*ebits[j]<<BITRES;
|
||||
|
||||
} else {
|
||||
/* For N=1, all bits go to fine energy except for a single sign bit */
|
||||
excess = MAX32(0,bit-(C<<BITRES));
|
||||
bits[j] = bit-excess;
|
||||
ebits[j] = 0;
|
||||
fine_priority[j] = 1;
|
||||
}
|
||||
|
||||
/* Fine energy can't take advantage of the re-balancing in
|
||||
quant_all_bands().
|
||||
Instead, do the re-balancing here.*/
|
||||
if(excess > 0)
|
||||
{
|
||||
int extra_fine;
|
||||
int extra_bits;
|
||||
extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]);
|
||||
ebits[j] += extra_fine;
|
||||
extra_bits = extra_fine*C<<BITRES;
|
||||
fine_priority[j] = extra_bits >= excess-balance;
|
||||
excess -= extra_bits;
|
||||
}
|
||||
balance = excess;
|
||||
|
||||
celt_assert(bits[j] >= 0);
|
||||
celt_assert(ebits[j] >= 0);
|
||||
}
|
||||
/* Save any remaining bits over the cap for the rebalancing in
|
||||
quant_all_bands(). */
|
||||
*_balance = balance;
|
||||
|
||||
/* The skipped bands use all their bits for fine energy. */
|
||||
for (;j<end;j++)
|
||||
{
|
||||
ebits[j] = bits[j] >> stereo >> BITRES;
|
||||
celt_assert(C*ebits[j]<<BITRES == bits[j]);
|
||||
bits[j] = 0;
|
||||
fine_priority[j] = ebits[j]<1;
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return codedBands;
|
||||
}
|
||||
|
||||
int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
|
||||
opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
|
||||
{
|
||||
int lo, hi, len, j;
|
||||
int codedBands;
|
||||
int skip_start;
|
||||
int skip_rsv;
|
||||
int intensity_rsv;
|
||||
int dual_stereo_rsv;
|
||||
VARDECL(int, bits1);
|
||||
VARDECL(int, bits2);
|
||||
VARDECL(int, thresh);
|
||||
VARDECL(int, trim_offset);
|
||||
SAVE_STACK;
|
||||
|
||||
total = IMAX(total, 0);
|
||||
len = m->nbEBands;
|
||||
skip_start = start;
|
||||
/* Reserve a bit to signal the end of manually skipped bands. */
|
||||
skip_rsv = total >= 1<<BITRES ? 1<<BITRES : 0;
|
||||
total -= skip_rsv;
|
||||
/* Reserve bits for the intensity and dual stereo parameters. */
|
||||
intensity_rsv = dual_stereo_rsv = 0;
|
||||
if (C==2)
|
||||
{
|
||||
intensity_rsv = LOG2_FRAC_TABLE[end-start];
|
||||
if (intensity_rsv>total)
|
||||
intensity_rsv = 0;
|
||||
else
|
||||
{
|
||||
total -= intensity_rsv;
|
||||
dual_stereo_rsv = total>=1<<BITRES ? 1<<BITRES : 0;
|
||||
total -= dual_stereo_rsv;
|
||||
}
|
||||
}
|
||||
ALLOC(bits1, len, int);
|
||||
ALLOC(bits2, len, int);
|
||||
ALLOC(thresh, len, int);
|
||||
ALLOC(trim_offset, len, int);
|
||||
|
||||
for (j=start;j<end;j++)
|
||||
{
|
||||
/* Below this threshold, we're sure not to allocate any PVQ bits */
|
||||
thresh[j] = IMAX((C)<<BITRES, (3*(m->eBands[j+1]-m->eBands[j])<<LM<<BITRES)>>4);
|
||||
/* Tilt of the allocation curve */
|
||||
trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1)
|
||||
*(1<<(LM+BITRES))>>6;
|
||||
/* Giving less resolution to single-coefficient bands because they get
|
||||
more benefit from having one coarse value per coefficient*/
|
||||
if ((m->eBands[j+1]-m->eBands[j])<<LM==1)
|
||||
trim_offset[j] -= C<<BITRES;
|
||||
}
|
||||
lo = 1;
|
||||
hi = m->nbAllocVectors - 1;
|
||||
do
|
||||
{
|
||||
int done = 0;
|
||||
int psum = 0;
|
||||
int mid = (lo+hi) >> 1;
|
||||
for (j=end;j-->start;)
|
||||
{
|
||||
int bitsj;
|
||||
int N = m->eBands[j+1]-m->eBands[j];
|
||||
bitsj = C*N*m->allocVectors[mid*len+j]<<LM>>2;
|
||||
if (bitsj > 0)
|
||||
bitsj = IMAX(0, bitsj + trim_offset[j]);
|
||||
bitsj += offsets[j];
|
||||
if (bitsj >= thresh[j] || done)
|
||||
{
|
||||
done = 1;
|
||||
/* Don't allocate more than we can actually use */
|
||||
psum += IMIN(bitsj, cap[j]);
|
||||
} else {
|
||||
if (bitsj >= C<<BITRES)
|
||||
psum += C<<BITRES;
|
||||
}
|
||||
}
|
||||
if (psum > total)
|
||||
hi = mid - 1;
|
||||
else
|
||||
lo = mid + 1;
|
||||
/*printf ("lo = %d, hi = %d\n", lo, hi);*/
|
||||
}
|
||||
while (lo <= hi);
|
||||
hi = lo--;
|
||||
/*printf ("interp between %d and %d\n", lo, hi);*/
|
||||
for (j=start;j<end;j++)
|
||||
{
|
||||
int bits1j, bits2j;
|
||||
int N = m->eBands[j+1]-m->eBands[j];
|
||||
bits1j = C*N*m->allocVectors[lo*len+j]<<LM>>2;
|
||||
bits2j = hi>=m->nbAllocVectors ?
|
||||
cap[j] : C*N*m->allocVectors[hi*len+j]<<LM>>2;
|
||||
if (bits1j > 0)
|
||||
bits1j = IMAX(0, bits1j + trim_offset[j]);
|
||||
if (bits2j > 0)
|
||||
bits2j = IMAX(0, bits2j + trim_offset[j]);
|
||||
if (lo > 0)
|
||||
bits1j += offsets[j];
|
||||
bits2j += offsets[j];
|
||||
if (offsets[j]>0)
|
||||
skip_start = j;
|
||||
bits2j = IMAX(0,bits2j-bits1j);
|
||||
bits1[j] = bits1j;
|
||||
bits2[j] = bits2j;
|
||||
}
|
||||
codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap,
|
||||
total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv,
|
||||
pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth);
|
||||
RESTORE_STACK;
|
||||
return codedBands;
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RATE_H
|
||||
#define RATE_H
|
||||
|
||||
#define MAX_PSEUDO 40
|
||||
#define LOG_MAX_PSEUDO 6
|
||||
|
||||
#define MAX_PULSES 128
|
||||
|
||||
#define MAX_FINE_BITS 8
|
||||
|
||||
#define FINE_OFFSET 21
|
||||
#define QTHETA_OFFSET 4
|
||||
#define QTHETA_OFFSET_TWOPHASE 16
|
||||
|
||||
#include "cwrs.h"
|
||||
#include "opus_modes.h"
|
||||
|
||||
void compute_pulse_cache(CELTMode *m, int LM);
|
||||
|
||||
static OPUS_INLINE int get_pulses(int i)
|
||||
{
|
||||
return i<8 ? i : (8 + (i&7)) << ((i>>3)-1);
|
||||
}
|
||||
|
||||
static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits)
|
||||
{
|
||||
int i;
|
||||
int lo, hi;
|
||||
const unsigned char *cache;
|
||||
|
||||
LM++;
|
||||
cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
|
||||
|
||||
lo = 0;
|
||||
hi = cache[0];
|
||||
bits--;
|
||||
for (i=0;i<LOG_MAX_PSEUDO;i++)
|
||||
{
|
||||
int mid = (lo+hi+1)>>1;
|
||||
/* OPT: Make sure this is implemented with a conditional move */
|
||||
if ((int)cache[mid] >= bits)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid;
|
||||
}
|
||||
if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits)
|
||||
return lo;
|
||||
else
|
||||
return hi;
|
||||
}
|
||||
|
||||
static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses)
|
||||
{
|
||||
const unsigned char *cache;
|
||||
|
||||
LM++;
|
||||
cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
|
||||
return pulses == 0 ? 0 : cache[pulses]+1;
|
||||
}
|
||||
|
||||
/** Compute the pulse allocation, i.e. how many pulses will go in each
|
||||
* band.
|
||||
@param m mode
|
||||
@param offsets Requested increase or decrease in the number of bits for
|
||||
each band
|
||||
@param total Number of bands
|
||||
@param pulses Number of pulses per band (returned)
|
||||
@return Total number of bits allocated
|
||||
*/
|
||||
int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero,
|
||||
opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,182 @@
|
|||
/* Copyright (C) 2002-2003 Jean-Marc Valin
|
||||
Copyright (C) 2007-2009 Xiph.Org Foundation */
|
||||
/**
|
||||
@file stack_alloc.h
|
||||
@brief Temporary memory allocation on stack
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef STACK_ALLOC_H
|
||||
#define STACK_ALLOC_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK))
|
||||
#define VAR_ARRAYS
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALLOCA
|
||||
# ifdef WIN32
|
||||
# include <malloc.h>
|
||||
# else
|
||||
# ifdef OPUS_HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef __linux__
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def ALIGN(stack, size)
|
||||
*
|
||||
* Aligns the stack to a 'size' boundary
|
||||
*
|
||||
* @param stack Stack
|
||||
* @param size New size boundary
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def PUSH(stack, size, type)
|
||||
*
|
||||
* Allocates 'size' elements of type 'type' on the stack
|
||||
*
|
||||
* @param stack Stack
|
||||
* @param size Number of elements
|
||||
* @param type Type of element
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def VARDECL(var)
|
||||
*
|
||||
* Declare variable on stack
|
||||
*
|
||||
* @param var Variable to declare
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def ALLOC(var, size, type)
|
||||
*
|
||||
* Allocate 'size' elements of 'type' on stack
|
||||
*
|
||||
* @param var Name of variable to allocate
|
||||
* @param size Number of elements
|
||||
* @param type Type of element
|
||||
*/
|
||||
|
||||
#if defined(VAR_ARRAYS)
|
||||
|
||||
#define VARDECL(type, var)
|
||||
#define ALLOC(var, size, type) type var[size]
|
||||
#define SAVE_STACK
|
||||
#define RESTORE_STACK
|
||||
#define ALLOC_STACK
|
||||
/* C99 does not allow VLAs of size zero */
|
||||
#define ALLOC_NONE 1
|
||||
|
||||
#elif defined(USE_ALLOCA)
|
||||
|
||||
#define VARDECL(type, var) type *var
|
||||
|
||||
# ifdef WIN32
|
||||
# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size)))
|
||||
# else
|
||||
# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size)))
|
||||
# endif
|
||||
|
||||
#define SAVE_STACK
|
||||
#define RESTORE_STACK
|
||||
#define ALLOC_STACK
|
||||
#define ALLOC_NONE 0
|
||||
|
||||
#else
|
||||
|
||||
#ifdef CELT_C
|
||||
char *global_stack=0;
|
||||
#else
|
||||
extern char *global_stack;
|
||||
#endif /* CELT_C */
|
||||
|
||||
#ifdef ENABLE_VALGRIND
|
||||
|
||||
#include <valgrind/memcheck.h>
|
||||
|
||||
#ifdef CELT_C
|
||||
char *global_stack_top=0;
|
||||
#else
|
||||
extern char *global_stack_top;
|
||||
#endif /* CELT_C */
|
||||
|
||||
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
|
||||
#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char))))
|
||||
#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack))
|
||||
#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack;
|
||||
|
||||
#else
|
||||
|
||||
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
|
||||
#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char))))
|
||||
#define RESTORE_STACK (global_stack = _saved_stack)
|
||||
#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? opus_alloc_scratch(GLOBAL_STACK_SIZE) : global_stack); _saved_stack = global_stack;
|
||||
|
||||
#endif /* ENABLE_VALGRIND */
|
||||
|
||||
#include "os_support.h"
|
||||
#define VARDECL(type, var) type *var
|
||||
#define ALLOC(var, size, type) var = PUSH(global_stack, size, type)
|
||||
#define SAVE_STACK char *_saved_stack = global_stack;
|
||||
#define ALLOC_NONE 0
|
||||
|
||||
#endif /* VAR_ARRAYS */
|
||||
|
||||
|
||||
#ifdef ENABLE_VALGRIND
|
||||
|
||||
#include <valgrind/memcheck.h>
|
||||
#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
|
||||
#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
|
||||
#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
|
||||
#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
|
||||
#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0)
|
||||
#define OPUS_FPRINTF fprintf
|
||||
|
||||
#else
|
||||
|
||||
static OPUS_INLINE int _opus_false(void) {return 0;}
|
||||
#define OPUS_CHECK_ARRAY(ptr, len) _opus_false()
|
||||
#define OPUS_CHECK_VALUE(value) _opus_false()
|
||||
#define OPUS_PRINT_INT(value) do{}while(0)
|
||||
#define OPUS_FPRINTF (void)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* STACK_ALLOC_H */
|
|
@ -0,0 +1,595 @@
|
|||
/* The contents of this file was automatically generated by dump_modes.c
|
||||
with arguments: 48000 960
|
||||
It contains static definitions for some pre-defined modes. */
|
||||
#include "opus_modes.h"
|
||||
#include "rate.h"
|
||||
|
||||
#ifndef DEF_WINDOW120
|
||||
#define DEF_WINDOW120
|
||||
static const opus_val16 window120[120] = {
|
||||
2, 20, 55, 108, 178,
|
||||
266, 372, 494, 635, 792,
|
||||
966, 1157, 1365, 1590, 1831,
|
||||
2089, 2362, 2651, 2956, 3276,
|
||||
3611, 3961, 4325, 4703, 5094,
|
||||
5499, 5916, 6346, 6788, 7241,
|
||||
7705, 8179, 8663, 9156, 9657,
|
||||
10167, 10684, 11207, 11736, 12271,
|
||||
12810, 13353, 13899, 14447, 14997,
|
||||
15547, 16098, 16648, 17197, 17744,
|
||||
18287, 18827, 19363, 19893, 20418,
|
||||
20936, 21447, 21950, 22445, 22931,
|
||||
23407, 23874, 24330, 24774, 25208,
|
||||
25629, 26039, 26435, 26819, 27190,
|
||||
27548, 27893, 28224, 28541, 28845,
|
||||
29135, 29411, 29674, 29924, 30160,
|
||||
30384, 30594, 30792, 30977, 31151,
|
||||
31313, 31463, 31602, 31731, 31849,
|
||||
31958, 32057, 32148, 32229, 32303,
|
||||
32370, 32429, 32481, 32528, 32568,
|
||||
32604, 32634, 32661, 32683, 32701,
|
||||
32717, 32729, 32740, 32748, 32754,
|
||||
32758, 32762, 32764, 32766, 32767,
|
||||
32767, 32767, 32767, 32767, 32767,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef DEF_LOGN400
|
||||
#define DEF_LOGN400
|
||||
static const opus_int16 logN400[21] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
|
||||
#endif
|
||||
|
||||
#ifndef DEF_PULSE_CACHE50
|
||||
#define DEF_PULSE_CACHE50
|
||||
static const opus_int16 cache_index50[105] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
|
||||
82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
|
||||
41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
|
||||
41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
|
||||
318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
|
||||
305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
|
||||
};
|
||||
static const unsigned char cache_bits50[392] = {
|
||||
40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
|
||||
31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
|
||||
51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
|
||||
66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
|
||||
64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
|
||||
94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
|
||||
124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
|
||||
97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
|
||||
142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
|
||||
28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
|
||||
153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
|
||||
229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
|
||||
166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
|
||||
86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
|
||||
25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
|
||||
185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
|
||||
110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
|
||||
74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
|
||||
163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
|
||||
228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
|
||||
90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
|
||||
87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
|
||||
106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
|
||||
224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
|
||||
182, 234, };
|
||||
static const unsigned char cache_caps50[168] = {
|
||||
224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
|
||||
178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
|
||||
240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
|
||||
160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
|
||||
138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
|
||||
204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
|
||||
185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
|
||||
207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
|
||||
188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
|
||||
193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
|
||||
204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
|
||||
140, 66, 40, };
|
||||
#endif
|
||||
|
||||
#ifndef FFT_TWIDDLES48000_960
|
||||
#define FFT_TWIDDLES48000_960
|
||||
static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
|
||||
{32767, 0}, {32766, -429},
|
||||
{32757, -858}, {32743, -1287},
|
||||
{32724, -1715}, {32698, -2143},
|
||||
{32667, -2570}, {32631, -2998},
|
||||
{32588, -3425}, {32541, -3851},
|
||||
{32488, -4277}, {32429, -4701},
|
||||
{32364, -5125}, {32295, -5548},
|
||||
{32219, -5971}, {32138, -6393},
|
||||
{32051, -6813}, {31960, -7231},
|
||||
{31863, -7650}, {31760, -8067},
|
||||
{31652, -8481}, {31539, -8895},
|
||||
{31419, -9306}, {31294, -9716},
|
||||
{31165, -10126}, {31030, -10532},
|
||||
{30889, -10937}, {30743, -11340},
|
||||
{30592, -11741}, {30436, -12141},
|
||||
{30274, -12540}, {30107, -12935},
|
||||
{29936, -13328}, {29758, -13718},
|
||||
{29577, -14107}, {29390, -14493},
|
||||
{29197, -14875}, {29000, -15257},
|
||||
{28797, -15635}, {28590, -16010},
|
||||
{28379, -16384}, {28162, -16753},
|
||||
{27940, -17119}, {27714, -17484},
|
||||
{27482, -17845}, {27246, -18205},
|
||||
{27006, -18560}, {26760, -18911},
|
||||
{26510, -19260}, {26257, -19606},
|
||||
{25997, -19947}, {25734, -20286},
|
||||
{25466, -20621}, {25194, -20952},
|
||||
{24918, -21281}, {24637, -21605},
|
||||
{24353, -21926}, {24063, -22242},
|
||||
{23770, -22555}, {23473, -22865},
|
||||
{23171, -23171}, {22866, -23472},
|
||||
{22557, -23769}, {22244, -24063},
|
||||
{21927, -24352}, {21606, -24636},
|
||||
{21282, -24917}, {20954, -25194},
|
||||
{20622, -25465}, {20288, -25733},
|
||||
{19949, -25997}, {19607, -26255},
|
||||
{19261, -26509}, {18914, -26760},
|
||||
{18561, -27004}, {18205, -27246},
|
||||
{17846, -27481}, {17485, -27713},
|
||||
{17122, -27940}, {16755, -28162},
|
||||
{16385, -28378}, {16012, -28590},
|
||||
{15636, -28797}, {15258, -28999},
|
||||
{14878, -29197}, {14494, -29389},
|
||||
{14108, -29576}, {13720, -29757},
|
||||
{13329, -29934}, {12937, -30107},
|
||||
{12540, -30274}, {12142, -30435},
|
||||
{11744, -30592}, {11342, -30743},
|
||||
{10939, -30889}, {10534, -31030},
|
||||
{10127, -31164}, {9718, -31294},
|
||||
{9307, -31418}, {8895, -31537},
|
||||
{8482, -31652}, {8067, -31759},
|
||||
{7650, -31862}, {7233, -31960},
|
||||
{6815, -32051}, {6393, -32138},
|
||||
{5973, -32219}, {5549, -32294},
|
||||
{5127, -32364}, {4703, -32429},
|
||||
{4278, -32487}, {3852, -32541},
|
||||
{3426, -32588}, {2999, -32630},
|
||||
{2572, -32667}, {2144, -32698},
|
||||
{1716, -32724}, {1287, -32742},
|
||||
{860, -32757}, {430, -32766},
|
||||
{0, -32767}, {-429, -32766},
|
||||
{-858, -32757}, {-1287, -32743},
|
||||
{-1715, -32724}, {-2143, -32698},
|
||||
{-2570, -32667}, {-2998, -32631},
|
||||
{-3425, -32588}, {-3851, -32541},
|
||||
{-4277, -32488}, {-4701, -32429},
|
||||
{-5125, -32364}, {-5548, -32295},
|
||||
{-5971, -32219}, {-6393, -32138},
|
||||
{-6813, -32051}, {-7231, -31960},
|
||||
{-7650, -31863}, {-8067, -31760},
|
||||
{-8481, -31652}, {-8895, -31539},
|
||||
{-9306, -31419}, {-9716, -31294},
|
||||
{-10126, -31165}, {-10532, -31030},
|
||||
{-10937, -30889}, {-11340, -30743},
|
||||
{-11741, -30592}, {-12141, -30436},
|
||||
{-12540, -30274}, {-12935, -30107},
|
||||
{-13328, -29936}, {-13718, -29758},
|
||||
{-14107, -29577}, {-14493, -29390},
|
||||
{-14875, -29197}, {-15257, -29000},
|
||||
{-15635, -28797}, {-16010, -28590},
|
||||
{-16384, -28379}, {-16753, -28162},
|
||||
{-17119, -27940}, {-17484, -27714},
|
||||
{-17845, -27482}, {-18205, -27246},
|
||||
{-18560, -27006}, {-18911, -26760},
|
||||
{-19260, -26510}, {-19606, -26257},
|
||||
{-19947, -25997}, {-20286, -25734},
|
||||
{-20621, -25466}, {-20952, -25194},
|
||||
{-21281, -24918}, {-21605, -24637},
|
||||
{-21926, -24353}, {-22242, -24063},
|
||||
{-22555, -23770}, {-22865, -23473},
|
||||
{-23171, -23171}, {-23472, -22866},
|
||||
{-23769, -22557}, {-24063, -22244},
|
||||
{-24352, -21927}, {-24636, -21606},
|
||||
{-24917, -21282}, {-25194, -20954},
|
||||
{-25465, -20622}, {-25733, -20288},
|
||||
{-25997, -19949}, {-26255, -19607},
|
||||
{-26509, -19261}, {-26760, -18914},
|
||||
{-27004, -18561}, {-27246, -18205},
|
||||
{-27481, -17846}, {-27713, -17485},
|
||||
{-27940, -17122}, {-28162, -16755},
|
||||
{-28378, -16385}, {-28590, -16012},
|
||||
{-28797, -15636}, {-28999, -15258},
|
||||
{-29197, -14878}, {-29389, -14494},
|
||||
{-29576, -14108}, {-29757, -13720},
|
||||
{-29934, -13329}, {-30107, -12937},
|
||||
{-30274, -12540}, {-30435, -12142},
|
||||
{-30592, -11744}, {-30743, -11342},
|
||||
{-30889, -10939}, {-31030, -10534},
|
||||
{-31164, -10127}, {-31294, -9718},
|
||||
{-31418, -9307}, {-31537, -8895},
|
||||
{-31652, -8482}, {-31759, -8067},
|
||||
{-31862, -7650}, {-31960, -7233},
|
||||
{-32051, -6815}, {-32138, -6393},
|
||||
{-32219, -5973}, {-32294, -5549},
|
||||
{-32364, -5127}, {-32429, -4703},
|
||||
{-32487, -4278}, {-32541, -3852},
|
||||
{-32588, -3426}, {-32630, -2999},
|
||||
{-32667, -2572}, {-32698, -2144},
|
||||
{-32724, -1716}, {-32742, -1287},
|
||||
{-32757, -860}, {-32766, -430},
|
||||
{-32767, 0}, {-32766, 429},
|
||||
{-32757, 858}, {-32743, 1287},
|
||||
{-32724, 1715}, {-32698, 2143},
|
||||
{-32667, 2570}, {-32631, 2998},
|
||||
{-32588, 3425}, {-32541, 3851},
|
||||
{-32488, 4277}, {-32429, 4701},
|
||||
{-32364, 5125}, {-32295, 5548},
|
||||
{-32219, 5971}, {-32138, 6393},
|
||||
{-32051, 6813}, {-31960, 7231},
|
||||
{-31863, 7650}, {-31760, 8067},
|
||||
{-31652, 8481}, {-31539, 8895},
|
||||
{-31419, 9306}, {-31294, 9716},
|
||||
{-31165, 10126}, {-31030, 10532},
|
||||
{-30889, 10937}, {-30743, 11340},
|
||||
{-30592, 11741}, {-30436, 12141},
|
||||
{-30274, 12540}, {-30107, 12935},
|
||||
{-29936, 13328}, {-29758, 13718},
|
||||
{-29577, 14107}, {-29390, 14493},
|
||||
{-29197, 14875}, {-29000, 15257},
|
||||
{-28797, 15635}, {-28590, 16010},
|
||||
{-28379, 16384}, {-28162, 16753},
|
||||
{-27940, 17119}, {-27714, 17484},
|
||||
{-27482, 17845}, {-27246, 18205},
|
||||
{-27006, 18560}, {-26760, 18911},
|
||||
{-26510, 19260}, {-26257, 19606},
|
||||
{-25997, 19947}, {-25734, 20286},
|
||||
{-25466, 20621}, {-25194, 20952},
|
||||
{-24918, 21281}, {-24637, 21605},
|
||||
{-24353, 21926}, {-24063, 22242},
|
||||
{-23770, 22555}, {-23473, 22865},
|
||||
{-23171, 23171}, {-22866, 23472},
|
||||
{-22557, 23769}, {-22244, 24063},
|
||||
{-21927, 24352}, {-21606, 24636},
|
||||
{-21282, 24917}, {-20954, 25194},
|
||||
{-20622, 25465}, {-20288, 25733},
|
||||
{-19949, 25997}, {-19607, 26255},
|
||||
{-19261, 26509}, {-18914, 26760},
|
||||
{-18561, 27004}, {-18205, 27246},
|
||||
{-17846, 27481}, {-17485, 27713},
|
||||
{-17122, 27940}, {-16755, 28162},
|
||||
{-16385, 28378}, {-16012, 28590},
|
||||
{-15636, 28797}, {-15258, 28999},
|
||||
{-14878, 29197}, {-14494, 29389},
|
||||
{-14108, 29576}, {-13720, 29757},
|
||||
{-13329, 29934}, {-12937, 30107},
|
||||
{-12540, 30274}, {-12142, 30435},
|
||||
{-11744, 30592}, {-11342, 30743},
|
||||
{-10939, 30889}, {-10534, 31030},
|
||||
{-10127, 31164}, {-9718, 31294},
|
||||
{-9307, 31418}, {-8895, 31537},
|
||||
{-8482, 31652}, {-8067, 31759},
|
||||
{-7650, 31862}, {-7233, 31960},
|
||||
{-6815, 32051}, {-6393, 32138},
|
||||
{-5973, 32219}, {-5549, 32294},
|
||||
{-5127, 32364}, {-4703, 32429},
|
||||
{-4278, 32487}, {-3852, 32541},
|
||||
{-3426, 32588}, {-2999, 32630},
|
||||
{-2572, 32667}, {-2144, 32698},
|
||||
{-1716, 32724}, {-1287, 32742},
|
||||
{-860, 32757}, {-430, 32766},
|
||||
{0, 32767}, {429, 32766},
|
||||
{858, 32757}, {1287, 32743},
|
||||
{1715, 32724}, {2143, 32698},
|
||||
{2570, 32667}, {2998, 32631},
|
||||
{3425, 32588}, {3851, 32541},
|
||||
{4277, 32488}, {4701, 32429},
|
||||
{5125, 32364}, {5548, 32295},
|
||||
{5971, 32219}, {6393, 32138},
|
||||
{6813, 32051}, {7231, 31960},
|
||||
{7650, 31863}, {8067, 31760},
|
||||
{8481, 31652}, {8895, 31539},
|
||||
{9306, 31419}, {9716, 31294},
|
||||
{10126, 31165}, {10532, 31030},
|
||||
{10937, 30889}, {11340, 30743},
|
||||
{11741, 30592}, {12141, 30436},
|
||||
{12540, 30274}, {12935, 30107},
|
||||
{13328, 29936}, {13718, 29758},
|
||||
{14107, 29577}, {14493, 29390},
|
||||
{14875, 29197}, {15257, 29000},
|
||||
{15635, 28797}, {16010, 28590},
|
||||
{16384, 28379}, {16753, 28162},
|
||||
{17119, 27940}, {17484, 27714},
|
||||
{17845, 27482}, {18205, 27246},
|
||||
{18560, 27006}, {18911, 26760},
|
||||
{19260, 26510}, {19606, 26257},
|
||||
{19947, 25997}, {20286, 25734},
|
||||
{20621, 25466}, {20952, 25194},
|
||||
{21281, 24918}, {21605, 24637},
|
||||
{21926, 24353}, {22242, 24063},
|
||||
{22555, 23770}, {22865, 23473},
|
||||
{23171, 23171}, {23472, 22866},
|
||||
{23769, 22557}, {24063, 22244},
|
||||
{24352, 21927}, {24636, 21606},
|
||||
{24917, 21282}, {25194, 20954},
|
||||
{25465, 20622}, {25733, 20288},
|
||||
{25997, 19949}, {26255, 19607},
|
||||
{26509, 19261}, {26760, 18914},
|
||||
{27004, 18561}, {27246, 18205},
|
||||
{27481, 17846}, {27713, 17485},
|
||||
{27940, 17122}, {28162, 16755},
|
||||
{28378, 16385}, {28590, 16012},
|
||||
{28797, 15636}, {28999, 15258},
|
||||
{29197, 14878}, {29389, 14494},
|
||||
{29576, 14108}, {29757, 13720},
|
||||
{29934, 13329}, {30107, 12937},
|
||||
{30274, 12540}, {30435, 12142},
|
||||
{30592, 11744}, {30743, 11342},
|
||||
{30889, 10939}, {31030, 10534},
|
||||
{31164, 10127}, {31294, 9718},
|
||||
{31418, 9307}, {31537, 8895},
|
||||
{31652, 8482}, {31759, 8067},
|
||||
{31862, 7650}, {31960, 7233},
|
||||
{32051, 6815}, {32138, 6393},
|
||||
{32219, 5973}, {32294, 5549},
|
||||
{32364, 5127}, {32429, 4703},
|
||||
{32487, 4278}, {32541, 3852},
|
||||
{32588, 3426}, {32630, 2999},
|
||||
{32667, 2572}, {32698, 2144},
|
||||
{32724, 1716}, {32742, 1287},
|
||||
{32757, 860}, {32766, 430},
|
||||
};
|
||||
#ifndef FFT_BITREV480
|
||||
#define FFT_BITREV480
|
||||
static const opus_int16 fft_bitrev480[480] = {
|
||||
0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330,
|
||||
450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225,
|
||||
345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95,
|
||||
215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440,
|
||||
110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310,
|
||||
430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205,
|
||||
325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61,
|
||||
181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406,
|
||||
76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276,
|
||||
396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171,
|
||||
291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41,
|
||||
161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386,
|
||||
56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242,
|
||||
362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137,
|
||||
257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7,
|
||||
127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457,
|
||||
22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352,
|
||||
472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222,
|
||||
342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117,
|
||||
237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423,
|
||||
93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318,
|
||||
438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188,
|
||||
308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83,
|
||||
203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403,
|
||||
73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298,
|
||||
418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154,
|
||||
274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49,
|
||||
169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369,
|
||||
39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264,
|
||||
384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134,
|
||||
254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29,
|
||||
149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_BITREV240
|
||||
#define FFT_BITREV240
|
||||
static const opus_int16 fft_bitrev240[240] = {
|
||||
0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165,
|
||||
225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110,
|
||||
170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55,
|
||||
115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211,
|
||||
46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156,
|
||||
216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101,
|
||||
161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32,
|
||||
92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202,
|
||||
37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147,
|
||||
207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78,
|
||||
138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23,
|
||||
83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193,
|
||||
28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124,
|
||||
184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69,
|
||||
129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14,
|
||||
74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_BITREV120
|
||||
#define FFT_BITREV120
|
||||
static const opus_int16 fft_bitrev120[120] = {
|
||||
0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80,
|
||||
110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46,
|
||||
76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26,
|
||||
56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97,
|
||||
22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63,
|
||||
93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43,
|
||||
73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9,
|
||||
39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_BITREV60
|
||||
#define FFT_BITREV60
|
||||
static const opus_int16 fft_bitrev60[60] = {
|
||||
0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31,
|
||||
46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22,
|
||||
37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13,
|
||||
28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_0
|
||||
#define FFT_STATE48000_960_0
|
||||
static const kiss_fft_state fft_state48000_960_0 = {
|
||||
480, /* nfft */
|
||||
-1, /* shift */
|
||||
{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev480, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_1
|
||||
#define FFT_STATE48000_960_1
|
||||
static const kiss_fft_state fft_state48000_960_1 = {
|
||||
240, /* nfft */
|
||||
1, /* shift */
|
||||
{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev240, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_2
|
||||
#define FFT_STATE48000_960_2
|
||||
static const kiss_fft_state fft_state48000_960_2 = {
|
||||
120, /* nfft */
|
||||
2, /* shift */
|
||||
{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev120, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_3
|
||||
#define FFT_STATE48000_960_3
|
||||
static const kiss_fft_state fft_state48000_960_3 = {
|
||||
60, /* nfft */
|
||||
3, /* shift */
|
||||
{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev60, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef MDCT_TWIDDLES960
|
||||
#define MDCT_TWIDDLES960
|
||||
static const opus_val16 mdct_twiddles960[481] = {
|
||||
32767, 32767, 32767, 32767, 32766,
|
||||
32763, 32762, 32759, 32757, 32753,
|
||||
32751, 32747, 32743, 32738, 32733,
|
||||
32729, 32724, 32717, 32711, 32705,
|
||||
32698, 32690, 32683, 32676, 32667,
|
||||
32658, 32650, 32640, 32631, 32620,
|
||||
32610, 32599, 32588, 32577, 32566,
|
||||
32554, 32541, 32528, 32515, 32502,
|
||||
32487, 32474, 32459, 32444, 32429,
|
||||
32413, 32397, 32381, 32364, 32348,
|
||||
32331, 32313, 32294, 32277, 32257,
|
||||
32239, 32219, 32200, 32180, 32159,
|
||||
32138, 32118, 32096, 32074, 32051,
|
||||
32029, 32006, 31984, 31960, 31936,
|
||||
31912, 31888, 31863, 31837, 31812,
|
||||
31786, 31760, 31734, 31707, 31679,
|
||||
31652, 31624, 31596, 31567, 31539,
|
||||
31508, 31479, 31450, 31419, 31388,
|
||||
31357, 31326, 31294, 31262, 31230,
|
||||
31198, 31164, 31131, 31097, 31063,
|
||||
31030, 30994, 30959, 30924, 30889,
|
||||
30853, 30816, 30779, 30743, 30705,
|
||||
30668, 30629, 30592, 30553, 30515,
|
||||
30475, 30435, 30396, 30356, 30315,
|
||||
30274, 30233, 30191, 30149, 30107,
|
||||
30065, 30022, 29979, 29936, 29891,
|
||||
29847, 29803, 29758, 29713, 29668,
|
||||
29622, 29577, 29529, 29483, 29436,
|
||||
29390, 29341, 29293, 29246, 29197,
|
||||
29148, 29098, 29050, 29000, 28949,
|
||||
28899, 28848, 28797, 28746, 28694,
|
||||
28642, 28590, 28537, 28485, 28432,
|
||||
28378, 28324, 28271, 28217, 28162,
|
||||
28106, 28051, 27995, 27940, 27884,
|
||||
27827, 27770, 27713, 27657, 27598,
|
||||
27540, 27481, 27423, 27365, 27305,
|
||||
27246, 27187, 27126, 27066, 27006,
|
||||
26945, 26883, 26822, 26760, 26698,
|
||||
26636, 26574, 26510, 26448, 26383,
|
||||
26320, 26257, 26191, 26127, 26062,
|
||||
25997, 25931, 25866, 25800, 25734,
|
||||
25667, 25601, 25533, 25466, 25398,
|
||||
25330, 25262, 25194, 25125, 25056,
|
||||
24987, 24917, 24848, 24778, 24707,
|
||||
24636, 24566, 24495, 24424, 24352,
|
||||
24280, 24208, 24135, 24063, 23990,
|
||||
23917, 23842, 23769, 23695, 23622,
|
||||
23546, 23472, 23398, 23322, 23246,
|
||||
23171, 23095, 23018, 22942, 22866,
|
||||
22788, 22711, 22634, 22557, 22478,
|
||||
22400, 22322, 22244, 22165, 22085,
|
||||
22006, 21927, 21846, 21766, 21687,
|
||||
21606, 21524, 21443, 21363, 21282,
|
||||
21199, 21118, 21035, 20954, 20870,
|
||||
20788, 20705, 20621, 20538, 20455,
|
||||
20371, 20286, 20202, 20118, 20034,
|
||||
19947, 19863, 19777, 19692, 19606,
|
||||
19520, 19434, 19347, 19260, 19174,
|
||||
19088, 18999, 18911, 18825, 18737,
|
||||
18648, 18560, 18472, 18384, 18294,
|
||||
18205, 18116, 18025, 17936, 17846,
|
||||
17757, 17666, 17576, 17485, 17395,
|
||||
17303, 17212, 17122, 17030, 16937,
|
||||
16846, 16755, 16662, 16569, 16477,
|
||||
16385, 16291, 16198, 16105, 16012,
|
||||
15917, 15824, 15730, 15636, 15541,
|
||||
15447, 15352, 15257, 15162, 15067,
|
||||
14973, 14875, 14781, 14685, 14589,
|
||||
14493, 14396, 14300, 14204, 14107,
|
||||
14010, 13914, 13815, 13718, 13621,
|
||||
13524, 13425, 13328, 13230, 13133,
|
||||
13033, 12935, 12836, 12738, 12638,
|
||||
12540, 12441, 12341, 12241, 12142,
|
||||
12044, 11943, 11843, 11744, 11643,
|
||||
11542, 11442, 11342, 11241, 11139,
|
||||
11039, 10939, 10836, 10736, 10635,
|
||||
10534, 10431, 10330, 10228, 10127,
|
||||
10024, 9921, 9820, 9718, 9614,
|
||||
9512, 9410, 9306, 9204, 9101,
|
||||
8998, 8895, 8791, 8689, 8585,
|
||||
8481, 8377, 8274, 8171, 8067,
|
||||
7962, 7858, 7753, 7650, 7545,
|
||||
7441, 7336, 7231, 7129, 7023,
|
||||
6917, 6813, 6709, 6604, 6498,
|
||||
6393, 6288, 6182, 6077, 5973,
|
||||
5867, 5760, 5656, 5549, 5445,
|
||||
5339, 5232, 5127, 5022, 4914,
|
||||
4809, 4703, 4596, 4490, 4384,
|
||||
4278, 4171, 4065, 3958, 3852,
|
||||
3745, 3640, 3532, 3426, 3318,
|
||||
3212, 3106, 2998, 2891, 2786,
|
||||
2679, 2570, 2465, 2358, 2251,
|
||||
2143, 2037, 1929, 1823, 1715,
|
||||
1609, 1501, 1393, 1287, 1180,
|
||||
1073, 964, 858, 751, 644,
|
||||
535, 429, 322, 214, 107,
|
||||
0, };
|
||||
#endif
|
||||
|
||||
static const CELTMode mode48000_960_120 = {
|
||||
48000, /* Fs */
|
||||
120, /* overlap */
|
||||
21, /* nbEBands */
|
||||
21, /* effEBands */
|
||||
{27853, 0, 4096, 8192, }, /* preemph */
|
||||
eband5ms, /* eBands */
|
||||
3, /* maxLM */
|
||||
8, /* nbShortMdcts */
|
||||
120, /* shortMdctSize */
|
||||
11, /* nbAllocVectors */
|
||||
band_allocation, /* allocVectors */
|
||||
logN400, /* logN */
|
||||
window120, /* window */
|
||||
{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */
|
||||
{392, cache_index50, cache_bits50, cache_caps50}, /* cache */
|
||||
};
|
||||
|
||||
/* List of all the available modes */
|
||||
#define TOTAL_MODES 1
|
||||
static const CELTMode * const static_mode_list[TOTAL_MODES] = {
|
||||
&mode48000_960_120,
|
||||
};
|
|
@ -0,0 +1,599 @@
|
|||
/* The contents of this file was automatically generated by dump_modes.c
|
||||
with arguments: 48000 960
|
||||
It contains static definitions for some pre-defined modes. */
|
||||
#include "opus_modes.h"
|
||||
#include "rate.h"
|
||||
|
||||
#ifndef DEF_WINDOW120
|
||||
#define DEF_WINDOW120
|
||||
static const opus_val16 window120[120] = {
|
||||
6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f,
|
||||
0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f,
|
||||
0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f,
|
||||
0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f,
|
||||
0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f,
|
||||
0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f,
|
||||
0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f,
|
||||
0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f,
|
||||
0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f,
|
||||
0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f,
|
||||
0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f,
|
||||
0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f,
|
||||
0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f,
|
||||
0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f,
|
||||
0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f,
|
||||
0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f,
|
||||
0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f,
|
||||
0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f,
|
||||
0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f,
|
||||
0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f,
|
||||
0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f,
|
||||
0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f,
|
||||
0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f,
|
||||
0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef DEF_LOGN400
|
||||
#define DEF_LOGN400
|
||||
static const opus_int16 logN400[21] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
|
||||
#endif
|
||||
|
||||
#ifndef DEF_PULSE_CACHE50
|
||||
#define DEF_PULSE_CACHE50
|
||||
static const opus_int16 cache_index50[105] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
|
||||
82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
|
||||
41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
|
||||
41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
|
||||
318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
|
||||
305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
|
||||
};
|
||||
static const unsigned char cache_bits50[392] = {
|
||||
40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
|
||||
31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
|
||||
51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
|
||||
66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
|
||||
64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
|
||||
94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
|
||||
124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
|
||||
97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
|
||||
142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
|
||||
28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
|
||||
153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
|
||||
229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
|
||||
166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
|
||||
86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
|
||||
25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
|
||||
185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
|
||||
110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
|
||||
74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
|
||||
163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
|
||||
228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
|
||||
90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
|
||||
87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
|
||||
106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
|
||||
224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
|
||||
182, 234, };
|
||||
static const unsigned char cache_caps50[168] = {
|
||||
224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
|
||||
178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
|
||||
240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
|
||||
160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
|
||||
138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
|
||||
204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
|
||||
185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
|
||||
207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
|
||||
188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
|
||||
193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
|
||||
204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
|
||||
140, 66, 40, };
|
||||
#endif
|
||||
|
||||
#ifndef FFT_TWIDDLES48000_960
|
||||
#define FFT_TWIDDLES48000_960
|
||||
static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
|
||||
{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f},
|
||||
{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f},
|
||||
{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f},
|
||||
{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f},
|
||||
{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f},
|
||||
{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f},
|
||||
{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f},
|
||||
{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f},
|
||||
{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f},
|
||||
{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f},
|
||||
{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f},
|
||||
{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f},
|
||||
{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f},
|
||||
{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f},
|
||||
{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f},
|
||||
{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f},
|
||||
{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f},
|
||||
{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f},
|
||||
{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f},
|
||||
{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f},
|
||||
{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f},
|
||||
{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f},
|
||||
{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f},
|
||||
{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f},
|
||||
{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f},
|
||||
{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f},
|
||||
{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f},
|
||||
{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f},
|
||||
{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f},
|
||||
{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f},
|
||||
{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f},
|
||||
{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f},
|
||||
{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f},
|
||||
{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f},
|
||||
{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f},
|
||||
{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f},
|
||||
{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f},
|
||||
{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f},
|
||||
{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f},
|
||||
{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f},
|
||||
{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f},
|
||||
{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f},
|
||||
{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f},
|
||||
{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f},
|
||||
{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f},
|
||||
{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f},
|
||||
{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f},
|
||||
{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f},
|
||||
{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f},
|
||||
{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f},
|
||||
{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f},
|
||||
{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f},
|
||||
{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f},
|
||||
{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f},
|
||||
{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f},
|
||||
{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f},
|
||||
{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f},
|
||||
{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f},
|
||||
{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f},
|
||||
{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f},
|
||||
{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f},
|
||||
{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f},
|
||||
{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f},
|
||||
{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f},
|
||||
{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f},
|
||||
{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f},
|
||||
{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f},
|
||||
{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f},
|
||||
{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f},
|
||||
{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f},
|
||||
{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f},
|
||||
{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f},
|
||||
{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f},
|
||||
{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f},
|
||||
{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f},
|
||||
{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f},
|
||||
{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f},
|
||||
{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f},
|
||||
{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f},
|
||||
{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f},
|
||||
{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f},
|
||||
{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f},
|
||||
{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f},
|
||||
{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f},
|
||||
{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f},
|
||||
{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f},
|
||||
{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f},
|
||||
{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f},
|
||||
{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f},
|
||||
{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f},
|
||||
{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f},
|
||||
{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f},
|
||||
{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f},
|
||||
{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f},
|
||||
{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f},
|
||||
{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f},
|
||||
{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f},
|
||||
{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f},
|
||||
{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f},
|
||||
{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f},
|
||||
{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f},
|
||||
{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f},
|
||||
{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f},
|
||||
{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f},
|
||||
{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f},
|
||||
{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f},
|
||||
{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f},
|
||||
{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f},
|
||||
{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f},
|
||||
{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f},
|
||||
{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f},
|
||||
{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f},
|
||||
{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f},
|
||||
{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f},
|
||||
{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f},
|
||||
{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f},
|
||||
{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f},
|
||||
{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f},
|
||||
{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f},
|
||||
{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f},
|
||||
{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f},
|
||||
{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f},
|
||||
{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f},
|
||||
{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f},
|
||||
{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f},
|
||||
{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f},
|
||||
{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f},
|
||||
{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f},
|
||||
{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f},
|
||||
{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f},
|
||||
{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f},
|
||||
{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f},
|
||||
{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f},
|
||||
{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f},
|
||||
{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f},
|
||||
{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f},
|
||||
{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f},
|
||||
{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f},
|
||||
{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f},
|
||||
{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f},
|
||||
{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f},
|
||||
{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f},
|
||||
{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f},
|
||||
{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f},
|
||||
{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f},
|
||||
{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f},
|
||||
{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f},
|
||||
{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f},
|
||||
{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f},
|
||||
{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f},
|
||||
{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f},
|
||||
{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f},
|
||||
{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f},
|
||||
{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f},
|
||||
{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f},
|
||||
{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f},
|
||||
{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f},
|
||||
{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f},
|
||||
{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f},
|
||||
{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f},
|
||||
{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f},
|
||||
{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f},
|
||||
{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f},
|
||||
{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f},
|
||||
{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f},
|
||||
{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f},
|
||||
{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f},
|
||||
{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f},
|
||||
{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f},
|
||||
{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f},
|
||||
{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f},
|
||||
{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f},
|
||||
{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f},
|
||||
{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f},
|
||||
{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f},
|
||||
{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f},
|
||||
{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f},
|
||||
{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f},
|
||||
{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f},
|
||||
{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f},
|
||||
{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f},
|
||||
{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f},
|
||||
{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f},
|
||||
{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f},
|
||||
{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f},
|
||||
{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f},
|
||||
{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f},
|
||||
{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f},
|
||||
{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f},
|
||||
{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f},
|
||||
{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f},
|
||||
{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f},
|
||||
{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f},
|
||||
{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f},
|
||||
{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f},
|
||||
{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f},
|
||||
{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f},
|
||||
{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f},
|
||||
{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f},
|
||||
{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f},
|
||||
{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f},
|
||||
{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f},
|
||||
{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f},
|
||||
{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f},
|
||||
{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f},
|
||||
{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f},
|
||||
{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f},
|
||||
{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f},
|
||||
{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f},
|
||||
{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f},
|
||||
{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f},
|
||||
{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f},
|
||||
{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f},
|
||||
{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f},
|
||||
{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f},
|
||||
{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f},
|
||||
{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f},
|
||||
{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f},
|
||||
{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f},
|
||||
{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f},
|
||||
{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f},
|
||||
{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f},
|
||||
{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f},
|
||||
{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f},
|
||||
{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f},
|
||||
{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f},
|
||||
{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f},
|
||||
{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f},
|
||||
{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f},
|
||||
{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f},
|
||||
{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f},
|
||||
{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f},
|
||||
{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f},
|
||||
{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f},
|
||||
{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f},
|
||||
{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f},
|
||||
{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f},
|
||||
{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f},
|
||||
{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f},
|
||||
{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f},
|
||||
};
|
||||
#ifndef FFT_BITREV480
|
||||
#define FFT_BITREV480
|
||||
static const opus_int16 fft_bitrev480[480] = {
|
||||
0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330,
|
||||
450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225,
|
||||
345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95,
|
||||
215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440,
|
||||
110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310,
|
||||
430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205,
|
||||
325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61,
|
||||
181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406,
|
||||
76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276,
|
||||
396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171,
|
||||
291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41,
|
||||
161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386,
|
||||
56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242,
|
||||
362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137,
|
||||
257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7,
|
||||
127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457,
|
||||
22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352,
|
||||
472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222,
|
||||
342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117,
|
||||
237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423,
|
||||
93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318,
|
||||
438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188,
|
||||
308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83,
|
||||
203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403,
|
||||
73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298,
|
||||
418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154,
|
||||
274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49,
|
||||
169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369,
|
||||
39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264,
|
||||
384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134,
|
||||
254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29,
|
||||
149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_BITREV240
|
||||
#define FFT_BITREV240
|
||||
static const opus_int16 fft_bitrev240[240] = {
|
||||
0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165,
|
||||
225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110,
|
||||
170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55,
|
||||
115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211,
|
||||
46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156,
|
||||
216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101,
|
||||
161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32,
|
||||
92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202,
|
||||
37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147,
|
||||
207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78,
|
||||
138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23,
|
||||
83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193,
|
||||
28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124,
|
||||
184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69,
|
||||
129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14,
|
||||
74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_BITREV120
|
||||
#define FFT_BITREV120
|
||||
static const opus_int16 fft_bitrev120[120] = {
|
||||
0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80,
|
||||
110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46,
|
||||
76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26,
|
||||
56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97,
|
||||
22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63,
|
||||
93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43,
|
||||
73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9,
|
||||
39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_BITREV60
|
||||
#define FFT_BITREV60
|
||||
static const opus_int16 fft_bitrev60[60] = {
|
||||
0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31,
|
||||
46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22,
|
||||
37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13,
|
||||
28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_0
|
||||
#define FFT_STATE48000_960_0
|
||||
static const kiss_fft_state fft_state48000_960_0 = {
|
||||
480, /* nfft */
|
||||
0.002083333f, /* scale */
|
||||
-1, /* shift */
|
||||
{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev480, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_1
|
||||
#define FFT_STATE48000_960_1
|
||||
static const kiss_fft_state fft_state48000_960_1 = {
|
||||
240, /* nfft */
|
||||
0.004166667f, /* scale */
|
||||
1, /* shift */
|
||||
{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev240, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_2
|
||||
#define FFT_STATE48000_960_2
|
||||
static const kiss_fft_state fft_state48000_960_2 = {
|
||||
120, /* nfft */
|
||||
0.008333333f, /* scale */
|
||||
2, /* shift */
|
||||
{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev120, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef FFT_STATE48000_960_3
|
||||
#define FFT_STATE48000_960_3
|
||||
static const kiss_fft_state fft_state48000_960_3 = {
|
||||
60, /* nfft */
|
||||
0.016666667f, /* scale */
|
||||
3, /* shift */
|
||||
{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
|
||||
fft_bitrev60, /* bitrev */
|
||||
fft_twiddles48000_960, /* bitrev */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef MDCT_TWIDDLES960
|
||||
#define MDCT_TWIDDLES960
|
||||
static const opus_val16 mdct_twiddles960[481] = {
|
||||
1.0000000f, 0.99999465f, 0.99997858f, 0.99995181f, 0.99991433f,
|
||||
0.99986614f, 0.99980724f, 0.99973764f, 0.99965732f, 0.99956631f,
|
||||
0.99946459f, 0.99935216f, 0.99922904f, 0.99909521f, 0.99895068f,
|
||||
0.99879546f, 0.99862953f, 0.99845292f, 0.99826561f, 0.99806761f,
|
||||
0.99785892f, 0.99763955f, 0.99740949f, 0.99716875f, 0.99691733f,
|
||||
0.99665524f, 0.99638247f, 0.99609903f, 0.99580493f, 0.99550016f,
|
||||
0.99518473f, 0.99485864f, 0.99452190f, 0.99417450f, 0.99381646f,
|
||||
0.99344778f, 0.99306846f, 0.99267850f, 0.99227791f, 0.99186670f,
|
||||
0.99144486f, 0.99101241f, 0.99056934f, 0.99011566f, 0.98965139f,
|
||||
0.98917651f, 0.98869104f, 0.98819498f, 0.98768834f, 0.98717112f,
|
||||
0.98664333f, 0.98610497f, 0.98555606f, 0.98499659f, 0.98442657f,
|
||||
0.98384600f, 0.98325491f, 0.98265328f, 0.98204113f, 0.98141846f,
|
||||
0.98078528f, 0.98014159f, 0.97948742f, 0.97882275f, 0.97814760f,
|
||||
0.97746197f, 0.97676588f, 0.97605933f, 0.97534232f, 0.97461487f,
|
||||
0.97387698f, 0.97312866f, 0.97236992f, 0.97160077f, 0.97082121f,
|
||||
0.97003125f, 0.96923091f, 0.96842019f, 0.96759909f, 0.96676764f,
|
||||
0.96592582f, 0.96507367f, 0.96421118f, 0.96333837f, 0.96245523f,
|
||||
0.96156180f, 0.96065806f, 0.95974403f, 0.95881973f, 0.95788517f,
|
||||
0.95694034f, 0.95598526f, 0.95501995f, 0.95404440f, 0.95305864f,
|
||||
0.95206267f, 0.95105651f, 0.95004016f, 0.94901364f, 0.94797697f,
|
||||
0.94693013f, 0.94587315f, 0.94480604f, 0.94372882f, 0.94264149f,
|
||||
0.94154406f, 0.94043656f, 0.93931897f, 0.93819133f, 0.93705365f,
|
||||
0.93590592f, 0.93474818f, 0.93358042f, 0.93240268f, 0.93121493f,
|
||||
0.93001722f, 0.92880955f, 0.92759193f, 0.92636438f, 0.92512690f,
|
||||
0.92387953f, 0.92262225f, 0.92135509f, 0.92007809f, 0.91879121f,
|
||||
0.91749449f, 0.91618795f, 0.91487161f, 0.91354545f, 0.91220952f,
|
||||
0.91086382f, 0.90950836f, 0.90814316f, 0.90676824f, 0.90538363f,
|
||||
0.90398929f, 0.90258528f, 0.90117161f, 0.89974828f, 0.89831532f,
|
||||
0.89687273f, 0.89542055f, 0.89395877f, 0.89248742f, 0.89100652f,
|
||||
0.88951606f, 0.88801610f, 0.88650661f, 0.88498764f, 0.88345918f,
|
||||
0.88192125f, 0.88037390f, 0.87881711f, 0.87725090f, 0.87567531f,
|
||||
0.87409035f, 0.87249599f, 0.87089232f, 0.86927933f, 0.86765699f,
|
||||
0.86602540f, 0.86438453f, 0.86273437f, 0.86107503f, 0.85940641f,
|
||||
0.85772862f, 0.85604161f, 0.85434547f, 0.85264014f, 0.85092572f,
|
||||
0.84920218f, 0.84746955f, 0.84572781f, 0.84397704f, 0.84221721f,
|
||||
0.84044838f, 0.83867056f, 0.83688375f, 0.83508799f, 0.83328325f,
|
||||
0.83146961f, 0.82964704f, 0.82781562f, 0.82597530f, 0.82412620f,
|
||||
0.82226820f, 0.82040144f, 0.81852589f, 0.81664154f, 0.81474847f,
|
||||
0.81284665f, 0.81093620f, 0.80901698f, 0.80708914f, 0.80515262f,
|
||||
0.80320752f, 0.80125378f, 0.79929149f, 0.79732067f, 0.79534125f,
|
||||
0.79335335f, 0.79135691f, 0.78935204f, 0.78733867f, 0.78531691f,
|
||||
0.78328674f, 0.78124818f, 0.77920122f, 0.77714595f, 0.77508232f,
|
||||
0.77301043f, 0.77093026f, 0.76884183f, 0.76674517f, 0.76464026f,
|
||||
0.76252720f, 0.76040593f, 0.75827656f, 0.75613907f, 0.75399349f,
|
||||
0.75183978f, 0.74967807f, 0.74750833f, 0.74533054f, 0.74314481f,
|
||||
0.74095112f, 0.73874950f, 0.73653993f, 0.73432251f, 0.73209718f,
|
||||
0.72986405f, 0.72762307f, 0.72537438f, 0.72311787f, 0.72085359f,
|
||||
0.71858162f, 0.71630192f, 0.71401459f, 0.71171956f, 0.70941701f,
|
||||
0.70710677f, 0.70478900f, 0.70246363f, 0.70013079f, 0.69779041f,
|
||||
0.69544260f, 0.69308738f, 0.69072466f, 0.68835458f, 0.68597709f,
|
||||
0.68359229f, 0.68120013f, 0.67880072f, 0.67639404f, 0.67398011f,
|
||||
0.67155892f, 0.66913059f, 0.66669509f, 0.66425240f, 0.66180265f,
|
||||
0.65934581f, 0.65688191f, 0.65441092f, 0.65193298f, 0.64944801f,
|
||||
0.64695613f, 0.64445727f, 0.64195160f, 0.63943902f, 0.63691954f,
|
||||
0.63439328f, 0.63186019f, 0.62932037f, 0.62677377f, 0.62422055f,
|
||||
0.62166055f, 0.61909394f, 0.61652065f, 0.61394081f, 0.61135435f,
|
||||
0.60876139f, 0.60616195f, 0.60355593f, 0.60094349f, 0.59832457f,
|
||||
0.59569929f, 0.59306758f, 0.59042957f, 0.58778523f, 0.58513460f,
|
||||
0.58247766f, 0.57981452f, 0.57714518f, 0.57446961f, 0.57178793f,
|
||||
0.56910013f, 0.56640624f, 0.56370623f, 0.56100023f, 0.55828818f,
|
||||
0.55557020f, 0.55284627f, 0.55011641f, 0.54738067f, 0.54463901f,
|
||||
0.54189157f, 0.53913828f, 0.53637921f, 0.53361450f, 0.53084398f,
|
||||
0.52806787f, 0.52528601f, 0.52249852f, 0.51970543f, 0.51690688f,
|
||||
0.51410279f, 0.51129310f, 0.50847793f, 0.50565732f, 0.50283139f,
|
||||
0.49999997f, 0.49716321f, 0.49432122f, 0.49147383f, 0.48862118f,
|
||||
0.48576340f, 0.48290042f, 0.48003216f, 0.47715876f, 0.47428025f,
|
||||
0.47139677f, 0.46850813f, 0.46561448f, 0.46271584f, 0.45981235f,
|
||||
0.45690383f, 0.45399042f, 0.45107214f, 0.44814915f, 0.44522124f,
|
||||
0.44228868f, 0.43935137f, 0.43640926f, 0.43346247f, 0.43051104f,
|
||||
0.42755511f, 0.42459449f, 0.42162932f, 0.41865964f, 0.41568558f,
|
||||
0.41270697f, 0.40972393f, 0.40673661f, 0.40374494f, 0.40074884f,
|
||||
0.39774844f, 0.39474390f, 0.39173501f, 0.38872193f, 0.38570469f,
|
||||
0.38268343f, 0.37965796f, 0.37662842f, 0.37359496f, 0.37055739f,
|
||||
0.36751585f, 0.36447038f, 0.36142122f, 0.35836797f, 0.35531089f,
|
||||
0.35225000f, 0.34918544f, 0.34611704f, 0.34304493f, 0.33996926f,
|
||||
0.33688983f, 0.33380680f, 0.33072019f, 0.32763015f, 0.32453650f,
|
||||
0.32143936f, 0.31833890f, 0.31523503f, 0.31212767f, 0.30901696f,
|
||||
0.30590306f, 0.30278577f, 0.29966524f, 0.29654150f, 0.29341470f,
|
||||
0.29028464f, 0.28715147f, 0.28401522f, 0.28087605f, 0.27773376f,
|
||||
0.27458861f, 0.27144052f, 0.26828940f, 0.26513541f, 0.26197859f,
|
||||
0.25881907f, 0.25565666f, 0.25249152f, 0.24932367f, 0.24615327f,
|
||||
0.24298012f, 0.23980436f, 0.23662604f, 0.23344530f, 0.23026206f,
|
||||
0.22707623f, 0.22388809f, 0.22069744f, 0.21750443f, 0.21430908f,
|
||||
0.21111156f, 0.20791165f, 0.20470953f, 0.20150520f, 0.19829884f,
|
||||
0.19509024f, 0.19187955f, 0.18866692f, 0.18545227f, 0.18223552f,
|
||||
0.17901681f, 0.17579631f, 0.17257380f, 0.16934945f, 0.16612328f,
|
||||
0.16289546f, 0.15966577f, 0.15643437f, 0.15320141f, 0.14996669f,
|
||||
0.14673037f, 0.14349260f, 0.14025329f, 0.13701235f, 0.13376995f,
|
||||
0.13052612f, 0.12728101f, 0.12403442f, 0.12078650f, 0.11753740f,
|
||||
0.11428693f, 0.11103523f, 0.10778234f, 0.10452842f, 0.10127326f,
|
||||
0.098017137f, 0.094759842f, 0.091501652f, 0.088242363f, 0.084982129f,
|
||||
0.081721103f, 0.078459084f, 0.075196224f, 0.071932560f, 0.068668243f,
|
||||
0.065403073f, 0.062137201f, 0.058870665f, 0.055603617f, 0.052335974f,
|
||||
0.049067651f, 0.045798921f, 0.042529582f, 0.039259788f, 0.035989573f,
|
||||
0.032719092f, 0.029448142f, 0.026176876f, 0.022905329f, 0.019633657f,
|
||||
0.016361655f, 0.013089478f, 0.0098171604f, 0.0065449764f, 0.0032724839f,
|
||||
-4.3711390e-08f, };
|
||||
#endif
|
||||
|
||||
static const CELTMode mode48000_960_120 = {
|
||||
48000, /* Fs */
|
||||
120, /* overlap */
|
||||
21, /* nbEBands */
|
||||
21, /* effEBands */
|
||||
{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */
|
||||
eband5ms, /* eBands */
|
||||
3, /* maxLM */
|
||||
8, /* nbShortMdcts */
|
||||
120, /* shortMdctSize */
|
||||
11, /* nbAllocVectors */
|
||||
band_allocation, /* allocVectors */
|
||||
logN400, /* logN */
|
||||
window120, /* window */
|
||||
{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */
|
||||
{392, cache_index50, cache_bits50, cache_caps50}, /* cache */
|
||||
};
|
||||
|
||||
/* List of all the available modes */
|
||||
#define TOTAL_MODES 1
|
||||
static const CELTMode * const static_mode_list[TOTAL_MODES] = {
|
||||
&mode48000_960_120,
|
||||
};
|
|
@ -0,0 +1,161 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
|
||||
Gregory Maxwell
|
||||
Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#else
|
||||
#define TEST_CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
#include "stack_alloc.h"
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
#include "cwrs.c"
|
||||
#include "mathops.c"
|
||||
#include "rate.h"
|
||||
|
||||
#define NMAX (240)
|
||||
#define KMAX (128)
|
||||
|
||||
#ifdef TEST_CUSTOM_MODES
|
||||
|
||||
#define NDIMS (44)
|
||||
static const int pn[NDIMS]={
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 18, 20, 22,
|
||||
24, 26, 28, 30, 32, 36, 40, 44, 48,
|
||||
52, 56, 60, 64, 72, 80, 88, 96, 104,
|
||||
112, 120, 128, 144, 160, 176, 192, 208
|
||||
};
|
||||
static const int pkmax[NDIMS]={
|
||||
128, 128, 128, 128, 88, 52, 36, 26, 22,
|
||||
18, 16, 15, 13, 12, 12, 11, 10, 9,
|
||||
9, 8, 8, 7, 7, 7, 7, 6, 6,
|
||||
6, 6, 6, 5, 5, 5, 5, 5, 5,
|
||||
4, 4, 4, 4, 4, 4, 4, 4
|
||||
};
|
||||
|
||||
#else /* TEST_CUSTOM_MODES */
|
||||
|
||||
#define NDIMS (22)
|
||||
static const int pn[NDIMS]={
|
||||
2, 3, 4, 6, 8, 9, 11, 12, 16,
|
||||
18, 22, 24, 32, 36, 44, 48, 64, 72,
|
||||
88, 96, 144, 176
|
||||
};
|
||||
static const int pkmax[NDIMS]={
|
||||
128, 128, 128, 88, 36, 26, 18, 16, 12,
|
||||
11, 9, 9, 7, 7, 6, 6, 5, 5,
|
||||
5, 5, 4, 4
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int main(void){
|
||||
int t;
|
||||
int n;
|
||||
ALLOC_STACK;
|
||||
for(t=0;t<NDIMS;t++){
|
||||
int pseudo;
|
||||
n=pn[t];
|
||||
for(pseudo=1;pseudo<41;pseudo++)
|
||||
{
|
||||
int k;
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
opus_uint32 uu[KMAX+2U];
|
||||
#endif
|
||||
opus_uint32 inc;
|
||||
opus_uint32 nc;
|
||||
opus_uint32 i;
|
||||
k=get_pulses(pseudo);
|
||||
if (k>pkmax[t])break;
|
||||
printf("Testing CWRS with N=%i, K=%i...\n",n,k);
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
nc=ncwrs_urow(n,k,uu);
|
||||
#else
|
||||
nc=CELT_PVQ_V(n,k);
|
||||
#endif
|
||||
inc=nc/20000;
|
||||
if(inc<1)inc=1;
|
||||
for(i=0;i<nc;i+=inc){
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
opus_uint32 u[KMAX+2U];
|
||||
#endif
|
||||
int y[NMAX];
|
||||
int sy;
|
||||
opus_uint32 v;
|
||||
opus_uint32 ii;
|
||||
int j;
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
memcpy(u,uu,(k+2U)*sizeof(*u));
|
||||
cwrsi(n,k,i,y,u);
|
||||
#else
|
||||
cwrsi(n,k,i,y);
|
||||
#endif
|
||||
sy=0;
|
||||
for(j=0;j<n;j++)sy+=ABS(y[j]);
|
||||
if(sy!=k){
|
||||
fprintf(stderr,"N=%d Pulse count mismatch in cwrsi (%d!=%d).\n",
|
||||
n,sy,k);
|
||||
return 99;
|
||||
}
|
||||
/*printf("%6u of %u:",i,nc);
|
||||
for(j=0;j<n;j++)printf(" %+3i",y[j]);
|
||||
printf(" ->");*/
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
ii=icwrs(n,k,&v,y,u);
|
||||
#else
|
||||
ii=icwrs(n,y);
|
||||
v=CELT_PVQ_V(n,k);
|
||||
#endif
|
||||
if(ii!=i){
|
||||
fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n",
|
||||
(long)ii,(long)i);
|
||||
return 1;
|
||||
}
|
||||
if(v!=nc){
|
||||
fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n",
|
||||
(long)v,(long)nc);
|
||||
return 2;
|
||||
}
|
||||
/*printf(" %6u\n",i);*/
|
||||
}
|
||||
/*printf("\n");*/
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/* Copyright (c) 2008 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#define SKIP_CONFIG_H
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define CELT_C
|
||||
#include "stack_alloc.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "kiss_fft.c"
|
||||
#include "mathops.c"
|
||||
#include "entcode.c"
|
||||
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
|
||||
void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0, snr;
|
||||
|
||||
for (bin=0;bin<nfft;++bin) {
|
||||
double ansr = 0;
|
||||
double ansi = 0;
|
||||
double difr;
|
||||
double difi;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
double phase = -2*M_PI*bin*k/nfft;
|
||||
double re = cos(phase);
|
||||
double im = sin(phase);
|
||||
if (isinverse)
|
||||
im = -im;
|
||||
|
||||
if (!isinverse)
|
||||
{
|
||||
re /= nfft;
|
||||
im /= nfft;
|
||||
}
|
||||
|
||||
ansr += in[k].r * re - in[k].i * im;
|
||||
ansi += in[k].r * im + in[k].i * re;
|
||||
}
|
||||
/*printf ("%d %d ", (int)ansr, (int)ansi);*/
|
||||
difr = ansr - out[bin].r;
|
||||
difi = ansi - out[bin].i;
|
||||
errpow += difr*difr + difi*difi;
|
||||
sigpow += ansr*ansr+ansi*ansi;
|
||||
}
|
||||
snr = 10*log10(sigpow/errpow);
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
|
||||
if (snr<60) {
|
||||
printf( "** poor snr: %f ** \n", snr);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void test1d(int nfft,int isinverse)
|
||||
{
|
||||
size_t buflen = sizeof(kiss_fft_cpx)*nfft;
|
||||
|
||||
kiss_fft_cpx * in = (kiss_fft_cpx*)malloc(buflen);
|
||||
kiss_fft_cpx * out= (kiss_fft_cpx*)malloc(buflen);
|
||||
kiss_fft_state *cfg = opus_fft_alloc(nfft,0,0);
|
||||
int k;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r = (rand() % 32767) - 16384;
|
||||
in[k].i = (rand() % 32767) - 16384;
|
||||
}
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r *= 32768;
|
||||
in[k].i *= 32768;
|
||||
}
|
||||
|
||||
if (isinverse)
|
||||
{
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r /= nfft;
|
||||
in[k].i /= nfft;
|
||||
}
|
||||
}
|
||||
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
|
||||
|
||||
if (isinverse)
|
||||
opus_ifft(cfg,in,out);
|
||||
else
|
||||
opus_fft(cfg,in,out);
|
||||
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
|
||||
|
||||
check(in,out,nfft,isinverse);
|
||||
|
||||
free(in);
|
||||
free(out);
|
||||
free(cfg);
|
||||
}
|
||||
|
||||
int main(int argc,char ** argv)
|
||||
{
|
||||
ALLOC_STACK;
|
||||
if (argc>1) {
|
||||
int k;
|
||||
for (k=1;k<argc;++k) {
|
||||
test1d(atoi(argv[k]),0);
|
||||
test1d(atoi(argv[k]),1);
|
||||
}
|
||||
}else{
|
||||
test1d(32,0);
|
||||
test1d(32,1);
|
||||
test1d(128,0);
|
||||
test1d(128,1);
|
||||
test1d(256,0);
|
||||
test1d(256,1);
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
test1d(36,0);
|
||||
test1d(36,1);
|
||||
test1d(50,0);
|
||||
test1d(50,1);
|
||||
test1d(120,0);
|
||||
test1d(120,1);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,382 @@
|
|||
/* Copyright (c) 2007-2011 Xiph.Org Foundation, Mozilla Corporation,
|
||||
Gregory Maxwell
|
||||
Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "entcode.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
|
||||
#ifndef M_LOG2E
|
||||
# define M_LOG2E 1.4426950408889634074
|
||||
#endif
|
||||
#define DATA_SIZE 10000000
|
||||
#define DATA_SIZE2 10000
|
||||
|
||||
int main(int _argc,char **_argv){
|
||||
ec_enc enc;
|
||||
ec_dec dec;
|
||||
long nbits;
|
||||
long nbits2;
|
||||
double entropy;
|
||||
int ft;
|
||||
int ftb;
|
||||
int sz;
|
||||
int i;
|
||||
int ret;
|
||||
unsigned int sym;
|
||||
unsigned int seed;
|
||||
unsigned char *ptr;
|
||||
const char *env_seed;
|
||||
ret=0;
|
||||
entropy=0;
|
||||
if (_argc > 2) {
|
||||
fprintf(stderr, "Usage: %s [<seed>]\n", _argv[0]);
|
||||
return 1;
|
||||
}
|
||||
env_seed = getenv("SEED");
|
||||
if (_argc > 1)
|
||||
seed = atoi(_argv[1]);
|
||||
else if (env_seed)
|
||||
seed = atoi(env_seed);
|
||||
else
|
||||
seed = time(NULL);
|
||||
/*Testing encoding of raw bit values.*/
|
||||
ptr = (unsigned char *)malloc(DATA_SIZE);
|
||||
ec_enc_init(&enc,ptr, DATA_SIZE);
|
||||
for(ft=2;ft<1024;ft++){
|
||||
for(i=0;i<ft;i++){
|
||||
entropy+=log(ft)*M_LOG2E;
|
||||
ec_enc_uint(&enc,i,ft);
|
||||
}
|
||||
}
|
||||
/*Testing encoding of raw bit values.*/
|
||||
for(ftb=1;ftb<16;ftb++){
|
||||
for(i=0;i<(1<<ftb);i++){
|
||||
entropy+=ftb;
|
||||
nbits=ec_tell(&enc);
|
||||
ec_enc_bits(&enc,i,ftb);
|
||||
nbits2=ec_tell(&enc);
|
||||
if(nbits2-nbits!=ftb){
|
||||
fprintf(stderr,"Used %li bits to encode %i bits directly.\n",
|
||||
nbits2-nbits,ftb);
|
||||
ret=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
nbits=ec_tell_frac(&enc);
|
||||
ec_enc_done(&enc);
|
||||
fprintf(stderr,
|
||||
"Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n",
|
||||
entropy,ldexp(nbits,-3),100*(nbits-ldexp(entropy,3))/nbits);
|
||||
fprintf(stderr,"Packed to %li bytes.\n",(long)ec_range_bytes(&enc));
|
||||
ec_dec_init(&dec,ptr,DATA_SIZE);
|
||||
for(ft=2;ft<1024;ft++){
|
||||
for(i=0;i<ft;i++){
|
||||
sym=ec_dec_uint(&dec,ft);
|
||||
if(sym!=(unsigned)i){
|
||||
fprintf(stderr,"Decoded %i instead of %i with ft of %i.\n",sym,i,ft);
|
||||
ret=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(ftb=1;ftb<16;ftb++){
|
||||
for(i=0;i<(1<<ftb);i++){
|
||||
sym=ec_dec_bits(&dec,ftb);
|
||||
if(sym!=(unsigned)i){
|
||||
fprintf(stderr,"Decoded %i instead of %i with ftb of %i.\n",sym,i,ftb);
|
||||
ret=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
nbits2=ec_tell_frac(&dec);
|
||||
if(nbits!=nbits2){
|
||||
fprintf(stderr,
|
||||
"Reported number of bits used was %0.2lf, should be %0.2lf.\n",
|
||||
ldexp(nbits2,-3),ldexp(nbits,-3));
|
||||
ret=-1;
|
||||
}
|
||||
/*Testing an encoder bust prefers range coder data over raw bits.
|
||||
This isn't a general guarantee, will only work for data that is buffered in
|
||||
the encoder state and not yet stored in the user buffer, and should never
|
||||
get used in practice.
|
||||
It's mostly here for code coverage completeness.*/
|
||||
/*Start with a 16-bit buffer.*/
|
||||
ec_enc_init(&enc,ptr,2);
|
||||
/*Write 7 raw bits.*/
|
||||
ec_enc_bits(&enc,0x55,7);
|
||||
/*Write 12.3 bits of range coder data.*/
|
||||
ec_enc_uint(&enc,1,2);
|
||||
ec_enc_uint(&enc,1,3);
|
||||
ec_enc_uint(&enc,1,4);
|
||||
ec_enc_uint(&enc,1,5);
|
||||
ec_enc_uint(&enc,2,6);
|
||||
ec_enc_uint(&enc,6,7);
|
||||
ec_enc_done(&enc);
|
||||
ec_dec_init(&dec,ptr,2);
|
||||
if(!enc.error
|
||||
/*The raw bits should have been overwritten by the range coder data.*/
|
||||
||ec_dec_bits(&dec,7)!=0x05
|
||||
/*And all the range coder data should have been encoded correctly.*/
|
||||
||ec_dec_uint(&dec,2)!=1
|
||||
||ec_dec_uint(&dec,3)!=1
|
||||
||ec_dec_uint(&dec,4)!=1
|
||||
||ec_dec_uint(&dec,5)!=1
|
||||
||ec_dec_uint(&dec,6)!=2
|
||||
||ec_dec_uint(&dec,7)!=6){
|
||||
fprintf(stderr,"Encoder bust overwrote range coder data with raw bits.\n");
|
||||
ret=-1;
|
||||
}
|
||||
srand(seed);
|
||||
fprintf(stderr,"Testing random streams... Random seed: %u (%.4X)\n", seed, rand() % 65536);
|
||||
for(i=0;i<409600;i++){
|
||||
unsigned *data;
|
||||
unsigned *tell;
|
||||
unsigned tell_bits;
|
||||
int j;
|
||||
int zeros;
|
||||
ft=rand()/((RAND_MAX>>(rand()%11U))+1U)+10;
|
||||
sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
|
||||
data=(unsigned *)malloc(sz*sizeof(*data));
|
||||
tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
zeros = rand()%13==0;
|
||||
tell[0]=ec_tell_frac(&enc);
|
||||
for(j=0;j<sz;j++){
|
||||
if (zeros)
|
||||
data[j]=0;
|
||||
else
|
||||
data[j]=rand()%ft;
|
||||
ec_enc_uint(&enc,data[j],ft);
|
||||
tell[j+1]=ec_tell_frac(&enc);
|
||||
}
|
||||
if (rand()%2==0)
|
||||
while(ec_tell(&enc)%8 != 0)
|
||||
ec_enc_uint(&enc, rand()%2, 2);
|
||||
tell_bits = ec_tell(&enc);
|
||||
ec_enc_done(&enc);
|
||||
if(tell_bits!=(unsigned)ec_tell(&enc)){
|
||||
fprintf(stderr,"ec_tell() changed after ec_enc_done(): %i instead of %i (Random seed: %u)\n",
|
||||
ec_tell(&enc),tell_bits,seed);
|
||||
ret=-1;
|
||||
}
|
||||
if ((tell_bits+7)/8 < ec_range_bytes(&enc))
|
||||
{
|
||||
fprintf (stderr, "ec_tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
|
||||
ec_range_bytes(&enc), (tell_bits+7)/8,seed);
|
||||
ret=-1;
|
||||
}
|
||||
ec_dec_init(&dec,ptr,DATA_SIZE2);
|
||||
if(ec_tell_frac(&dec)!=tell[0]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
0,ec_tell_frac(&dec),tell[0],seed);
|
||||
}
|
||||
for(j=0;j<sz;j++){
|
||||
sym=ec_dec_uint(&dec,ft);
|
||||
if(sym!=data[j]){
|
||||
fprintf(stderr,
|
||||
"Decoded %i instead of %i with ft of %i at position %i of %i (Random seed: %u).\n",
|
||||
sym,data[j],ft,j,sz,seed);
|
||||
ret=-1;
|
||||
}
|
||||
if(ec_tell_frac(&dec)!=tell[j+1]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
j+1,ec_tell_frac(&dec),tell[j+1],seed);
|
||||
}
|
||||
}
|
||||
free(tell);
|
||||
free(data);
|
||||
}
|
||||
/*Test compatibility between multiple different encode/decode routines.*/
|
||||
for(i=0;i<409600;i++){
|
||||
unsigned *logp1;
|
||||
unsigned *data;
|
||||
unsigned *tell;
|
||||
unsigned *enc_method;
|
||||
int j;
|
||||
sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
|
||||
logp1=(unsigned *)malloc(sz*sizeof(*logp1));
|
||||
data=(unsigned *)malloc(sz*sizeof(*data));
|
||||
tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
|
||||
enc_method=(unsigned *)malloc(sz*sizeof(*enc_method));
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
tell[0]=ec_tell_frac(&enc);
|
||||
for(j=0;j<sz;j++){
|
||||
data[j]=rand()/((RAND_MAX>>1)+1);
|
||||
logp1[j]=(rand()%15)+1;
|
||||
enc_method[j]=rand()/((RAND_MAX>>2)+1);
|
||||
switch(enc_method[j]){
|
||||
case 0:{
|
||||
ec_encode(&enc,data[j]?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(data[j]?0:1),1<<logp1[j]);
|
||||
}break;
|
||||
case 1:{
|
||||
ec_encode_bin(&enc,data[j]?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(data[j]?0:1),logp1[j]);
|
||||
}break;
|
||||
case 2:{
|
||||
ec_enc_bit_logp(&enc,data[j],logp1[j]);
|
||||
}break;
|
||||
case 3:{
|
||||
unsigned char icdf[2];
|
||||
icdf[0]=1;
|
||||
icdf[1]=0;
|
||||
ec_enc_icdf(&enc,data[j],icdf,logp1[j]);
|
||||
}break;
|
||||
}
|
||||
tell[j+1]=ec_tell_frac(&enc);
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if((ec_tell(&enc)+7U)/8U<ec_range_bytes(&enc)){
|
||||
fprintf(stderr,"tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
|
||||
ec_range_bytes(&enc),(ec_tell(&enc)+7)/8,seed);
|
||||
ret=-1;
|
||||
}
|
||||
ec_dec_init(&dec,ptr,DATA_SIZE2);
|
||||
if(ec_tell_frac(&dec)!=tell[0]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
0,ec_tell_frac(&dec),tell[0],seed);
|
||||
}
|
||||
for(j=0;j<sz;j++){
|
||||
int fs;
|
||||
int dec_method;
|
||||
dec_method=rand()/((RAND_MAX>>2)+1);
|
||||
switch(dec_method){
|
||||
case 0:{
|
||||
fs=ec_decode(&dec,1<<logp1[j]);
|
||||
sym=fs>=(1<<logp1[j])-1;
|
||||
ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(sym?0:1),1<<logp1[j]);
|
||||
}break;
|
||||
case 1:{
|
||||
fs=ec_decode_bin(&dec,logp1[j]);
|
||||
sym=fs>=(1<<logp1[j])-1;
|
||||
ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(sym?0:1),1<<logp1[j]);
|
||||
}break;
|
||||
case 2:{
|
||||
sym=ec_dec_bit_logp(&dec,logp1[j]);
|
||||
}break;
|
||||
case 3:{
|
||||
unsigned char icdf[2];
|
||||
icdf[0]=1;
|
||||
icdf[1]=0;
|
||||
sym=ec_dec_icdf(&dec,icdf,logp1[j]);
|
||||
}break;
|
||||
}
|
||||
if(sym!=data[j]){
|
||||
fprintf(stderr,
|
||||
"Decoded %i instead of %i with logp1 of %i at position %i of %i (Random seed: %u).\n",
|
||||
sym,data[j],logp1[j],j,sz,seed);
|
||||
fprintf(stderr,"Encoding method: %i, decoding method: %i\n",
|
||||
enc_method[j],dec_method);
|
||||
ret=-1;
|
||||
}
|
||||
if(ec_tell_frac(&dec)!=tell[j+1]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
j+1,ec_tell_frac(&dec),tell[j+1],seed);
|
||||
}
|
||||
}
|
||||
free(enc_method);
|
||||
free(tell);
|
||||
free(data);
|
||||
free(logp1);
|
||||
}
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,2);
|
||||
ec_enc_patch_initial_bits(&enc,3,2);
|
||||
if(enc.error){
|
||||
fprintf(stderr,"patch_initial_bits failed");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_patch_initial_bits(&enc,0,5);
|
||||
if(!enc.error){
|
||||
fprintf(stderr,"patch_initial_bits didn't fail when it should have");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(ec_range_bytes(&enc)!=1||ptr[0]!=192){
|
||||
fprintf(stderr,"Got %d when expecting 192 for patch_initial_bits",ptr[0]);
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,1,6);
|
||||
ec_enc_bit_logp(&enc,0,2);
|
||||
ec_enc_patch_initial_bits(&enc,0,2);
|
||||
if(enc.error){
|
||||
fprintf(stderr,"patch_initial_bits failed");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(ec_range_bytes(&enc)!=2||ptr[0]!=63){
|
||||
fprintf(stderr,"Got %d when expecting 63 for patch_initial_bits",ptr[0]);
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_init(&enc,ptr,2);
|
||||
ec_enc_bit_logp(&enc,0,2);
|
||||
for(i=0;i<48;i++){
|
||||
ec_enc_bits(&enc,0,1);
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(!enc.error){
|
||||
fprintf(stderr,"Raw bits overfill didn't fail when it should have");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_init(&enc,ptr,2);
|
||||
for(i=0;i<17;i++){
|
||||
ec_enc_bits(&enc,0,1);
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(!enc.error){
|
||||
fprintf(stderr,"17 raw bits encoded in two bytes");
|
||||
ret=-1;
|
||||
}
|
||||
free(ptr);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation
|
||||
Written by Jean-Marc Valin and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "laplace.h"
|
||||
#define CELT_C
|
||||
#include "stack_alloc.h"
|
||||
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
#include "laplace.c"
|
||||
|
||||
#define DATA_SIZE 40000
|
||||
|
||||
int ec_laplace_get_start_freq(int decay)
|
||||
{
|
||||
opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
|
||||
int fs = (ft*(16384-decay))/(16384+decay);
|
||||
return fs+LAPLACE_MINP;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
ec_enc enc;
|
||||
ec_dec dec;
|
||||
unsigned char *ptr;
|
||||
int val[10000], decay[10000];
|
||||
ALLOC_STACK;
|
||||
ptr = (unsigned char *)malloc(DATA_SIZE);
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE);
|
||||
|
||||
val[0] = 3; decay[0] = 6000;
|
||||
val[1] = 0; decay[1] = 5800;
|
||||
val[2] = -1; decay[2] = 5600;
|
||||
for (i=3;i<10000;i++)
|
||||
{
|
||||
val[i] = rand()%15-7;
|
||||
decay[i] = rand()%11000+5000;
|
||||
}
|
||||
for (i=0;i<10000;i++)
|
||||
ec_laplace_encode(&enc, &val[i],
|
||||
ec_laplace_get_start_freq(decay[i]), decay[i]);
|
||||
|
||||
ec_enc_done(&enc);
|
||||
|
||||
ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc));
|
||||
|
||||
for (i=0;i<10000;i++)
|
||||
{
|
||||
int d = ec_laplace_decode(&dec,
|
||||
ec_laplace_get_start_freq(decay[i]), decay[i]);
|
||||
if (d != val[i])
|
||||
{
|
||||
fprintf (stderr, "Got %d instead of %d\n", d, val[i]);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
|
||||
Gregory Maxwell
|
||||
Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
|
||||
#include "mathops.c"
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
#include "bands.c"
|
||||
#include "quant_bands.c"
|
||||
#include "laplace.c"
|
||||
#include "vq.c"
|
||||
#include "cwrs.c"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
#define WORD "%d"
|
||||
#else
|
||||
#define WORD "%f"
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
|
||||
void testdiv(void)
|
||||
{
|
||||
opus_int32 i;
|
||||
for (i=1;i<=327670;i++)
|
||||
{
|
||||
double prod;
|
||||
opus_val32 val;
|
||||
val = celt_rcp(i);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
prod = (1./32768./65526.)*val*i;
|
||||
#else
|
||||
prod = val*i;
|
||||
#endif
|
||||
if (fabs(prod-1) > .00025)
|
||||
{
|
||||
fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testsqrt(void)
|
||||
{
|
||||
opus_int32 i;
|
||||
for (i=1;i<=1000000000;i++)
|
||||
{
|
||||
double ratio;
|
||||
opus_val16 val;
|
||||
val = celt_sqrt(i);
|
||||
ratio = val/sqrt(i);
|
||||
if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2)
|
||||
{
|
||||
fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio);
|
||||
ret = 1;
|
||||
}
|
||||
i+= i>>10;
|
||||
}
|
||||
}
|
||||
|
||||
void testbitexactcos(void)
|
||||
{
|
||||
int i;
|
||||
opus_int32 min_d,max_d,last,chk;
|
||||
chk=max_d=0;
|
||||
last=min_d=32767;
|
||||
for(i=64;i<=16320;i++)
|
||||
{
|
||||
opus_int32 d;
|
||||
opus_int32 q=bitexact_cos(i);
|
||||
chk ^= q*i;
|
||||
d = last - q;
|
||||
if (d>max_d)max_d=d;
|
||||
if (d<min_d)min_d=d;
|
||||
last = q;
|
||||
}
|
||||
if ((chk!=89408644)||(max_d!=5)||(min_d!=0)||(bitexact_cos(64)!=32767)||
|
||||
(bitexact_cos(16320)!=200)||(bitexact_cos(8192)!=23171))
|
||||
{
|
||||
fprintf (stderr, "bitexact_cos failed\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void testbitexactlog2tan(void)
|
||||
{
|
||||
int i,fail;
|
||||
opus_int32 min_d,max_d,last,chk;
|
||||
fail=chk=max_d=0;
|
||||
last=min_d=15059;
|
||||
for(i=64;i<8193;i++)
|
||||
{
|
||||
opus_int32 d;
|
||||
opus_int32 mid=bitexact_cos(i);
|
||||
opus_int32 side=bitexact_cos(16384-i);
|
||||
opus_int32 q=bitexact_log2tan(mid,side);
|
||||
chk ^= q*i;
|
||||
d = last - q;
|
||||
if (q!=-1*bitexact_log2tan(side,mid))
|
||||
fail = 1;
|
||||
if (d>max_d)max_d=d;
|
||||
if (d<min_d)min_d=d;
|
||||
last = q;
|
||||
}
|
||||
if ((chk!=15821257)||(max_d!=61)||(min_d!=-2)||fail||
|
||||
(bitexact_log2tan(32767,200)!=15059)||(bitexact_log2tan(30274,12540)!=2611)||
|
||||
(bitexact_log2tan(23171,23171)!=0))
|
||||
{
|
||||
fprintf (stderr, "bitexact_log2tan failed\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
void testlog2(void)
|
||||
{
|
||||
float x;
|
||||
for (x=0.001;x<1677700.0;x+=(x/8.0))
|
||||
{
|
||||
float error = fabs((1.442695040888963387*log(x))-celt_log2(x));
|
||||
if (error>0.0009)
|
||||
{
|
||||
fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2(void)
|
||||
{
|
||||
float x;
|
||||
for (x=-11.0;x<24.0;x+=0.0007)
|
||||
{
|
||||
float error = fabs(x-(1.442695040888963387*log(celt_exp2(x))));
|
||||
if (error>0.0002)
|
||||
{
|
||||
fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2log2(void)
|
||||
{
|
||||
float x;
|
||||
for (x=-11.0;x<24.0;x+=0.0007)
|
||||
{
|
||||
float error = fabs(x-(celt_log2(celt_exp2(x))));
|
||||
if (error>0.001)
|
||||
{
|
||||
fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void testlog2(void)
|
||||
{
|
||||
opus_val32 x;
|
||||
for (x=8;x<1073741824;x+=(x>>3))
|
||||
{
|
||||
float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0);
|
||||
if (error>0.003)
|
||||
{
|
||||
fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2(void)
|
||||
{
|
||||
opus_val16 x;
|
||||
for (x=-32768;x<15360;x++)
|
||||
{
|
||||
float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0)));
|
||||
float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0);
|
||||
if (error1>0.0002&&error2>0.00004)
|
||||
{
|
||||
fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2log2(void)
|
||||
{
|
||||
opus_val32 x;
|
||||
for (x=8;x<65536;x+=(x>>3))
|
||||
{
|
||||
float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384;
|
||||
if (error>0.004)
|
||||
{
|
||||
fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testilog2(void)
|
||||
{
|
||||
opus_val32 x;
|
||||
for (x=1;x<=268435455;x+=127)
|
||||
{
|
||||
opus_val32 lg;
|
||||
opus_val32 y;
|
||||
|
||||
lg = celt_ilog2(x);
|
||||
if (lg<0 || lg>=31)
|
||||
{
|
||||
printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg);
|
||||
ret = 1;
|
||||
}
|
||||
y = 1<<lg;
|
||||
|
||||
if (x<y || (x>>1)>=y)
|
||||
{
|
||||
printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
testbitexactcos();
|
||||
testbitexactlog2tan();
|
||||
testdiv();
|
||||
testsqrt();
|
||||
testlog2();
|
||||
testexp2();
|
||||
testexp2log2();
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
testilog2();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#define SKIP_CONFIG_H
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define CELT_C
|
||||
#include "mdct.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
#include "kiss_fft.c"
|
||||
#include "mdct.c"
|
||||
#include "mathops.c"
|
||||
#include "entcode.c"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0;
|
||||
double snr;
|
||||
for (bin=0;bin<nfft/2;++bin) {
|
||||
double ansr = 0;
|
||||
double difr;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
double phase = 2*M_PI*(k+.5+.25*nfft)*(bin+.5)/nfft;
|
||||
double re = cos(phase);
|
||||
|
||||
re /= nfft/4;
|
||||
|
||||
ansr += in[k] * re;
|
||||
}
|
||||
/*printf ("%f %f\n", ansr, out[bin]);*/
|
||||
difr = ansr - out[bin];
|
||||
errpow += difr*difr;
|
||||
sigpow += ansr*ansr;
|
||||
}
|
||||
snr = 10*log10(sigpow/errpow);
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
|
||||
if (snr<60) {
|
||||
printf( "** poor snr: %f **\n", snr);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void check_inv(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0;
|
||||
double snr;
|
||||
for (bin=0;bin<nfft;++bin) {
|
||||
double ansr = 0;
|
||||
double difr;
|
||||
|
||||
for (k=0;k<nfft/2;++k) {
|
||||
double phase = 2*M_PI*(bin+.5+.25*nfft)*(k+.5)/nfft;
|
||||
double re = cos(phase);
|
||||
|
||||
/*re *= 2;*/
|
||||
|
||||
ansr += in[k] * re;
|
||||
}
|
||||
/*printf ("%f %f\n", ansr, out[bin]);*/
|
||||
difr = ansr - out[bin];
|
||||
errpow += difr*difr;
|
||||
sigpow += ansr*ansr;
|
||||
}
|
||||
snr = 10*log10(sigpow/errpow);
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
|
||||
if (snr<60) {
|
||||
printf( "** poor snr: %f **\n", snr);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test1d(int nfft,int isinverse)
|
||||
{
|
||||
celt_mdct_lookup cfg;
|
||||
size_t buflen = sizeof(kiss_fft_scalar)*nfft;
|
||||
|
||||
kiss_fft_scalar * in = (kiss_fft_scalar*)malloc(buflen);
|
||||
kiss_fft_scalar * in_copy = (kiss_fft_scalar*)malloc(buflen);
|
||||
kiss_fft_scalar * out= (kiss_fft_scalar*)malloc(buflen);
|
||||
opus_val16 * window= (opus_val16*)malloc(sizeof(opus_val16)*nfft/2);
|
||||
int k;
|
||||
|
||||
clt_mdct_init(&cfg, nfft, 0);
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k] = (rand() % 32768) - 16384;
|
||||
}
|
||||
|
||||
for (k=0;k<nfft/2;++k) {
|
||||
window[k] = Q15ONE;
|
||||
}
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k] *= 32768;
|
||||
}
|
||||
|
||||
if (isinverse)
|
||||
{
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k] /= nfft;
|
||||
}
|
||||
}
|
||||
|
||||
for (k=0;k<nfft;++k)
|
||||
in_copy[k] = in[k];
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
|
||||
|
||||
if (isinverse)
|
||||
{
|
||||
for (k=0;k<nfft;++k)
|
||||
out[k] = 0;
|
||||
clt_mdct_backward(&cfg,in,out, window, nfft/2, 0, 1);
|
||||
/* apply TDAC because clt_mdct_backward() no longer does that */
|
||||
for (k=0;k<nfft/4;++k)
|
||||
out[nfft-k-1] = out[nfft/2+k];
|
||||
check_inv(in,out,nfft,isinverse);
|
||||
} else {
|
||||
clt_mdct_forward(&cfg,in,out,window, nfft/2, 0, 1);
|
||||
check(in_copy,out,nfft,isinverse);
|
||||
}
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
|
||||
|
||||
|
||||
free(in);
|
||||
free(out);
|
||||
clt_mdct_clear(&cfg);
|
||||
}
|
||||
|
||||
int main(int argc,char ** argv)
|
||||
{
|
||||
ALLOC_STACK;
|
||||
if (argc>1) {
|
||||
int k;
|
||||
for (k=1;k<argc;++k) {
|
||||
test1d(atoi(argv[k]),0);
|
||||
test1d(atoi(argv[k]),1);
|
||||
}
|
||||
}else{
|
||||
test1d(32,0);
|
||||
test1d(32,1);
|
||||
test1d(256,0);
|
||||
test1d(256,1);
|
||||
test1d(512,0);
|
||||
test1d(512,1);
|
||||
test1d(1024,0);
|
||||
test1d(1024,1);
|
||||
test1d(2048,0);
|
||||
test1d(2048,1);
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
test1d(36,0);
|
||||
test1d(36,1);
|
||||
test1d(40,0);
|
||||
test1d(40,1);
|
||||
test1d(60,0);
|
||||
test1d(60,1);
|
||||
test1d(120,0);
|
||||
test1d(120,1);
|
||||
test1d(240,0);
|
||||
test1d(240,1);
|
||||
test1d(480,0);
|
||||
test1d(480,1);
|
||||
test1d(960,0);
|
||||
test1d(960,1);
|
||||
test1d(1920,0);
|
||||
test1d(1920,1);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "vq.c"
|
||||
#include "cwrs.c"
|
||||
#include "entcode.c"
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "mathops.c"
|
||||
#include "bands.h"
|
||||
#include <math.h>
|
||||
#define MAX_SIZE 100
|
||||
|
||||
int ret=0;
|
||||
void test_rotation(int N, int K)
|
||||
{
|
||||
int i;
|
||||
double err = 0, ener = 0, snr, snr0;
|
||||
opus_val16 x0[MAX_SIZE];
|
||||
opus_val16 x1[MAX_SIZE];
|
||||
for (i=0;i<N;i++)
|
||||
x1[i] = x0[i] = rand()%32767-16384;
|
||||
exp_rotation(x1, N, 1, 1, K, SPREAD_NORMAL);
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
|
||||
ener += x0[i]*(double)x0[i];
|
||||
}
|
||||
snr0 = 20*log10(ener/err);
|
||||
err = ener = 0;
|
||||
exp_rotation(x1, N, -1, 1, K, SPREAD_NORMAL);
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
|
||||
ener += x0[i]*(double)x0[i];
|
||||
}
|
||||
snr = 20*log10(ener/err);
|
||||
printf ("SNR for size %d (%d pulses) is %f (was %f without inverse)\n", N, K, snr, snr0);
|
||||
if (snr < 60 || snr0 > 20)
|
||||
{
|
||||
fprintf(stderr, "FAIL!\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ALLOC_STACK;
|
||||
test_rotation(15, 3);
|
||||
test_rotation(23, 5);
|
||||
test_rotation(50, 3);
|
||||
test_rotation(80, 1);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "opus_types.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
opus_int16 i = 1;
|
||||
i <<= 14;
|
||||
if (i>>14 != 1)
|
||||
{
|
||||
fprintf(stderr, "opus_int16 isn't 16 bits\n");
|
||||
return 1;
|
||||
}
|
||||
if (sizeof(opus_int16)*2 != sizeof(opus_int32))
|
||||
{
|
||||
fprintf(stderr, "16*2 != 32\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,415 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "mathops.h"
|
||||
#include "cwrs.h"
|
||||
#include "vq.h"
|
||||
#include "arch.h"
|
||||
#include "os_support.h"
|
||||
#include "bands.h"
|
||||
#include "rate.h"
|
||||
|
||||
static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
|
||||
{
|
||||
int i;
|
||||
celt_norm *Xptr;
|
||||
Xptr = X;
|
||||
for (i=0;i<len-stride;i++)
|
||||
{
|
||||
celt_norm x1, x2;
|
||||
x1 = Xptr[0];
|
||||
x2 = Xptr[stride];
|
||||
Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15));
|
||||
*Xptr++ = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15));
|
||||
}
|
||||
Xptr = &X[len-2*stride-1];
|
||||
for (i=len-2*stride-1;i>=0;i--)
|
||||
{
|
||||
celt_norm x1, x2;
|
||||
x1 = Xptr[0];
|
||||
x2 = Xptr[stride];
|
||||
Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15));
|
||||
*Xptr-- = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15));
|
||||
}
|
||||
}
|
||||
|
||||
static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
|
||||
{
|
||||
static const int SPREAD_FACTOR[3]={15,10,5};
|
||||
int i;
|
||||
opus_val16 c, s;
|
||||
opus_val16 gain, theta;
|
||||
int stride2=0;
|
||||
int factor;
|
||||
|
||||
if (2*K>=len || spread==SPREAD_NONE)
|
||||
return;
|
||||
factor = SPREAD_FACTOR[spread-1];
|
||||
|
||||
gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K));
|
||||
theta = HALF16(MULT16_16_Q15(gain,gain));
|
||||
|
||||
c = celt_cos_norm(EXTEND32(theta));
|
||||
s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
|
||||
|
||||
if (len>=8*stride)
|
||||
{
|
||||
stride2 = 1;
|
||||
/* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
|
||||
It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
|
||||
while ((stride2*stride2+stride2)*stride + (stride>>2) < len)
|
||||
stride2++;
|
||||
}
|
||||
/*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
|
||||
extract_collapse_mask().*/
|
||||
len /= stride;
|
||||
for (i=0;i<stride;i++)
|
||||
{
|
||||
if (dir < 0)
|
||||
{
|
||||
if (stride2)
|
||||
exp_rotation1(X+i*len, len, stride2, s, c);
|
||||
exp_rotation1(X+i*len, len, 1, c, s);
|
||||
} else {
|
||||
exp_rotation1(X+i*len, len, 1, c, -s);
|
||||
if (stride2)
|
||||
exp_rotation1(X+i*len, len, stride2, s, -c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Takes the pitch vector and the decoded residual vector, computes the gain
|
||||
that will give ||p+g*y||=1 and mixes the residual with the pitch. */
|
||||
static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X,
|
||||
int N, opus_val32 Ryy, opus_val16 gain)
|
||||
{
|
||||
int i;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
int k;
|
||||
#endif
|
||||
opus_val32 t;
|
||||
opus_val16 g;
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
k = celt_ilog2(Ryy)>>1;
|
||||
#endif
|
||||
t = VSHR32(Ryy, 2*(k-7));
|
||||
g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
|
||||
|
||||
i=0;
|
||||
do
|
||||
X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1));
|
||||
while (++i < N);
|
||||
}
|
||||
|
||||
static unsigned extract_collapse_mask(int *iy, int N, int B)
|
||||
{
|
||||
unsigned collapse_mask;
|
||||
int N0;
|
||||
int i;
|
||||
if (B<=1)
|
||||
return 1;
|
||||
/*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
|
||||
exp_rotation().*/
|
||||
N0 = N/B;
|
||||
collapse_mask = 0;
|
||||
i=0; do {
|
||||
int j;
|
||||
j=0; do {
|
||||
collapse_mask |= (iy[i*N0+j]!=0)<<i;
|
||||
} while (++j<N0);
|
||||
} while (++i<B);
|
||||
return collapse_mask;
|
||||
}
|
||||
|
||||
unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
||||
#ifdef RESYNTH
|
||||
, opus_val16 gain
|
||||
#endif
|
||||
)
|
||||
{
|
||||
VARDECL(celt_norm, y);
|
||||
VARDECL(int, iy);
|
||||
VARDECL(opus_val16, signx);
|
||||
int i, j;
|
||||
opus_val16 s;
|
||||
int pulsesLeft;
|
||||
opus_val32 sum;
|
||||
opus_val32 xy;
|
||||
opus_val16 yy;
|
||||
unsigned collapse_mask;
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert2(K>0, "alg_quant() needs at least one pulse");
|
||||
celt_assert2(N>1, "alg_quant() needs at least two dimensions");
|
||||
|
||||
ALLOC(y, N, celt_norm);
|
||||
ALLOC(iy, N, int);
|
||||
ALLOC(signx, N, opus_val16);
|
||||
|
||||
exp_rotation(X, N, 1, B, K, spread);
|
||||
|
||||
/* Get rid of the sign */
|
||||
sum = 0;
|
||||
j=0; do {
|
||||
if (X[j]>0)
|
||||
signx[j]=1;
|
||||
else {
|
||||
signx[j]=-1;
|
||||
X[j]=-X[j];
|
||||
}
|
||||
iy[j] = 0;
|
||||
y[j] = 0;
|
||||
} while (++j<N);
|
||||
|
||||
xy = yy = 0;
|
||||
|
||||
pulsesLeft = K;
|
||||
|
||||
/* Do a pre-search by projecting on the pyramid */
|
||||
if (K > (N>>1))
|
||||
{
|
||||
opus_val16 rcp;
|
||||
j=0; do {
|
||||
sum += X[j];
|
||||
} while (++j<N);
|
||||
|
||||
/* If X is too small, just replace it with a pulse at 0 */
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
if (sum <= K)
|
||||
#else
|
||||
/* Prevents infinities and NaNs from causing too many pulses
|
||||
to be allocated. 64 is an approximation of infinity here. */
|
||||
if (!(sum > EPSILON && sum < 64))
|
||||
#endif
|
||||
{
|
||||
X[0] = QCONST16(1.f,14);
|
||||
j=1; do
|
||||
X[j]=0;
|
||||
while (++j<N);
|
||||
sum = QCONST16(1.f,14);
|
||||
}
|
||||
rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
|
||||
j=0; do {
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
/* It's really important to round *towards zero* here */
|
||||
iy[j] = MULT16_16_Q15(X[j],rcp);
|
||||
#else
|
||||
iy[j] = (int)floor(rcp*X[j]);
|
||||
#endif
|
||||
y[j] = (celt_norm)iy[j];
|
||||
yy = MAC16_16(yy, y[j],y[j]);
|
||||
xy = MAC16_16(xy, X[j],y[j]);
|
||||
y[j] *= 2;
|
||||
pulsesLeft -= iy[j];
|
||||
} while (++j<N);
|
||||
}
|
||||
celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
|
||||
|
||||
/* This should never happen, but just in case it does (e.g. on silence)
|
||||
we fill the first bin with pulses. */
|
||||
#ifdef OPUS_FIXED_POINT_DEBUG
|
||||
celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass");
|
||||
#endif
|
||||
if (pulsesLeft > N+3)
|
||||
{
|
||||
opus_val16 tmp = (opus_val16)pulsesLeft;
|
||||
yy = MAC16_16(yy, tmp, tmp);
|
||||
yy = MAC16_16(yy, tmp, y[0]);
|
||||
iy[0] += pulsesLeft;
|
||||
pulsesLeft=0;
|
||||
}
|
||||
|
||||
s = 1;
|
||||
for (i=0;i<pulsesLeft;i++)
|
||||
{
|
||||
int best_id;
|
||||
opus_val32 best_num = -VERY_LARGE16;
|
||||
opus_val16 best_den = 0;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
int rshift;
|
||||
#endif
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
rshift = 1+celt_ilog2(K-pulsesLeft+i+1);
|
||||
#endif
|
||||
best_id = 0;
|
||||
/* The squared magnitude term gets added anyway, so we might as well
|
||||
add it outside the loop */
|
||||
yy = ADD32(yy, 1);
|
||||
j=0;
|
||||
do {
|
||||
opus_val16 Rxy, Ryy;
|
||||
/* Temporary sums of the new pulse(s) */
|
||||
Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
Ryy = ADD16(yy, y[j]);
|
||||
|
||||
/* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
|
||||
Rxy is positive because the sign is pre-computed) */
|
||||
Rxy = MULT16_16_Q15(Rxy,Rxy);
|
||||
/* The idea is to check for num/den >= best_num/best_den, but that way
|
||||
we can do it without any division */
|
||||
/* OPT: Make sure to use conditional moves here */
|
||||
if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
|
||||
{
|
||||
best_den = Ryy;
|
||||
best_num = Rxy;
|
||||
best_id = j;
|
||||
}
|
||||
} while (++j<N);
|
||||
|
||||
/* Updating the sums of the new pulse(s) */
|
||||
xy = ADD32(xy, EXTEND32(X[best_id]));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
yy = ADD16(yy, y[best_id]);
|
||||
|
||||
/* Only now that we've made the final choice, update y/iy */
|
||||
/* Multiplying y[j] by 2 so we don't have to do it everywhere else */
|
||||
y[best_id] += 2*s;
|
||||
iy[best_id]++;
|
||||
}
|
||||
|
||||
/* Put the original sign back */
|
||||
j=0;
|
||||
do {
|
||||
X[j] = MULT16_16(signx[j],X[j]);
|
||||
if (signx[j] < 0)
|
||||
iy[j] = -iy[j];
|
||||
} while (++j<N);
|
||||
encode_pulses(iy, N, K, enc);
|
||||
|
||||
#ifdef RESYNTH
|
||||
normalise_residual(iy, X, N, yy, gain);
|
||||
exp_rotation(X, N, -1, B, K, spread);
|
||||
#endif
|
||||
|
||||
collapse_mask = extract_collapse_mask(iy, N, B);
|
||||
RESTORE_STACK;
|
||||
return collapse_mask;
|
||||
}
|
||||
|
||||
/** Decode pulse vector and combine the result with the pitch vector to produce
|
||||
the final normalised signal in the current band. */
|
||||
unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
|
||||
ec_dec *dec, opus_val16 gain)
|
||||
{
|
||||
int i;
|
||||
opus_val32 Ryy;
|
||||
unsigned collapse_mask;
|
||||
VARDECL(int, iy);
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert2(K>0, "alg_unquant() needs at least one pulse");
|
||||
celt_assert2(N>1, "alg_unquant() needs at least two dimensions");
|
||||
ALLOC(iy, N, int);
|
||||
decode_pulses(iy, N, K, dec);
|
||||
Ryy = 0;
|
||||
i=0;
|
||||
do {
|
||||
Ryy = MAC16_16(Ryy, iy[i], iy[i]);
|
||||
} while (++i < N);
|
||||
normalise_residual(iy, X, N, Ryy, gain);
|
||||
exp_rotation(X, N, -1, B, K, spread);
|
||||
collapse_mask = extract_collapse_mask(iy, N, B);
|
||||
RESTORE_STACK;
|
||||
return collapse_mask;
|
||||
}
|
||||
|
||||
void renormalise_vector(celt_norm *X, int N, opus_val16 gain)
|
||||
{
|
||||
int i;
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
int k;
|
||||
#endif
|
||||
opus_val32 E = EPSILON;
|
||||
opus_val16 g;
|
||||
opus_val32 t;
|
||||
celt_norm *xptr = X;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
E = MAC16_16(E, *xptr, *xptr);
|
||||
xptr++;
|
||||
}
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
k = celt_ilog2(E)>>1;
|
||||
#endif
|
||||
t = VSHR32(E, 2*(k-7));
|
||||
g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
|
||||
|
||||
xptr = X;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
*xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
|
||||
xptr++;
|
||||
}
|
||||
/*return celt_sqrt(E);*/
|
||||
}
|
||||
|
||||
int stereo_itheta(celt_norm *X, celt_norm *Y, int stereo, int N)
|
||||
{
|
||||
int i;
|
||||
int itheta;
|
||||
opus_val16 mid, side;
|
||||
opus_val32 Emid, Eside;
|
||||
|
||||
Emid = Eside = EPSILON;
|
||||
if (stereo)
|
||||
{
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
celt_norm m, s;
|
||||
m = ADD16(SHR16(X[i],1),SHR16(Y[i],1));
|
||||
s = SUB16(SHR16(X[i],1),SHR16(Y[i],1));
|
||||
Emid = MAC16_16(Emid, m, m);
|
||||
Eside = MAC16_16(Eside, s, s);
|
||||
}
|
||||
} else {
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
celt_norm m, s;
|
||||
m = X[i];
|
||||
s = Y[i];
|
||||
Emid = MAC16_16(Emid, m, m);
|
||||
Eside = MAC16_16(Eside, s, s);
|
||||
}
|
||||
}
|
||||
mid = celt_sqrt(Emid);
|
||||
side = celt_sqrt(Eside);
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
/* 0.63662 = 2/pi */
|
||||
itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
|
||||
#else
|
||||
itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid));
|
||||
#endif
|
||||
|
||||
return itheta;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/**
|
||||
@file vq.h
|
||||
@brief Vector quantisation of the residual
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VQ_H
|
||||
#define VQ_H
|
||||
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
#include "opus_modes.h"
|
||||
|
||||
/** Algebraic pulse-vector quantiser. The signal x is replaced by the sum of
|
||||
* the pitch and a combination of pulses such that its norm is still equal
|
||||
* to 1. This is the function that will typically require the most CPU.
|
||||
* @param X Residual signal to quantise/encode (returns quantised version)
|
||||
* @param N Number of samples to encode
|
||||
* @param K Number of pulses to use
|
||||
* @param enc Entropy encoder state
|
||||
* @ret A mask indicating which blocks in the band received pulses
|
||||
*/
|
||||
unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
|
||||
ec_enc *enc
|
||||
#ifdef RESYNTH
|
||||
, opus_val16 gain
|
||||
#endif
|
||||
);
|
||||
|
||||
/** Algebraic pulse decoder
|
||||
* @param X Decoded normalised spectrum (returned)
|
||||
* @param N Number of samples to decode
|
||||
* @param K Number of pulses to use
|
||||
* @param dec Entropy decoder state
|
||||
* @ret A mask indicating which blocks in the band received pulses
|
||||
*/
|
||||
unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
|
||||
ec_dec *dec, opus_val16 gain);
|
||||
|
||||
void renormalise_vector(celt_norm *X, int N, opus_val16 gain);
|
||||
|
||||
int stereo_itheta(celt_norm *X, celt_norm *Y, int stereo, int N);
|
||||
|
||||
#endif /* VQ_H */
|
|
@ -0,0 +1,156 @@
|
|||
/* Copyright (c) 2013 Jean-Marc Valin and John Ridges */
|
||||
/**
|
||||
@file pitch_sse.h
|
||||
@brief Pitch analysis
|
||||
*/
|
||||
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PITCH_SSE_H
|
||||
#define PITCH_SSE_H
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#include "arch.h"
|
||||
|
||||
#define OVERRIDE_XCORR_KERNEL
|
||||
static OPUS_INLINE void xcorr_kernel(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len)
|
||||
{
|
||||
int j;
|
||||
__m128 xsum1, xsum2;
|
||||
xsum1 = _mm_loadu_ps(sum);
|
||||
xsum2 = _mm_setzero_ps();
|
||||
|
||||
for (j = 0; j < len-3; j += 4)
|
||||
{
|
||||
__m128 x0 = _mm_loadu_ps(x+j);
|
||||
__m128 yj = _mm_loadu_ps(y+j);
|
||||
__m128 y3 = _mm_loadu_ps(y+j+3);
|
||||
|
||||
xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj));
|
||||
xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55),
|
||||
_mm_shuffle_ps(yj,y3,0x49)));
|
||||
xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa),
|
||||
_mm_shuffle_ps(yj,y3,0x9e)));
|
||||
xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3));
|
||||
}
|
||||
if (j < len)
|
||||
{
|
||||
xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
|
||||
if (++j < len)
|
||||
{
|
||||
xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
|
||||
if (++j < len)
|
||||
{
|
||||
xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2));
|
||||
}
|
||||
|
||||
#define OVERRIDE_DUAL_INNER_PROD
|
||||
static OPUS_INLINE void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||
int N, opus_val32 *xy1, opus_val32 *xy2)
|
||||
{
|
||||
int i;
|
||||
__m128 xsum1, xsum2;
|
||||
xsum1 = _mm_setzero_ps();
|
||||
xsum2 = _mm_setzero_ps();
|
||||
for (i=0;i<N-3;i+=4)
|
||||
{
|
||||
__m128 xi = _mm_loadu_ps(x+i);
|
||||
__m128 y1i = _mm_loadu_ps(y01+i);
|
||||
__m128 y2i = _mm_loadu_ps(y02+i);
|
||||
xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(xi, y1i));
|
||||
xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(xi, y2i));
|
||||
}
|
||||
/* Horizontal sum */
|
||||
xsum1 = _mm_add_ps(xsum1, _mm_movehl_ps(xsum1, xsum1));
|
||||
xsum1 = _mm_add_ss(xsum1, _mm_shuffle_ps(xsum1, xsum1, 0x55));
|
||||
_mm_store_ss(xy1, xsum1);
|
||||
xsum2 = _mm_add_ps(xsum2, _mm_movehl_ps(xsum2, xsum2));
|
||||
xsum2 = _mm_add_ss(xsum2, _mm_shuffle_ps(xsum2, xsum2, 0x55));
|
||||
_mm_store_ss(xy2, xsum2);
|
||||
for (;i<N;i++)
|
||||
{
|
||||
*xy1 = MAC16_16(*xy1, x[i], y01[i]);
|
||||
*xy2 = MAC16_16(*xy2, x[i], y02[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#define OVERRIDE_COMB_FILTER_CONST
|
||||
static OPUS_INLINE void comb_filter_const(opus_val32 *y, opus_val32 *x, int T, int N,
|
||||
opus_val16 g10, opus_val16 g11, opus_val16 g12)
|
||||
{
|
||||
int i;
|
||||
__m128 x0v;
|
||||
__m128 g10v, g11v, g12v;
|
||||
g10v = _mm_load1_ps(&g10);
|
||||
g11v = _mm_load1_ps(&g11);
|
||||
g12v = _mm_load1_ps(&g12);
|
||||
x0v = _mm_loadu_ps(&x[-T-2]);
|
||||
for (i=0;i<N-3;i+=4)
|
||||
{
|
||||
__m128 yi, yi2, x1v, x2v, x3v, x4v;
|
||||
const opus_val32 *xp = &x[i-T-2];
|
||||
yi = _mm_loadu_ps(x+i);
|
||||
x4v = _mm_loadu_ps(xp+4);
|
||||
#if 0
|
||||
/* Slower version with all loads */
|
||||
x1v = _mm_loadu_ps(xp+1);
|
||||
x2v = _mm_loadu_ps(xp+2);
|
||||
x3v = _mm_loadu_ps(xp+3);
|
||||
#else
|
||||
x2v = _mm_shuffle_ps(x0v, x4v, 0x4e);
|
||||
x1v = _mm_shuffle_ps(x0v, x2v, 0x99);
|
||||
x3v = _mm_shuffle_ps(x2v, x4v, 0x99);
|
||||
#endif
|
||||
|
||||
yi = _mm_add_ps(yi, _mm_mul_ps(g10v,x2v));
|
||||
#if 0 /* Set to 1 to make it bit-exact with the non-SSE version */
|
||||
yi = _mm_add_ps(yi, _mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)));
|
||||
yi = _mm_add_ps(yi, _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
|
||||
#else
|
||||
/* Use partial sums */
|
||||
yi2 = _mm_add_ps(_mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)),
|
||||
_mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
|
||||
yi = _mm_add_ps(yi, yi2);
|
||||
#endif
|
||||
x0v=x4v;
|
||||
_mm_storeu_ps(y+i, yi);
|
||||
}
|
||||
#ifdef CUSTOM_MODES
|
||||
for (;i<N;i++)
|
||||
{
|
||||
y[i] = x[i]
|
||||
+ MULT16_32_Q15(g10,x[i-T])
|
||||
+ MULT16_32_Q15(g11,ADD32(x[i-T+1],x[i-T-1]))
|
||||
+ MULT16_32_Q15(g12,ADD32(x[i-T+2],x[i-T-2]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,687 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
static unsigned op_parse_uint16le(const unsigned char *_data){
|
||||
return _data[0]|_data[1]<<8;
|
||||
}
|
||||
|
||||
static int op_parse_int16le(const unsigned char *_data){
|
||||
int ret;
|
||||
ret=_data[0]|_data[1]<<8;
|
||||
return (ret^0x8000)-0x8000;
|
||||
}
|
||||
|
||||
static opus_uint32 op_parse_uint32le(const unsigned char *_data){
|
||||
return _data[0]|(opus_uint32)_data[1]<<8|
|
||||
(opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24;
|
||||
}
|
||||
|
||||
static opus_uint32 op_parse_uint32be(const unsigned char *_data){
|
||||
return _data[3]|(opus_uint32)_data[2]<<8|
|
||||
(opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24;
|
||||
}
|
||||
|
||||
int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
|
||||
OpusHead head;
|
||||
if(_len<8)return OP_ENOTFORMAT;
|
||||
if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
|
||||
if(_len<9)return OP_EBADHEADER;
|
||||
head.version=_data[8];
|
||||
if(head.version>15)return OP_EVERSION;
|
||||
if(_len<19)return OP_EBADHEADER;
|
||||
head.channel_count=_data[9];
|
||||
head.pre_skip=op_parse_uint16le(_data+10);
|
||||
head.input_sample_rate=op_parse_uint32le(_data+12);
|
||||
head.output_gain=op_parse_int16le(_data+16);
|
||||
head.mapping_family=_data[18];
|
||||
if(head.mapping_family==0){
|
||||
if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
|
||||
if(head.version<=1&&_len>19)return OP_EBADHEADER;
|
||||
head.stream_count=1;
|
||||
head.coupled_count=head.channel_count-1;
|
||||
if(_head!=NULL){
|
||||
_head->mapping[0]=0;
|
||||
_head->mapping[1]=1;
|
||||
}
|
||||
}
|
||||
else if(head.mapping_family==1){
|
||||
size_t size;
|
||||
int ci;
|
||||
if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
|
||||
size=21+head.channel_count;
|
||||
if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
|
||||
head.stream_count=_data[19];
|
||||
if(head.stream_count<1)return OP_EBADHEADER;
|
||||
head.coupled_count=_data[20];
|
||||
if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
|
||||
for(ci=0;ci<head.channel_count;ci++){
|
||||
if(_data[21+ci]>=head.stream_count+head.coupled_count
|
||||
&&_data[21+ci]!=255){
|
||||
return OP_EBADHEADER;
|
||||
}
|
||||
}
|
||||
if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
|
||||
}
|
||||
/*General purpose players should not attempt to play back content with
|
||||
channel mapping family 255.*/
|
||||
else if(head.mapping_family==255)return OP_EIMPL;
|
||||
/*No other channel mapping families are currently defined.*/
|
||||
else return OP_EBADHEADER;
|
||||
if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void opus_tags_init(OpusTags *_tags){
|
||||
memset(_tags,0,sizeof(*_tags));
|
||||
}
|
||||
|
||||
void opus_tags_clear(OpusTags *_tags){
|
||||
int ci;
|
||||
for(ci=_tags->comments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
|
||||
_ogg_free(_tags->user_comments);
|
||||
_ogg_free(_tags->comment_lengths);
|
||||
_ogg_free(_tags->vendor);
|
||||
}
|
||||
|
||||
/*Ensure there's room for up to _ncomments comments.*/
|
||||
static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
|
||||
char **user_comments;
|
||||
int *comment_lengths;
|
||||
size_t size;
|
||||
if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
|
||||
size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
|
||||
if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
|
||||
comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
|
||||
if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
|
||||
comment_lengths[_ncomments]=0;
|
||||
_tags->comment_lengths=comment_lengths;
|
||||
size=sizeof(*_tags->user_comments)*(_ncomments+1);
|
||||
if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
|
||||
user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
|
||||
if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
|
||||
user_comments[_ncomments]=NULL;
|
||||
_tags->user_comments=user_comments;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Duplicate a (possibly non-NUL terminated) string with a known length.*/
|
||||
static char *op_strdup_with_len(const char *_s,size_t _len){
|
||||
size_t size;
|
||||
char *ret;
|
||||
size=sizeof(*ret)*(_len+1);
|
||||
if(OP_UNLIKELY(size<_len))return NULL;
|
||||
ret=(char *)_ogg_malloc(size);
|
||||
if(OP_LIKELY(ret!=NULL)){
|
||||
ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
|
||||
ret[_len]='\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_tags_parse().
|
||||
Unlike the public API, this function requires _tags to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
static int opus_tags_parse_impl(OpusTags *_tags,
|
||||
const unsigned char *_data,size_t _len){
|
||||
opus_uint32 count;
|
||||
size_t len;
|
||||
int ncomments;
|
||||
int ci;
|
||||
len=_len;
|
||||
if(len<8)return OP_ENOTFORMAT;
|
||||
if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
|
||||
if(len<16)return OP_EBADHEADER;
|
||||
_data+=8;
|
||||
len-=8;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
if(count>len)return OP_EBADHEADER;
|
||||
if(_tags!=NULL){
|
||||
_tags->vendor=op_strdup_with_len((char *)_data,count);
|
||||
if(_tags->vendor==NULL)return OP_EFAULT;
|
||||
}
|
||||
_data+=count;
|
||||
len-=count;
|
||||
if(len<4)return OP_EBADHEADER;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
/*Check to make sure there's minimally sufficient data left in the packet.*/
|
||||
if(count>len>>2)return OP_EBADHEADER;
|
||||
/*Check for overflow (the API limits this to an int).*/
|
||||
if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
|
||||
if(_tags!=NULL){
|
||||
int ret;
|
||||
ret=op_tags_ensure_capacity(_tags,count);
|
||||
if(ret<0)return ret;
|
||||
}
|
||||
ncomments=(int)count;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
/*Check to make sure there's minimally sufficient data left in the packet.*/
|
||||
if((size_t)(ncomments-ci)>len>>2)return OP_EBADHEADER;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
if(count>len)return OP_EBADHEADER;
|
||||
/*Check for overflow (the API limits this to an int).*/
|
||||
if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
|
||||
if(_tags!=NULL){
|
||||
_tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
|
||||
if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
|
||||
_tags->comment_lengths[ci]=(int)count;
|
||||
_tags->comments=ci+1;
|
||||
}
|
||||
_data+=count;
|
||||
len-=count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
|
||||
if(_tags!=NULL){
|
||||
OpusTags tags;
|
||||
int ret;
|
||||
opus_tags_init(&tags);
|
||||
ret=opus_tags_parse_impl(&tags,_data,_len);
|
||||
if(ret<0)opus_tags_clear(&tags);
|
||||
else *_tags=*&tags;
|
||||
return ret;
|
||||
}
|
||||
else return opus_tags_parse_impl(NULL,_data,_len);
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_tags_copy().
|
||||
Unlike the public API, this function requires _dst to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
|
||||
char *vendor;
|
||||
int ncomments;
|
||||
int ret;
|
||||
int ci;
|
||||
vendor=_src->vendor;
|
||||
_dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
|
||||
if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
|
||||
ncomments=_src->comments;
|
||||
ret=op_tags_ensure_capacity(_dst,ncomments);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
int len;
|
||||
len=_src->comment_lengths[ci];
|
||||
OP_ASSERT(len>=0);
|
||||
_dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
|
||||
if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
|
||||
_dst->comment_lengths[ci]=len;
|
||||
_dst->comments=ci+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
|
||||
OpusTags dst;
|
||||
int ret;
|
||||
opus_tags_init(&dst);
|
||||
ret=opus_tags_copy_impl(&dst,_src);
|
||||
if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
|
||||
else *_dst=*&dst;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
|
||||
char *comment;
|
||||
int tag_len;
|
||||
int value_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
ncomments=_tags->comments;
|
||||
ret=op_tags_ensure_capacity(_tags,ncomments+1);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
tag_len=strlen(_tag);
|
||||
value_len=strlen(_value);
|
||||
/*+2 for '=' and '\0'.*/
|
||||
_tags->comment_lengths[ncomments]=0;
|
||||
_tags->user_comments[ncomments]=comment=
|
||||
(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
|
||||
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
|
||||
memcpy(comment,_tag,sizeof(*comment)*tag_len);
|
||||
comment[tag_len]='=';
|
||||
memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
|
||||
_tags->comment_lengths[ncomments]=tag_len+value_len+1;
|
||||
_tags->comments=ncomments+1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
|
||||
int comment_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
ncomments=_tags->comments;
|
||||
ret=op_tags_ensure_capacity(_tags,ncomments+1);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
comment_len=(int)strlen(_comment);
|
||||
_tags->comment_lengths[ncomments]=0;
|
||||
_tags->user_comments[ncomments]=op_strdup_with_len(_comment,comment_len);
|
||||
if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
|
||||
_tags->comment_lengths[ncomments]=comment_len;
|
||||
_tags->comments=ncomments+1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tagcompare(const char *_tag_name,const char *_comment){
|
||||
return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
|
||||
}
|
||||
|
||||
int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
|
||||
int ret;
|
||||
OP_ASSERT(_tag_len>=0);
|
||||
ret=op_strncasecmp(_tag_name,_comment,_tag_len);
|
||||
return ret?ret:'='-_comment[_tag_len];
|
||||
}
|
||||
|
||||
const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
|
||||
/*We return a pointer to the data, not a copy.*/
|
||||
if(_count==found++)return user_comments[ci]+tag_len+1;
|
||||
}
|
||||
}
|
||||
/*Didn't find anything.*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
|
||||
char **comments;
|
||||
int ncomments;
|
||||
int ci;
|
||||
comments=_tags->user_comments;
|
||||
ncomments=_tags->comments;
|
||||
/*Look for the first valid R128_TRACK_GAIN tag and use that.*/
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(opus_tagncompare("R128_TRACK_GAIN",15,comments[ci])==0){
|
||||
char *p;
|
||||
opus_int32 gain_q8;
|
||||
int negative;
|
||||
p=comments[ci]+16;
|
||||
negative=0;
|
||||
if(*p=='-'){
|
||||
negative=-1;
|
||||
p++;
|
||||
}
|
||||
else if(*p=='+')p++;
|
||||
gain_q8=0;
|
||||
while(*p>='0'&&*p<='9'){
|
||||
gain_q8=10*gain_q8+*p-'0';
|
||||
if(gain_q8>32767-negative)break;
|
||||
p++;
|
||||
}
|
||||
/*This didn't look like a signed 16-bit decimal integer.
|
||||
Not a valid R128_TRACK_GAIN tag.*/
|
||||
if(*p!='\0')continue;
|
||||
*_gain_q8=(int)(gain_q8+negative^negative);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return OP_FALSE;
|
||||
}
|
||||
|
||||
static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0
|
||||
&&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0;
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
JPEG.
|
||||
On failure, simply leaves its outputs unmodified.*/
|
||||
static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
|
||||
opus_uint32 *_width,opus_uint32 *_height,
|
||||
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
|
||||
if(op_is_jpeg(_buf,_buf_sz)){
|
||||
size_t offs;
|
||||
offs=2;
|
||||
for(;;){
|
||||
size_t segment_len;
|
||||
int marker;
|
||||
while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
|
||||
while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
|
||||
marker=_buf[offs];
|
||||
offs++;
|
||||
/*If we hit EOI* (end of image), or another SOI* (start of image),
|
||||
or SOS (start of scan), then stop now.*/
|
||||
if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
|
||||
/*RST* (restart markers): skip (no segment length).*/
|
||||
else if(marker>=0xD0&&marker<=0xD7)continue;
|
||||
/*Read the length of the marker segment.*/
|
||||
if(_buf_sz-offs<2)break;
|
||||
segment_len=_buf[offs]<<8|_buf[offs+1];
|
||||
if(segment_len<2||_buf_sz-offs<segment_len)break;
|
||||
if(marker==0xC0||(marker>0xC0&&marker<0xD0&&(marker&3)!=0)){
|
||||
/*Found a SOFn (start of frame) marker segment:*/
|
||||
if(segment_len>=8){
|
||||
*_height=_buf[offs+3]<<8|_buf[offs+4];
|
||||
*_width=_buf[offs+5]<<8|_buf[offs+6];
|
||||
*_depth=_buf[offs+2]*_buf[offs+7];
|
||||
*_colors=0;
|
||||
*_has_palette=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*Other markers: skip the whole marker segment.*/
|
||||
offs+=segment_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
PNG.
|
||||
On failure, simply leaves its outputs unmodified.*/
|
||||
static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
|
||||
opus_uint32 *_width,opus_uint32 *_height,
|
||||
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
|
||||
if(op_is_png(_buf,_buf_sz)){
|
||||
size_t offs;
|
||||
offs=8;
|
||||
while(_buf_sz-offs>=12){
|
||||
ogg_uint32_t chunk_len;
|
||||
chunk_len=op_parse_uint32be(_buf+offs);
|
||||
if(chunk_len>_buf_sz-(offs+12))break;
|
||||
else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
|
||||
int color_type;
|
||||
*_width=op_parse_uint32be(_buf+offs+8);
|
||||
*_height=op_parse_uint32be(_buf+offs+12);
|
||||
color_type=_buf[offs+17];
|
||||
if(color_type==3){
|
||||
*_depth=24;
|
||||
*_has_palette=1;
|
||||
}
|
||||
else{
|
||||
int sample_depth;
|
||||
sample_depth=_buf[offs+16];
|
||||
if(color_type==0)*_depth=sample_depth;
|
||||
else if(color_type==2)*_depth=sample_depth*3;
|
||||
else if(color_type==4)*_depth=sample_depth*2;
|
||||
else if(color_type==6)*_depth=sample_depth*4;
|
||||
*_colors=0;
|
||||
*_has_palette=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
|
||||
*_colors=chunk_len/3;
|
||||
break;
|
||||
}
|
||||
offs+=12+chunk_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
GIF.
|
||||
On failure, simply leaves its outputs unmodified.*/
|
||||
static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
|
||||
opus_uint32 *_width,opus_uint32 *_height,
|
||||
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
|
||||
if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
|
||||
*_width=_buf[6]|_buf[7]<<8;
|
||||
*_height=_buf[8]|_buf[9]<<8;
|
||||
/*libFLAC hard-codes the depth to 24.*/
|
||||
*_depth=24;
|
||||
*_colors=1<<((_buf[10]&7)+1);
|
||||
*_has_palette=1;
|
||||
}
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_picture_tag_parse().
|
||||
Unlike the public API, this function requires _pic to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
|
||||
unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
|
||||
opus_int32 picture_type;
|
||||
opus_uint32 mime_type_length;
|
||||
char *mime_type;
|
||||
opus_uint32 description_length;
|
||||
char *description;
|
||||
opus_uint32 width;
|
||||
opus_uint32 height;
|
||||
opus_uint32 depth;
|
||||
opus_uint32 colors;
|
||||
opus_uint32 data_length;
|
||||
opus_uint32 file_width;
|
||||
opus_uint32 file_height;
|
||||
opus_uint32 file_depth;
|
||||
opus_uint32 file_colors;
|
||||
int format;
|
||||
int has_palette;
|
||||
int colors_set;
|
||||
size_t i;
|
||||
/*Decode the BASE64 data.*/
|
||||
for(i=0;i<_base64_sz;i++){
|
||||
opus_uint32 value;
|
||||
int j;
|
||||
value=0;
|
||||
for(j=0;j<4;j++){
|
||||
unsigned c;
|
||||
unsigned d;
|
||||
c=(unsigned char)_tag[4*i+j];
|
||||
if(c=='+')d=62;
|
||||
else if(c=='/')d=63;
|
||||
else if(c>='0'&&c<='9')d=52+c-'0';
|
||||
else if(c>='a'&&c<='z')d=26+c-'a';
|
||||
else if(c>='A'&&c<='Z')d=c-'A';
|
||||
else if(c=='='&&3*i+j>_buf_sz)d=0;
|
||||
else return OP_ENOTFORMAT;
|
||||
value=value<<6|d;
|
||||
}
|
||||
_buf[3*i]=(unsigned char)(value>>16);
|
||||
if(3*i+1<_buf_sz){
|
||||
_buf[3*i+1]=(unsigned char)(value>>8);
|
||||
if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
|
||||
}
|
||||
}
|
||||
i=0;
|
||||
picture_type=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
/*Extract the MIME type.*/
|
||||
mime_type_length=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
|
||||
mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
|
||||
if(mime_type==NULL)return OP_EFAULT;
|
||||
memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
|
||||
mime_type[mime_type_length]='\0';
|
||||
_pic->mime_type=mime_type;
|
||||
i+=mime_type_length;
|
||||
/*Extract the description string.*/
|
||||
description_length=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
|
||||
description=
|
||||
(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
|
||||
if(description==NULL)return OP_EFAULT;
|
||||
memcpy(description,_buf+i,sizeof(*description)*description_length);
|
||||
description[description_length]='\0';
|
||||
_pic->description=description;
|
||||
i+=description_length;
|
||||
/*Extract the remaining fields.*/
|
||||
width=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
height=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
depth=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
colors=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
/*If one of these is set, they all must be, but colors==0 is a valid value.*/
|
||||
colors_set=width!=0||height!=0||depth!=0||colors!=0;
|
||||
if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT;
|
||||
data_length=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
|
||||
/*Trim extraneous data so we don't copy it below.*/
|
||||
_buf_sz=i+data_length;
|
||||
/*Attempt to determine the image format.*/
|
||||
format=OP_PIC_FORMAT_UNKNOWN;
|
||||
if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
|
||||
format=OP_PIC_FORMAT_URL;
|
||||
/*Picture type 1 must be a 32x32 PNG.*/
|
||||
if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
|
||||
return OP_ENOTFORMAT;
|
||||
}
|
||||
/*Append a terminating NUL for the convenience of our callers.*/
|
||||
_buf[_buf_sz++]='\0';
|
||||
}
|
||||
else{
|
||||
if(mime_type_length==10
|
||||
&&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
|
||||
if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
|
||||
}
|
||||
else if(mime_type_length==9
|
||||
&&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
|
||||
if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
|
||||
}
|
||||
else if(mime_type_length==9
|
||||
&&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
|
||||
if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
|
||||
}
|
||||
else if(mime_type_length==0||(mime_type_length==6
|
||||
&&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
|
||||
if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
|
||||
else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
|
||||
else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
|
||||
}
|
||||
file_width=file_height=file_depth=file_colors=0;
|
||||
has_palette=-1;
|
||||
switch(format){
|
||||
case OP_PIC_FORMAT_JPEG:{
|
||||
op_extract_jpeg_params(_buf+i,data_length,
|
||||
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
|
||||
}break;
|
||||
case OP_PIC_FORMAT_PNG:{
|
||||
op_extract_png_params(_buf+i,data_length,
|
||||
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
|
||||
}break;
|
||||
case OP_PIC_FORMAT_GIF:{
|
||||
op_extract_gif_params(_buf+i,data_length,
|
||||
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
|
||||
}break;
|
||||
}
|
||||
if(has_palette>=0){
|
||||
/*If we successfully extracted these parameters from the image, override
|
||||
any declared values.*/
|
||||
width=file_width;
|
||||
height=file_height;
|
||||
depth=file_depth;
|
||||
colors=file_colors;
|
||||
}
|
||||
/*Picture type 1 must be a 32x32 PNG.*/
|
||||
if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
|
||||
return OP_ENOTFORMAT;
|
||||
}
|
||||
}
|
||||
/*Adjust _buf_sz instead of using data_length to capture the terminating NUL
|
||||
for URLs.*/
|
||||
_buf_sz-=i;
|
||||
memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
|
||||
_buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
|
||||
if(_buf_sz>0&&_buf==NULL)return OP_EFAULT;
|
||||
_pic->type=picture_type;
|
||||
_pic->width=width;
|
||||
_pic->height=height;
|
||||
_pic->depth=depth;
|
||||
_pic->colors=colors;
|
||||
_pic->data_length=data_length;
|
||||
_pic->data=_buf;
|
||||
_pic->format=format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
|
||||
OpusPictureTag pic;
|
||||
unsigned char *buf;
|
||||
size_t base64_sz;
|
||||
size_t buf_sz;
|
||||
size_t tag_length;
|
||||
int ret;
|
||||
if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
|
||||
/*Figure out how much BASE64-encoded data we have.*/
|
||||
tag_length=strlen(_tag);
|
||||
if(tag_length&3)return OP_ENOTFORMAT;
|
||||
base64_sz=tag_length>>2;
|
||||
buf_sz=3*base64_sz;
|
||||
if(buf_sz<32)return OP_ENOTFORMAT;
|
||||
if(_tag[tag_length-1]=='=')buf_sz--;
|
||||
if(_tag[tag_length-2]=='=')buf_sz--;
|
||||
if(buf_sz<32)return OP_ENOTFORMAT;
|
||||
/*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
|
||||
buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
|
||||
if(buf==NULL)return OP_EFAULT;
|
||||
opus_picture_tag_init(&pic);
|
||||
ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
|
||||
if(ret<0){
|
||||
opus_picture_tag_clear(&pic);
|
||||
_ogg_free(buf);
|
||||
}
|
||||
else *_pic=*&pic;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void opus_picture_tag_init(OpusPictureTag *_pic){
|
||||
memset(_pic,0,sizeof(*_pic));
|
||||
}
|
||||
|
||||
void opus_picture_tag_clear(OpusPictureTag *_pic){
|
||||
_ogg_free(_pic->description);
|
||||
_ogg_free(_pic->mime_type);
|
||||
_ogg_free(_pic->data);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#if defined(OP_ENABLE_ASSERTIONS)
|
||||
void op_fatal_impl(const char *_str,const char *_file,int _line){
|
||||
fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n",
|
||||
_file,_line,_str);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*A version of strncasecmp() that is guaranteed to only ignore the case of
|
||||
ASCII characters.*/
|
||||
int op_strncasecmp(const char *_a,const char *_b,int _n){
|
||||
int i;
|
||||
for(i=0;i<_n;i++){
|
||||
int a;
|
||||
int b;
|
||||
int d;
|
||||
a=_a[i];
|
||||
b=_b[i];
|
||||
if(a>='a'&&a<='z')a-='a'-'A';
|
||||
if(b>='a'&&b<='z')b-='a'-'A';
|
||||
d=a-b;
|
||||
if(d)return d;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#if !defined(_opusfile_internal_h)
|
||||
# define _opusfile_internal_h (1)
|
||||
|
||||
# if !defined(_REENTRANT)
|
||||
# define _REENTRANT
|
||||
# endif
|
||||
# if !defined(_GNU_SOURCE)
|
||||
# define _GNU_SOURCE
|
||||
# endif
|
||||
# if !defined(_LARGEFILE_SOURCE)
|
||||
# define _LARGEFILE_SOURCE
|
||||
# endif
|
||||
# if !defined(_LARGEFILE64_SOURCE)
|
||||
# define _LARGEFILE64_SOURCE
|
||||
# endif
|
||||
# if !defined(_FILE_OFFSET_BITS)
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <opus/opusfile.h>
|
||||
|
||||
typedef struct OggOpusLink OggOpusLink;
|
||||
|
||||
# if defined(OPUS_FIXED_POINT)
|
||||
|
||||
typedef opus_int16 op_sample;
|
||||
|
||||
# else
|
||||
|
||||
typedef float op_sample;
|
||||
|
||||
/*We're using this define to test for libopus 1.1 or later until libopus
|
||||
provides a better mechanism.*/
|
||||
# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
|
||||
/*Enable soft clipping prevention in 16-bit decodes.*/
|
||||
# define OP_SOFT_CLIP (1)
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
# if OP_GNUC_PREREQ(4,2)
|
||||
/*Disable excessive warnings about the order of operations.*/
|
||||
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||
# elif defined(_MSC_VER)
|
||||
/*Disable excessive warnings about the order of operations.*/
|
||||
# pragma warning(disable:4554)
|
||||
/*Disable warnings about "deprecated" POSIX functions.*/
|
||||
# pragma warning(disable:4996)
|
||||
# endif
|
||||
|
||||
# if OP_GNUC_PREREQ(3,0)
|
||||
/*Another alternative is
|
||||
(__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1))
|
||||
but that evaluates _x multiple times, which may be bad.*/
|
||||
# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1))
|
||||
# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0))
|
||||
# else
|
||||
# define OP_LIKELY(_x) (!!(_x))
|
||||
# define OP_UNLIKELY(_x) (!!(_x))
|
||||
# endif
|
||||
|
||||
# if defined(OP_ENABLE_ASSERTIONS)
|
||||
# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590
|
||||
__attribute__((noreturn))
|
||||
# endif
|
||||
void op_fatal_impl(const char *_str,const char *_file,int _line);
|
||||
|
||||
# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__))
|
||||
|
||||
# define OP_ASSERT(_cond) \
|
||||
do{ \
|
||||
if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \
|
||||
} \
|
||||
while(0)
|
||||
# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond)
|
||||
|
||||
# else
|
||||
# define OP_FATAL(_str) abort()
|
||||
# define OP_ASSERT(_cond)
|
||||
# define OP_ALWAYS_TRUE(_cond) ((void)(_cond))
|
||||
# endif
|
||||
|
||||
# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1)
|
||||
# define OP_INT64_MIN (-OP_INT64_MAX-1)
|
||||
# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1)
|
||||
# define OP_INT32_MIN (-OP_INT32_MAX-1)
|
||||
|
||||
# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
|
||||
# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
|
||||
# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi)))
|
||||
|
||||
/*Advance a file offset by the given amount, clamping against OP_INT64_MAX.
|
||||
This is used to advance a known offset by things like OP_CHUNK_SIZE or
|
||||
OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow.
|
||||
It assumes that both _offset and _amount are non-negative.*/
|
||||
#define OP_ADV_OFFSET(_offset,_amount) \
|
||||
(OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount))
|
||||
|
||||
/*The maximum channel count for any mapping we'll actually decode.*/
|
||||
# define OP_NCHANNELS_MAX (8)
|
||||
|
||||
/*Initial state.*/
|
||||
# define OP_NOTOPEN (0)
|
||||
/*We've found the first Opus stream in the first link.*/
|
||||
# define OP_PARTOPEN (1)
|
||||
# define OP_OPENED (2)
|
||||
/*We've found the first Opus stream in the current link.*/
|
||||
# define OP_STREAMSET (3)
|
||||
/*We've initialized the decoder for the chosen Opus stream in the current
|
||||
link.*/
|
||||
# define OP_INITSET (4)
|
||||
|
||||
/*Information cached for a single link in a chained Ogg Opus file.
|
||||
We choose the first Opus stream encountered in each link to play back (and
|
||||
require at least one).*/
|
||||
struct OggOpusLink{
|
||||
/*The byte offset of the first header page in this link.*/
|
||||
opus_int64 offset;
|
||||
/*The byte offset of the first data page from the chosen Opus stream in this
|
||||
link (after the headers).*/
|
||||
opus_int64 data_offset;
|
||||
/*The byte offset of the last page from the chosen Opus stream in this link.
|
||||
This is used when seeking to ensure we find a page before the last one, so
|
||||
that end-trimming calculations work properly.
|
||||
This is only valid for seekable sources.*/
|
||||
opus_int64 end_offset;
|
||||
/*The granule position of the last sample.
|
||||
This is only valid for seekable sources.*/
|
||||
ogg_int64_t pcm_end;
|
||||
/*The granule position before the first sample.*/
|
||||
ogg_int64_t pcm_start;
|
||||
/*The serial number.*/
|
||||
ogg_uint32_t serialno;
|
||||
/*The contents of the info header.*/
|
||||
OpusHead head;
|
||||
/*The contents of the comment header.*/
|
||||
OpusTags tags;
|
||||
};
|
||||
|
||||
struct OggOpusFile{
|
||||
/*The callbacks used to access the data source.*/
|
||||
OpusFileCallbacks callbacks;
|
||||
/*A FILE *, memory bufer, etc.*/
|
||||
void *source;
|
||||
/*Whether or not we can seek with this data source.*/
|
||||
int seekable;
|
||||
/*The number of links in this chained Ogg Opus file.*/
|
||||
int nlinks;
|
||||
/*The cached information from each link in a chained Ogg Opus file.
|
||||
If source isn't seekable (e.g., it's a pipe), only the current link
|
||||
appears.*/
|
||||
OggOpusLink *links;
|
||||
/*The number of serial numbers from a single link.*/
|
||||
int nserialnos;
|
||||
/*The capacity of the list of serial numbers from a single link.*/
|
||||
int cserialnos;
|
||||
/*Storage for the list of serial numbers from a single link.*/
|
||||
ogg_uint32_t *serialnos;
|
||||
/*This is the current offset of the data processed by the ogg_sync_state.
|
||||
After a seek, this should be set to the target offset so that we can track
|
||||
the byte offsets of subsequent pages.
|
||||
After a call to op_get_next_page(), this will point to the first byte after
|
||||
that page.*/
|
||||
opus_int64 offset;
|
||||
/*The total size of this data source, or -1 if it's unseekable.*/
|
||||
opus_int64 end;
|
||||
/*Used to locate pages in the data source.*/
|
||||
ogg_sync_state oy;
|
||||
/*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/
|
||||
int ready_state;
|
||||
/*The current link being played back.*/
|
||||
int cur_link;
|
||||
/*The number of decoded samples to discard from the start of decoding.*/
|
||||
opus_int32 cur_discard_count;
|
||||
/*The granule position of the previous packet (current packet start time).*/
|
||||
ogg_int64_t prev_packet_gp;
|
||||
/*The number of bytes read since the last bitrate query, including framing.*/
|
||||
opus_int64 bytes_tracked;
|
||||
/*The number of samples decoded since the last bitrate query.*/
|
||||
ogg_int64_t samples_tracked;
|
||||
/*Takes physical pages and welds them into a logical stream of packets.*/
|
||||
ogg_stream_state os;
|
||||
/*Re-timestamped packets from a single page.
|
||||
Buffering these relies on the undocumented libogg behavior that ogg_packet
|
||||
pointers remain valid until the next page is submitted to the
|
||||
ogg_stream_state they came from.*/
|
||||
ogg_packet op[255];
|
||||
/*The index of the next packet to return.*/
|
||||
int op_pos;
|
||||
/*The total number of packets available.*/
|
||||
int op_count;
|
||||
/*Central working state for the packet-to-PCM decoder.*/
|
||||
OpusMSDecoder *od;
|
||||
/*The application-provided packet decode callback.*/
|
||||
op_decode_cb_func decode_cb;
|
||||
/*The application-provided packet decode callback context.*/
|
||||
void *decode_cb_ctx;
|
||||
/*The stream count used to initialize the decoder.*/
|
||||
int od_stream_count;
|
||||
/*The coupled stream count used to initialize the decoder.*/
|
||||
int od_coupled_count;
|
||||
/*The channel count used to initialize the decoder.*/
|
||||
int od_channel_count;
|
||||
/*The channel mapping used to initialize the decoder.*/
|
||||
unsigned char od_mapping[OP_NCHANNELS_MAX];
|
||||
/*The buffered data for one decoded packet.*/
|
||||
op_sample *od_buffer;
|
||||
/*The current position in the decoded buffer.*/
|
||||
int od_buffer_pos;
|
||||
/*The number of valid samples in the decoded buffer.*/
|
||||
int od_buffer_size;
|
||||
/*The type of gain offset to apply.
|
||||
One of OP_HEADER_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
|
||||
int gain_type;
|
||||
/*The offset to apply to the gain.*/
|
||||
opus_int32 gain_offset_q8;
|
||||
/*Internal state for soft clipping and dithering float->short output.*/
|
||||
#if !defined(OPUS_FIXED_POINT)
|
||||
# if defined(OP_SOFT_CLIP)
|
||||
float clip_state[OP_NCHANNELS_MAX];
|
||||
# endif
|
||||
float dither_a[OP_NCHANNELS_MAX*4];
|
||||
float dither_b[OP_NCHANNELS_MAX*4];
|
||||
opus_uint32 dither_seed;
|
||||
int dither_mute;
|
||||
int dither_disabled;
|
||||
/*The number of channels represented by the internal state.
|
||||
This gets set to 0 whenever anything that would prevent state propagation
|
||||
occurs (switching between the float/short APIs, or between the
|
||||
stereo/multistream APIs).*/
|
||||
int state_channel_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
int op_strncasecmp(const char *_a,const char *_b,int _n);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#include <math.h>
|
||||
#include "mlp.h"
|
||||
#include "arch.h"
|
||||
#include "tansig_table.h"
|
||||
#define MAX_NEURONS 100
|
||||
|
||||
#if 0
|
||||
static OPUS_INLINE opus_val16 tansig_approx(opus_val32 _x) /* Q19 */
|
||||
{
|
||||
int i;
|
||||
opus_val16 xx; /* Q11 */
|
||||
/*double x, y;*/
|
||||
opus_val16 dy, yy; /* Q14 */
|
||||
/*x = 1.9073e-06*_x;*/
|
||||
if (_x>=QCONST32(8,19))
|
||||
return QCONST32(1.,14);
|
||||
if (_x<=-QCONST32(8,19))
|
||||
return -QCONST32(1.,14);
|
||||
xx = EXTRACT16(SHR32(_x, 8));
|
||||
/*i = lrint(25*x);*/
|
||||
i = SHR32(ADD32(1024,MULT16_16(25, xx)),11);
|
||||
/*x -= .04*i;*/
|
||||
xx -= EXTRACT16(SHR32(MULT16_16(20972,i),8));
|
||||
/*x = xx*(1./2048);*/
|
||||
/*y = tansig_table[250+i];*/
|
||||
yy = tansig_table[250+i];
|
||||
/*y = yy*(1./16384);*/
|
||||
dy = 16384-MULT16_16_Q14(yy,yy);
|
||||
yy = yy + MULT16_16_Q14(MULT16_16_Q11(xx,dy),(16384 - MULT16_16_Q11(yy,xx)));
|
||||
return yy;
|
||||
}
|
||||
#else
|
||||
/*extern const float tansig_table[501];*/
|
||||
static OPUS_INLINE float tansig_approx(float x)
|
||||
{
|
||||
int i;
|
||||
float y, dy;
|
||||
float sign=1;
|
||||
/* Tests are reversed to catch NaNs */
|
||||
if (!(x<8))
|
||||
return 1;
|
||||
if (!(x>-8))
|
||||
return -1;
|
||||
if (x<0)
|
||||
{
|
||||
x=-x;
|
||||
sign=-1;
|
||||
}
|
||||
i = (int)floor(.5f+25*x);
|
||||
x -= .04f*i;
|
||||
y = tansig_table[i];
|
||||
dy = 1-y*y;
|
||||
y = y + x*dy*(1 - y*x);
|
||||
return sign*y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void mlp_process(const MLP *m, const opus_val16 *in, opus_val16 *out)
|
||||
{
|
||||
int j;
|
||||
opus_val16 hidden[MAX_NEURONS];
|
||||
const opus_val16 *W = m->weights;
|
||||
/* Copy to tmp_in */
|
||||
for (j=0;j<m->topo[1];j++)
|
||||
{
|
||||
int k;
|
||||
opus_val32 sum = SHL32(EXTEND32(*W++),8);
|
||||
for (k=0;k<m->topo[0];k++)
|
||||
sum = MAC16_16(sum, in[k],*W++);
|
||||
hidden[j] = tansig_approx(sum);
|
||||
}
|
||||
for (j=0;j<m->topo[2];j++)
|
||||
{
|
||||
int k;
|
||||
opus_val32 sum = SHL32(EXTEND32(*W++),14);
|
||||
for (k=0;k<m->topo[1];k++)
|
||||
sum = MAC16_16(sum, hidden[k], *W++);
|
||||
out[j] = tansig_approx(EXTRACT16(PSHR32(sum,17)));
|
||||
}
|
||||
}
|
||||
#else
|
||||
void mlp_process(const MLP *m, const float *in, float *out)
|
||||
{
|
||||
int j;
|
||||
float hidden[MAX_NEURONS];
|
||||
const float *W = m->weights;
|
||||
/* Copy to tmp_in */
|
||||
for (j=0;j<m->topo[1];j++)
|
||||
{
|
||||
int k;
|
||||
float sum = *W++;
|
||||
for (k=0;k<m->topo[0];k++)
|
||||
sum = sum + in[k]**W++;
|
||||
hidden[j] = tansig_approx(sum);
|
||||
}
|
||||
for (j=0;j<m->topo[2];j++)
|
||||
{
|
||||
int k;
|
||||
float sum = *W++;
|
||||
for (k=0;k<m->topo[1];k++)
|
||||
sum = sum + hidden[k]**W++;
|
||||
out[j] = tansig_approx(sum);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _MLP_H_
|
||||
#define _MLP_H_
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
typedef struct {
|
||||
int layers;
|
||||
const int *topo;
|
||||
const float *weights;
|
||||
} MLP;
|
||||
|
||||
void mlp_process(const MLP *m, const float *in, float *out);
|
||||
|
||||
#endif /* _MLP_H_ */
|
|
@ -0,0 +1,105 @@
|
|||
/* The contents of this file was automatically generated by mlp_train.c
|
||||
It contains multi-layer perceptron (MLP) weights. */
|
||||
|
||||
#include "mlp.h"
|
||||
|
||||
/* RMS error was 0.138320, seed was 1361535663 */
|
||||
|
||||
static const float weights[422] = {
|
||||
|
||||
/* hidden layer */
|
||||
-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
|
||||
-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
|
||||
-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
|
||||
0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
|
||||
0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
|
||||
24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
|
||||
-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
|
||||
-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
|
||||
-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
|
||||
1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
|
||||
15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
|
||||
0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
|
||||
-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
|
||||
0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
|
||||
0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
|
||||
-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
|
||||
-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
|
||||
-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
|
||||
0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
|
||||
-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
|
||||
2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
|
||||
0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
|
||||
-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
|
||||
0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
|
||||
0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
|
||||
-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
|
||||
5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
|
||||
-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
|
||||
-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
|
||||
-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
|
||||
1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
|
||||
-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
|
||||
-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
|
||||
0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
|
||||
0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
|
||||
-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
|
||||
10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
|
||||
-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
|
||||
-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
|
||||
-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
|
||||
0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
|
||||
-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
|
||||
0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
|
||||
0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
|
||||
-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
|
||||
0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
|
||||
-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
|
||||
-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
|
||||
-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
|
||||
-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
|
||||
-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
|
||||
5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
|
||||
1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
|
||||
0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
|
||||
-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
|
||||
0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
|
||||
-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
|
||||
-975268.f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
|
||||
0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
|
||||
-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
|
||||
-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
|
||||
0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
|
||||
-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
|
||||
0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
|
||||
-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
|
||||
-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
|
||||
0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
|
||||
-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
|
||||
0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
|
||||
-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
|
||||
0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
|
||||
-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
|
||||
4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
|
||||
0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
|
||||
-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
|
||||
0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
|
||||
0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
|
||||
3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
|
||||
|
||||
/* output layer */
|
||||
-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
|
||||
0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
|
||||
0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
|
||||
0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
|
||||
4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
|
||||
-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
|
||||
3.87308f, 3.52558f};
|
||||
|
||||
static const int topo[3] = {25, 15, 2};
|
||||
|
||||
const MLP net = {
|
||||
3,
|
||||
topo,
|
||||
weights
|
||||
};
|
|
@ -0,0 +1,329 @@
|
|||
/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited
|
||||
Written by Jean-Marc Valin and Koen Vos */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
#include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#include "opus.h"
|
||||
#include "opus_private.h"
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
float *x;
|
||||
|
||||
if (C<1 || N<1 || !_x || !declip_mem) return;
|
||||
|
||||
/* First thing: saturate everything to +/- 2 which is the highest level our
|
||||
non-linearity can handle. At the point where the signal reaches +/-2,
|
||||
the derivative will be zero anyway, so this doesn't introduce any
|
||||
discontinuity in the derivative. */
|
||||
for (i=0;i<N*C;i++)
|
||||
_x[i] = MAX16(-2.f, MIN16(2.f, _x[i]));
|
||||
for (c=0;c<C;c++)
|
||||
{
|
||||
float a;
|
||||
float x0;
|
||||
int curr;
|
||||
|
||||
x = _x+c;
|
||||
a = declip_mem[c];
|
||||
/* Continue applying the non-linearity from the previous frame to avoid
|
||||
any discontinuity. */
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
if (x[i*C]*a>=0)
|
||||
break;
|
||||
x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
|
||||
}
|
||||
|
||||
curr=0;
|
||||
x0 = x[0];
|
||||
while(1)
|
||||
{
|
||||
int start, end;
|
||||
float maxval;
|
||||
int special=0;
|
||||
int peak_pos;
|
||||
for (i=curr;i<N;i++)
|
||||
{
|
||||
if (x[i*C]>1 || x[i*C]<-1)
|
||||
break;
|
||||
}
|
||||
if (i==N)
|
||||
{
|
||||
a=0;
|
||||
break;
|
||||
}
|
||||
peak_pos = i;
|
||||
start=end=i;
|
||||
maxval=ABS16(x[i*C]);
|
||||
/* Look for first zero crossing before clipping */
|
||||
while (start>0 && x[i*C]*x[(start-1)*C]>=0)
|
||||
start--;
|
||||
/* Look for first zero crossing after clipping */
|
||||
while (end<N && x[i*C]*x[end*C]>=0)
|
||||
{
|
||||
/* Look for other peaks until the next zero-crossing. */
|
||||
if (ABS16(x[end*C])>maxval)
|
||||
{
|
||||
maxval = ABS16(x[end*C]);
|
||||
peak_pos = end;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
/* Detect the special case where we clip before the first zero crossing */
|
||||
special = (start==0 && x[i*C]*x[0]>=0);
|
||||
|
||||
/* Compute a such that maxval + a*maxval^2 = 1 */
|
||||
a=(maxval-1)/(maxval*maxval);
|
||||
if (x[i*C]>0)
|
||||
a = -a;
|
||||
/* Apply soft clipping */
|
||||
for (i=start;i<end;i++)
|
||||
x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
|
||||
|
||||
if (special && peak_pos>=2)
|
||||
{
|
||||
/* Add a linear ramp from the first sample to the signal peak.
|
||||
This avoids a discontinuity at the beginning of the frame. */
|
||||
float delta;
|
||||
float offset = x0-x[0];
|
||||
delta = offset / peak_pos;
|
||||
for (i=curr;i<peak_pos;i++)
|
||||
{
|
||||
offset -= delta;
|
||||
x[i*C] += offset;
|
||||
x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C]));
|
||||
}
|
||||
}
|
||||
curr = end;
|
||||
if (curr==N)
|
||||
break;
|
||||
}
|
||||
declip_mem[c] = a;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int encode_size(int size, unsigned char *data)
|
||||
{
|
||||
if (size < 252)
|
||||
{
|
||||
data[0] = size;
|
||||
return 1;
|
||||
} else {
|
||||
data[0] = 252+(size&0x3);
|
||||
data[1] = (size-(int)data[0])>>2;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
|
||||
{
|
||||
if (len<1)
|
||||
{
|
||||
*size = -1;
|
||||
return -1;
|
||||
} else if (data[0]<252)
|
||||
{
|
||||
*size = data[0];
|
||||
return 1;
|
||||
} else if (len<2)
|
||||
{
|
||||
*size = -1;
|
||||
return -1;
|
||||
} else {
|
||||
*size = 4*data[1] + data[0];
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
|
||||
int self_delimited, unsigned char *out_toc,
|
||||
const unsigned char *frames[48], opus_int16 size[48],
|
||||
int *payload_offset, opus_int32 *packet_offset)
|
||||
{
|
||||
int i, bytes;
|
||||
int count;
|
||||
int cbr;
|
||||
unsigned char ch, toc;
|
||||
int framesize;
|
||||
opus_int32 last_size;
|
||||
opus_int32 pad = 0;
|
||||
const unsigned char *data0 = data;
|
||||
|
||||
if (size==NULL)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
framesize = opus_packet_get_samples_per_frame(data, 48000);
|
||||
|
||||
cbr = 0;
|
||||
toc = *data++;
|
||||
len--;
|
||||
last_size = len;
|
||||
switch (toc&0x3)
|
||||
{
|
||||
/* One frame */
|
||||
case 0:
|
||||
count=1;
|
||||
break;
|
||||
/* Two CBR frames */
|
||||
case 1:
|
||||
count=2;
|
||||
cbr = 1;
|
||||
if (!self_delimited)
|
||||
{
|
||||
if (len&0x1)
|
||||
return OPUS_INVALID_PACKET;
|
||||
last_size = len/2;
|
||||
/* If last_size doesn't fit in size[0], we'll catch it later */
|
||||
size[0] = (opus_int16)last_size;
|
||||
}
|
||||
break;
|
||||
/* Two VBR frames */
|
||||
case 2:
|
||||
count = 2;
|
||||
bytes = parse_size(data, len, size);
|
||||
len -= bytes;
|
||||
if (size[0]<0 || size[0] > len)
|
||||
return OPUS_INVALID_PACKET;
|
||||
data += bytes;
|
||||
last_size = len-size[0];
|
||||
break;
|
||||
/* Multiple CBR/VBR frames (from 0 to 120 ms) */
|
||||
default: /*case 3:*/
|
||||
if (len<1)
|
||||
return OPUS_INVALID_PACKET;
|
||||
/* Number of frames encoded in bits 0 to 5 */
|
||||
ch = *data++;
|
||||
count = ch&0x3F;
|
||||
if (count <= 0 || framesize*count > 5760)
|
||||
return OPUS_INVALID_PACKET;
|
||||
len--;
|
||||
/* Padding flag is bit 6 */
|
||||
if (ch&0x40)
|
||||
{
|
||||
int p;
|
||||
do {
|
||||
int tmp;
|
||||
if (len<=0)
|
||||
return OPUS_INVALID_PACKET;
|
||||
p = *data++;
|
||||
len--;
|
||||
tmp = p==255 ? 254: p;
|
||||
len -= tmp;
|
||||
pad += tmp;
|
||||
} while (p==255);
|
||||
}
|
||||
if (len<0)
|
||||
return OPUS_INVALID_PACKET;
|
||||
/* VBR flag is bit 7 */
|
||||
cbr = !(ch&0x80);
|
||||
if (!cbr)
|
||||
{
|
||||
/* VBR case */
|
||||
last_size = len;
|
||||
for (i=0;i<count-1;i++)
|
||||
{
|
||||
bytes = parse_size(data, len, size+i);
|
||||
len -= bytes;
|
||||
if (size[i]<0 || size[i] > len)
|
||||
return OPUS_INVALID_PACKET;
|
||||
data += bytes;
|
||||
last_size -= bytes+size[i];
|
||||
}
|
||||
if (last_size<0)
|
||||
return OPUS_INVALID_PACKET;
|
||||
} else if (!self_delimited)
|
||||
{
|
||||
/* CBR case */
|
||||
last_size = len/count;
|
||||
if (last_size*count!=len)
|
||||
return OPUS_INVALID_PACKET;
|
||||
for (i=0;i<count-1;i++)
|
||||
size[i] = (opus_int16)last_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Self-delimited framing has an extra size for the last frame. */
|
||||
if (self_delimited)
|
||||
{
|
||||
bytes = parse_size(data, len, size+count-1);
|
||||
len -= bytes;
|
||||
if (size[count-1]<0 || size[count-1] > len)
|
||||
return OPUS_INVALID_PACKET;
|
||||
data += bytes;
|
||||
/* For CBR packets, apply the size to all the frames. */
|
||||
if (cbr)
|
||||
{
|
||||
if (size[count-1]*count > len)
|
||||
return OPUS_INVALID_PACKET;
|
||||
for (i=0;i<count-1;i++)
|
||||
size[i] = size[count-1];
|
||||
} else if (bytes+size[count-1] > last_size)
|
||||
return OPUS_INVALID_PACKET;
|
||||
} else
|
||||
{
|
||||
/* Because it's not encoded explicitly, it's possible the size of the
|
||||
last packet (or all the packets, for the CBR case) is larger than
|
||||
1275. Reject them here.*/
|
||||
if (last_size > 1275)
|
||||
return OPUS_INVALID_PACKET;
|
||||
size[count-1] = (opus_int16)last_size;
|
||||
}
|
||||
|
||||
if (payload_offset)
|
||||
*payload_offset = (int)(data-data0);
|
||||
|
||||
for (i=0;i<count;i++)
|
||||
{
|
||||
if (frames)
|
||||
frames[i] = data;
|
||||
data += size[i];
|
||||
}
|
||||
|
||||
if (packet_offset)
|
||||
*packet_offset = pad+(opus_int32)(data-data0);
|
||||
|
||||
if (out_toc)
|
||||
*out_toc = toc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int opus_packet_parse(const unsigned char *data, opus_int32 len,
|
||||
unsigned char *out_toc, const unsigned char *frames[48],
|
||||
opus_int16 size[48], int *payload_offset)
|
||||
{
|
||||
return opus_packet_parse_impl(data, len, 0, out_toc,
|
||||
frames, size, payload_offset, NULL);
|
||||
}
|
||||
|
|
@ -0,0 +1,978 @@
|
|||
/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
|
||||
Written by Jean-Marc Valin and Koen Vos */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file opus.h
|
||||
* @brief Opus reference implementation API
|
||||
*/
|
||||
|
||||
#ifndef OPUS_H
|
||||
#define OPUS_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @mainpage Opus
|
||||
*
|
||||
* The Opus codec is designed for interactive speech and audio transmission over the Internet.
|
||||
* It is designed by the IETF Codec Working Group and incorporates technology from
|
||||
* Skype's SILK codec and Xiph.Org's CELT codec.
|
||||
*
|
||||
* The Opus codec is designed to handle a wide range of interactive audio applications,
|
||||
* including Voice over IP, videoconferencing, in-game chat, and even remote live music
|
||||
* performances. It can scale from low bit-rate narrowband speech to very high quality
|
||||
* stereo music. Its main features are:
|
||||
|
||||
* @li Sampling rates from 8 to 48 kHz
|
||||
* @li Bit-rates from 6 kb/s to 510 kb/s
|
||||
* @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
|
||||
* @li Audio bandwidth from narrowband to full-band
|
||||
* @li Support for speech and music
|
||||
* @li Support for mono and stereo
|
||||
* @li Support for multichannel (up to 255 channels)
|
||||
* @li Frame sizes from 2.5 ms to 60 ms
|
||||
* @li Good loss robustness and packet loss concealment (PLC)
|
||||
* @li Floating point and fixed-point implementation
|
||||
*
|
||||
* Documentation sections:
|
||||
* @li @ref opus_encoder
|
||||
* @li @ref opus_decoder
|
||||
* @li @ref opus_repacketizer
|
||||
* @li @ref opus_multistream
|
||||
* @li @ref opus_libinfo
|
||||
* @li @ref opus_custom
|
||||
*/
|
||||
|
||||
/** @defgroup opus_encoder Opus Encoder
|
||||
* @{
|
||||
*
|
||||
* @brief This page describes the process and functions used to encode Opus.
|
||||
*
|
||||
* Since Opus is a stateful codec, the encoding process starts with creating an encoder
|
||||
* state. This can be done with:
|
||||
*
|
||||
* @code
|
||||
* int error;
|
||||
* OpusEncoder *enc;
|
||||
* enc = opus_encoder_create(Fs, channels, application, &error);
|
||||
* @endcode
|
||||
*
|
||||
* From this point, @c enc can be used for encoding an audio stream. An encoder state
|
||||
* @b must @b not be used for more than one stream at the same time. Similarly, the encoder
|
||||
* state @b must @b not be re-initialized for each frame.
|
||||
*
|
||||
* While opus_encoder_create() allocates memory for the state, it's also possible
|
||||
* to initialize pre-allocated memory:
|
||||
*
|
||||
* @code
|
||||
* int size;
|
||||
* int error;
|
||||
* OpusEncoder *enc;
|
||||
* size = opus_encoder_get_size(channels);
|
||||
* enc = malloc(size);
|
||||
* error = opus_encoder_init(enc, Fs, channels, application);
|
||||
* @endcode
|
||||
*
|
||||
* where opus_encoder_get_size() returns the required size for the encoder state. Note that
|
||||
* future versions of this code may change the size, so no assuptions should be made about it.
|
||||
*
|
||||
* The encoder state is always continuous in memory and only a shallow copy is sufficient
|
||||
* to copy it (e.g. memcpy())
|
||||
*
|
||||
* It is possible to change some of the encoder's settings using the opus_encoder_ctl()
|
||||
* interface. All these settings already default to the recommended value, so they should
|
||||
* only be changed when necessary. The most common settings one may want to change are:
|
||||
*
|
||||
* @code
|
||||
* opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
|
||||
* opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
|
||||
* opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
|
||||
* @endcode
|
||||
*
|
||||
* where
|
||||
*
|
||||
* @arg bitrate is in bits per second (b/s)
|
||||
* @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
|
||||
* @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
|
||||
*
|
||||
* See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
|
||||
*
|
||||
* To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
|
||||
* @code
|
||||
* len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
|
||||
* @endcode
|
||||
*
|
||||
* where
|
||||
* <ul>
|
||||
* <li>audio_frame is the audio data in opus_int16 (or float for opus_encode_float())</li>
|
||||
* <li>frame_size is the duration of the frame in samples (per channel)</li>
|
||||
* <li>packet is the byte array to which the compressed data is written</li>
|
||||
* <li>max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
|
||||
* Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.</li>
|
||||
* </ul>
|
||||
*
|
||||
* opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
|
||||
* The return value <b>can be negative</b>, which indicates that an error has occurred. If the return value
|
||||
* is 1 byte, then the packet does not need to be transmitted (DTX).
|
||||
*
|
||||
* Once the encoder state if no longer needed, it can be destroyed with
|
||||
*
|
||||
* @code
|
||||
* opus_encoder_destroy(enc);
|
||||
* @endcode
|
||||
*
|
||||
* If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
|
||||
* then no action is required aside from potentially freeing the memory that was manually
|
||||
* allocated for it (calling free(enc) for the example above)
|
||||
*
|
||||
*/
|
||||
|
||||
/** Opus encoder state.
|
||||
* This contains the complete state of an Opus encoder.
|
||||
* It is position independent and can be freely copied.
|
||||
* @see opus_encoder_create,opus_encoder_init
|
||||
*/
|
||||
typedef struct OpusEncoder OpusEncoder;
|
||||
|
||||
/** Gets the size of an <code>OpusEncoder</code> structure.
|
||||
* @param[in] channels <tt>int</tt>: Number of channels.
|
||||
* This must be 1 or 2.
|
||||
* @returns The size in bytes.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
/** Allocates and initializes an encoder state.
|
||||
* There are three coding modes:
|
||||
*
|
||||
* @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
|
||||
* signals. It enhances the input signal by high-pass filtering and
|
||||
* emphasizing formants and harmonics. Optionally it includes in-band
|
||||
* forward error correction to protect against packet loss. Use this
|
||||
* mode for typical VoIP applications. Because of the enhancement,
|
||||
* even at high bitrates the output may sound different from the input.
|
||||
*
|
||||
* @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
|
||||
* non-voice signals like music. Use this mode for music and mixed
|
||||
* (music/voice) content, broadcast, and applications requiring less
|
||||
* than 15 ms of coding delay.
|
||||
*
|
||||
* @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
|
||||
* disables the speech-optimized mode in exchange for slightly reduced delay.
|
||||
* This mode can only be set on an newly initialized or freshly reset encoder
|
||||
* because it changes the codec delay.
|
||||
*
|
||||
* This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
||||
* @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
||||
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
|
||||
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
|
||||
* can switch to a lower audio bandwidth or number of channels if the bitrate
|
||||
* selected is too low. This also means that it is safe to always use 48 kHz stereo input
|
||||
* and let the encoder optimize the encoding.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int application,
|
||||
int *error
|
||||
);
|
||||
|
||||
/** Initializes a previously allocated encoder state
|
||||
* The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_encoder_create(),opus_encoder_get_size()
|
||||
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusEncoder*</tt>: Encoder state
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
||||
* @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
||||
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_EXPORT int opus_encoder_init(
|
||||
OpusEncoder *st,
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int application
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Encodes an Opus frame.
|
||||
* @param [in] st <tt>OpusEncoder*</tt>: Encoder state
|
||||
* @param [in] pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
|
||||
* input signal.
|
||||
* This must be an Opus frame size for
|
||||
* the encoder's sampling rate.
|
||||
* For example, at 48 kHz the permitted
|
||||
* values are 120, 240, 480, 960, 1920,
|
||||
* and 2880.
|
||||
* Passing in a duration of less than
|
||||
* 10 ms (480 samples at 48 kHz) will
|
||||
* prevent the encoder from using the LPC
|
||||
* or hybrid modes.
|
||||
* @param [out] data <tt>unsigned char*</tt>: Output payload.
|
||||
* This must contain storage for at
|
||||
* least \a max_data_bytes.
|
||||
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
|
||||
* memory for the output
|
||||
* payload. This may be
|
||||
* used to impose an upper limit on
|
||||
* the instant bitrate, but should
|
||||
* not be used as the only bitrate
|
||||
* control. Use #OPUS_SET_BITRATE to
|
||||
* control the bitrate.
|
||||
* @returns The length of the encoded packet (in bytes) on success or a
|
||||
* negative error code (see @ref opus_errorcodes) on failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
|
||||
OpusEncoder *st,
|
||||
const opus_int16 *pcm,
|
||||
int frame_size,
|
||||
unsigned char *data,
|
||||
opus_int32 max_data_bytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Encodes an Opus frame from floating point input.
|
||||
* @param [in] st <tt>OpusEncoder*</tt>: Encoder state
|
||||
* @param [in] pcm <tt>float*</tt>: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
|
||||
* Samples with a range beyond +/-1.0 are supported but will
|
||||
* be clipped by decoders using the integer API and should
|
||||
* only be used if it is known that the far end supports
|
||||
* extended dynamic range.
|
||||
* length is frame_size*channels*sizeof(float)
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
|
||||
* input signal.
|
||||
* This must be an Opus frame size for
|
||||
* the encoder's sampling rate.
|
||||
* For example, at 48 kHz the permitted
|
||||
* values are 120, 240, 480, 960, 1920,
|
||||
* and 2880.
|
||||
* Passing in a duration of less than
|
||||
* 10 ms (480 samples at 48 kHz) will
|
||||
* prevent the encoder from using the LPC
|
||||
* or hybrid modes.
|
||||
* @param [out] data <tt>unsigned char*</tt>: Output payload.
|
||||
* This must contain storage for at
|
||||
* least \a max_data_bytes.
|
||||
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
|
||||
* memory for the output
|
||||
* payload. This may be
|
||||
* used to impose an upper limit on
|
||||
* the instant bitrate, but should
|
||||
* not be used as the only bitrate
|
||||
* control. Use #OPUS_SET_BITRATE to
|
||||
* control the bitrate.
|
||||
* @returns The length of the encoded packet (in bytes) on success or a
|
||||
* negative error code (see @ref opus_errorcodes) on failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
|
||||
OpusEncoder *st,
|
||||
const float *pcm,
|
||||
int frame_size,
|
||||
unsigned char *data,
|
||||
opus_int32 max_data_bytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Frees an <code>OpusEncoder</code> allocated by opus_encoder_create().
|
||||
* @param[in] st <tt>OpusEncoder*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
|
||||
|
||||
/** Perform a CTL function on an Opus encoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated
|
||||
* by a convenience macro.
|
||||
* @param st <tt>OpusEncoder*</tt>: Encoder state.
|
||||
* @param request This and all remaining parameters should be replaced by one
|
||||
* of the convenience macros in @ref opus_genericctls or
|
||||
* @ref opus_encoderctls.
|
||||
* @see opus_genericctls
|
||||
* @see opus_encoderctls
|
||||
*/
|
||||
OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_decoder Opus Decoder
|
||||
* @{
|
||||
*
|
||||
* @brief This page describes the process and functions used to decode Opus.
|
||||
*
|
||||
* The decoding process also starts with creating a decoder
|
||||
* state. This can be done with:
|
||||
* @code
|
||||
* int error;
|
||||
* OpusDecoder *dec;
|
||||
* dec = opus_decoder_create(Fs, channels, &error);
|
||||
* @endcode
|
||||
* where
|
||||
* @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
|
||||
* @li channels is the number of channels (1 or 2)
|
||||
* @li error will hold the error code in case of failure (or #OPUS_OK on success)
|
||||
* @li the return value is a newly created decoder state to be used for decoding
|
||||
*
|
||||
* While opus_decoder_create() allocates memory for the state, it's also possible
|
||||
* to initialize pre-allocated memory:
|
||||
* @code
|
||||
* int size;
|
||||
* int error;
|
||||
* OpusDecoder *dec;
|
||||
* size = opus_decoder_get_size(channels);
|
||||
* dec = malloc(size);
|
||||
* error = opus_decoder_init(dec, Fs, channels);
|
||||
* @endcode
|
||||
* where opus_decoder_get_size() returns the required size for the decoder state. Note that
|
||||
* future versions of this code may change the size, so no assuptions should be made about it.
|
||||
*
|
||||
* The decoder state is always continuous in memory and only a shallow copy is sufficient
|
||||
* to copy it (e.g. memcpy())
|
||||
*
|
||||
* To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
|
||||
* @code
|
||||
* frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
|
||||
* @endcode
|
||||
* where
|
||||
*
|
||||
* @li packet is the byte array containing the compressed data
|
||||
* @li len is the exact number of bytes contained in the packet
|
||||
* @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
|
||||
* @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
|
||||
*
|
||||
* opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
|
||||
* If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
|
||||
* buffer is too small to hold the decoded audio.
|
||||
*
|
||||
* Opus is a stateful codec with overlapping blocks and as a result Opus
|
||||
* packets are not coded independently of each other. Packets must be
|
||||
* passed into the decoder serially and in the correct order for a correct
|
||||
* decode. Lost packets can be replaced with loss concealment by calling
|
||||
* the decoder with a null pointer and zero length for the missing packet.
|
||||
*
|
||||
* A single codec state may only be accessed from a single thread at
|
||||
* a time and any required locking must be performed by the caller. Separate
|
||||
* streams must be decoded with separate decoder states and can be decoded
|
||||
* in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
|
||||
* defined.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Opus decoder state.
|
||||
* This contains the complete state of an Opus decoder.
|
||||
* It is position independent and can be freely copied.
|
||||
* @see opus_decoder_create,opus_decoder_init
|
||||
*/
|
||||
typedef struct OpusDecoder OpusDecoder;
|
||||
|
||||
/** Gets the size of an <code>OpusDecoder</code> structure.
|
||||
* @param [in] channels <tt>int</tt>: Number of channels.
|
||||
* This must be 1 or 2.
|
||||
* @returns The size in bytes.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
|
||||
|
||||
/** Allocates and initializes a decoder state.
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sample rate to decode at (Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
|
||||
* @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
|
||||
*
|
||||
* Internally Opus stores data at 48000 Hz, so that should be the default
|
||||
* value for Fs. However, the decoder can efficiently decode to buffers
|
||||
* at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
|
||||
* data at the full sample rate, or knows the compressed data doesn't
|
||||
* use the full frequency range, it can request decoding at a reduced
|
||||
* rate. Likewise, the decoder is capable of filling in either mono or
|
||||
* interleaved stereo pcm buffers, at the caller's request.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int *error
|
||||
);
|
||||
|
||||
/** Initializes a previously allocated decoder state.
|
||||
* The state must be at least the size returned by opus_decoder_get_size().
|
||||
* This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
|
||||
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state.
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
|
||||
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_EXPORT int opus_decoder_init(
|
||||
OpusDecoder *st,
|
||||
opus_int32 Fs,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Decode an Opus packet.
|
||||
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
|
||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
||||
* @param [in] len <tt>opus_int32</tt>: Number of bytes in payload*
|
||||
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
||||
* is frame_size*channels*sizeof(opus_int16)
|
||||
* @param [in] frame_size Number of samples per channel of available space in \a pcm.
|
||||
* If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
|
||||
* not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
|
||||
* then frame_size needs to be exactly the duration of audio that is missing, otherwise the
|
||||
* decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
|
||||
* FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
|
||||
* @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
|
||||
* decoded. If no such data is available, the frame is decoded as if it were lost.
|
||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
|
||||
OpusDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
opus_int16 *pcm,
|
||||
int frame_size,
|
||||
int decode_fec
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Decode an Opus packet with floating point output.
|
||||
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
|
||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
||||
* @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
|
||||
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
||||
* is frame_size*channels*sizeof(float)
|
||||
* @param [in] frame_size Number of samples per channel of available space in \a pcm.
|
||||
* If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
|
||||
* not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
|
||||
* then frame_size needs to be exactly the duration of audio that is missing, otherwise the
|
||||
* decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
|
||||
* FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
|
||||
* @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
|
||||
* decoded. If no such data is available the frame is decoded as if it were lost.
|
||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
|
||||
OpusDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
float *pcm,
|
||||
int frame_size,
|
||||
int decode_fec
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Perform a CTL function on an Opus decoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated
|
||||
* by a convenience macro.
|
||||
* @param st <tt>OpusDecoder*</tt>: Decoder state.
|
||||
* @param request This and all remaining parameters should be replaced by one
|
||||
* of the convenience macros in @ref opus_genericctls or
|
||||
* @ref opus_decoderctls.
|
||||
* @see opus_genericctls
|
||||
* @see opus_decoderctls
|
||||
*/
|
||||
OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Frees an <code>OpusDecoder</code> allocated by opus_decoder_create().
|
||||
* @param[in] st <tt>OpusDecoder*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
|
||||
|
||||
/** Parse an opus packet into one or more frames.
|
||||
* Opus_decode will perform this operation internally so most applications do
|
||||
* not need to use this function.
|
||||
* This function does not copy the frames, the returned pointers are pointers into
|
||||
* the input packet.
|
||||
* @param [in] data <tt>char*</tt>: Opus packet to be parsed
|
||||
* @param [in] len <tt>opus_int32</tt>: size of data
|
||||
* @param [out] out_toc <tt>char*</tt>: TOC pointer
|
||||
* @param [out] frames <tt>char*[48]</tt> encapsulated frames
|
||||
* @param [out] size <tt>opus_int16[48]</tt> sizes of the encapsulated frames
|
||||
* @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)
|
||||
* @returns number of frames
|
||||
*/
|
||||
OPUS_EXPORT int opus_packet_parse(
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
unsigned char *out_toc,
|
||||
const unsigned char *frames[48],
|
||||
opus_int16 size[48],
|
||||
int *payload_offset
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Gets the bandwidth of an Opus packet.
|
||||
* @param [in] data <tt>char*</tt>: Opus packet
|
||||
* @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
|
||||
* @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
|
||||
* @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
|
||||
* @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
|
||||
* @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
|
||||
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Gets the number of samples per frame from an Opus packet.
|
||||
* @param [in] data <tt>char*</tt>: Opus packet.
|
||||
* This must contain at least one byte of
|
||||
* data.
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
|
||||
* This must be a multiple of 400, or
|
||||
* inaccurate results will be returned.
|
||||
* @returns Number of samples per frame.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Gets the number of channels from an Opus packet.
|
||||
* @param [in] data <tt>char*</tt>: Opus packet
|
||||
* @returns Number of channels
|
||||
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Gets the number of frames in an Opus packet.
|
||||
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||
* @param [in] len <tt>opus_int32</tt>: Length of packet
|
||||
* @returns Number of frames
|
||||
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
|
||||
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Gets the number of samples of an Opus packet.
|
||||
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||
* @param [in] len <tt>opus_int32</tt>: Length of packet
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
|
||||
* This must be a multiple of 400, or
|
||||
* inaccurate results will be returned.
|
||||
* @returns Number of samples
|
||||
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
|
||||
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Gets the number of samples of an Opus packet.
|
||||
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
|
||||
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||
* @param [in] len <tt>opus_int32</tt>: Length of packet
|
||||
* @returns Number of samples
|
||||
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
|
||||
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
|
||||
* the signal is already in that range, nothing is done. If there are values
|
||||
* outside of [-1,1], then the signal is clipped as smoothly as possible to
|
||||
* both fit in the range and avoid creating excessive distortion in the
|
||||
* process.
|
||||
* @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
|
||||
* @param [in] frame_size <tt>int</tt> Number of samples per channel to process
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
|
||||
*/
|
||||
OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_repacketizer Repacketizer
|
||||
* @{
|
||||
*
|
||||
* The repacketizer can be used to merge multiple Opus packets into a single
|
||||
* packet or alternatively to split Opus packets that have previously been
|
||||
* merged. Splitting valid Opus packets is always guaranteed to succeed,
|
||||
* whereas merging valid packets only succeeds if all frames have the same
|
||||
* mode, bandwidth, and frame size, and when the total duration of the merged
|
||||
* packet is no more than 120 ms.
|
||||
* The repacketizer currently only operates on elementary Opus
|
||||
* streams. It will not manipualte multistream packets successfully, except in
|
||||
* the degenerate case where they consist of data from a single stream.
|
||||
*
|
||||
* The repacketizing process starts with creating a repacketizer state, either
|
||||
* by calling opus_repacketizer_create() or by allocating the memory yourself,
|
||||
* e.g.,
|
||||
* @code
|
||||
* OpusRepacketizer *rp;
|
||||
* rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
|
||||
* if (rp != NULL)
|
||||
* opus_repacketizer_init(rp);
|
||||
* @endcode
|
||||
*
|
||||
* Then the application should submit packets with opus_repacketizer_cat(),
|
||||
* extract new packets with opus_repacketizer_out() or
|
||||
* opus_repacketizer_out_range(), and then reset the state for the next set of
|
||||
* input packets via opus_repacketizer_init().
|
||||
*
|
||||
* For example, to split a sequence of packets into individual frames:
|
||||
* @code
|
||||
* unsigned char *data;
|
||||
* int len;
|
||||
* while (get_next_packet(&data, &len))
|
||||
* {
|
||||
* unsigned char out[1276];
|
||||
* opus_int32 out_len;
|
||||
* int nb_frames;
|
||||
* int err;
|
||||
* int i;
|
||||
* err = opus_repacketizer_cat(rp, data, len);
|
||||
* if (err != OPUS_OK)
|
||||
* {
|
||||
* release_packet(data);
|
||||
* return err;
|
||||
* }
|
||||
* nb_frames = opus_repacketizer_get_nb_frames(rp);
|
||||
* for (i = 0; i < nb_frames; i++)
|
||||
* {
|
||||
* out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
|
||||
* if (out_len < 0)
|
||||
* {
|
||||
* release_packet(data);
|
||||
* return (int)out_len;
|
||||
* }
|
||||
* output_next_packet(out, out_len);
|
||||
* }
|
||||
* opus_repacketizer_init(rp);
|
||||
* release_packet(data);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Alternatively, to combine a sequence of frames into packets that each
|
||||
* contain up to <code>TARGET_DURATION_MS</code> milliseconds of data:
|
||||
* @code
|
||||
* // The maximum number of packets with duration TARGET_DURATION_MS occurs
|
||||
* // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
|
||||
* // packets.
|
||||
* unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
|
||||
* opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
|
||||
* int nb_packets;
|
||||
* unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
|
||||
* opus_int32 out_len;
|
||||
* int prev_toc;
|
||||
* nb_packets = 0;
|
||||
* while (get_next_packet(data+nb_packets, len+nb_packets))
|
||||
* {
|
||||
* int nb_frames;
|
||||
* int err;
|
||||
* nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
|
||||
* if (nb_frames < 1)
|
||||
* {
|
||||
* release_packets(data, nb_packets+1);
|
||||
* return nb_frames;
|
||||
* }
|
||||
* nb_frames += opus_repacketizer_get_nb_frames(rp);
|
||||
* // If adding the next packet would exceed our target, or it has an
|
||||
* // incompatible TOC sequence, output the packets we already have before
|
||||
* // submitting it.
|
||||
* // N.B., The nb_packets > 0 check ensures we've submitted at least one
|
||||
* // packet since the last call to opus_repacketizer_init(). Otherwise a
|
||||
* // single packet longer than TARGET_DURATION_MS would cause us to try to
|
||||
* // output an (invalid) empty packet. It also ensures that prev_toc has
|
||||
* // been set to a valid value. Additionally, len[nb_packets] > 0 is
|
||||
* // guaranteed by the call to opus_packet_get_nb_frames() above, so the
|
||||
* // reference to data[nb_packets][0] should be valid.
|
||||
* if (nb_packets > 0 && (
|
||||
* ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
|
||||
* opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
|
||||
* TARGET_DURATION_MS*48))
|
||||
* {
|
||||
* out_len = opus_repacketizer_out(rp, out, sizeof(out));
|
||||
* if (out_len < 0)
|
||||
* {
|
||||
* release_packets(data, nb_packets+1);
|
||||
* return (int)out_len;
|
||||
* }
|
||||
* output_next_packet(out, out_len);
|
||||
* opus_repacketizer_init(rp);
|
||||
* release_packets(data, nb_packets);
|
||||
* data[0] = data[nb_packets];
|
||||
* len[0] = len[nb_packets];
|
||||
* nb_packets = 0;
|
||||
* }
|
||||
* err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
|
||||
* if (err != OPUS_OK)
|
||||
* {
|
||||
* release_packets(data, nb_packets+1);
|
||||
* return err;
|
||||
* }
|
||||
* prev_toc = data[nb_packets][0];
|
||||
* nb_packets++;
|
||||
* }
|
||||
* // Output the final, partial packet.
|
||||
* if (nb_packets > 0)
|
||||
* {
|
||||
* out_len = opus_repacketizer_out(rp, out, sizeof(out));
|
||||
* release_packets(data, nb_packets);
|
||||
* if (out_len < 0)
|
||||
* return (int)out_len;
|
||||
* output_next_packet(out, out_len);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* An alternate way of merging packets is to simply call opus_repacketizer_cat()
|
||||
* unconditionally until it fails. At that point, the merged packet can be
|
||||
* obtained with opus_repacketizer_out() and the input packet for which
|
||||
* opus_repacketizer_cat() needs to be re-added to a newly reinitialized
|
||||
* repacketizer state.
|
||||
*/
|
||||
|
||||
typedef struct OpusRepacketizer OpusRepacketizer;
|
||||
|
||||
/** Gets the size of an <code>OpusRepacketizer</code> structure.
|
||||
* @returns The size in bytes.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
|
||||
|
||||
/** (Re)initializes a previously allocated repacketizer state.
|
||||
* The state must be at least the size returned by opus_repacketizer_get_size().
|
||||
* This can be used for applications which use their own allocator instead of
|
||||
* malloc().
|
||||
* It must also be called to reset the queue of packets waiting to be
|
||||
* repacketized, which is necessary if the maximum packet duration of 120 ms
|
||||
* is reached or if you wish to submit packets with a different Opus
|
||||
* configuration (coding mode, audio bandwidth, frame size, or channel count).
|
||||
* Failure to do so will prevent a new packet from being added with
|
||||
* opus_repacketizer_cat().
|
||||
* @see opus_repacketizer_create
|
||||
* @see opus_repacketizer_get_size
|
||||
* @see opus_repacketizer_cat
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to
|
||||
* (re)initialize.
|
||||
* @returns A pointer to the same repacketizer state that was passed in.
|
||||
*/
|
||||
OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Allocates memory and initializes the new repacketizer with
|
||||
* opus_repacketizer_init().
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
|
||||
|
||||
/** Frees an <code>OpusRepacketizer</code> allocated by
|
||||
* opus_repacketizer_create().
|
||||
* @param[in] rp <tt>OpusRepacketizer*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
|
||||
|
||||
/** Add a packet to the current repacketizer state.
|
||||
* This packet must match the configuration of any packets already submitted
|
||||
* for repacketization since the last call to opus_repacketizer_init().
|
||||
* This means that it must have the same coding mode, audio bandwidth, frame
|
||||
* size, and channel count.
|
||||
* This can be checked in advance by examining the top 6 bits of the first
|
||||
* byte of the packet, and ensuring they match the top 6 bits of the first
|
||||
* byte of any previously submitted packet.
|
||||
* The total duration of audio in the repacketizer state also must not exceed
|
||||
* 120 ms, the maximum duration of a single packet, after adding this packet.
|
||||
*
|
||||
* The contents of the current repacketizer state can be extracted into new
|
||||
* packets using opus_repacketizer_out() or opus_repacketizer_out_range().
|
||||
*
|
||||
* In order to add a packet with a different configuration or to add more
|
||||
* audio beyond 120 ms, you must clear the repacketizer state by calling
|
||||
* opus_repacketizer_init().
|
||||
* If a packet is too large to add to the current repacketizer state, no part
|
||||
* of it is added, even if it contains multiple frames, some of which might
|
||||
* fit.
|
||||
* If you wish to be able to add parts of such packets, you should first use
|
||||
* another repacketizer to split the packet into pieces and add them
|
||||
* individually.
|
||||
* @see opus_repacketizer_out_range
|
||||
* @see opus_repacketizer_out
|
||||
* @see opus_repacketizer_init
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to
|
||||
* add the packet.
|
||||
* @param[in] data <tt>const unsigned char*</tt>: The packet data.
|
||||
* The application must ensure
|
||||
* this pointer remains valid
|
||||
* until the next call to
|
||||
* opus_repacketizer_init() or
|
||||
* opus_repacketizer_destroy().
|
||||
* @param len <tt>opus_int32</tt>: The number of bytes in the packet data.
|
||||
* @returns An error code indicating whether or not the operation succeeded.
|
||||
* @retval #OPUS_OK The packet's contents have been added to the repacketizer
|
||||
* state.
|
||||
* @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
|
||||
* the packet's TOC sequence was not compatible
|
||||
* with previously submitted packets (because
|
||||
* the coding mode, audio bandwidth, frame size,
|
||||
* or channel count did not match), or adding
|
||||
* this packet would increase the total amount of
|
||||
* audio stored in the repacketizer state to more
|
||||
* than 120 ms.
|
||||
*/
|
||||
OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
|
||||
/** Construct a new packet from data previously submitted to the repacketizer
|
||||
* state via opus_repacketizer_cat().
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
|
||||
* construct the new packet.
|
||||
* @param begin <tt>int</tt>: The index of the first frame in the current
|
||||
* repacketizer state to include in the output.
|
||||
* @param end <tt>int</tt>: One past the index of the last frame in the
|
||||
* current repacketizer state to include in the
|
||||
* output.
|
||||
* @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
|
||||
* store the output packet.
|
||||
* @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
|
||||
* the output buffer. In order to guarantee
|
||||
* success, this should be at least
|
||||
* <code>1276</code> for a single frame,
|
||||
* or for multiple frames,
|
||||
* <code>1277*(end-begin)</code>.
|
||||
* However, <code>1*(end-begin)</code> plus
|
||||
* the size of all packet data submitted to
|
||||
* the repacketizer since the last call to
|
||||
* opus_repacketizer_init() or
|
||||
* opus_repacketizer_create() is also
|
||||
* sufficient, and possibly much smaller.
|
||||
* @returns The total size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of
|
||||
* frames (begin < 0, begin >= end, or end >
|
||||
* opus_repacketizer_get_nb_frames()).
|
||||
* @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
|
||||
* complete output packet.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Return the total number of frames contained in packet data submitted to
|
||||
* the repacketizer state so far via opus_repacketizer_cat() since the last
|
||||
* call to opus_repacketizer_init() or opus_repacketizer_create().
|
||||
* This defines the valid range of packets that can be extracted with
|
||||
* opus_repacketizer_out_range() or opus_repacketizer_out().
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the
|
||||
* frames.
|
||||
* @returns The total number of frames contained in the packet data submitted
|
||||
* to the repacketizer state.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Construct a new packet from data previously submitted to the repacketizer
|
||||
* state via opus_repacketizer_cat().
|
||||
* This is a convenience routine that returns all the data submitted so far
|
||||
* in a single packet.
|
||||
* It is equivalent to calling
|
||||
* @code
|
||||
* opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
|
||||
* data, maxlen)
|
||||
* @endcode
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
|
||||
* construct the new packet.
|
||||
* @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
|
||||
* store the output packet.
|
||||
* @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
|
||||
* the output buffer. In order to guarantee
|
||||
* success, this should be at least
|
||||
* <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.
|
||||
* However,
|
||||
* <code>1*opus_repacketizer_get_nb_frames(rp)</code>
|
||||
* plus the size of all packet data
|
||||
* submitted to the repacketizer since the
|
||||
* last call to opus_repacketizer_init() or
|
||||
* opus_repacketizer_create() is also
|
||||
* sufficient, and possibly much smaller.
|
||||
* @returns The total size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
|
||||
* complete output packet.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to pad.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
|
||||
* This must be at least as large as len.
|
||||
* @returns an error code
|
||||
* @retval #OPUS_OK \a on success.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
|
||||
|
||||
/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
|
||||
* minimize space usage.
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to strip.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @returns The new size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
|
||||
|
||||
/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to pad.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
|
||||
* This must be at least 1.
|
||||
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
|
||||
* This must be at least as large as len.
|
||||
* @returns an error code
|
||||
* @retval #OPUS_OK \a on success.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
|
||||
|
||||
/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
|
||||
* minimize space usage.
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to strip.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
|
||||
* This must be at least 1.
|
||||
* @returns The new size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPUS_H */
|
|
@ -0,0 +1,379 @@
|
|||
/* Copyright (c) 2011-2012 Xiph.Org Foundation, Mozilla Corporation
|
||||
Written by Jean-Marc Valin and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OPUS_PI (3.14159265F)
|
||||
|
||||
#define OPUS_COSF(_x) ((float)cos(_x))
|
||||
#define OPUS_SINF(_x) ((float)sin(_x))
|
||||
|
||||
static void *check_alloc(void *_ptr){
|
||||
if(_ptr==NULL){
|
||||
fprintf(stderr,"Out of memory.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
static void *opus_malloc(size_t _size){
|
||||
return check_alloc(malloc(_size));
|
||||
}
|
||||
|
||||
static void *opus_realloc(void *_ptr,size_t _size){
|
||||
return check_alloc(realloc(_ptr,_size));
|
||||
}
|
||||
|
||||
static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){
|
||||
unsigned char buf[1024];
|
||||
float *samples;
|
||||
size_t nsamples;
|
||||
size_t csamples;
|
||||
size_t xi;
|
||||
size_t nread;
|
||||
samples=NULL;
|
||||
nsamples=csamples=0;
|
||||
for(;;){
|
||||
nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin);
|
||||
if(nread<=0)break;
|
||||
if(nsamples+nread>csamples){
|
||||
do csamples=csamples<<1|1;
|
||||
while(nsamples+nread>csamples);
|
||||
samples=(float *)opus_realloc(samples,
|
||||
_nchannels*csamples*sizeof(*samples));
|
||||
}
|
||||
for(xi=0;xi<nread;xi++){
|
||||
int ci;
|
||||
for(ci=0;ci<_nchannels;ci++){
|
||||
int s;
|
||||
s=buf[2*(xi*_nchannels+ci)+1]<<8|buf[2*(xi*_nchannels+ci)];
|
||||
s=((s&0xFFFF)^0x8000)-0x8000;
|
||||
samples[(nsamples+xi)*_nchannels+ci]=s;
|
||||
}
|
||||
}
|
||||
nsamples+=nread;
|
||||
}
|
||||
*_samples=(float *)opus_realloc(samples,
|
||||
_nchannels*nsamples*sizeof(*samples));
|
||||
return nsamples;
|
||||
}
|
||||
|
||||
static void band_energy(float *_out,float *_ps,const int *_bands,int _nbands,
|
||||
const float *_in,int _nchannels,size_t _nframes,int _window_sz,
|
||||
int _step,int _downsample){
|
||||
float *window;
|
||||
float *x;
|
||||
float *c;
|
||||
float *s;
|
||||
size_t xi;
|
||||
int xj;
|
||||
int ps_sz;
|
||||
window=(float *)opus_malloc((3+_nchannels)*_window_sz*sizeof(*window));
|
||||
c=window+_window_sz;
|
||||
s=c+_window_sz;
|
||||
x=s+_window_sz;
|
||||
ps_sz=_window_sz/2;
|
||||
for(xj=0;xj<_window_sz;xj++){
|
||||
window[xj]=0.5F-0.5F*OPUS_COSF((2*OPUS_PI/(_window_sz-1))*xj);
|
||||
}
|
||||
for(xj=0;xj<_window_sz;xj++){
|
||||
c[xj]=OPUS_COSF((2*OPUS_PI/_window_sz)*xj);
|
||||
}
|
||||
for(xj=0;xj<_window_sz;xj++){
|
||||
s[xj]=OPUS_SINF((2*OPUS_PI/_window_sz)*xj);
|
||||
}
|
||||
for(xi=0;xi<_nframes;xi++){
|
||||
int ci;
|
||||
int xk;
|
||||
int bi;
|
||||
for(ci=0;ci<_nchannels;ci++){
|
||||
for(xk=0;xk<_window_sz;xk++){
|
||||
x[ci*_window_sz+xk]=window[xk]*_in[(xi*_step+xk)*_nchannels+ci];
|
||||
}
|
||||
}
|
||||
for(bi=xj=0;bi<_nbands;bi++){
|
||||
float p[2]={0};
|
||||
for(;xj<_bands[bi+1];xj++){
|
||||
for(ci=0;ci<_nchannels;ci++){
|
||||
float re;
|
||||
float im;
|
||||
int ti;
|
||||
ti=0;
|
||||
re=im=0;
|
||||
for(xk=0;xk<_window_sz;xk++){
|
||||
re+=c[ti]*x[ci*_window_sz+xk];
|
||||
im-=s[ti]*x[ci*_window_sz+xk];
|
||||
ti+=xj;
|
||||
if(ti>=_window_sz)ti-=_window_sz;
|
||||
}
|
||||
re*=_downsample;
|
||||
im*=_downsample;
|
||||
_ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000;
|
||||
p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci];
|
||||
}
|
||||
}
|
||||
if(_out){
|
||||
_out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]);
|
||||
if(_nchannels==2){
|
||||
_out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(window);
|
||||
}
|
||||
|
||||
#define NBANDS (21)
|
||||
#define NFREQS (240)
|
||||
|
||||
/*Bands on which we compute the pseudo-NMR (Bark-derived
|
||||
CELT bands).*/
|
||||
static const int BANDS[NBANDS+1]={
|
||||
0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200
|
||||
};
|
||||
|
||||
#define TEST_WIN_SIZE (480)
|
||||
#define TEST_WIN_STEP (120)
|
||||
|
||||
int main(int _argc,const char **_argv){
|
||||
FILE *fin1;
|
||||
FILE *fin2;
|
||||
float *x;
|
||||
float *y;
|
||||
float *xb;
|
||||
float *X;
|
||||
float *Y;
|
||||
double err;
|
||||
float Q;
|
||||
size_t xlength;
|
||||
size_t ylength;
|
||||
size_t nframes;
|
||||
size_t xi;
|
||||
int ci;
|
||||
int xj;
|
||||
int bi;
|
||||
int nchannels;
|
||||
unsigned rate;
|
||||
int downsample;
|
||||
int ybands;
|
||||
int yfreqs;
|
||||
int max_compare;
|
||||
if(_argc<3||_argc>6){
|
||||
fprintf(stderr,"Usage: %s [-s] [-r rate2] <file1.sw> <file2.sw>\n",
|
||||
_argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
nchannels=1;
|
||||
if(strcmp(_argv[1],"-s")==0){
|
||||
nchannels=2;
|
||||
_argv++;
|
||||
}
|
||||
rate=48000;
|
||||
ybands=NBANDS;
|
||||
yfreqs=NFREQS;
|
||||
downsample=1;
|
||||
if(strcmp(_argv[1],"-r")==0){
|
||||
rate=atoi(_argv[2]);
|
||||
if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){
|
||||
fprintf(stderr,
|
||||
"Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
downsample=48000/rate;
|
||||
switch(rate){
|
||||
case 8000:ybands=13;break;
|
||||
case 12000:ybands=15;break;
|
||||
case 16000:ybands=17;break;
|
||||
case 24000:ybands=19;break;
|
||||
}
|
||||
yfreqs=NFREQS/downsample;
|
||||
_argv+=2;
|
||||
}
|
||||
fin1=fopen(_argv[1],"rb");
|
||||
if(fin1==NULL){
|
||||
fprintf(stderr,"Error opening '%s'.\n",_argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fin2=fopen(_argv[2],"rb");
|
||||
if(fin2==NULL){
|
||||
fprintf(stderr,"Error opening '%s'.\n",_argv[2]);
|
||||
fclose(fin1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/*Read in the data and allocate scratch space.*/
|
||||
xlength=read_pcm16(&x,fin1,2);
|
||||
if(nchannels==1){
|
||||
for(xi=0;xi<xlength;xi++)x[xi]=.5*(x[2*xi]+x[2*xi+1]);
|
||||
}
|
||||
fclose(fin1);
|
||||
ylength=read_pcm16(&y,fin2,nchannels);
|
||||
fclose(fin2);
|
||||
if(xlength!=ylength*downsample){
|
||||
fprintf(stderr,"Sample counts do not match (%lu!=%lu).\n",
|
||||
(unsigned long)xlength,(unsigned long)ylength*downsample);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(xlength<TEST_WIN_SIZE){
|
||||
fprintf(stderr,"Insufficient sample data (%lu<%i).\n",
|
||||
(unsigned long)xlength,TEST_WIN_SIZE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
nframes=(xlength-TEST_WIN_SIZE+TEST_WIN_STEP)/TEST_WIN_STEP;
|
||||
xb=(float *)opus_malloc(nframes*NBANDS*nchannels*sizeof(*xb));
|
||||
X=(float *)opus_malloc(nframes*NFREQS*nchannels*sizeof(*X));
|
||||
Y=(float *)opus_malloc(nframes*yfreqs*nchannels*sizeof(*Y));
|
||||
/*Compute the per-band spectral energy of the original signal
|
||||
and the error.*/
|
||||
band_energy(xb,X,BANDS,NBANDS,x,nchannels,nframes,
|
||||
TEST_WIN_SIZE,TEST_WIN_STEP,1);
|
||||
free(x);
|
||||
band_energy(NULL,Y,BANDS,ybands,y,nchannels,nframes,
|
||||
TEST_WIN_SIZE/downsample,TEST_WIN_STEP/downsample,downsample);
|
||||
free(y);
|
||||
for(xi=0;xi<nframes;xi++){
|
||||
/*Frequency masking (low to high): 10 dB/Bark slope.*/
|
||||
for(bi=1;bi<NBANDS;bi++){
|
||||
for(ci=0;ci<nchannels;ci++){
|
||||
xb[(xi*NBANDS+bi)*nchannels+ci]+=
|
||||
0.1F*xb[(xi*NBANDS+bi-1)*nchannels+ci];
|
||||
}
|
||||
}
|
||||
/*Frequency masking (high to low): 15 dB/Bark slope.*/
|
||||
for(bi=NBANDS-1;bi-->0;){
|
||||
for(ci=0;ci<nchannels;ci++){
|
||||
xb[(xi*NBANDS+bi)*nchannels+ci]+=
|
||||
0.03F*xb[(xi*NBANDS+bi+1)*nchannels+ci];
|
||||
}
|
||||
}
|
||||
if(xi>0){
|
||||
/*Temporal masking: -3 dB/2.5ms slope.*/
|
||||
for(bi=0;bi<NBANDS;bi++){
|
||||
for(ci=0;ci<nchannels;ci++){
|
||||
xb[(xi*NBANDS+bi)*nchannels+ci]+=
|
||||
0.5F*xb[((xi-1)*NBANDS+bi)*nchannels+ci];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Allowing some cross-talk */
|
||||
if(nchannels==2){
|
||||
for(bi=0;bi<NBANDS;bi++){
|
||||
float l,r;
|
||||
l=xb[(xi*NBANDS+bi)*nchannels+0];
|
||||
r=xb[(xi*NBANDS+bi)*nchannels+1];
|
||||
xb[(xi*NBANDS+bi)*nchannels+0]+=0.01F*r;
|
||||
xb[(xi*NBANDS+bi)*nchannels+1]+=0.01F*l;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply masking */
|
||||
for(bi=0;bi<ybands;bi++){
|
||||
for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
|
||||
for(ci=0;ci<nchannels;ci++){
|
||||
X[(xi*NFREQS+xj)*nchannels+ci]+=
|
||||
0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
|
||||
Y[(xi*yfreqs+xj)*nchannels+ci]+=
|
||||
0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Average of consecutive frames to make comparison slightly less sensitive */
|
||||
for(bi=0;bi<ybands;bi++){
|
||||
for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
|
||||
for(ci=0;ci<nchannels;ci++){
|
||||
float xtmp;
|
||||
float ytmp;
|
||||
xtmp = X[xj*nchannels+ci];
|
||||
ytmp = Y[xj*nchannels+ci];
|
||||
for(xi=1;xi<nframes;xi++){
|
||||
float xtmp2;
|
||||
float ytmp2;
|
||||
xtmp2 = X[(xi*NFREQS+xj)*nchannels+ci];
|
||||
ytmp2 = Y[(xi*yfreqs+xj)*nchannels+ci];
|
||||
X[(xi*NFREQS+xj)*nchannels+ci] += xtmp;
|
||||
Y[(xi*yfreqs+xj)*nchannels+ci] += ytmp;
|
||||
xtmp = xtmp2;
|
||||
ytmp = ytmp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*If working at a lower sampling rate, don't take into account the last
|
||||
300 Hz to allow for different transition bands.
|
||||
For 12 kHz, we don't skip anything, because the last band already skips
|
||||
400 Hz.*/
|
||||
if(rate==48000)max_compare=BANDS[NBANDS];
|
||||
else if(rate==12000)max_compare=BANDS[ybands];
|
||||
else max_compare=BANDS[ybands]-3;
|
||||
err=0;
|
||||
for(xi=0;xi<nframes;xi++){
|
||||
double Ef;
|
||||
Ef=0;
|
||||
for(bi=0;bi<ybands;bi++){
|
||||
double Eb;
|
||||
Eb=0;
|
||||
for(xj=BANDS[bi];xj<BANDS[bi+1]&&xj<max_compare;xj++){
|
||||
for(ci=0;ci<nchannels;ci++){
|
||||
float re;
|
||||
float im;
|
||||
re=Y[(xi*yfreqs+xj)*nchannels+ci]/X[(xi*NFREQS+xj)*nchannels+ci];
|
||||
im=re-log(re)-1;
|
||||
/*Make comparison less sensitive around the SILK/CELT cross-over to
|
||||
allow for mode freedom in the filters.*/
|
||||
if(xj>=79&&xj<=81)im*=0.1F;
|
||||
if(xj==80)im*=0.1F;
|
||||
Eb+=im;
|
||||
}
|
||||
}
|
||||
Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels;
|
||||
Ef += Eb*Eb;
|
||||
}
|
||||
/*Using a fixed normalization value means we're willing to accept slightly
|
||||
lower quality for lower sampling rates.*/
|
||||
Ef/=NBANDS;
|
||||
Ef*=Ef;
|
||||
err+=Ef*Ef;
|
||||
}
|
||||
err=pow(err/nframes,1.0/16);
|
||||
Q=100*(1-0.5*log(1+err)/log(1.13));
|
||||
if(Q<0){
|
||||
fprintf(stderr,"Test vector FAILS\n");
|
||||
fprintf(stderr,"Internal weighted error is %f\n",err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else{
|
||||
fprintf(stderr,"Test vector PASSES\n");
|
||||
fprintf(stderr,
|
||||
"Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* Opus configuration header */
|
||||
/* Based on the output of libopus configure script */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `lrint' function. */
|
||||
#define HAVE_LRINT 1
|
||||
|
||||
/* Define to 1 if you have the `lrintf' function. */
|
||||
#define HAVE_LRINTF 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
#ifdef OPUS_ARM_OPT
|
||||
/* Make use of ARM asm optimization */
|
||||
#define OPUS_ARM_ASM 1
|
||||
|
||||
/* Use generic ARMv4 inline asm optimizations */
|
||||
#define OPUS_ARM_INLINE_ASM 1
|
||||
|
||||
/* Use ARMv5E inline asm optimizations */
|
||||
#define OPUS_ARM_INLINE_EDSP 1
|
||||
|
||||
/* Use ARMv6 inline asm optimizations */
|
||||
#define OPUS_ARM_INLINE_MEDIA 1
|
||||
|
||||
/* Use ARM NEON inline asm optimizations */
|
||||
#define OPUS_ARM_INLINE_NEON 1
|
||||
|
||||
/* Define if assembler supports EDSP instructions */
|
||||
#define OPUS_ARM_MAY_HAVE_EDSP 1
|
||||
|
||||
/* Define if assembler supports ARMv6 media instructions */
|
||||
#define OPUS_ARM_MAY_HAVE_MEDIA 1
|
||||
|
||||
/* Define if compiler supports NEON instructions */
|
||||
#define OPUS_ARM_MAY_HAVE_NEON 1
|
||||
#endif // OPUS_ARM_OPT
|
||||
|
||||
#ifdef OPUS_ARM64_OPT
|
||||
/* Make use of ARM asm optimization */
|
||||
#define OPUS_ARM_ASM 1
|
||||
|
||||
/* Use ARMv6 inline asm optimizations */
|
||||
#define OPUS_ARM_INLINE_MEDIA 1 // work
|
||||
|
||||
/* Use ARM NEON inline asm optimizations */
|
||||
#define OPUS_ARM_INLINE_NEON 1 // work
|
||||
|
||||
/* Define if assembler supports EDSP instructions */
|
||||
#define OPUS_ARM_MAY_HAVE_EDSP 1 // work
|
||||
|
||||
/* Define if assembler supports ARMv6 media instructions */
|
||||
#define OPUS_ARM_MAY_HAVE_MEDIA 1 // work
|
||||
|
||||
/* Define if compiler supports NEON instructions */
|
||||
#define OPUS_ARM_MAY_HAVE_NEON 1
|
||||
|
||||
#endif // OPUS_ARM64_OPT
|
||||
|
||||
/* This is a build of OPUS */
|
||||
#define OPUS_BUILD /**/
|
||||
|
||||
#ifndef WIN32
|
||||
/* Use C99 variable-size arrays */
|
||||
#define VAR_ARRAYS 1
|
||||
#else
|
||||
/* Fixes VS 2013 compile error */
|
||||
#define USE_ALLOCA 1
|
||||
#endif
|
||||
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to the equivalent of the C99 'restrict' keyword, or to
|
||||
nothing if this is not supported. Do not define if restrict is
|
||||
supported directly. */
|
||||
#define restrict __restrict
|
||||
/* Work around a bug in Sun C++: it does not support _Restrict or
|
||||
__restrict__, even though the corresponding Sun C compiler ends up with
|
||||
"#define restrict _Restrict" or "#define restrict __restrict__" in the
|
||||
previous line. Perhaps some future version of Sun C++ will work with
|
||||
restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
|
||||
#if defined __SUNPRO_CC && !defined __RESTRICT
|
||||
# define _Restrict
|
||||
# define __restrict__
|
||||
#endif
|
|
@ -0,0 +1,342 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2008-2012 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file opus_custom.h
|
||||
@brief Opus-Custom reference implementation API
|
||||
*/
|
||||
|
||||
#ifndef OPUS_CUSTOM_H
|
||||
#define OPUS_CUSTOM_H
|
||||
|
||||
#include "opus_defines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
|
||||
#else
|
||||
# define OPUS_CUSTOM_EXPORT
|
||||
# ifdef OPUS_BUILD
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
|
||||
# else
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** @defgroup opus_custom Opus Custom
|
||||
* @{
|
||||
* Opus Custom is an optional part of the Opus specification and
|
||||
* reference implementation which uses a distinct API from the regular
|
||||
* API and supports frame sizes that are not normally supported.\ Use
|
||||
* of Opus Custom is discouraged for all but very special applications
|
||||
* for which a frame size different from 2.5, 5, 10, or 20 ms is needed
|
||||
* (for either complexity or latency reasons) and where interoperability
|
||||
* is less important.
|
||||
*
|
||||
* In addition to the interoperability limitations the use of Opus custom
|
||||
* disables a substantial chunk of the codec and generally lowers the
|
||||
* quality available at a given bitrate. Normally when an application needs
|
||||
* a different frame size from the codec it should buffer to match the
|
||||
* sizes but this adds a small amount of delay which may be important
|
||||
* in some very low latency applications. Some transports (especially
|
||||
* constant rate RF transports) may also work best with frames of
|
||||
* particular durations.
|
||||
*
|
||||
* Libopus only supports custom modes if they are enabled at compile time.
|
||||
*
|
||||
* The Opus Custom API is similar to the regular API but the
|
||||
* @ref opus_encoder_create and @ref opus_decoder_create calls take
|
||||
* an additional mode parameter which is a structure produced by
|
||||
* a call to @ref opus_custom_mode_create. Both the encoder and decoder
|
||||
* must create a mode using the same sample rate (fs) and frame size
|
||||
* (frame size) so these parameters must either be signaled out of band
|
||||
* or fixed in a particular implementation.
|
||||
*
|
||||
* Similar to regular Opus the custom modes support on the fly frame size
|
||||
* switching, but the sizes available depend on the particular frame size in
|
||||
* use. For some initial frame sizes on a single on the fly size is available.
|
||||
*/
|
||||
|
||||
/** Contains the state of an encoder. One encoder state is needed
|
||||
for each stream. It is initialized once at the beginning of the
|
||||
stream. Do *not* re-initialize the state for every frame.
|
||||
@brief Encoder state
|
||||
*/
|
||||
typedef struct OpusCustomEncoder OpusCustomEncoder;
|
||||
|
||||
/** State of the decoder. One decoder state is needed for each stream.
|
||||
It is initialized once at the beginning of the stream. Do *not*
|
||||
re-initialize the state for every frame.
|
||||
@brief Decoder state
|
||||
*/
|
||||
typedef struct OpusCustomDecoder OpusCustomDecoder;
|
||||
|
||||
/** The mode contains all the information necessary to create an
|
||||
encoder. Both the encoder and decoder need to be initialized
|
||||
with exactly the same mode, otherwise the output will be
|
||||
corrupted.
|
||||
@brief Mode configuration
|
||||
*/
|
||||
typedef struct OpusCustomMode OpusCustomMode;
|
||||
|
||||
/** Creates a new mode struct. This will be passed to an encoder or
|
||||
* decoder. The mode MUST NOT BE DESTROYED until the encoders and
|
||||
* decoders that use it are destroyed as well.
|
||||
* @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
|
||||
* packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
|
||||
* @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
|
||||
* @return A newly created mode
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
|
||||
|
||||
/** Destroys a mode struct. Only call this after all encoders and
|
||||
* decoders using this mode are destroyed as well.
|
||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
|
||||
|
||||
|
||||
#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
|
||||
|
||||
/* Encoder */
|
||||
/** Gets the size of an OpusCustomEncoder structure.
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @returns size
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
# ifdef CUSTOM_MODES
|
||||
/** Initializes a previously allocated encoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
|
||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* decoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
|
||||
OpusCustomEncoder *st,
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/** Creates a new encoder state. Each stream needs its own encoder
|
||||
* state (can't be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* decoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
||||
* @return Newly created encoder state.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
|
||||
const OpusCustomMode *mode,
|
||||
int channels,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
/** Destroys a an encoder state.
|
||||
* @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
|
||||
|
||||
/** Encodes a frame of audio.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
|
||||
* Samples with a range beyond +/-1.0 are supported but will
|
||||
* be clipped by decoders using the integer API and should
|
||||
* only be used if it is known that the far end supports
|
||||
* extended dynamic range. There must be exactly
|
||||
* frame_size samples per channel.
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
||||
* (can change from one frame to another)
|
||||
* @return Number of bytes written to "compressed".
|
||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
||||
* decoding is possible.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
|
||||
OpusCustomEncoder *st,
|
||||
const float *pcm,
|
||||
int frame_size,
|
||||
unsigned char *compressed,
|
||||
int maxCompressedBytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Encodes a frame of audio.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
|
||||
* There must be exactly frame_size samples per channel.
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
||||
* (can change from one frame to another)
|
||||
* @return Number of bytes written to "compressed".
|
||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
||||
* decoding is possible.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
|
||||
OpusCustomEncoder *st,
|
||||
const opus_int16 *pcm,
|
||||
int frame_size,
|
||||
unsigned char *compressed,
|
||||
int maxCompressedBytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Perform a CTL function on an Opus custom encoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated
|
||||
* by a convenience macro.
|
||||
* @see opus_encoderctls
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
|
||||
/* Decoder */
|
||||
|
||||
/** Gets the size of an OpusCustomDecoder structure.
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @returns size
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Initializes a previously allocated decoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
|
||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* encoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
|
||||
OpusCustomDecoder *st,
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Creates a new decoder state. Each stream needs its own decoder state (can't
|
||||
* be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
|
||||
* stream (must be the same characteristics as used for the encoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
||||
* @return Newly created decoder state.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
|
||||
const OpusCustomMode *mode,
|
||||
int channels,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Destroys a an decoder state.
|
||||
* @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
|
||||
|
||||
/** Decode an opus custom frame with floating point output
|
||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
||||
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
||||
* is frame_size*channels*sizeof(float)
|
||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
|
||||
OpusCustomDecoder *st,
|
||||
const unsigned char *data,
|
||||
int len,
|
||||
float *pcm,
|
||||
int frame_size
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Decode an opus custom frame
|
||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
||||
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
||||
* is frame_size*channels*sizeof(opus_int16)
|
||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
|
||||
OpusCustomDecoder *st,
|
||||
const unsigned char *data,
|
||||
int len,
|
||||
opus_int16 *pcm,
|
||||
int frame_size
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Perform a CTL function on an Opus custom decoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated
|
||||
* by a convenience macro.
|
||||
* @see opus_genericctls
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPUS_CUSTOM_H */
|
|
@ -0,0 +1,970 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
|
||||
Written by Jean-Marc Valin and Koen Vos */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef OPUS_HAVE_CONFIG_H
|
||||
# include "opus_config.h"
|
||||
#endif
|
||||
|
||||
#ifndef OPUS_BUILD
|
||||
# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__)
|
||||
# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "celt.h"
|
||||
#include "opus.h"
|
||||
#include "entdec.h"
|
||||
#include "opus_modes.h"
|
||||
#include "API.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "float_cast.h"
|
||||
#include "opus_private.h"
|
||||
#include "os_support.h"
|
||||
#include "structs.h"
|
||||
#include "define.h"
|
||||
#include "mathops.h"
|
||||
#include "cpu_support.h"
|
||||
|
||||
struct OpusDecoder {
|
||||
int celt_dec_offset;
|
||||
int silk_dec_offset;
|
||||
int channels;
|
||||
opus_int32 Fs; /** Sampling rate (at the API level) */
|
||||
silk_DecControlStruct DecControl;
|
||||
int decode_gain;
|
||||
|
||||
/* Everything beyond this point gets cleared on a reset */
|
||||
#define OPUS_DECODER_RESET_START stream_channels
|
||||
int stream_channels;
|
||||
|
||||
int bandwidth;
|
||||
int mode;
|
||||
int prev_mode;
|
||||
int frame_size;
|
||||
int prev_redundancy;
|
||||
int last_packet_duration;
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
opus_val16 softclip_mem[2];
|
||||
#endif
|
||||
|
||||
opus_uint32 rangeFinal;
|
||||
};
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
||||
return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int opus_decoder_get_size(int channels)
|
||||
{
|
||||
int silkDecSizeBytes, celtDecSizeBytes;
|
||||
int ret;
|
||||
if (channels<1 || channels > 2)
|
||||
return 0;
|
||||
ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
|
||||
if(ret)
|
||||
return 0;
|
||||
silkDecSizeBytes = align(silkDecSizeBytes);
|
||||
celtDecSizeBytes = celt_decoder_get_size(channels);
|
||||
return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
|
||||
}
|
||||
|
||||
int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
|
||||
{
|
||||
void *silk_dec;
|
||||
CELTDecoder *celt_dec;
|
||||
int ret, silkDecSizeBytes;
|
||||
|
||||
if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
|
||||
|| (channels!=1&&channels!=2))
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
|
||||
/* Initialize SILK encoder */
|
||||
ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
|
||||
if (ret)
|
||||
return OPUS_INTERNAL_ERROR;
|
||||
|
||||
silkDecSizeBytes = align(silkDecSizeBytes);
|
||||
st->silk_dec_offset = align(sizeof(OpusDecoder));
|
||||
st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
|
||||
silk_dec = (char*)st+st->silk_dec_offset;
|
||||
celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
|
||||
st->stream_channels = st->channels = channels;
|
||||
|
||||
st->Fs = Fs;
|
||||
st->DecControl.API_sampleRate = st->Fs;
|
||||
st->DecControl.nChannelsAPI = st->channels;
|
||||
|
||||
/* Reset decoder */
|
||||
ret = silk_InitDecoder( silk_dec );
|
||||
if(ret)return OPUS_INTERNAL_ERROR;
|
||||
|
||||
/* Initialize CELT decoder */
|
||||
ret = celt_decoder_init(celt_dec, Fs, channels);
|
||||
if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR;
|
||||
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
|
||||
|
||||
st->prev_mode = 0;
|
||||
st->frame_size = Fs/400;
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
|
||||
{
|
||||
int ret;
|
||||
OpusDecoder *st;
|
||||
if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
|
||||
|| (channels!=1&&channels!=2))
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_BAD_ARG;
|
||||
return NULL;
|
||||
}
|
||||
st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
|
||||
if (st == NULL)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_ALLOC_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
ret = opus_decoder_init(st, Fs, channels);
|
||||
if (error)
|
||||
*error = ret;
|
||||
if (ret != OPUS_OK)
|
||||
{
|
||||
opus_free(st);
|
||||
st = NULL;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2,
|
||||
opus_val16 *out, int overlap, int channels,
|
||||
const opus_val16 *window, opus_int32 Fs)
|
||||
{
|
||||
int i, c;
|
||||
int inc = 48000/Fs;
|
||||
for (c=0;c<channels;c++)
|
||||
{
|
||||
for (i=0;i<overlap;i++)
|
||||
{
|
||||
opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]);
|
||||
out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]),
|
||||
Q15ONE-w, in1[i*channels+c]), 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int opus_packet_get_mode(const unsigned char *data)
|
||||
{
|
||||
int mode;
|
||||
if (data[0]&0x80)
|
||||
{
|
||||
mode = MODE_CELT_ONLY;
|
||||
} else if ((data[0]&0x60) == 0x60)
|
||||
{
|
||||
mode = MODE_HYBRID;
|
||||
} else {
|
||||
mode = MODE_SILK_ONLY;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
void *silk_dec;
|
||||
CELTDecoder *celt_dec;
|
||||
int i, silk_ret=0, celt_ret=0;
|
||||
ec_dec dec;
|
||||
opus_int32 silk_frame_size;
|
||||
int pcm_silk_size;
|
||||
VARDECL(opus_int16, pcm_silk);
|
||||
int pcm_transition_silk_size;
|
||||
VARDECL(opus_val16, pcm_transition_silk);
|
||||
int pcm_transition_celt_size;
|
||||
VARDECL(opus_val16, pcm_transition_celt);
|
||||
opus_val16 *pcm_transition;
|
||||
int redundant_audio_size;
|
||||
VARDECL(opus_val16, redundant_audio);
|
||||
|
||||
int audiosize;
|
||||
int mode;
|
||||
int transition=0;
|
||||
int start_band;
|
||||
int redundancy=0;
|
||||
int redundancy_bytes = 0;
|
||||
int celt_to_silk=0;
|
||||
int c;
|
||||
int F2_5, F5, F10, F20;
|
||||
const opus_val16 *window;
|
||||
opus_uint32 redundant_rng = 0;
|
||||
ALLOC_STACK;
|
||||
|
||||
silk_dec = (char*)st+st->silk_dec_offset;
|
||||
celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
|
||||
F20 = st->Fs/50;
|
||||
F10 = F20>>1;
|
||||
F5 = F10>>1;
|
||||
F2_5 = F5>>1;
|
||||
if (frame_size < F2_5)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
/* Limit frame_size to avoid excessive stack allocations. */
|
||||
frame_size = IMIN(frame_size, st->Fs/25*3);
|
||||
/* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
|
||||
if (len<=1)
|
||||
{
|
||||
data = NULL;
|
||||
/* In that case, don't conceal more than what the ToC says */
|
||||
frame_size = IMIN(frame_size, st->frame_size);
|
||||
}
|
||||
if (data != NULL)
|
||||
{
|
||||
audiosize = st->frame_size;
|
||||
mode = st->mode;
|
||||
ec_dec_init(&dec,(unsigned char*)data,len);
|
||||
} else {
|
||||
audiosize = frame_size;
|
||||
mode = st->prev_mode;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
/* If we haven't got any packet yet, all we can do is return zeros */
|
||||
for (i=0;i<audiosize*st->channels;i++)
|
||||
pcm[i] = 0;
|
||||
RESTORE_STACK;
|
||||
return audiosize;
|
||||
}
|
||||
|
||||
/* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
|
||||
10, or 20 (e.g. 12.5 or 30 ms). */
|
||||
if (audiosize > F20)
|
||||
{
|
||||
do {
|
||||
int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0);
|
||||
if (ret<0)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
pcm += ret*st->channels;
|
||||
audiosize -= ret;
|
||||
} while (audiosize > 0);
|
||||
RESTORE_STACK;
|
||||
return frame_size;
|
||||
} else if (audiosize < F20)
|
||||
{
|
||||
if (audiosize > F10)
|
||||
audiosize = F10;
|
||||
else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
|
||||
audiosize = F5;
|
||||
}
|
||||
}
|
||||
|
||||
pcm_transition_silk_size = ALLOC_NONE;
|
||||
pcm_transition_celt_size = ALLOC_NONE;
|
||||
if (data!=NULL && st->prev_mode > 0 && (
|
||||
(mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy)
|
||||
|| (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) )
|
||||
)
|
||||
{
|
||||
transition = 1;
|
||||
/* Decide where to allocate the stack memory for pcm_transition */
|
||||
if (mode == MODE_CELT_ONLY)
|
||||
pcm_transition_celt_size = F5*st->channels;
|
||||
else
|
||||
pcm_transition_silk_size = F5*st->channels;
|
||||
}
|
||||
ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16);
|
||||
if (transition && mode == MODE_CELT_ONLY)
|
||||
{
|
||||
pcm_transition = pcm_transition_celt;
|
||||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
|
||||
}
|
||||
if (audiosize > frame_size)
|
||||
{
|
||||
/*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
} else {
|
||||
frame_size = audiosize;
|
||||
}
|
||||
|
||||
/* Don't allocate any memory when in CELT-only mode */
|
||||
pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
|
||||
ALLOC(pcm_silk, pcm_silk_size, opus_int16);
|
||||
|
||||
/* SILK processing */
|
||||
if (mode != MODE_CELT_ONLY)
|
||||
{
|
||||
int lost_flag, decoded_samples;
|
||||
opus_int16 *pcm_ptr = pcm_silk;
|
||||
|
||||
if (st->prev_mode==MODE_CELT_ONLY)
|
||||
silk_InitDecoder( silk_dec );
|
||||
|
||||
/* The SILK PLC cannot produce frames of less than 10 ms */
|
||||
st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs);
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
st->DecControl.nChannelsInternal = st->stream_channels;
|
||||
if( mode == MODE_SILK_ONLY ) {
|
||||
if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
|
||||
st->DecControl.internalSampleRate = 8000;
|
||||
} else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
|
||||
st->DecControl.internalSampleRate = 12000;
|
||||
} else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
|
||||
st->DecControl.internalSampleRate = 16000;
|
||||
} else {
|
||||
st->DecControl.internalSampleRate = 16000;
|
||||
silk_assert( 0 );
|
||||
}
|
||||
} else {
|
||||
/* Hybrid mode */
|
||||
st->DecControl.internalSampleRate = 16000;
|
||||
}
|
||||
}
|
||||
|
||||
lost_flag = data == NULL ? 1 : 2 * decode_fec;
|
||||
decoded_samples = 0;
|
||||
do {
|
||||
/* Call SILK decoder */
|
||||
int first_frame = decoded_samples == 0;
|
||||
silk_ret = silk_Decode( silk_dec, &st->DecControl,
|
||||
lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size );
|
||||
if( silk_ret ) {
|
||||
if (lost_flag) {
|
||||
/* PLC failure should not be fatal */
|
||||
silk_frame_size = frame_size;
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm_ptr[i] = 0;
|
||||
} else {
|
||||
RESTORE_STACK;
|
||||
return OPUS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
pcm_ptr += silk_frame_size * st->channels;
|
||||
decoded_samples += silk_frame_size;
|
||||
} while( decoded_samples < frame_size );
|
||||
}
|
||||
|
||||
start_band = 0;
|
||||
if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
|
||||
&& ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len)
|
||||
{
|
||||
/* Check if we have a redundant 0-8 kHz band */
|
||||
if (mode == MODE_HYBRID)
|
||||
redundancy = ec_dec_bit_logp(&dec, 12);
|
||||
else
|
||||
redundancy = 1;
|
||||
if (redundancy)
|
||||
{
|
||||
celt_to_silk = ec_dec_bit_logp(&dec, 1);
|
||||
/* redundancy_bytes will be at least two, in the non-hybrid
|
||||
case due to the ec_tell() check above */
|
||||
redundancy_bytes = mode==MODE_HYBRID ?
|
||||
(opus_int32)ec_dec_uint(&dec, 256)+2 :
|
||||
len-((ec_tell(&dec)+7)>>3);
|
||||
len -= redundancy_bytes;
|
||||
/* This is a sanity check. It should never happen for a valid
|
||||
packet, so the exact behaviour is not normative. */
|
||||
if (len*8 < ec_tell(&dec))
|
||||
{
|
||||
len = 0;
|
||||
redundancy_bytes = 0;
|
||||
redundancy = 0;
|
||||
}
|
||||
/* Shrink decoder because of raw bits */
|
||||
dec.storage -= redundancy_bytes;
|
||||
}
|
||||
}
|
||||
if (mode != MODE_CELT_ONLY)
|
||||
start_band = 17;
|
||||
|
||||
{
|
||||
int endband=21;
|
||||
|
||||
switch(st->bandwidth)
|
||||
{
|
||||
case OPUS_BANDWIDTH_NARROWBAND:
|
||||
endband = 13;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_MEDIUMBAND:
|
||||
case OPUS_BANDWIDTH_WIDEBAND:
|
||||
endband = 17;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_SUPERWIDEBAND:
|
||||
endband = 19;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_FULLBAND:
|
||||
endband = 21;
|
||||
break;
|
||||
}
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband));
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels));
|
||||
}
|
||||
|
||||
if (redundancy)
|
||||
{
|
||||
transition = 0;
|
||||
pcm_transition_silk_size=ALLOC_NONE;
|
||||
}
|
||||
|
||||
ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);
|
||||
|
||||
if (transition && mode != MODE_CELT_ONLY)
|
||||
{
|
||||
pcm_transition = pcm_transition_silk;
|
||||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
|
||||
}
|
||||
|
||||
/* Only allocation memory for redundancy if/when needed */
|
||||
redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
|
||||
ALLOC(redundant_audio, redundant_audio_size, opus_val16);
|
||||
|
||||
/* 5 ms redundant frame for CELT->SILK*/
|
||||
if (redundancy && celt_to_silk)
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
|
||||
redundant_audio, F5, NULL);
|
||||
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
||||
}
|
||||
|
||||
/* MUST be after PLC */
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
|
||||
|
||||
if (mode != MODE_SILK_ONLY)
|
||||
{
|
||||
int celt_frame_size = IMIN(F20, frame_size);
|
||||
/* Make sure to discard any previous CELT state */
|
||||
if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy)
|
||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||
/* Decode CELT */
|
||||
celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
|
||||
len, pcm, celt_frame_size, &dec);
|
||||
} else {
|
||||
unsigned char silence[2] = {0xFF, 0xFF};
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm[i] = 0;
|
||||
/* For hybrid -> SILK transitions, we let the CELT MDCT
|
||||
do a fade-out by decoding a silence frame */
|
||||
if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != MODE_CELT_ONLY)
|
||||
{
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
|
||||
#else
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
const CELTMode *celt_mode;
|
||||
celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
|
||||
window = celt_mode->window;
|
||||
}
|
||||
|
||||
/* 5 ms redundant frame for SILK->CELT */
|
||||
if (redundancy && !celt_to_silk)
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
|
||||
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
|
||||
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
||||
smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
|
||||
pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
|
||||
}
|
||||
if (redundancy && celt_to_silk)
|
||||
{
|
||||
for (c=0;c<st->channels;c++)
|
||||
{
|
||||
for (i=0;i<F2_5;i++)
|
||||
pcm[st->channels*i+c] = redundant_audio[st->channels*i+c];
|
||||
}
|
||||
smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5,
|
||||
pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs);
|
||||
}
|
||||
if (transition)
|
||||
{
|
||||
if (audiosize >= F5)
|
||||
{
|
||||
for (i=0;i<st->channels*F2_5;i++)
|
||||
pcm[i] = pcm_transition[i];
|
||||
smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5,
|
||||
pcm+st->channels*F2_5, F2_5,
|
||||
st->channels, window, st->Fs);
|
||||
} else {
|
||||
/* Not enough time to do a clean transition, but we do it anyway
|
||||
This will not preserve amplitude perfectly and may introduce
|
||||
a bit of temporal aliasing, but it shouldn't be too bad and
|
||||
that's pretty much the best we can do. In any case, generating this
|
||||
transition it pretty silly in the first place */
|
||||
smooth_fade(pcm_transition, pcm,
|
||||
pcm, F2_5,
|
||||
st->channels, window, st->Fs);
|
||||
}
|
||||
}
|
||||
|
||||
if(st->decode_gain)
|
||||
{
|
||||
opus_val32 gain;
|
||||
gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain));
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
{
|
||||
opus_val32 x;
|
||||
x = MULT16_32_P16(pcm[i],gain);
|
||||
pcm[i] = SATURATE(x, 32767);
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= 1)
|
||||
st->rangeFinal = 0;
|
||||
else
|
||||
st->rangeFinal = dec.rng ^ redundant_rng;
|
||||
|
||||
st->prev_mode = mode;
|
||||
st->prev_redundancy = redundancy && !celt_to_silk;
|
||||
|
||||
if (celt_ret>=0)
|
||||
{
|
||||
if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
|
||||
OPUS_PRINT_INT(audiosize);
|
||||
}
|
||||
|
||||
RESTORE_STACK;
|
||||
return celt_ret < 0 ? celt_ret : audiosize;
|
||||
|
||||
}
|
||||
|
||||
int opus_decode_native(OpusDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
|
||||
int self_delimited, opus_int32 *packet_offset, int soft_clip)
|
||||
{
|
||||
int i, nb_samples;
|
||||
int count, offset;
|
||||
unsigned char toc;
|
||||
int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
|
||||
/* 48 x 2.5 ms = 120 ms */
|
||||
opus_int16 size[48];
|
||||
if (decode_fec<0 || decode_fec>1)
|
||||
return OPUS_BAD_ARG;
|
||||
/* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
|
||||
if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
|
||||
return OPUS_BAD_ARG;
|
||||
if (len==0 || data==NULL)
|
||||
{
|
||||
int pcm_count=0;
|
||||
do {
|
||||
int ret;
|
||||
ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
|
||||
if (ret<0)
|
||||
return ret;
|
||||
pcm_count += ret;
|
||||
} while (pcm_count < frame_size);
|
||||
celt_assert(pcm_count == frame_size);
|
||||
if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
|
||||
OPUS_PRINT_INT(pcm_count);
|
||||
st->last_packet_duration = pcm_count;
|
||||
return pcm_count;
|
||||
} else if (len<0)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
packet_mode = opus_packet_get_mode(data);
|
||||
packet_bandwidth = opus_packet_get_bandwidth(data);
|
||||
packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
|
||||
packet_stream_channels = opus_packet_get_nb_channels(data);
|
||||
|
||||
count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
|
||||
size, &offset, packet_offset);
|
||||
if (count<0)
|
||||
return count;
|
||||
|
||||
data += offset;
|
||||
|
||||
if (decode_fec)
|
||||
{
|
||||
int duration_copy;
|
||||
int ret;
|
||||
/* If no FEC can be present, run the PLC (recursive call) */
|
||||
if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
|
||||
return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
|
||||
/* Otherwise, run the PLC on everything except the size for which we might have FEC */
|
||||
duration_copy = st->last_packet_duration;
|
||||
if (frame_size-packet_frame_size!=0)
|
||||
{
|
||||
ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
|
||||
if (ret<0)
|
||||
{
|
||||
st->last_packet_duration = duration_copy;
|
||||
return ret;
|
||||
}
|
||||
celt_assert(ret==frame_size-packet_frame_size);
|
||||
}
|
||||
/* Complete with FEC */
|
||||
st->mode = packet_mode;
|
||||
st->bandwidth = packet_bandwidth;
|
||||
st->frame_size = packet_frame_size;
|
||||
st->stream_channels = packet_stream_channels;
|
||||
ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
|
||||
packet_frame_size, 1);
|
||||
if (ret<0)
|
||||
return ret;
|
||||
else {
|
||||
if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
|
||||
OPUS_PRINT_INT(frame_size);
|
||||
st->last_packet_duration = frame_size;
|
||||
return frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (count*packet_frame_size > frame_size)
|
||||
return OPUS_BUFFER_TOO_SMALL;
|
||||
|
||||
/* Update the state as the last step to avoid updating it on an invalid packet */
|
||||
st->mode = packet_mode;
|
||||
st->bandwidth = packet_bandwidth;
|
||||
st->frame_size = packet_frame_size;
|
||||
st->stream_channels = packet_stream_channels;
|
||||
|
||||
nb_samples=0;
|
||||
for (i=0;i<count;i++)
|
||||
{
|
||||
int ret;
|
||||
ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
|
||||
if (ret<0)
|
||||
return ret;
|
||||
celt_assert(ret==packet_frame_size);
|
||||
data += size[i];
|
||||
nb_samples += ret;
|
||||
}
|
||||
st->last_packet_duration = nb_samples;
|
||||
if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
|
||||
OPUS_PRINT_INT(nb_samples);
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
if (soft_clip)
|
||||
opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
|
||||
else
|
||||
st->softclip_mem[0]=st->softclip_mem[1]=0;
|
||||
#endif
|
||||
return nb_samples;
|
||||
}
|
||||
|
||||
#ifdef OPUS_FIXED_POINT
|
||||
|
||||
int opus_decode(OpusDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
if(frame_size<=0)
|
||||
return OPUS_BAD_ARG;
|
||||
return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
int opus_decode_float(OpusDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, float *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
VARDECL(opus_int16, out);
|
||||
int ret, i;
|
||||
ALLOC_STACK;
|
||||
|
||||
if(frame_size<=0)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
ALLOC(out, frame_size*st->channels, opus_int16);
|
||||
|
||||
ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
|
||||
if (ret > 0)
|
||||
{
|
||||
for (i=0;i<ret*st->channels;i++)
|
||||
pcm[i] = (1.f/32768.f)*(out[i]);
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
int opus_decode(OpusDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
VARDECL(float, out);
|
||||
int ret, i;
|
||||
ALLOC_STACK;
|
||||
|
||||
if(frame_size<=0)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
ALLOC(out, frame_size*st->channels, float);
|
||||
|
||||
ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
|
||||
if (ret > 0)
|
||||
{
|
||||
for (i=0;i<ret*st->channels;i++)
|
||||
pcm[i] = FLOAT2INT16(out[i]);
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int opus_decode_float(OpusDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
if(frame_size<=0)
|
||||
return OPUS_BAD_ARG;
|
||||
return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int opus_decoder_ctl(OpusDecoder *st, int request, ...)
|
||||
{
|
||||
int ret = OPUS_OK;
|
||||
va_list ap;
|
||||
void *silk_dec;
|
||||
CELTDecoder *celt_dec;
|
||||
|
||||
silk_dec = (char*)st+st->silk_dec_offset;
|
||||
celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
|
||||
|
||||
|
||||
va_start(ap, request);
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case OPUS_GET_BANDWIDTH_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->bandwidth;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_FINAL_RANGE_REQUEST:
|
||||
{
|
||||
opus_uint32 *value = va_arg(ap, opus_uint32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->rangeFinal;
|
||||
}
|
||||
break;
|
||||
case OPUS_RESET_STATE:
|
||||
{
|
||||
OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
|
||||
sizeof(OpusDecoder)-
|
||||
((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
|
||||
|
||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||
silk_InitDecoder( silk_dec );
|
||||
st->stream_channels = st->channels;
|
||||
st->frame_size = st->Fs/400;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_SAMPLE_RATE_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->Fs;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_PITCH_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
if (st->prev_mode == MODE_CELT_ONLY)
|
||||
celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
|
||||
else
|
||||
*value = st->DecControl.prevPitchLag;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_GAIN_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->decode_gain;
|
||||
}
|
||||
break;
|
||||
case OPUS_SET_GAIN_REQUEST:
|
||||
{
|
||||
opus_int32 value = va_arg(ap, opus_int32);
|
||||
if (value<-32768 || value>32767)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
st->decode_gain = value;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
|
||||
{
|
||||
opus_uint32 *value = va_arg(ap, opus_uint32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->last_packet_duration;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
|
||||
ret = OPUS_UNIMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return ret;
|
||||
bad_arg:
|
||||
va_end(ap);
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
void opus_decoder_destroy(OpusDecoder *st)
|
||||
{
|
||||
opus_free(st);
|
||||
}
|
||||
|
||||
|
||||
int opus_packet_get_bandwidth(const unsigned char *data)
|
||||
{
|
||||
int bandwidth;
|
||||
if (data[0]&0x80)
|
||||
{
|
||||
bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3);
|
||||
if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
|
||||
bandwidth = OPUS_BANDWIDTH_NARROWBAND;
|
||||
} else if ((data[0]&0x60) == 0x60)
|
||||
{
|
||||
bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND :
|
||||
OPUS_BANDWIDTH_SUPERWIDEBAND;
|
||||
} else {
|
||||
bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3);
|
||||
}
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
int opus_packet_get_samples_per_frame(const unsigned char *data,
|
||||
opus_int32 Fs)
|
||||
{
|
||||
int audiosize;
|
||||
if (data[0]&0x80)
|
||||
{
|
||||
audiosize = ((data[0]>>3)&0x3);
|
||||
audiosize = (Fs<<audiosize)/400;
|
||||
} else if ((data[0]&0x60) == 0x60)
|
||||
{
|
||||
audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
|
||||
} else {
|
||||
audiosize = ((data[0]>>3)&0x3);
|
||||
if (audiosize == 3)
|
||||
audiosize = Fs*60/1000;
|
||||
else
|
||||
audiosize = (Fs<<audiosize)/100;
|
||||
}
|
||||
return audiosize;
|
||||
}
|
||||
|
||||
int opus_packet_get_nb_channels(const unsigned char *data)
|
||||
{
|
||||
return (data[0]&0x4) ? 2 : 1;
|
||||
}
|
||||
|
||||
int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len)
|
||||
{
|
||||
int count;
|
||||
if (len<1)
|
||||
return OPUS_BAD_ARG;
|
||||
count = packet[0]&0x3;
|
||||
if (count==0)
|
||||
return 1;
|
||||
else if (count!=3)
|
||||
return 2;
|
||||
else if (len<2)
|
||||
return OPUS_INVALID_PACKET;
|
||||
else
|
||||
return packet[1]&0x3F;
|
||||
}
|
||||
|
||||
int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
|
||||
opus_int32 Fs)
|
||||
{
|
||||
int samples;
|
||||
int count = opus_packet_get_nb_frames(packet, len);
|
||||
|
||||
if (count<0)
|
||||
return count;
|
||||
|
||||
samples = count*opus_packet_get_samples_per_frame(packet, Fs);
|
||||
/* Can't have more than 120 ms */
|
||||
if (samples*25 > Fs*3)
|
||||
return OPUS_INVALID_PACKET;
|
||||
else
|
||||
return samples;
|
||||
}
|
||||
|
||||
int opus_decoder_get_nb_samples(const OpusDecoder *dec,
|
||||
const unsigned char packet[], opus_int32 len)
|
||||
{
|
||||
return opus_packet_get_nb_samples(packet, len, dec->Fs);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue