ChucK/Patches/Clip
From CSWiki
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 );
