Created
November 2, 2012 10:45
-
-
Save auroranockert/4000105 to your computer and use it in GitHub Desktop.
Spidermonkey patch adding DSP API support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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