ChucK/Patches/Clip

From CSWiki
Jump to: navigation, search

This patch for ChucK implements two signal processing UGens, for clipping and soft clipping sample values at a set level. The levels can be set separately for positive and negative values for asymmetric clipping. This is "free software". You may use it for whatever purpose you will.

Index: ugen_xxx.cpp
===================================================================
RCS file: /cvs/chuck_dev/v2/ugen_xxx.cpp,v
retrieving revision 1.59
diff -u -r1.59 ugen_xxx.cpp
--- ugen_xxx.cpp	11 Sep 2006 22:48:50 -0000	1.59
+++ ugen_xxx.cpp	15 Oct 2006 21:06:23 -0000
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <limits.h>
+#include <float.h>
 
 #if defined(__CK_SNDFILE_NATIVE__)
 #include <sndfile.h>
@@ -65,6 +66,8 @@
 static t_CKUINT zerox_offset_data = 0;
 static t_CKUINT delayp_offset_data = 0;
 static t_CKUINT sndbuf_offset_data = 0;
+static t_CKUINT clip_offset_data = 0;
+static t_CKUINT softclip_offset_data = 0;
 
 Chuck_Type * g_t_dac = NULL;
 Chuck_Type * g_t_adc = NULL;
@@ -653,6 +656,74 @@
     if( !type_engine_import_class_end( env ) )
         return FALSE;
 
+    // add clip
+    //! hard clip
+    //! clamp sample values to be between nlimit (<0) and plimit (>0)
+    //! both limits can be set simultaneously using 'limit'
+    // ------------------------------------------------------------
+    // init as a base class: Clip
+    // ------------------------------------------------------------
+
+    if( !type_engine_import_ugen_begin( env, "Clip", "UGen", env->global(),
+                                                clip_ctor, clip_tick, NULL ) )
+        return FALSE;
+
+     func = make_new_mfun( "float", "limit", clip_ctrl_limit );
+     func->add_arg( "float", "limit") ;
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "plimit", clip_ctrl_plimit );
+     func->add_arg( "float", "plimit") ;
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "plimit", clip_cget_plimit );
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "nlimit", clip_ctrl_nlimit );
+     func->add_arg( "float", "nlimit") ;
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "nlimit", clip_cget_nlimit );
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     if( !type_engine_import_class_end( env ) )
+        return FALSE;
+
+    // add softclip
+    //! soft clip
+    //! process sample values using an increasing function which is
+    //! approximately linear near 0 and which always stays between
+    //! nlimit (<0) and plimit (>0)
+    //! both limits can be set simultaneously using 'limit'
+    // ------------------------------------------------------------
+    // init as a base class: SoftClip
+    // ------------------------------------------------------------
+
+    if( !type_engine_import_ugen_begin( env, "SoftClip", "UGen", env->global(),
+                                                softclip_ctor, softclip_tick, NULL ) )
+        return FALSE;
+
+     func = make_new_mfun( "float", "limit", softclip_ctrl_limit );
+     func->add_arg( "float", "limit") ;
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "plimit", softclip_ctrl_plimit );
+     func->add_arg( "float", "plimit") ;
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "plimit", softclip_cget_plimit );
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "nlimit", softclip_ctrl_nlimit );
+     func->add_arg( "float", "nlimit") ;
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     func = make_new_mfun( "float", "nlimit", softclip_cget_nlimit );
+     if (!type_engine_import_mfun( env, func ) ) goto error;
+
+     if( !type_engine_import_class_end( env ) )
+        return FALSE;
+
     return TRUE;
 
 error:
@@ -2234,3 +2305,159 @@
     if( d->fd ) sndbuf_load( d, i );
     RETURN->v_float = ( i > d->num_frames || i < 0 ) ? 0 : d->buffer[i];
 }
+
+// clip
+
+struct Clip_Data
+{
+    SAMPLE plimit, nlimit;
+    Clip_Data( ) {
+        plimit = 1.0f;
+        nlimit = -1.0f;
+    }
+};
+
+CK_DLL_CTOR( clip_ctor )
+{
+    // return data to be used later
+    OBJ_MEMBER_UINT( SELF, clip_offset_data ) = (t_CKUINT)new Clip_Data;
+}
+
+CK_DLL_DTOR( clip_dtor )
+{
+    delete (Clip_Data *)OBJ_MEMBER_UINT( SELF, clip_offset_data );
+}
+
+CK_DLL_TICK( clip_tick )
+{
+    Clip_Data *d = (Clip_Data *)OBJ_MEMBER_UINT(SELF, clip_offset_data );
+    if (in > d->plimit ) {
+        *out = d->plimit;
+    } else if (in < d->nlimit) {
+        *out = d->nlimit;
+    } else {
+        *out = in;
+    }
+    return TRUE;
+}
+
+CK_DLL_CTRL( clip_ctrl_limit )
+{
+    Clip_Data *d = (Clip_Data *)OBJ_MEMBER_UINT(SELF, clip_offset_data );
+    d->plimit = GET_CK_FLOAT(ARGS);
+    if (d->plimit < 0.0f) {
+        d->plimit = 0.0f;
+    }
+    d->nlimit = -d->plimit;
+    RETURN->v_float = (t_CKFLOAT)d->plimit;
+}
+
+CK_DLL_CTRL( clip_ctrl_plimit )
+{
+    Clip_Data *d = (Clip_Data *)OBJ_MEMBER_UINT(SELF, clip_offset_data );
+    d->plimit = GET_CK_FLOAT(ARGS);
+    if (d->plimit < 0.0f) {
+        d->plimit = 0.0f;
+    }
+    RETURN->v_float = (t_CKFLOAT)d->plimit;
+}
+
+CK_DLL_CGET( clip_cget_plimit )
+{
+    Clip_Data * d = (Clip_Data *)OBJ_MEMBER_UINT( SELF, clip_offset_data );
+    RETURN->v_float = (t_CKFLOAT)d->plimit;
+}
+
+CK_DLL_CTRL( clip_ctrl_nlimit )
+{
+    Clip_Data *d = (Clip_Data *)OBJ_MEMBER_UINT(SELF, clip_offset_data );
+    d->nlimit = GET_CK_FLOAT(ARGS);
+    if (d->nlimit > 0.0f) {
+        d->nlimit = 0.0f;
+    }
+    RETURN->v_float = (t_CKFLOAT)d->nlimit;
+}
+
+CK_DLL_CGET( clip_cget_nlimit )
+{
+    Clip_Data * d = (Clip_Data *)OBJ_MEMBER_UINT( SELF, clip_offset_data );
+    RETURN->v_float = (t_CKFLOAT)d->nlimit;
+}
+
+
+// soft clip
+
+struct SoftClip_Data
+{
+    SAMPLE plimit, nlimit;
+    SoftClip_Data( ) {
+        plimit = 1.0f;
+        nlimit = -1.0f;
+    }
+};
+
+CK_DLL_CTOR( softclip_ctor )
+{
+    // return data to be used later
+    OBJ_MEMBER_UINT( SELF, softclip_offset_data ) = (t_CKUINT)new SoftClip_Data;
+}
+
+CK_DLL_DTOR( softclip_dtor )
+{
+    delete (SoftClip_Data *)OBJ_MEMBER_UINT( SELF, softclip_offset_data );
+}
+
+CK_DLL_TICK( softclip_tick )
+{
+    SoftClip_Data *d = (SoftClip_Data *)OBJ_MEMBER_UINT(SELF, softclip_offset_data );
+    if (in < 0.0f ) {
+        *out = d->nlimit * in / (d->nlimit + in);
+    } else {
+        *out = d->plimit * in / (d->plimit + in);
+    }
+    return TRUE;
+}
+
+CK_DLL_CTRL( softclip_ctrl_limit )
+{
+    SoftClip_Data *d = (SoftClip_Data *)OBJ_MEMBER_UINT(SELF, softclip_offset_data );
+    d->plimit = GET_CK_FLOAT(ARGS);
+    if (d->plimit <= 0.0f) {
+        d->plimit = FLT_MIN;
+    }
+    d->nlimit = -d->plimit;
+    RETURN->v_float = (t_CKFLOAT)d->plimit;
+}
+
+CK_DLL_CTRL( softclip_ctrl_plimit )
+{
+    SoftClip_Data *d = (SoftClip_Data *)OBJ_MEMBER_UINT(SELF, softclip_offset_data );
+    d->plimit = GET_CK_FLOAT(ARGS);
+    if (d->plimit <= 0.0f) {
+        d->plimit = FLT_MIN;
+    }
+    RETURN->v_float = (t_CKFLOAT)d->plimit;
+}
+
+CK_DLL_CGET( softclip_cget_plimit )
+{
+    SoftClip_Data * d = (SoftClip_Data *)OBJ_MEMBER_UINT( SELF, softclip_offset_data );
+    RETURN->v_float = (t_CKFLOAT)d->plimit;
+}
+
+CK_DLL_CTRL( softclip_ctrl_nlimit )
+{
+    SoftClip_Data *d = (SoftClip_Data *)OBJ_MEMBER_UINT(SELF, softclip_offset_data );
+    d->nlimit = GET_CK_FLOAT(ARGS);
+    if (d->nlimit >= 0.0f) {
+        d->nlimit = -FLT_MIN;
+    }
+    RETURN->v_float = (t_CKFLOAT)d->nlimit;
+}
+
+CK_DLL_CGET( softclip_cget_nlimit )
+{
+    SoftClip_Data * d = (SoftClip_Data *)OBJ_MEMBER_UINT( SELF, softclip_offset_data );
+    RETURN->v_float = (t_CKFLOAT)d->nlimit;
+}
+
Index: ugen_xxx.h
===================================================================
RCS file: /cvs/chuck_dev/v2/ugen_xxx.h,v
retrieving revision 1.12
diff -u -r1.12 ugen_xxx.h
--- ugen_xxx.h	2 Mar 2006 00:46:12 -0000	1.12
+++ ugen_xxx.h	15 Oct 2006 21:06:23 -0000
@@ -157,6 +157,23 @@
 CK_DLL_CGET( sndbuf_cget_channels );
 CK_DLL_CGET( sndbuf_cget_valueAt );
 
+// clip
+CK_DLL_CTOR( clip_ctor );
+CK_DLL_TICK( clip_tick );
+CK_DLL_CGET( clip_ctrl_limit );
+CK_DLL_CGET( clip_ctrl_plimit );
+CK_DLL_CGET( clip_cget_plimit );
+CK_DLL_CGET( clip_ctrl_nlimit );
+CK_DLL_CGET( clip_cget_nlimit );
+
+// soft clip
+CK_DLL_CTOR( softclip_ctor );
+CK_DLL_TICK( softclip_tick );
+CK_DLL_CGET( softclip_ctrl_limit );
+CK_DLL_CGET( softclip_ctrl_plimit );
+CK_DLL_CGET( softclip_cget_plimit );
+CK_DLL_CGET( softclip_ctrl_nlimit );
+CK_DLL_CGET( softclip_cget_nlimit );