Skip to content

Instantly share code, notes, and snippets.

@auroranockert
Created November 2, 2012 10:45
Show Gist options
  • Save auroranockert/4000105 to your computer and use it in GitHub Desktop.
Save auroranockert/4000105 to your computer and use it in GitHub Desktop.
Spidermonkey patch adding DSP API support
# HG changeset patch
# User Jens Nockert <jens@nockert.se>
# Date 1351851203 -3600
# Branch dsp-api
# Node ID 914a1146cfc003e787219d258a43ca6c737e0602
# Parent 5bd5bb168eb1d25d43ad61dde8fed56d2a4346a9
Start DSP implementation
diff --git a/js/src/Makefile.in b/js/src/Makefile.in
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -140,16 +140,17 @@ CPPSRCS = \
RegExp.cpp \
Marking.cpp \
Memory.cpp \
Statistics.cpp \
StoreBuffer.cpp \
StringBuffer.cpp \
Unicode.cpp \
Xdr.cpp \
+ csdsp.cpp \
$(NULL)
# Changes to internal header files, used externally, massively slow down
# browser builds. Don't add new files here unless you know what you're
# doing!
INSTALLED_HEADERS = \
js-config.h \
jscpucfg.h \
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -49,16 +49,18 @@
#include "jsstr.h"
#include "prmjtime.h"
#include "jsweakmap.h"
#include "jsworkers.h"
#include "jswrapper.h"
#include "jstypedarray.h"
#include "jsxml.h"
+#include "csdsp.h"
+
#include "builtin/Eval.h"
#include "builtin/MapObject.h"
#include "builtin/RegExp.h"
#include "builtin/ParallelArray.h"
#include "ds/LifoAlloc.h"
#include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h"
#include "gc/Memory.h"
@@ -1787,16 +1789,17 @@ static JSStdName standard_class_atoms[]
{js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
#endif
{js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
{js_InitWeakMapClass, EAGER_CLASS_ATOM(WeakMap), &js::WeakMapClass},
{js_InitMapClass, EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
{js_InitSetClass, EAGER_CLASS_ATOM(Set), &js::SetObject::class_},
{js_InitParallelArrayClass, EAGER_CLASS_ATOM(ParallelArray), &js::ParallelArrayObject::class_},
+ {js_InitDSPClass, EAGER_ATOM_AND_CLASP(DSP)},
{NULL, 0, NULL}
};
/*
* Table of top-level function and constant names and their init functions.
* If you add a "standard" global function or property, remember to update
* this table.
*/
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -40,16 +40,18 @@
#include "jsscript.h"
#include "jsstr.h"
#include "jsdbgapi.h"
#include "json.h"
#include "jswatchpoint.h"
#include "jswrapper.h"
#include "jsxml.h"
+#include "csdsp.h"
+
#include "builtin/MapObject.h"
#include "builtin/ParallelArray.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/Parser.h"
#include "gc/Marking.h"
#include "js/MemoryMetrics.h"
#include "vm/StringBuffer.h"
#include "vm/Xdr.h"
diff --git a/js/src/jsobj.h b/js/src/jsobj.h
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -220,16 +220,17 @@ extern Class RegExpStaticsClass;
extern Class SetIteratorClass;
extern Class SlowArrayClass;
extern Class StopIterationClass;
extern Class StringClass;
extern Class StrictArgumentsObjectClass;
extern Class WeakMapClass;
extern Class WithClass;
extern Class XMLFilterClass;
+extern Class DSPClass;
class ArgumentsObject;
class ArrayBufferObject;
class BlockObject;
class BooleanObject;
class ClonedBlockObject;
class DataViewObject;
class DebugScopeObject;
diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -55,10 +55,11 @@
macro(Uint8ClampedArray, 33, js_InitTypedArrayClasses) \
macro(Proxy, 34, js_InitProxyClass) \
macro(AnyName, 35, js_InitNullClass) \
macro(WeakMap, 36, js_InitWeakMapClass) \
macro(Map, 37, js_InitMapClass) \
macro(Set, 38, js_InitSetClass) \
macro(DataView, 39, js_InitTypedArrayClasses) \
macro(ParallelArray, 40, js_InitParallelArrayClass) \
+ macro(DSP, 41, js_InitDSPClass) \
#endif /* jsprototypes_h___ */
# HG changeset patch
# User Jens Nockert <jens@nockert.se>
# Date 1351851689 -3600
# Branch dsp-api
# Node ID f1d96ac2aa249a28137468c575cb72fdecf15f7b
# Parent 914a1146cfc003e787219d258a43ca6c737e0602
Add actual implementation
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -2,16 +2,19 @@
# Filenames that should be ignored wherever they appear
~$
\.py(c|o)$
(?i)(^|/)TAGS$
(^|/)ID$
(^|/)\.DS_Store$
+\.o$
+\.o\.pp$
+
# Vim swap files.
^\.sw.$
.[^/]*\.sw.$
# User files that may appear at the root
^\.mozconfig
^mozconfig*
^configure$
@@ -46,8 +49,12 @@ _OPT\.OBJ/
\.project$
\.cproject$
\.settings/
# Python stuff installed at build time.
^python/psutil/.*\.so
^python/psutil/.*\.pyd
^python/psutil/build/
+
+js/src/config/system_wrappers_js
+js/src/dist
+js/src/\.deps
diff --git a/js/src/csdsp.cpp b/js/src/csdsp.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/csdsp.cpp
@@ -0,0 +1,591 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=99:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JS DSP package.
+ *
+ * TODO: List of functions or signatures to implement
+ *
+ * void add (Float32Array dst, Float32Array x, double y);
+ * void sub (Float32Array dst, Float32Array x, double y);
+ * void mul (Float32Array dst, Float32Array x, double y);
+ * void div (Float32Array dst, Float32Array x, double y);
+ * void pow (Float32Array dst, Float32Array x, double y);
+ * void madd (Float32Array dst, Float32Array x, Float32Array y, double z);
+ *
+ * void mulCplx (Float32Array dstReal, Float32Array dstImag, Float32Array xReal, Float32Array xImag, double yReal, double yImag);
+ * void divCplx (Float32Array dstReal, Float32Array dstImag, Float32Array xReal, Float32Array xImag, double yReal, double yImag);
+ *
+ * void random (Float32Array dst, optional double low=0, optional optional double high=1);
+ * void clamp (Float32Array dst, Float32Array x, double xMin, double xMax);
+ * void ramp (Float32Array dst, double first, double last);
+ * void sampleLinear (Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
+ * void sampleCubic (Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
+ *
+ * void pack (TypedArray dst, unsigned long offset, unsigned long stride, Float32Array src1, optional Float32Array src2, optional optional Float32Array src3, optional optional Float32Array src4);
+ * void unpack (TypedArray src, unsigned long offset, unsigned long stride, Float32Array dst1, optional Float32Array dst2, optional optional Float32Array dst3, optional optional Float32Array dst4);
+ */
+
+
+#include <stdlib.h>
+
+#include <cmath>
+#include <complex>
+#include <algorithm>
+
+#include "jsapi.h"
+
+#include "jsfriendapi.h"
+
+#include "jsobjinlines.h"
+
+using namespace js;
+
+Class js::DSPClass = {
+ "DSP",
+ JSCLASS_HAS_CACHED_PROTO(JSProto_DSP),
+ JS_PropertyStub, /* addProperty */
+ JS_PropertyStub, /* delProperty */
+ JS_PropertyStub, /* getProperty */
+ JS_StrictPropertyStub, /* setProperty */
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub
+};
+
+#if JS_HAS_TOSOURCE
+// Is not supported yet…
+#endif
+
+static inline bool
+get_float32_array(JSContext *cx, Value *vp, unsigned arg, float ** result, uint32_t * length) {
+ JSObject * object = vp[2 + arg].toObjectOrNull();
+
+ *result = JS_GetFloat32ArrayData(object, cx);
+ *length = JS_GetTypedArrayLength(object, cx);
+
+ return *result != NULL;
+}
+
+typedef float (*operator_unary_real)(float a);
+typedef float (*operator_binary_real)(float a, float b);
+typedef float (*operator_trinary_real)(float a, float b, float c);
+
+typedef std::complex<float> cs_complex;
+
+typedef cs_complex (*operator_binary_complex)(cs_complex a, cs_complex b);
+
+typedef float (*operator_unary_complex_to_real)(cs_complex a);
+
+typedef void (*reduction_unary_real)(void * state, float a);
+typedef double (*reduction_unary_real_get_result)(const void * state);
+
+static inline JSBool
+cs_dsp_unary_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_real f)
+{
+ if (argc < 2) {
+ return JS_FALSE;
+ }
+
+ float * dst, * a0;
+ uint32_t dst_length, a0_length;
+
+ if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
+ return JS_FALSE;
+ }
+
+ if (get_float32_array(cx, vp, 1, &a0, &a0_length)) {
+ uint32_t length = std::min(dst_length, a0_length);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i] = f(a0[i]);
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+ } else {
+ return JS_FALSE;
+ }
+}
+
+static inline JSBool
+cs_dsp_unary_complex_to_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_complex_to_real f)
+{
+ if (argc < 3) {
+ return JS_FALSE;
+ }
+
+ float * dst, * a0_r, * a0_i;
+ uint32_t dst_length, a0_r_length, a0_i_length;
+
+ if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 1, &a0_r, &a0_r_length)) {
+ return JS_FALSE;
+ }
+
+ if (get_float32_array(cx, vp, 2, &a0_i, &a0_i_length)) {
+ uint32_t length = std::min(dst_length, std::min(a0_r_length, a0_i_length));
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i] = f(cs_complex(a0_r[i], a0_i[i]));
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+ } else {
+ return JS_FALSE;
+ }
+}
+
+static inline JSBool
+cs_dsp_binary_real(JSContext * cx, unsigned argc, Value *vp, operator_binary_real f)
+{
+ if (argc < 3) {
+ return JS_FALSE;
+ }
+
+ float * dst, * a0, * a1;
+ uint32_t dst_length, a0_length, a1_length;
+
+ if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 1, &a0, &a0_length)) {
+ return JS_FALSE;
+ }
+
+ if (get_float32_array(cx, vp, 2, &a1, &a1_length)) {
+ uint32_t length = std::min(std::min(dst_length, a0_length), a1_length);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i] = f(a0[i], a1[i]);
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+ } else {
+ return JS_FALSE;
+ }
+}
+
+static inline JSBool
+cs_dsp_binary_complex(JSContext * cx, unsigned argc, Value *vp, operator_binary_complex f)
+{
+ if (argc < 6) {
+ return JS_FALSE;
+ }
+
+ float * dst_r, * dst_i, * a0_r, * a0_i, * a1_r, * a1_i;
+ uint32_t dst_r_length, dst_i_length, a0_r_length, a0_i_length, a1_r_length, a1_i_length;
+
+ if (!get_float32_array(cx, vp, 0, &dst_r, &dst_r_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 1, &dst_i, &dst_i_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 2, &a0_r, &a0_r_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 3, &a0_i, &a0_i_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 4, &a1_r, &a1_r_length)) {
+ return JS_FALSE;
+ }
+
+ if (get_float32_array(cx, vp, 5, &a1_i, &a1_i_length)) {
+ uint32_t length = std::min(std::min(std::min(dst_r_length, dst_i_length), std::min(a0_r_length, a0_i_length)), std::min(a1_r_length, a1_i_length));
+
+ for (uint32_t i = 0; i < length; i++) {
+ cs_complex r = f(cs_complex(a0_r[i], a0_i[i]), cs_complex(a1_r[i], a1_i[i]));
+
+ dst_r[i] = r.real();
+ dst_i[i] = r.imag();
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+ } else {
+ return JS_FALSE;
+ }
+}
+
+static inline JSBool
+cs_dsp_trinary_real(JSContext * cx, unsigned argc, Value *vp, operator_trinary_real f)
+{
+ if (argc < 4) {
+ return JS_FALSE;
+ }
+
+ float * dst, * a0, * a1, * a2;
+ uint32_t dst_length, a0_length, a1_length, a2_length;
+
+ if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 1, &a0, &a0_length)) {
+ return JS_FALSE;
+ }
+
+ if (!get_float32_array(cx, vp, 2, &a1, &a1_length)) {
+ return JS_FALSE;
+ }
+
+ if (get_float32_array(cx, vp, 3, &a2, &a2_length)) {
+ uint32_t length = std::min(std::min(std::min(dst_length, a0_length), a1_length), a2_length);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i] = f(a0[i], a1[i], a2[i]);
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+ } else {
+ return JS_FALSE;
+ }
+}
+
+static inline JSBool
+cs_dsp_unary_real_reduction(JSContext * cx, unsigned argc, Value *vp, reduction_unary_real f, reduction_unary_real_get_result g, void * state)
+{
+ if (argc < 1) {
+ return JS_FALSE;
+ }
+
+ float * a0;
+ uint32_t a0_length;
+
+ if (get_float32_array(cx, vp, 0, &a0, &a0_length)) {
+ for (uint32_t i = 0; i < a0_length; i++) {
+ f(state, a0[i]);
+ }
+
+ vp->setNumber(g(state));
+
+ return JS_TRUE;
+ } else {
+ return JS_FALSE;
+ }
+}
+
+static inline float cs_dsp_abs_impl(float x) {
+ return std::fabs(x);
+}
+
+static inline float cs_dsp_sqrt_impl(float x) {
+ return std::sqrt(x);
+}
+
+static inline float cs_dsp_cabs_impl(cs_complex x) {
+ return std::abs(x);
+}
+
+/* Trigonometric functions */
+
+static inline float cs_dsp_cos_impl(float x) {
+ return std::cos(x);
+}
+
+static inline float cs_dsp_sin_impl(float x) {
+ return std::sin(x);
+}
+
+static inline float cs_dsp_tan_impl(float x) {
+ return std::tan(x);
+}
+
+static inline float cs_dsp_acos_impl(float x) {
+ return std::acos(x);
+}
+
+static inline float cs_dsp_asin_impl(float x) {
+ return std::asin(x);
+}
+
+static inline float cs_dsp_atan_impl(float x) {
+ return std::atan(x);
+}
+
+static inline float cs_dsp_atan2_impl(float x, float y) {
+ return std::atan2(x, y);
+}
+
+/* Exponential functions */
+
+static inline float cs_dsp_exp_impl(float x) {
+ return std::exp(x);
+}
+
+static inline float cs_dsp_log_impl(float x) {
+ return std::log(x);
+}
+
+/* Rounding functions */
+
+static inline float cs_dsp_ceil_impl(float x) {
+ return std::ceil(x);
+}
+
+static inline float cs_dsp_floor_impl(float x) {
+ return std::floor(x);
+}
+
+static inline float cs_dsp_round_impl(float x) {
+ // TODO: Should check for overflow…
+
+ // TODO: Should use the C99 version of copysign, but haters…
+ return __builtin_copysign(std::floor(x + 0.5f), x);
+}
+
+/* FP functions */
+
+static inline float cs_dsp_sign_impl(float x) {
+ // TODO: Should use the C99 version of copysign, but haters…
+ return __builtin_copysign(1.0f, x);
+}
+
+static inline float cs_dsp_fract_impl(float x) {
+ return x - std::floor(x);
+}
+
+/* Arithmetic functions */
+
+static inline float cs_dsp_add_impl(float x, float y) {
+ return x + y;
+}
+
+static inline float cs_dsp_sub_impl(float x, float y) {
+ return x - y;
+}
+
+static inline float cs_dsp_mul_impl(float x, float y) {
+ return x * y;
+}
+
+static inline float cs_dsp_div_impl(float x, float y) {
+ return x / y;
+}
+
+static inline float cs_dsp_pow_impl(float x, float y) {
+ return std::pow(x, y);
+}
+
+static inline float cs_dsp_madd_impl(float x, float y, float z) {
+ return x * y + z;
+}
+
+static inline cs_complex cs_dsp_cmul_impl(cs_complex x, cs_complex y) {
+ return x * y;
+}
+
+static inline cs_complex cs_dsp_cdiv_impl(cs_complex x, cs_complex y) {
+ return x / y;
+}
+
+/* Reductions */
+
+typedef struct {
+ float value;
+} cs_dsp_minmax_state;
+
+static inline void cs_dsp_min_impl(void * state, float x) {
+ cs_dsp_minmax_state * s = (cs_dsp_minmax_state *)state;
+
+ s->value = std::min(s->value, x);
+}
+
+static inline void cs_dsp_max_impl(void * state, float x) {
+ cs_dsp_minmax_state * s = (cs_dsp_minmax_state *)state;
+
+ s->value = std::max(s->value, x);
+}
+
+static inline double cs_dsp_minmax_final(const void * state) {
+ return ((cs_dsp_minmax_state *)state)->value;
+}
+
+static JSBool
+cs_dsp_min(JSContext *cx, unsigned argc, Value *vp) {
+ cs_dsp_minmax_state state = { 1.0f / 0.0f };
+
+ return cs_dsp_unary_real_reduction(cx, argc, vp, cs_dsp_min_impl, cs_dsp_minmax_final, &state);
+}
+
+static JSBool
+cs_dsp_max(JSContext *cx, unsigned argc, Value *vp) {
+ cs_dsp_minmax_state state = { -1.0f / 0.0f };
+
+ return cs_dsp_unary_real_reduction(cx, argc, vp, cs_dsp_max_impl, cs_dsp_minmax_final, &state);
+}
+
+typedef struct {
+ double sum, compensation; // Look ma, double-precision! Should together with the Kahan summation give adequate performance
+} cs_dsp_kahan_summation;
+
+static inline void cs_dsp_sum_impl(void * state, float x) {
+ cs_dsp_kahan_summation * s = (cs_dsp_kahan_summation *)state;
+
+ double y = (double)x - s->compensation;
+ double t = s->sum + y;
+
+ s->compensation = (t - s->sum) - y;
+ s->sum = t;
+}
+
+static inline double cs_dsp_sum_final(const void * state) {
+ return ((cs_dsp_kahan_summation *)state)->sum;
+}
+
+static JSBool
+cs_dsp_sum(JSContext *cx, unsigned argc, Value *vp) {
+ cs_dsp_kahan_summation state = { 0.0, 0.0 };
+
+ return cs_dsp_unary_real_reduction(cx, argc, vp, cs_dsp_sum_impl, cs_dsp_sum_final, &state);
+}
+
+#define cs_unary_real_op(name) static JSBool \
+name(JSContext *cx, unsigned argc, Value *vp) { \
+ return cs_dsp_unary_real(cx, argc, vp, name ## _impl); \
+}
+
+#define cs_unary_complex_to_real_op(name) static JSBool \
+name(JSContext *cx, unsigned argc, Value *vp) { \
+ return cs_dsp_unary_complex_to_real(cx, argc, vp, name ## _impl); \
+}
+
+#define cs_binary_real_op(name) static JSBool \
+name(JSContext *cx, unsigned argc, Value *vp) { \
+ return cs_dsp_binary_real(cx, argc, vp, name ## _impl); \
+}
+
+#define cs_binary_complex_op(name) static JSBool \
+name(JSContext *cx, unsigned argc, Value *vp) { \
+ return cs_dsp_binary_complex(cx, argc, vp, name ## _impl); \
+}
+
+#define cs_trinary_real_op(name) static JSBool \
+name(JSContext *cx, unsigned argc, Value *vp) { \
+ return cs_dsp_trinary_real(cx, argc, vp, name ## _impl); \
+}
+
+cs_unary_real_op(cs_dsp_abs)
+cs_unary_real_op(cs_dsp_sqrt)
+
+cs_unary_complex_to_real_op(cs_dsp_cabs)
+
+
+/* Trigonometric functions */
+
+cs_unary_real_op(cs_dsp_cos)
+cs_unary_real_op(cs_dsp_sin)
+cs_unary_real_op(cs_dsp_tan)
+
+cs_unary_real_op(cs_dsp_acos)
+cs_unary_real_op(cs_dsp_asin)
+cs_unary_real_op(cs_dsp_atan)
+
+cs_binary_real_op(cs_dsp_atan2)
+
+/* Exponential functions */
+
+cs_unary_real_op(cs_dsp_exp)
+cs_unary_real_op(cs_dsp_log)
+
+/* Rounding functions */
+
+cs_unary_real_op(cs_dsp_ceil)
+cs_unary_real_op(cs_dsp_floor)
+cs_unary_real_op(cs_dsp_round)
+
+/* FP functions */
+
+cs_unary_real_op(cs_dsp_sign)
+cs_unary_real_op(cs_dsp_fract)
+
+/* Arithmetic functions */
+
+cs_binary_real_op(cs_dsp_add)
+cs_binary_real_op(cs_dsp_sub)
+cs_binary_real_op(cs_dsp_mul)
+cs_binary_real_op(cs_dsp_div)
+cs_binary_real_op(cs_dsp_pow)
+
+cs_trinary_real_op(cs_dsp_madd)
+
+cs_binary_complex_op(cs_dsp_cmul)
+cs_binary_complex_op(cs_dsp_cdiv)
+
+static JSFunctionSpec dsp_static_methods[] = {
+#if JS_HAS_TOSOURCE
+ // TODO: Is not supportedyet… JS_FN(js_toSource_str, dsp_toSource, 0, 0),
+#endif
+ /* Unary real functions */
+ JS_FN("abs", cs_dsp_abs, 2, 0),
+ JS_FN("sqrt", cs_dsp_sqrt, 2, 0),
+ JS_FN("absCplx", cs_dsp_cabs, 3, 0),
+ JS_FN("cos", cs_dsp_cos, 2, 0),
+ JS_FN("sin", cs_dsp_sin, 2, 0),
+ JS_FN("tan", cs_dsp_tan, 2, 0),
+ JS_FN("acos", cs_dsp_acos, 2, 0),
+ JS_FN("asin", cs_dsp_asin, 2, 0),
+ JS_FN("atan", cs_dsp_atan, 2, 0),
+ JS_FN("atan2", cs_dsp_atan2, 3, 0),
+ JS_FN("exp", cs_dsp_exp, 2, 0),
+ JS_FN("log", cs_dsp_log, 2, 0),
+ JS_FN("ceil", cs_dsp_ceil, 2, 0),
+ JS_FN("floor", cs_dsp_floor, 2, 0),
+ JS_FN("round", cs_dsp_round, 2, 0),
+ JS_FN("sign", cs_dsp_sign, 2, 0),
+ JS_FN("fract", cs_dsp_fract, 2, 0),
+ JS_FN("add", cs_dsp_add, 3, 0),
+ JS_FN("sub", cs_dsp_sub, 3, 0),
+ JS_FN("mul", cs_dsp_mul, 3, 0),
+ JS_FN("div", cs_dsp_div, 3, 0),
+ JS_FN("pow", cs_dsp_pow, 3, 0),
+ JS_FN("madd", cs_dsp_madd, 4, 0),
+ JS_FN("mulCplx", cs_dsp_cmul, 6, 0),
+ JS_FN("divCplx", cs_dsp_cdiv, 6, 0),
+ JS_FN("min", cs_dsp_min, 1, 0),
+ JS_FN("max", cs_dsp_max, 1, 0),
+ JS_FN("sum", cs_dsp_sum, 1, 0),
+ JS_FS_END
+};
+
+JSObject *
+js_InitDSPClass(JSContext *cx, HandleObject obj)
+{
+ RootedObject DSP(cx, NewObjectWithClassProto(cx, &DSPClass, NULL, obj));
+
+ if (!DSP || !JSObject::setSingletonType(cx, DSP))
+ return NULL;
+
+ if (!JS_DefineProperty(cx, obj, "DSP", OBJECT_TO_JSVAL(DSP), JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+ return NULL;
+ }
+
+ if (!JS_DefineFunctions(cx, DSP, dsp_static_methods))
+ return NULL;
+
+ MarkStandardClassInitializedNoProto(obj, &DSPClass);
+
+ return DSP;
+}
diff --git a/js/src/csdsp.h b/js/src/csdsp.h
new file mode 100644
--- /dev/null
+++ b/js/src/csdsp.h
@@ -0,0 +1,13 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef csdsp_h___
+#define csdsp_h___
+
+extern JSObject *
+js_InitDSPClass(JSContext *cx, js::HandleObject obj);
+
+#endif /* csdsp_h___ */
# HG changeset patch
# User Jens Nockert <jens@nockert.se>
# Date 1351867514 -3600
# Branch dsp-api
# Node ID 4c73a4ed2e9d9d501cff633f4b62f8824291f5f7
# Parent f1d96ac2aa249a28137468c575cb72fdecf15f7b
Support scalar arguments
diff --git a/js/src/csdsp.cpp b/js/src/csdsp.cpp
--- a/js/src/csdsp.cpp
+++ b/js/src/csdsp.cpp
@@ -4,26 +4,16 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* JS DSP package.
*
* TODO: List of functions or signatures to implement
- *
- * void add (Float32Array dst, Float32Array x, double y);
- * void sub (Float32Array dst, Float32Array x, double y);
- * void mul (Float32Array dst, Float32Array x, double y);
- * void div (Float32Array dst, Float32Array x, double y);
- * void pow (Float32Array dst, Float32Array x, double y);
- * void madd (Float32Array dst, Float32Array x, Float32Array y, double z);
- *
- * void mulCplx (Float32Array dstReal, Float32Array dstImag, Float32Array xReal, Float32Array xImag, double yReal, double yImag);
- * void divCplx (Float32Array dstReal, Float32Array dstImag, Float32Array xReal, Float32Array xImag, double yReal, double yImag);
*
* void random (Float32Array dst, optional double low=0, optional optional double high=1);
* void clamp (Float32Array dst, Float32Array x, double xMin, double xMax);
* void ramp (Float32Array dst, double first, double last);
* void sampleLinear (Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
* void sampleCubic (Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
*
* void pack (TypedArray dst, unsigned long offset, unsigned long stride, Float32Array src1, optional Float32Array src2, optional optional Float32Array src3, optional optional Float32Array src4);
@@ -56,24 +46,52 @@ Class js::DSPClass = {
JS_ResolveStub,
JS_ConvertStub
};
#if JS_HAS_TOSOURCE
// Is not supported yet…
#endif
-static inline bool
-get_float32_array(JSContext *cx, Value *vp, unsigned arg, float ** result, uint32_t * length) {
+static inline float *
+get_float32(bool initialized, JSContext *cx, Value *vp, unsigned arg, uint32_t * length, uint32_t * stride, float * scalar) {
JSObject * object = vp[2 + arg].toObjectOrNull();
- *result = JS_GetFloat32ArrayData(object, cx);
- *length = JS_GetTypedArrayLength(object, cx);
+ float * result = JS_GetFloat32ArrayData(object, cx);
- return *result != NULL;
+ if (result) {
+ uint32_t l = JS_GetTypedArrayLength(object, cx);
+
+ *length = initialized ? std::min(*length, l) : l;
+ *stride = 1;
+
+ return result;
+ } else {
+ scalar[0] = vp[2 + arg].toNumber();
+
+ *stride = 0;
+
+ return scalar;
+ }
+}
+
+static inline float *
+get_float32_array(bool initialized, JSContext *cx, Value *vp, unsigned arg, uint32_t * length, uint32_t * stride) {
+ JSObject * object = vp[2 + arg].toObjectOrNull();
+
+ float * result = JS_GetFloat32ArrayData(object, cx);
+
+ if (result) {
+ uint32_t l = JS_GetTypedArrayLength(object, cx);
+
+ *length = initialized ? std::min(*length, l) : l;
+ *stride = 1;
+ }
+
+ return result;
}
typedef float (*operator_unary_real)(float a);
typedef float (*operator_binary_real)(float a, float b);
typedef float (*operator_trinary_real)(float a, float b, float c);
typedef std::complex<float> cs_complex;
@@ -82,214 +100,165 @@ typedef cs_complex (*operator_binary_com
typedef float (*operator_unary_complex_to_real)(cs_complex a);
typedef void (*reduction_unary_real)(void * state, float a);
typedef double (*reduction_unary_real_get_result)(const void * state);
static inline JSBool
cs_dsp_unary_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_real f)
{
- if (argc < 2) {
- return JS_FALSE;
+ if (argc < 2) { return JS_FALSE; }
+
+ float s[1];
+
+ uint32_t length, dst_stride, a0_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+
+ if (!dst) { return JS_FALSE; }
+
+ float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i * dst_stride] = f(a0[i * a0_stride]);
}
- float * dst, * a0;
- uint32_t dst_length, a0_length;
+ vp->setUndefined();
- if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
- return JS_FALSE;
- }
-
- if (get_float32_array(cx, vp, 1, &a0, &a0_length)) {
- uint32_t length = std::min(dst_length, a0_length);
-
- for (uint32_t i = 0; i < length; i++) {
- dst[i] = f(a0[i]);
- }
-
- vp->setUndefined();
-
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ return JS_TRUE;
}
static inline JSBool
cs_dsp_unary_complex_to_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_complex_to_real f)
{
- if (argc < 3) {
- return JS_FALSE;
+ if (argc < 3) { return JS_FALSE; }
+
+ float s[2];
+
+ uint32_t length, dst_stride, a0_r_stride, a0_i_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+
+ if (!dst) { return JS_FALSE; }
+
+ float * a0_r = get_float32(true, cx, vp, 1, &length, &a0_r_stride, &s[0]);
+ float * a0_i = get_float32(true, cx, vp, 2, &length, &a0_i_stride, &s[1]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i * dst_stride] = f(cs_complex(a0_r[i * a0_r_stride], a0_i[i * a0_i_stride]));
}
- float * dst, * a0_r, * a0_i;
- uint32_t dst_length, a0_r_length, a0_i_length;
+ vp->setUndefined();
- if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 1, &a0_r, &a0_r_length)) {
- return JS_FALSE;
- }
-
- if (get_float32_array(cx, vp, 2, &a0_i, &a0_i_length)) {
- uint32_t length = std::min(dst_length, std::min(a0_r_length, a0_i_length));
-
- for (uint32_t i = 0; i < length; i++) {
- dst[i] = f(cs_complex(a0_r[i], a0_i[i]));
- }
-
- vp->setUndefined();
-
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ return JS_TRUE;
}
static inline JSBool
cs_dsp_binary_real(JSContext * cx, unsigned argc, Value *vp, operator_binary_real f)
{
- if (argc < 3) {
- return JS_FALSE;
+ if (argc < 3) { return JS_FALSE; }
+
+ float s[2];
+
+ uint32_t length, dst_stride, a0_stride, a1_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+
+ if (!dst) { return JS_FALSE; }
+
+ float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
+ float * a1 = get_float32(true, cx, vp, 2, &length, &a1_stride, &s[1]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i * dst_stride] = f(a0[i * a0_stride], a1[i * a1_stride]);
}
- float * dst, * a0, * a1;
- uint32_t dst_length, a0_length, a1_length;
+ vp->setUndefined();
- if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 1, &a0, &a0_length)) {
- return JS_FALSE;
- }
-
- if (get_float32_array(cx, vp, 2, &a1, &a1_length)) {
- uint32_t length = std::min(std::min(dst_length, a0_length), a1_length);
-
- for (uint32_t i = 0; i < length; i++) {
- dst[i] = f(a0[i], a1[i]);
- }
-
- vp->setUndefined();
-
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ return JS_TRUE;
}
static inline JSBool
cs_dsp_binary_complex(JSContext * cx, unsigned argc, Value *vp, operator_binary_complex f)
{
- if (argc < 6) {
- return JS_FALSE;
+ if (argc < 6) { return JS_FALSE; }
+
+ float s[4];
+
+ uint32_t length, dst_r_stride, dst_i_stride, a0_r_stride, a0_i_stride, a1_r_stride, a1_i_stride;
+
+ float * dst_r = get_float32_array(false, cx, vp, 0, &length, &dst_r_stride);
+ float * dst_i = get_float32_array(true, cx, vp, 1, &length, &dst_i_stride);
+
+ if (!dst_r) { return JS_FALSE; }
+ if (!dst_i) { return JS_FALSE; }
+
+ float * a0_r = get_float32(true, cx, vp, 2, &length, &a0_r_stride, &s[0]);
+ float * a0_i = get_float32(true, cx, vp, 3, &length, &a0_i_stride, &s[1]);
+ float * a1_r = get_float32(true, cx, vp, 4, &length, &a1_r_stride, &s[2]);
+ float * a1_i = get_float32(true, cx, vp, 5, &length, &a1_i_stride, &s[3]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ cs_complex result = f(cs_complex(a0_r[i * a0_r_stride], a0_i[i * a0_i_stride]), cs_complex(a1_r[i * a1_r_stride], a1_i[i * a1_i_stride]));
+
+ dst_r[i * dst_r_stride] = result.real();
+ dst_i[i * dst_i_stride] = result.imag();
}
- float * dst_r, * dst_i, * a0_r, * a0_i, * a1_r, * a1_i;
- uint32_t dst_r_length, dst_i_length, a0_r_length, a0_i_length, a1_r_length, a1_i_length;
+ vp->setUndefined();
- if (!get_float32_array(cx, vp, 0, &dst_r, &dst_r_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 1, &dst_i, &dst_i_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 2, &a0_r, &a0_r_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 3, &a0_i, &a0_i_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 4, &a1_r, &a1_r_length)) {
- return JS_FALSE;
- }
-
- if (get_float32_array(cx, vp, 5, &a1_i, &a1_i_length)) {
- uint32_t length = std::min(std::min(std::min(dst_r_length, dst_i_length), std::min(a0_r_length, a0_i_length)), std::min(a1_r_length, a1_i_length));
-
- for (uint32_t i = 0; i < length; i++) {
- cs_complex r = f(cs_complex(a0_r[i], a0_i[i]), cs_complex(a1_r[i], a1_i[i]));
-
- dst_r[i] = r.real();
- dst_i[i] = r.imag();
- }
-
- vp->setUndefined();
-
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ return JS_TRUE;
}
static inline JSBool
cs_dsp_trinary_real(JSContext * cx, unsigned argc, Value *vp, operator_trinary_real f)
{
- if (argc < 4) {
- return JS_FALSE;
+ if (argc < 4) { return JS_FALSE; }
+
+ float s[3];
+
+ uint32_t length, dst_stride, a0_stride, a1_stride, a2_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+
+ if (!dst) { return JS_FALSE; }
+
+ float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
+ float * a1 = get_float32(true, cx, vp, 2, &length, &a1_stride, &s[1]);
+ float * a2 = get_float32(true, cx, vp, 3, &length, &a2_stride, &s[2]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i * dst_stride] = f(a0[i * a0_stride], a1[i * a1_stride], a2[i * a2_stride]);
}
- float * dst, * a0, * a1, * a2;
- uint32_t dst_length, a0_length, a1_length, a2_length;
+ vp->setUndefined();
- if (!get_float32_array(cx, vp, 0, &dst, &dst_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 1, &a0, &a0_length)) {
- return JS_FALSE;
- }
-
- if (!get_float32_array(cx, vp, 2, &a1, &a1_length)) {
- return JS_FALSE;
- }
-
- if (get_float32_array(cx, vp, 3, &a2, &a2_length)) {
- uint32_t length = std::min(std::min(std::min(dst_length, a0_length), a1_length), a2_length);
-
- for (uint32_t i = 0; i < length; i++) {
- dst[i] = f(a0[i], a1[i], a2[i]);
- }
-
- vp->setUndefined();
-
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ return JS_TRUE;
}
static inline JSBool
cs_dsp_unary_real_reduction(JSContext * cx, unsigned argc, Value *vp, reduction_unary_real f, reduction_unary_real_get_result g, void * state)
{
- if (argc < 1) {
- return JS_FALSE;
+ if (argc < 1) { return JS_FALSE; }
+
+ float * a0;
+
+ uint32_t length, a0_stride;
+
+ a0 = get_float32_array(false, cx, vp, 0, &length, &a0_stride);
+
+ if (!a0) { return JS_FALSE; }
+
+ for (uint32_t i = 0; i < length; i++) {
+ f(state, a0[i * a0_stride]);
}
- float * a0;
- uint32_t a0_length;
+ vp->setNumber(g(state));
- if (get_float32_array(cx, vp, 0, &a0, &a0_length)) {
- for (uint32_t i = 0; i < a0_length; i++) {
- f(state, a0[i]);
- }
-
- vp->setNumber(g(state));
-
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ return JS_TRUE;
}
static inline float cs_dsp_abs_impl(float x) {
return std::fabs(x);
}
static inline float cs_dsp_sqrt_impl(float x) {
return std::sqrt(x);
# HG changeset patch
# User Jens Nockert <jens@nockert.se>
# Date 1351870001 -3600
# Branch dsp-api
# Node ID f479a784f43c0242f66d8441e848a2267fe2881d
# Parent 4c73a4ed2e9d9d501cff633f4b62f8824291f5f7
Add ramp, random
diff --git a/js/src/csdsp.cpp b/js/src/csdsp.cpp
--- a/js/src/csdsp.cpp
+++ b/js/src/csdsp.cpp
@@ -5,34 +5,31 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* JS DSP package.
*
* TODO: List of functions or signatures to implement
*
- * void random (Float32Array dst, optional double low=0, optional optional double high=1);
- * void clamp (Float32Array dst, Float32Array x, double xMin, double xMax);
- * void ramp (Float32Array dst, double first, double last);
- * void sampleLinear (Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
- * void sampleCubic (Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
+ * void sampleLinear(Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
+ * void sampleCubic(Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
*
- * void pack (TypedArray dst, unsigned long offset, unsigned long stride, Float32Array src1, optional Float32Array src2, optional optional Float32Array src3, optional optional Float32Array src4);
- * void unpack (TypedArray src, unsigned long offset, unsigned long stride, Float32Array dst1, optional Float32Array dst2, optional optional Float32Array dst3, optional optional Float32Array dst4);
+ * void pack(TypedArray dst, unsigned long offset, unsigned long stride, Float32Array src1, optional Float32Array src2, optional optional Float32Array src3, optional optional Float32Array src4);
+ * void unpack(TypedArray src, unsigned long offset, unsigned long stride, Float32Array dst1, optional Float32Array dst2, optional optional Float32Array dst3, optional optional Float32Array dst4);
*/
-
#include <stdlib.h>
#include <cmath>
#include <complex>
#include <algorithm>
#include "jsapi.h"
+#include "jsmath.h"
#include "jsfriendapi.h"
#include "jsobjinlines.h"
using namespace js;
Class js::DSPClass = {
@@ -84,46 +81,67 @@ get_float32_array(bool initialized, JSCo
*length = initialized ? std::min(*length, l) : l;
*stride = 1;
}
return result;
}
-typedef float (*operator_unary_real)(float a);
+typedef float (*operator_none_real)(void * state, uint32_t i, uint32_t length);
+typedef float (*operator_unary_real)(void * state, float a);
typedef float (*operator_binary_real)(float a, float b);
typedef float (*operator_trinary_real)(float a, float b, float c);
typedef std::complex<float> cs_complex;
typedef cs_complex (*operator_binary_complex)(cs_complex a, cs_complex b);
typedef float (*operator_unary_complex_to_real)(cs_complex a);
typedef void (*reduction_unary_real)(void * state, float a);
typedef double (*reduction_unary_real_get_result)(const void * state);
static inline JSBool
-cs_dsp_unary_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_real f)
+cs_dsp_none_real(JSContext * cx, unsigned argc, Value *vp, operator_none_real f, void * state)
+{
+ if (argc < 1) { return JS_FALSE; }
+
+ uint32_t length, dst_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+
+ if (!dst) { return JS_FALSE; }
+
+ for (uint32_t i = 0; i < length; i++) {
+ dst[i * dst_stride] = f(state, i, length);
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+}
+
+static inline JSBool
+cs_dsp_unary_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_real f, void * state)
{
if (argc < 2) { return JS_FALSE; }
float s[1];
uint32_t length, dst_stride, a0_stride;
float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
if (!dst) { return JS_FALSE; }
float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
for (uint32_t i = 0; i < length; i++) {
- dst[i * dst_stride] = f(a0[i * a0_stride]);
+ dst[i * dst_stride] = f(state, a0[i * a0_stride]);
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
@@ -251,93 +269,93 @@ cs_dsp_unary_real_reduction(JSContext *
f(state, a0[i * a0_stride]);
}
vp->setNumber(g(state));
return JS_TRUE;
}
-static inline float cs_dsp_abs_impl(float x) {
+static inline float cs_dsp_abs_impl(void * state, float x) {
return std::fabs(x);
}
-static inline float cs_dsp_sqrt_impl(float x) {
+static inline float cs_dsp_sqrt_impl(void * state, float x) {
return std::sqrt(x);
}
static inline float cs_dsp_cabs_impl(cs_complex x) {
return std::abs(x);
}
/* Trigonometric functions */
-static inline float cs_dsp_cos_impl(float x) {
+static inline float cs_dsp_cos_impl(void * state, float x) {
return std::cos(x);
}
-static inline float cs_dsp_sin_impl(float x) {
+static inline float cs_dsp_sin_impl(void * state, float x) {
return std::sin(x);
}
-static inline float cs_dsp_tan_impl(float x) {
+static inline float cs_dsp_tan_impl(void * state, float x) {
return std::tan(x);
}
-static inline float cs_dsp_acos_impl(float x) {
+static inline float cs_dsp_acos_impl(void * state, float x) {
return std::acos(x);
}
-static inline float cs_dsp_asin_impl(float x) {
+static inline float cs_dsp_asin_impl(void * state, float x) {
return std::asin(x);
}
-static inline float cs_dsp_atan_impl(float x) {
+static inline float cs_dsp_atan_impl(void * state, float x) {
return std::atan(x);
}
static inline float cs_dsp_atan2_impl(float x, float y) {
return std::atan2(x, y);
}
/* Exponential functions */
-static inline float cs_dsp_exp_impl(float x) {
+static inline float cs_dsp_exp_impl(void * state, float x) {
return std::exp(x);
}
-static inline float cs_dsp_log_impl(float x) {
+static inline float cs_dsp_log_impl(void * state, float x) {
return std::log(x);
}
/* Rounding functions */
-static inline float cs_dsp_ceil_impl(float x) {
+static inline float cs_dsp_ceil_impl(void * state, float x) {
return std::ceil(x);
}
-static inline float cs_dsp_floor_impl(float x) {
+static inline float cs_dsp_floor_impl(void * state, float x) {
return std::floor(x);
}
-static inline float cs_dsp_round_impl(float x) {
+static inline float cs_dsp_round_impl(void * state, float x) {
// TODO: Should check for overflow…
// TODO: Should use the C99 version of copysign, but haters…
return __builtin_copysign(std::floor(x + 0.5f), x);
}
/* FP functions */
-static inline float cs_dsp_sign_impl(float x) {
+static inline float cs_dsp_sign_impl(void * state, float x) {
// TODO: Should use the C99 version of copysign, but haters…
return __builtin_copysign(1.0f, x);
}
-static inline float cs_dsp_fract_impl(float x) {
+static inline float cs_dsp_fract_impl(void * state, float x) {
return x - std::floor(x);
}
/* Arithmetic functions */
static inline float cs_dsp_add_impl(float x, float y) {
return x + y;
}
@@ -426,19 +444,73 @@ static inline double cs_dsp_sum_final(co
static JSBool
cs_dsp_sum(JSContext *cx, unsigned argc, Value *vp) {
cs_dsp_kahan_summation state = { 0.0, 0.0 };
return cs_dsp_unary_real_reduction(cx, argc, vp, cs_dsp_sum_impl, cs_dsp_sum_final, &state);
}
+typedef struct {
+ float min, max;
+} cs_dsp_clamp_state;
+
+static inline float cs_dsp_clamp_impl(void * state, float x) {
+ cs_dsp_clamp_state * s = (cs_dsp_clamp_state *)state;
+
+ return std::min(s->max, std::max(s->min, x));
+}
+
+static JSBool
+cs_dsp_clamp(JSContext *cx, unsigned argc, Value *vp) {
+ if (argc < 4) { return JS_FALSE; }
+
+ cs_dsp_clamp_state state = { (float)vp[4].toNumber(), (float)vp[5].toNumber() };
+
+ return cs_dsp_unary_real(cx, argc - 2, vp, cs_dsp_clamp_impl, &state);
+}
+
+static inline float cs_dsp_ramp_impl(void * state, uint32_t i, uint32_t length) {
+ cs_dsp_clamp_state * s = (cs_dsp_clamp_state *)state;
+
+ return s->min + i * (s->max / (length - 1));
+}
+
+static JSBool
+cs_dsp_ramp(JSContext *cx, unsigned argc, Value *vp) {
+ if (argc < 3) { return JS_FALSE; }
+
+ cs_dsp_clamp_state state = { (float)vp[3].toNumber(), (float)vp[4].toNumber() - (float)vp[3].toNumber() };
+
+ return cs_dsp_none_real(cx, argc - 2, vp, cs_dsp_ramp_impl, &state);
+}
+
+typedef struct {
+ float min, max;
+ JSContext * context;
+} cs_dsp_random_state;
+
+static inline float cs_dsp_random_impl(void * state, uint32_t i, uint32_t length) {
+ cs_dsp_random_state * s = (cs_dsp_random_state *)state;
+
+ return s->min + math_random_no_outparam(s->context) * s->max;
+}
+
+static JSBool
+cs_dsp_random(JSContext *cx, unsigned argc, Value *vp) {
+ if (argc < 3) { return JS_FALSE; }
+
+ cs_dsp_random_state state = { (float)vp[3].toNumber(), (float)vp[4].toNumber() - (float)vp[3].toNumber(), cx };
+
+ return cs_dsp_none_real(cx, argc - 2, vp, cs_dsp_random_impl, &state);
+}
+
#define cs_unary_real_op(name) static JSBool \
name(JSContext *cx, unsigned argc, Value *vp) { \
- return cs_dsp_unary_real(cx, argc, vp, name ## _impl); \
+ return cs_dsp_unary_real(cx, argc, vp, name ## _impl, NULL); \
}
#define cs_unary_complex_to_real_op(name) static JSBool \
name(JSContext *cx, unsigned argc, Value *vp) { \
return cs_dsp_unary_complex_to_real(cx, argc, vp, name ## _impl); \
}
#define cs_binary_real_op(name) static JSBool \
@@ -531,16 +603,19 @@ static JSFunctionSpec dsp_static_methods
JS_FN("div", cs_dsp_div, 3, 0),
JS_FN("pow", cs_dsp_pow, 3, 0),
JS_FN("madd", cs_dsp_madd, 4, 0),
JS_FN("mulCplx", cs_dsp_cmul, 6, 0),
JS_FN("divCplx", cs_dsp_cdiv, 6, 0),
JS_FN("min", cs_dsp_min, 1, 0),
JS_FN("max", cs_dsp_max, 1, 0),
JS_FN("sum", cs_dsp_sum, 1, 0),
+ JS_FN("clamp", cs_dsp_clamp, 4, 0),
+ JS_FN("ramp", cs_dsp_ramp, 3, 0),
+ JS_FN("random", cs_dsp_random, 3, 0),
JS_FS_END
};
JSObject *
js_InitDSPClass(JSContext *cx, HandleObject obj)
{
RootedObject DSP(cx, NewObjectWithClassProto(cx, &DSPClass, NULL, obj));
# HG changeset patch
# User Jens Nockert <jens@nockert.se>
# Date 1351871582 -3600
# Branch dsp-api
# Node ID d78200e090b9a70483b6818c86b4c45717c3913d
# Parent f479a784f43c0242f66d8441e848a2267fe2881d
Implement pack and unpack lazily
diff --git a/js/src/csdsp.cpp b/js/src/csdsp.cpp
--- a/js/src/csdsp.cpp
+++ b/js/src/csdsp.cpp
@@ -498,16 +498,88 @@ static JSBool
cs_dsp_random(JSContext *cx, unsigned argc, Value *vp) {
if (argc < 3) { return JS_FALSE; }
cs_dsp_random_state state = { (float)vp[3].toNumber(), (float)vp[4].toNumber() - (float)vp[3].toNumber(), cx };
return cs_dsp_none_real(cx, argc - 2, vp, cs_dsp_random_impl, &state);
}
+static JSBool
+cs_dsp_pack(JSContext *cx, unsigned argc, Value *vp) {
+ if (argc < 4) { return JS_FALSE; }
+
+ uint32_t length, offset = (uint32_t)vp[3].toInt32(), stride = (uint32_t)vp[4].toInt32(), dst_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+
+ if (!dst) { return JS_FALSE; }
+
+ length = (length - offset) / stride; /* TODO: Bad feeling about this, but too lazy to think… */
+
+ uint32_t n = argc - 3;
+
+ /* TODO: Maybe implement the actual algorithm, that does not require calloc, or not… */
+
+ uint32_t * strides = (uint32_t *)calloc(n, sizeof(uint32_t));
+ float ** sources = (float **)calloc(n, sizeof(float *)), * s = (float *)calloc(n, sizeof(float));
+
+ for (uint32_t i = 0; i < n; i++) {
+ sources[i] = get_float32(true, cx, vp, 3 + i, &length, &strides[i], &s[i]);
+ }
+
+ for (uint32_t i = 0; i < length; i++) {
+ for (uint32_t j = 0; j < n; j++) {
+ dst[offset + stride * dst_stride * i + j] = sources[j][i * strides[j]];
+ }
+ }
+
+ free(strides), free(sources), free(s);
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+}
+
+static JSBool
+cs_dsp_unpack(JSContext *cx, unsigned argc, Value *vp) {
+ if (argc < 4) { return JS_FALSE; }
+
+ uint32_t length, offset = (uint32_t)vp[3].toInt32(), stride = (uint32_t)vp[4].toInt32(), src_stride;
+
+ float * src = get_float32_array(false, cx, vp, 0, &length, &src_stride);
+
+ if (!src) { return JS_FALSE; }
+
+ length = (length - offset) / stride; /* TODO: Bad feeling about this, but too lazy to think… */
+
+ uint32_t n = argc - 3;
+
+ /* TODO: Maybe implement the actual algorithm, that does not require calloc, or not… */
+
+ uint32_t * strides = (uint32_t *)calloc(n, sizeof(uint32_t));
+ float ** destinations = (float **)calloc(n, sizeof(float *)), * s = (float *)calloc(n, sizeof(float));
+
+ for (uint32_t i = 0; i < n; i++) {
+ destinations[i] = get_float32(true, cx, vp, 3 + i, &length, &strides[i], &s[i]);
+ }
+
+ for (uint32_t i = 0; i < length; i++) {
+ for (uint32_t j = 0; j < n; j++) {
+ destinations[j][i * strides[i]] = src[offset + stride * src_stride * i + j];
+ }
+ }
+
+ free(strides), free(destinations), free(s);
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+}
+
#define cs_unary_real_op(name) static JSBool \
name(JSContext *cx, unsigned argc, Value *vp) { \
return cs_dsp_unary_real(cx, argc, vp, name ## _impl, NULL); \
}
#define cs_unary_complex_to_real_op(name) static JSBool \
name(JSContext *cx, unsigned argc, Value *vp) { \
return cs_dsp_unary_complex_to_real(cx, argc, vp, name ## _impl); \
@@ -606,16 +678,18 @@ static JSFunctionSpec dsp_static_methods
JS_FN("mulCplx", cs_dsp_cmul, 6, 0),
JS_FN("divCplx", cs_dsp_cdiv, 6, 0),
JS_FN("min", cs_dsp_min, 1, 0),
JS_FN("max", cs_dsp_max, 1, 0),
JS_FN("sum", cs_dsp_sum, 1, 0),
JS_FN("clamp", cs_dsp_clamp, 4, 0),
JS_FN("ramp", cs_dsp_ramp, 3, 0),
JS_FN("random", cs_dsp_random, 3, 0),
+ JS_FN("pack", cs_dsp_pack, 4, 0),
+ JS_FN("unpack", cs_dsp_unpack, 4, 0),
JS_FS_END
};
JSObject *
js_InitDSPClass(JSContext *cx, HandleObject obj)
{
RootedObject DSP(cx, NewObjectWithClassProto(cx, &DSPClass, NULL, obj));
# HG changeset patch
# User Jens Nockert <jens@nockert.se>
# Date 1351874658 -3600
# Branch dsp-api
# Node ID ea0daf26aa4f4edc41425ddeea0bd948aef5e530
# Parent d78200e090b9a70483b6818c86b4c45717c3913d
Implement sample
diff --git a/js/src/csdsp.cpp b/js/src/csdsp.cpp
--- a/js/src/csdsp.cpp
+++ b/js/src/csdsp.cpp
@@ -2,24 +2,16 @@
* vim: set ts=4 sw=4 et tw=99:
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* JS DSP package.
- *
- * TODO: List of functions or signatures to implement
- *
- * void sampleLinear(Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
- * void sampleCubic(Float32Array dst, Float32Array x, Float32Array t, optional boolean repeat=false);
- *
- * void pack(TypedArray dst, unsigned long offset, unsigned long stride, Float32Array src1, optional Float32Array src2, optional optional Float32Array src3, optional optional Float32Array src4);
- * void unpack(TypedArray src, unsigned long offset, unsigned long stride, Float32Array dst1, optional Float32Array dst2, optional optional Float32Array dst3, optional optional Float32Array dst4);
*/
#include <stdlib.h>
#include <cmath>
#include <complex>
#include <algorithm>
@@ -66,26 +58,25 @@ get_float32(bool initialized, JSContext
*stride = 0;
return scalar;
}
}
static inline float *
-get_float32_array(bool initialized, JSContext *cx, Value *vp, unsigned arg, uint32_t * length, uint32_t * stride) {
+get_float32_array(bool initialized, JSContext *cx, Value *vp, unsigned arg, uint32_t * length) {
JSObject * object = vp[2 + arg].toObjectOrNull();
float * result = JS_GetFloat32ArrayData(object, cx);
if (result) {
uint32_t l = JS_GetTypedArrayLength(object, cx);
*length = initialized ? std::min(*length, l) : l;
- *stride = 1;
}
return result;
}
typedef float (*operator_none_real)(void * state, uint32_t i, uint32_t length);
typedef float (*operator_unary_real)(void * state, float a);
typedef float (*operator_binary_real)(float a, float b);
@@ -100,178 +91,178 @@ typedef float (*operator_unary_complex_t
typedef void (*reduction_unary_real)(void * state, float a);
typedef double (*reduction_unary_real_get_result)(const void * state);
static inline JSBool
cs_dsp_none_real(JSContext * cx, unsigned argc, Value *vp, operator_none_real f, void * state)
{
if (argc < 1) { return JS_FALSE; }
- uint32_t length, dst_stride;
+ uint32_t length;
- float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
if (!dst) { return JS_FALSE; }
for (uint32_t i = 0; i < length; i++) {
- dst[i * dst_stride] = f(state, i, length);
+ dst[i] = f(state, i, length);
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
cs_dsp_unary_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_real f, void * state)
{
if (argc < 2) { return JS_FALSE; }
float s[1];
- uint32_t length, dst_stride, a0_stride;
+ uint32_t length, a0_stride;
- float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
if (!dst) { return JS_FALSE; }
float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
for (uint32_t i = 0; i < length; i++) {
- dst[i * dst_stride] = f(state, a0[i * a0_stride]);
+ dst[i] = f(state, a0[i * a0_stride]);
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
cs_dsp_unary_complex_to_real(JSContext * cx, unsigned argc, Value *vp, operator_unary_complex_to_real f)
{
if (argc < 3) { return JS_FALSE; }
float s[2];
- uint32_t length, dst_stride, a0_r_stride, a0_i_stride;
+ uint32_t length, a0_r_stride, a0_i_stride;
- float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
if (!dst) { return JS_FALSE; }
float * a0_r = get_float32(true, cx, vp, 1, &length, &a0_r_stride, &s[0]);
float * a0_i = get_float32(true, cx, vp, 2, &length, &a0_i_stride, &s[1]);
for (uint32_t i = 0; i < length; i++) {
- dst[i * dst_stride] = f(cs_complex(a0_r[i * a0_r_stride], a0_i[i * a0_i_stride]));
+ dst[i] = f(cs_complex(a0_r[i * a0_r_stride], a0_i[i * a0_i_stride]));
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
cs_dsp_binary_real(JSContext * cx, unsigned argc, Value *vp, operator_binary_real f)
{
if (argc < 3) { return JS_FALSE; }
float s[2];
- uint32_t length, dst_stride, a0_stride, a1_stride;
+ uint32_t length, a0_stride, a1_stride;
- float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
if (!dst) { return JS_FALSE; }
float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
float * a1 = get_float32(true, cx, vp, 2, &length, &a1_stride, &s[1]);
for (uint32_t i = 0; i < length; i++) {
- dst[i * dst_stride] = f(a0[i * a0_stride], a1[i * a1_stride]);
+ dst[i] = f(a0[i * a0_stride], a1[i * a1_stride]);
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
cs_dsp_binary_complex(JSContext * cx, unsigned argc, Value *vp, operator_binary_complex f)
{
if (argc < 6) { return JS_FALSE; }
float s[4];
- uint32_t length, dst_r_stride, dst_i_stride, a0_r_stride, a0_i_stride, a1_r_stride, a1_i_stride;
+ uint32_t length, a0_r_stride, a0_i_stride, a1_r_stride, a1_i_stride;
- float * dst_r = get_float32_array(false, cx, vp, 0, &length, &dst_r_stride);
- float * dst_i = get_float32_array(true, cx, vp, 1, &length, &dst_i_stride);
+ float * dst_r = get_float32_array(false, cx, vp, 0, &length);
+ float * dst_i = get_float32_array(true, cx, vp, 1, &length);
if (!dst_r) { return JS_FALSE; }
if (!dst_i) { return JS_FALSE; }
float * a0_r = get_float32(true, cx, vp, 2, &length, &a0_r_stride, &s[0]);
float * a0_i = get_float32(true, cx, vp, 3, &length, &a0_i_stride, &s[1]);
float * a1_r = get_float32(true, cx, vp, 4, &length, &a1_r_stride, &s[2]);
float * a1_i = get_float32(true, cx, vp, 5, &length, &a1_i_stride, &s[3]);
for (uint32_t i = 0; i < length; i++) {
cs_complex result = f(cs_complex(a0_r[i * a0_r_stride], a0_i[i * a0_i_stride]), cs_complex(a1_r[i * a1_r_stride], a1_i[i * a1_i_stride]));
- dst_r[i * dst_r_stride] = result.real();
- dst_i[i * dst_i_stride] = result.imag();
+ dst_r[i] = result.real();
+ dst_i[i] = result.imag();
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
cs_dsp_trinary_real(JSContext * cx, unsigned argc, Value *vp, operator_trinary_real f)
{
if (argc < 4) { return JS_FALSE; }
float s[3];
- uint32_t length, dst_stride, a0_stride, a1_stride, a2_stride;
+ uint32_t length, a0_stride, a1_stride, a2_stride;
- float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
if (!dst) { return JS_FALSE; }
float * a0 = get_float32(true, cx, vp, 1, &length, &a0_stride, &s[0]);
float * a1 = get_float32(true, cx, vp, 2, &length, &a1_stride, &s[1]);
float * a2 = get_float32(true, cx, vp, 3, &length, &a2_stride, &s[2]);
for (uint32_t i = 0; i < length; i++) {
- dst[i * dst_stride] = f(a0[i * a0_stride], a1[i * a1_stride], a2[i * a2_stride]);
+ dst[i] = f(a0[i * a0_stride], a1[i * a1_stride], a2[i * a2_stride]);
}
vp->setUndefined();
return JS_TRUE;
}
static inline JSBool
cs_dsp_unary_real_reduction(JSContext * cx, unsigned argc, Value *vp, reduction_unary_real f, reduction_unary_real_get_result g, void * state)
{
if (argc < 1) { return JS_FALSE; }
float * a0;
- uint32_t length, a0_stride;
+ uint32_t length;
- a0 = get_float32_array(false, cx, vp, 0, &length, &a0_stride);
+ a0 = get_float32_array(false, cx, vp, 0, &length);
if (!a0) { return JS_FALSE; }
for (uint32_t i = 0; i < length; i++) {
- f(state, a0[i * a0_stride]);
+ f(state, a0[i]);
}
vp->setNumber(g(state));
return JS_TRUE;
}
static inline float cs_dsp_abs_impl(void * state, float x) {
@@ -502,19 +493,19 @@ cs_dsp_random(JSContext *cx, unsigned ar
return cs_dsp_none_real(cx, argc - 2, vp, cs_dsp_random_impl, &state);
}
static JSBool
cs_dsp_pack(JSContext *cx, unsigned argc, Value *vp) {
if (argc < 4) { return JS_FALSE; }
- uint32_t length, offset = (uint32_t)vp[3].toInt32(), stride = (uint32_t)vp[4].toInt32(), dst_stride;
+ uint32_t length, offset = (uint32_t)vp[3].toInt32(), stride = (uint32_t)vp[4].toInt32();
- float * dst = get_float32_array(false, cx, vp, 0, &length, &dst_stride);
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
if (!dst) { return JS_FALSE; }
length = (length - offset) / stride; /* TODO: Bad feeling about this, but too lazy to think… */
uint32_t n = argc - 3;
/* TODO: Maybe implement the actual algorithm, that does not require calloc, or not… */
@@ -523,34 +514,34 @@ cs_dsp_pack(JSContext *cx, unsigned argc
float ** sources = (float **)calloc(n, sizeof(float *)), * s = (float *)calloc(n, sizeof(float));
for (uint32_t i = 0; i < n; i++) {
sources[i] = get_float32(true, cx, vp, 3 + i, &length, &strides[i], &s[i]);
}
for (uint32_t i = 0; i < length; i++) {
for (uint32_t j = 0; j < n; j++) {
- dst[offset + stride * dst_stride * i + j] = sources[j][i * strides[j]];
+ dst[offset + stride * i + j] = sources[j][i * strides[j]];
}
}
free(strides), free(sources), free(s);
vp->setUndefined();
return JS_TRUE;
}
static JSBool
cs_dsp_unpack(JSContext *cx, unsigned argc, Value *vp) {
if (argc < 4) { return JS_FALSE; }
- uint32_t length, offset = (uint32_t)vp[3].toInt32(), stride = (uint32_t)vp[4].toInt32(), src_stride;
+ uint32_t length, offset = (uint32_t)vp[3].toInt32(), stride = (uint32_t)vp[4].toInt32();
- float * src = get_float32_array(false, cx, vp, 0, &length, &src_stride);
+ float * src = get_float32_array(false, cx, vp, 0, &length);
if (!src) { return JS_FALSE; }
length = (length - offset) / stride; /* TODO: Bad feeling about this, but too lazy to think… */
uint32_t n = argc - 3;
/* TODO: Maybe implement the actual algorithm, that does not require calloc, or not… */
@@ -559,27 +550,137 @@ cs_dsp_unpack(JSContext *cx, unsigned ar
float ** destinations = (float **)calloc(n, sizeof(float *)), * s = (float *)calloc(n, sizeof(float));
for (uint32_t i = 0; i < n; i++) {
destinations[i] = get_float32(true, cx, vp, 3 + i, &length, &strides[i], &s[i]);
}
for (uint32_t i = 0; i < length; i++) {
for (uint32_t j = 0; j < n; j++) {
- destinations[j][i * strides[i]] = src[offset + stride * src_stride * i + j];
+ destinations[j][i * strides[i]] = src[offset + stride * i + j];
}
}
free(strides), free(destinations), free(s);
vp->setUndefined();
return JS_TRUE;
}
+static inline JSBool
+cs_dsp_linear(JSContext * cx, unsigned argc, Value *vp)
+{
+ if (argc < 3) { return JS_FALSE; }
+
+ bool repeat = argc < 4 ? false : vp[5].toBoolean();
+
+ float s[2];
+
+ uint32_t length, x_length, a1_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
+ float * a0 = get_float32_array(false, cx, vp, 1, &x_length);
+
+ if (!dst) { return JS_FALSE; }
+ if (!a0) { return JS_FALSE; }
+
+ float * a1 = get_float32(true, cx, vp, 2, &length, &a1_stride, &s[1]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ if (repeat) {
+ float t = std::fmod(a1[i * a1_stride], (float)x_length);
+
+ uint32_t j = (uint32_t)std::floor(t);
+
+ float p1 = a0[j], p2 = a0[(j + 1) % x_length], w = t - j;
+
+ dst[i] = (1 - w) * p1 + w * p2;
+ } else {
+ float t = std::min(x_length - 1.0f, std::max(0.0f, a1[i * a1_stride]));
+
+ uint32_t j = (uint32_t)std::floor(t);
+
+ float p1 = a0[j], p2 = a0[std::min(j + 1, x_length - 1)], w = t - j;
+
+ dst[i] = (1 - w) * p1 + w * p2;
+ }
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+}
+
+static inline JSBool
+cs_dsp_cubic(JSContext * cx, unsigned argc, Value *vp)
+{
+ if (argc < 3) { return JS_FALSE; }
+
+ bool repeat = argc < 4 ? false : vp[5].toBoolean();
+
+ float s[2];
+
+ uint32_t length, x_length, a1_stride;
+
+ float * dst = get_float32_array(false, cx, vp, 0, &length);
+ float * a0 = get_float32_array(false, cx, vp, 1, &x_length);
+
+ if (!dst) { return JS_FALSE; }
+ if (!a0) { return JS_FALSE; }
+
+ float * a1 = get_float32(true, cx, vp, 2, &length, &a1_stride, &s[1]);
+
+ for (uint32_t i = 0; i < length; i++) {
+ if (repeat) {
+ float t = std::fmod(a1[i * a1_stride], (float)x_length);
+
+ uint32_t j = (uint32_t)std::floor(t);
+
+ float w = t - j;
+ float w2 = w * w, w3 = w * w * w;
+
+ float h1 = 2.0f * w3 - 3.0f * w2 + 1.0f;
+ float h2 = -2.0f * w3 + 3.0f * w2;
+ float h3 = 0.5f * (w3 - 2.0f * w2 + w);
+ float h4 = 0.5f * (w3 - w2);
+
+ float p1 = a0[(j + x_length - 1) % x_length]; /* TODO: Make this moar safe, underflow etc. */
+ float p2 = a0[j];
+ float p3 = a0[(j + 1) % x_length];
+ float p4 = a0[(j + 2) % x_length];
+
+ dst[i] = h1 * p2 + h2 * p3 + h3 * (p3 - p1) + h4 * (p4 - p2);
+ } else {
+ float t = std::min((float)x_length - 1.0f, std::max(0.0f, a1[i * a1_stride]));
+
+ uint32_t j = (uint32_t)std::floor(t);
+
+ float w = t - j;
+ float w2 = w * w, w3 = w * w * w;
+
+ float h1 = 2.0f * w3 - 3.0f * w2 + 1.0f;
+ float h2 = -2.0f * w3 + 3.0f * w2;
+ float h3 = 0.5f * (w3 - 2.0f * w2 + w);
+ float h4 = 0.5f * (w3 - w2);
+
+ float p1 = a0[j == 0 ? 0 : j - 1]; /* TODO: Make this moar safe, underflow etc. */
+ float p2 = a0[j];
+ float p3 = a0[std::min(j + 1, x_length - 1)];
+ float p4 = a0[std::min(j + 2, x_length - 1)];
+
+ dst[i] = h1 * p2 + h2 * p3 + h3 * (p3 - p1) + h4 * (p4 - p2);
+ }
+ }
+
+ vp->setUndefined();
+
+ return JS_TRUE;
+}
+
#define cs_unary_real_op(name) static JSBool \
name(JSContext *cx, unsigned argc, Value *vp) { \
return cs_dsp_unary_real(cx, argc, vp, name ## _impl, NULL); \
}
#define cs_unary_complex_to_real_op(name) static JSBool \
name(JSContext *cx, unsigned argc, Value *vp) { \
return cs_dsp_unary_complex_to_real(cx, argc, vp, name ## _impl); \
@@ -647,49 +748,51 @@ cs_trinary_real_op(cs_dsp_madd)
cs_binary_complex_op(cs_dsp_cmul)
cs_binary_complex_op(cs_dsp_cdiv)
static JSFunctionSpec dsp_static_methods[] = {
#if JS_HAS_TOSOURCE
// TODO: Is not supportedyet… JS_FN(js_toSource_str, dsp_toSource, 0, 0),
#endif
/* Unary real functions */
- JS_FN("abs", cs_dsp_abs, 2, 0),
- JS_FN("sqrt", cs_dsp_sqrt, 2, 0),
- JS_FN("absCplx", cs_dsp_cabs, 3, 0),
- JS_FN("cos", cs_dsp_cos, 2, 0),
- JS_FN("sin", cs_dsp_sin, 2, 0),
- JS_FN("tan", cs_dsp_tan, 2, 0),
- JS_FN("acos", cs_dsp_acos, 2, 0),
- JS_FN("asin", cs_dsp_asin, 2, 0),
- JS_FN("atan", cs_dsp_atan, 2, 0),
- JS_FN("atan2", cs_dsp_atan2, 3, 0),
- JS_FN("exp", cs_dsp_exp, 2, 0),
- JS_FN("log", cs_dsp_log, 2, 0),
- JS_FN("ceil", cs_dsp_ceil, 2, 0),
- JS_FN("floor", cs_dsp_floor, 2, 0),
- JS_FN("round", cs_dsp_round, 2, 0),
- JS_FN("sign", cs_dsp_sign, 2, 0),
- JS_FN("fract", cs_dsp_fract, 2, 0),
- JS_FN("add", cs_dsp_add, 3, 0),
- JS_FN("sub", cs_dsp_sub, 3, 0),
- JS_FN("mul", cs_dsp_mul, 3, 0),
- JS_FN("div", cs_dsp_div, 3, 0),
- JS_FN("pow", cs_dsp_pow, 3, 0),
- JS_FN("madd", cs_dsp_madd, 4, 0),
- JS_FN("mulCplx", cs_dsp_cmul, 6, 0),
- JS_FN("divCplx", cs_dsp_cdiv, 6, 0),
- JS_FN("min", cs_dsp_min, 1, 0),
- JS_FN("max", cs_dsp_max, 1, 0),
- JS_FN("sum", cs_dsp_sum, 1, 0),
- JS_FN("clamp", cs_dsp_clamp, 4, 0),
- JS_FN("ramp", cs_dsp_ramp, 3, 0),
- JS_FN("random", cs_dsp_random, 3, 0),
- JS_FN("pack", cs_dsp_pack, 4, 0),
- JS_FN("unpack", cs_dsp_unpack, 4, 0),
+ JS_FN("abs", cs_dsp_abs, 2, 0),
+ JS_FN("sqrt", cs_dsp_sqrt, 2, 0),
+ JS_FN("absCplx", cs_dsp_cabs, 3, 0),
+ JS_FN("cos", cs_dsp_cos, 2, 0),
+ JS_FN("sin", cs_dsp_sin, 2, 0),
+ JS_FN("tan", cs_dsp_tan, 2, 0),
+ JS_FN("acos", cs_dsp_acos, 2, 0),
+ JS_FN("asin", cs_dsp_asin, 2, 0),
+ JS_FN("atan", cs_dsp_atan, 2, 0),
+ JS_FN("atan2", cs_dsp_atan2, 3, 0),
+ JS_FN("exp", cs_dsp_exp, 2, 0),
+ JS_FN("log", cs_dsp_log, 2, 0),
+ JS_FN("ceil", cs_dsp_ceil, 2, 0),
+ JS_FN("floor", cs_dsp_floor, 2, 0),
+ JS_FN("round", cs_dsp_round, 2, 0),
+ JS_FN("sign", cs_dsp_sign, 2, 0),
+ JS_FN("fract", cs_dsp_fract, 2, 0),
+ JS_FN("add", cs_dsp_add, 3, 0),
+ JS_FN("sub", cs_dsp_sub, 3, 0),
+ JS_FN("mul", cs_dsp_mul, 3, 0),
+ JS_FN("div", cs_dsp_div, 3, 0),
+ JS_FN("pow", cs_dsp_pow, 3, 0),
+ JS_FN("madd", cs_dsp_madd, 4, 0),
+ JS_FN("mulCplx", cs_dsp_cmul, 6, 0),
+ JS_FN("divCplx", cs_dsp_cdiv, 6, 0),
+ JS_FN("min", cs_dsp_min, 1, 0),
+ JS_FN("max", cs_dsp_max, 1, 0),
+ JS_FN("sum", cs_dsp_sum, 1, 0),
+ JS_FN("clamp", cs_dsp_clamp, 4, 0),
+ JS_FN("ramp", cs_dsp_ramp, 3, 0),
+ JS_FN("random", cs_dsp_random, 3, 0),
+ JS_FN("pack", cs_dsp_pack, 4, 0),
+ JS_FN("unpack", cs_dsp_unpack, 4, 0),
+ JS_FN("sampleLinear", cs_dsp_linear, 3, 0),
+ JS_FN("sampleCubic", cs_dsp_cubic, 3, 0),
JS_FS_END
};
JSObject *
js_InitDSPClass(JSContext *cx, HandleObject obj)
{
RootedObject DSP(cx, NewObjectWithClassProto(cx, &DSPClass, NULL, obj));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment