//------------------------------------------------------------------------------
// Pd Spectral Toolkit
//
// binmix~.c
//
// Combines right inlet values based on matching left inlet values and zeroes the rest
//
// Created by Cooper Baker on 6/26/12.
// Updated for 64 Bit Support in September 2019.
// Copyright (C) 2019 Cooper Baker. All Rights Reserved.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// headers
//------------------------------------------------------------------------------
// main header for pd
#include "m_pd.h"
// utility header for Pd Spectral Toolkit project
#include "utility.h"
// c standard library used for realloc and free
#include <stdlib.h>
// c string library used for memset and memcpy
#include <string.h>
// disable compiler warnings on windows
#ifdef NT
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif
//------------------------------------------------------------------------------
// binmix_class - pointer to this object's definition
//------------------------------------------------------------------------------
static t_class* binmix_class;
//------------------------------------------------------------------------------
// binmix - data structure holding this object's data
//------------------------------------------------------------------------------
typedef struct binmix
{
// this object - must always be first variable in struct
t_object object;
// needed for CLASS_MAINSIGNALIN macro call in in_tilde_setup
t_float inlet_1;
// needed for signalinlet_new call in binmix_new
t_float inlet_2;
// pointers to arrays used for sorting
t_float* a;
t_float* b;
t_float* c;
t_float* a_temp;
t_float* b_temp;
// pointer to array containing audio vector frame indices
t_float* vector_index;
// vector memory size
t_float memory_size;
} t_binmix;
//------------------------------------------------------------------------------
// function prototypes
//------------------------------------------------------------------------------
static t_int* binmix_perform ( t_int* io );
static void binmix_dsp ( t_binmix* object, t_signal **sig );
static void* binmix_new ( t_symbol *s, t_int argc, t_atom *argv );
static void binmix_free ( t_binmix* object );
void binmix_tilde_setup ( void );
static inline void binmix_quicksort_c ( t_binmix* object, t_int beginning, t_int end );
static inline void binmix_sort_ab ( t_binmix* object, t_int size );
static inline void binmix_combine ( t_binmix* object, t_int size );
static inline void binmix_unsort ( t_binmix* object, t_int size );
//------------------------------------------------------------------------------
// binmix_quicksort_c - sorts array c based on the contents of a
//------------------------------------------------------------------------------
static inline void binmix_quicksort_c( t_binmix* object, t_int beginning, t_int end )
{
t_float* a = object->a;
t_float* c = object->c;
if( end > ( beginning + 1 ) )
{
t_float pivot = a[ ( t_int )c[ beginning ] ];
t_int left = beginning + 1;
t_int right = end;
t_float temp;
while( left < right )
{
if( a[ ( t_int )c[ left ] ] <= pivot )
{
++left;
}
else
{
--right;
// swap c values
temp = c[ left ];
c[ left ] = c[ right ];
c[ right ] = temp;
}
}
--left;
// swap c values
temp = c[ left ];
c[ left ] = c[ beginning ];
c[ beginning ] = temp;
binmix_quicksort_c( object, beginning, left );
binmix_quicksort_c( object, right, end );
}
}
//------------------------------------------------------------------------------
// binmix_combine - mixes together b values in largest b location when
// a values match, then zeros other values
//------------------------------------------------------------------------------
static inline void binmix_combine( t_binmix* object, t_int size )
{
t_float* a = object->a;
t_float* b = object->b;
t_float* a_temp = object->a_temp;
t_float* b_temp = object->b_temp;
t_float memory_size = object->memory_size;
t_int sum = FALSE;
t_float a_val;
t_float b_max;
t_int b_max_index;
t_float b_sum;
t_int i = -1;
// set temp array values to 0
memset( a_temp, 0, memory_size );
memset( b_temp, 0, memory_size );
// iterate through the arrays
while( ++i < ( size - 1 ) )
{
// set initial values for combining b values
if( sum == FALSE )
{
b_sum = b[ i ];
b_max = b[ i ];
b_max_index = i;
}
// while a values match, combine b values and find largest b value location
while( a[ i ] == a[ i + 1 ] )
{
a_val = a[ i ];
b_sum += b[ i + 1 ];
if( b[ i + 1 ] > b_max )
{
b_max = b[ i + 1 ];
b_max_index = i + 1;
}
++i;
sum = TRUE;
}
// write combined values into correct temp array locations
if( sum )
{
a_temp[ b_max_index ] = a_val;
b_temp[ b_max_index ] = b_sum;
sum = FALSE;
}
// write all other values directly into temp arrays
else
{
a_temp[ i ] = a[ i ];
b_temp[ i ] = b[ i ];
}
}
// catch unique final maximum a values and write directly into temp arrays
if( a[ size - 2 ] != a[ size - 1 ] )
{
a_temp[ i ] = a[ i ];
b_temp[ i ] = b[ i ];
}
// clear working arrays
memset( a, 0, memory_size );
memset( b, 0, memory_size );
// copy temp arrays to working arrays
memcpy( a, a_temp, memory_size );
memcpy( b, b_temp, memory_size );
}
//------------------------------------------------------------------------------
// binmix_sort_ab - sorts a and b array values according to c array values
//------------------------------------------------------------------------------
static inline void binmix_sort_ab( t_binmix* object, t_int size )
{
t_float* a = object->a;
t_float* b = object->b;
t_float* c = object->c;
t_float* a_temp = object->a_temp;
t_float* b_temp = object->b_temp;
t_int i = -1;
while( ++i < size )
{
a_temp[ i ] = a[ ( t_int )c[ i ] ];
b_temp[ i ] = b[ ( t_int )c[ i ] ];
}
memcpy( a, a_temp, object->memory_size );
memcpy( b, b_temp, object->memory_size );
}
//------------------------------------------------------------------------------
// binmix_unsort - move array values back to their original locations
//------------------------------------------------------------------------------
static inline void binmix_unsort( t_binmix* object, t_int size )
{
t_float* a = object->a;
t_float* b = object->b;
t_float* c = object->c;
t_float* a_temp = object->a_temp;
t_float* b_temp = object->b_temp;
t_float memory_size = object->memory_size;
t_int i = -1;
// move modified values back to their corresponding original indices
while( ++i < size )
{
a_temp[ ( t_int )c[ i ] ] = a[ i ];
b_temp[ ( t_int )c[ i ] ] = b[ i ];
}
// copy temp arrays to working arrays
memcpy( a, a_temp, memory_size );
memcpy( b, b_temp, memory_size );
}
//------------------------------------------------------------------------------
// binmix_perform - the signal processing function of this object
//------------------------------------------------------------------------------
static t_int* binmix_perform( t_int* io )
{
// store variables from dsp input/output array
t_float* in1 = ( t_float* )( io[ 1 ] );
t_float* in2 = ( t_float* )( io[ 2 ] );
t_float* out1 = ( t_float* )( io[ 3 ] );
t_float* out2 = ( t_float* )( io[ 4 ] );
t_int frames = ( t_int )( io[ 5 ] );
t_binmix* object = ( t_binmix* )( io[ 6 ] );
// store local copies of object variables
t_float* a = object->a;
t_float* b = object->b;
t_float* c = object->c;
t_float* vector_index = object->vector_index;
t_float memory_size = object->memory_size;
// copy signal vectors to temp arrays
memcpy( a, in1, memory_size );
memcpy( b, in2, memory_size );
memcpy( c, vector_index, memory_size );
// sort c based on a values
binmix_quicksort_c( object, 0, frames );
// rearrange a and b
binmix_sort_ab( object, frames );
// for matching a values, combine b values into largest b location and clear the other a and b values
binmix_combine( object, frames );
// unsort the values back to their original locations
binmix_unsort( object, frames );
// copy sorted temp arrays to outlet arrays
memcpy( out1, a, memory_size );
memcpy( out2, b, memory_size );
// return the dsp input/output array address plus one more than its size
// to provide a pointer to the next perform function in pd's call list
return &( io[ 7 ] );
}
//------------------------------------------------------------------------------
// binmix_dsp - installs this object's dsp function in pd's callback list
//------------------------------------------------------------------------------
static void binmix_dsp( t_binmix* object, t_signal **sig )
{
// temporary frame size variable
t_int frames = sig[ 0 ]->s_n;
// calculate memory size for realloc and memset
t_float memory_size = frames * sizeof( t_float );
// allocate one frame's worth of memory to each pointer ( a and c need an extra location )
object->a = realloc( object->a, memory_size + sizeof( t_float ) );
object->b = realloc( object->b, memory_size );
object->c = realloc( object->c, memory_size + sizeof( t_float ) );
object->a_temp = realloc( object->a_temp, memory_size );
object->b_temp = realloc( object->b_temp, memory_size );
object->vector_index = realloc( object->vector_index, memory_size );
// init extra sorting location
object->a [ frames ] = C_FLOAT_MIN;
object->c [ frames ] = 0;
// increment values stored in vector_index
for( t_int index = 0 ; index < frames ; ++index )
{
object->vector_index[ index ] = ( t_float )index;
}
// save memory size
object->memory_size = memory_size;
// dsp_add arguments
//--------------------------------------------------------------------------
// perform routine
// number of passed parameters
// inlet 1 sample vector
// inlet 2 sample vector
// outlet 1 sample vector
// outlet 2 sample vector
// sample frames to process (vector size)
// object
dsp_add
(
binmix_perform,
6,
sig[ 0 ]->s_vec,
sig[ 1 ]->s_vec,
sig[ 2 ]->s_vec,
sig[ 3 ]->s_vec,
frames,
object
);
}
//------------------------------------------------------------------------------
// binmix_new - instantiates a copy of this object in pd
//------------------------------------------------------------------------------
static void* binmix_new( t_symbol *s, t_int argc, t_atom *argv )
{
// create a pointer to this object
t_binmix* object = ( t_binmix* )pd_new( binmix_class );
// create an additional signal inlet
signalinlet_new( &object->object, object->inlet_2 );
// create two signal outlets
outlet_new( &object->object, gensym( "signal" ) );
outlet_new( &object->object, gensym( "signal" ) );
// initialize the inlet variables
object->inlet_1 = 0;
object->inlet_2 = 0;
// initialize array pointers to null
object->a = NULL;
object->b = NULL;
object->c = NULL;
object->a_temp = NULL;
object->b_temp = NULL;
object->vector_index = NULL;
return object;
}
//------------------------------------------------------------------------------
// binmix_free - cleans up memory allocated by this object
//------------------------------------------------------------------------------
static void binmix_free( t_binmix* object )
{
// if memory is allocated
if( object->a )
{
// free the memory
free( object->a );
// set memory pointer to null
object->a = NULL;
}
// . . .
if( object->b )
{
free( object->b );
object->b = NULL;
}
if( object->c )
{
free( object->c );
object->c = NULL;
}
if( object->a_temp )
{
free( object->a_temp );
object->a_temp = NULL;
}
if( object->b_temp )
{
free( object->b_temp );
object->b_temp = NULL;
}
if( object->vector_index )
{
free( object->vector_index );
object->vector_index = NULL;
}
}
//------------------------------------------------------------------------------
// binmix_tilde_setup - describes the attributes of this object to pd so it may be properly instantiated
// (must always be named with _tilde replacing ~ in the object name)
//------------------------------------------------------------------------------
void binmix_tilde_setup( void )
{
// binmix class
//--------------------------------------------------------------------------
// creates an instance of this object and describes it to pd
binmix_class = class_new( gensym( "binmix~" ), ( t_newmethod )binmix_new, ( t_method )binmix_free, sizeof( t_binmix ), 0, A_GIMME, 0 );
// declares leftmost inlet as a signal inlet
CLASS_MAINSIGNALIN( binmix_class, t_binmix, inlet_1 );
// installs binmix_dsp so that it will be called when dsp is turned on
class_addmethod( binmix_class, ( t_method )binmix_dsp, gensym( "dsp" ), 0 );
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------
// Pd Spectral Toolkit
//
// binmix~.c
//
// Combines right inlet values based on matching left inlet values and zeroes the rest
//
// Created by Cooper Baker on 6/26/12.
// Updated for 64 Bit Support in September 2019.
// Copyright (C) 2019 Cooper Baker. All Rights Reserved.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// headers
//------------------------------------------------------------------------------
// main header for pd
#include "m_pd.h"
// utility header for Pd Spectral Toolkit project
#include "utility.h"
// c standard library used for realloc and free
#include <stdlib.h>
// c string library used for memset and memcpy
#include <string.h>
// disable compiler warnings on windows
#ifdef NT
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif
//------------------------------------------------------------------------------
// binmix_class - pointer to this object's definition
//------------------------------------------------------------------------------
static t_class* binmix_class;
//------------------------------------------------------------------------------
// binmix - data structure holding this object's data
//------------------------------------------------------------------------------
typedef struct binmix
{
// this object - must always be first variable in struct
t_object object;
// needed for CLASS_MAINSIGNALIN macro call in in_tilde_setup
t_float inlet_1;
// needed for signalinlet_new call in binmix_new
t_float inlet_2;
// pointers to arrays used for sorting
t_float* a;
t_float* b;
t_float* c;
t_float* a_temp;
t_float* b_temp;
// pointer to array containing audio vector frame indices
t_float* vector_index;
// vector memory size
t_float memory_size;
} t_binmix;
//------------------------------------------------------------------------------
// function prototypes
//------------------------------------------------------------------------------
static t_int* binmix_perform ( t_int* io );
static void binmix_dsp ( t_binmix* object, t_signal **sig );
static void* binmix_new ( t_symbol *s, t_int argc, t_atom *argv );
static void binmix_free ( t_binmix* object );
void binmix_tilde_setup ( void );
static inline void binmix_quicksort_c ( t_binmix* object, t_int beginning, t_int end );
static inline void binmix_sort_ab ( t_binmix* object, t_int size );
static inline void binmix_combine ( t_binmix* object, t_int size );
static inline void binmix_unsort ( t_binmix* object, t_int size );
//------------------------------------------------------------------------------
// binmix_quicksort_c - sorts array c based on the contents of a
//------------------------------------------------------------------------------
static inline void binmix_quicksort_c( t_binmix* object, t_int beginning, t_int end )
{
t_float* a = object->a;
t_float* c = object->c;
if( end > ( beginning + 1 ) )
{
t_float pivot = a[ ( t_int )c[ beginning ] ];
t_int left = beginning + 1;
t_int right = end;
t_float temp;
while( left < right )
{
if( a[ ( t_int )c[ left ] ] <= pivot )
{
++left;
}
else
{
--right;
// swap c values
temp = c[ left ];
c[ left ] = c[ right ];
c[ right ] = temp;
}
}
--left;
// swap c values
temp = c[ left ];
c[ left ] = c[ beginning ];
c[ beginning ] = temp;
binmix_quicksort_c( object, beginning, left );
binmix_quicksort_c( object, right, end );
}
}
//------------------------------------------------------------------------------
// binmix_combine - mixes together b values in largest b location when
// a values match, then zeros other values
//------------------------------------------------------------------------------
static inline void binmix_combine( t_binmix* object, t_int size )
{
t_float* a = object->a;
t_float* b = object->b;
t_float* a_temp = object->a_temp;
t_float* b_temp = object->b_temp;
t_float memory_size = object->memory_size;
t_int sum = FALSE;
t_float a_val;
t_float b_max;
t_int b_max_index;
t_float b_sum;
t_int i = -1;
// set temp array values to 0
memset( a_temp, 0, memory_size );
memset( b_temp, 0, memory_size );
// iterate through the arrays
while( ++i < ( size - 1 ) )
{
// set initial values for combining b values
if( sum == FALSE )
{
b_sum = b[ i ];
b_max = b[ i ];
b_max_index = i;
}
// while a values match, combine b values and find largest b value location
while( a[ i ] == a[ i + 1 ] )
{
a_val = a[ i ];
b_sum += b[ i + 1 ];
if( b[ i + 1 ] > b_max )
{
b_max = b[ i + 1 ];
b_max_index = i + 1;
}
++i;
sum = TRUE;
}
// write combined values into correct temp array locations
if( sum )
{
a_temp[ b_max_index ] = a_val;
b_temp[ b_max_index ] = b_sum;
sum = FALSE;
}
// write all other values directly into temp arrays
else
{
a_temp[ i ] = a[ i ];
b_temp[ i ] = b[ i ];
}
}
// catch unique final maximum a values and write directly into temp arrays
if( a[ size - 2 ] != a[ size - 1 ] )
{
a_temp[ i ] = a[ i ];
b_temp[ i ] = b[ i ];
}
// clear working arrays
memset( a, 0, memory_size );
memset( b, 0, memory_size );
// copy temp arrays to working arrays
memcpy( a, a_temp, memory_size );
memcpy( b, b_temp, memory_size );
}
//------------------------------------------------------------------------------
// binmix_sort_ab - sorts a and b array values according to c array values
//------------------------------------------------------------------------------
static inline void binmix_sort_ab( t_binmix* object, t_int size )
{
t_float* a = object->a;
t_float* b = object->b;
t_float* c = object->c;
t_float* a_temp = object->a_temp;
t_float* b_temp = object->b_temp;
t_int i = -1;
while( ++i < size )
{
a_temp[ i ] = a[ ( t_int )c[ i ] ];
b_temp[ i ] = b[ ( t_int )c[ i ] ];
}
memcpy( a, a_temp, object->memory_size );
memcpy( b, b_temp, object->memory_size );
}
//------------------------------------------------------------------------------
// binmix_unsort - move array values back to their original locations
//------------------------------------------------------------------------------
static inline void binmix_unsort( t_binmix* object, t_int size )
{
t_float* a = object->a;
t_float* b = object->b;
t_float* c = object->c;
t_float* a_temp = object->a_temp;
t_float* b_temp = object->b_temp;
t_float memory_size = object->memory_size;
t_int i = -1;
// move modified values back to their corresponding original indices
while( ++i < size )
{
a_temp[ ( t_int )c[ i ] ] = a[ i ];
b_temp[ ( t_int )c[ i ] ] = b[ i ];
}
// copy temp arrays to working arrays
memcpy( a, a_temp, memory_size );
memcpy( b, b_temp, memory_size );
}
//------------------------------------------------------------------------------
// binmix_perform - the signal processing function of this object
//------------------------------------------------------------------------------
static t_int* binmix_perform( t_int* io )
{
// store variables from dsp input/output array
t_float* in1 = ( t_float* )( io[ 1 ] );
t_float* in2 = ( t_float* )( io[ 2 ] );
t_float* out1 = ( t_float* )( io[ 3 ] );
t_float* out2 = ( t_float* )( io[ 4 ] );
t_int frames = ( t_int )( io[ 5 ] );
t_binmix* object = ( t_binmix* )( io[ 6 ] );
// store local copies of object variables
t_float* a = object->a;
t_float* b = object->b;
t_float* c = object->c;
t_float* vector_index = object->vector_index;
t_float memory_size = object->memory_size;
// copy signal vectors to temp arrays
memcpy( a, in1, memory_size );
memcpy( b, in2, memory_size );
memcpy( c, vector_index, memory_size );
// sort c based on a values
binmix_quicksort_c( object, 0, frames );
// rearrange a and b
binmix_sort_ab( object, frames );
// for matching a values, combine b values into largest b location and clear the other a and b values
binmix_combine( object, frames );
// unsort the values back to their original locations
binmix_unsort( object, frames );
// copy sorted temp arrays to outlet arrays
memcpy( out1, a, memory_size );
memcpy( out2, b, memory_size );
// return the dsp input/output array address plus one more than its size
// to provide a pointer to the next perform function in pd's call list
return &( io[ 7 ] );
}
//------------------------------------------------------------------------------
// binmix_dsp - installs this object's dsp function in pd's callback list
//------------------------------------------------------------------------------
static void binmix_dsp( t_binmix* object, t_signal **sig )
{
// temporary frame size variable
t_int frames = sig[ 0 ]->s_n;
// calculate memory size for realloc and memset
t_float memory_size = frames * sizeof( t_float );
// allocate one frame's worth of memory to each pointer ( a and c need an extra location )
object->a = realloc( object->a, memory_size + sizeof( t_float ) );
object->b = realloc( object->b, memory_size );
object->c = realloc( object->c, memory_size + sizeof( t_float ) );
object->a_temp = realloc( object->a_temp, memory_size );
object->b_temp = realloc( object->b_temp, memory_size );
object->vector_index = realloc( object->vector_index, memory_size );
// init extra sorting location
object->a [ frames ] = C_FLOAT_MIN;
object->c [ frames ] = 0;
// increment values stored in vector_index
for( t_int index = 0 ; index < frames ; ++index )
{
object->vector_index[ index ] = ( t_float )index;
}
// save memory size
object->memory_size = memory_size;
// dsp_add arguments
//--------------------------------------------------------------------------
// perform routine
// number of passed parameters
// inlet 1 sample vector
// inlet 2 sample vector
// outlet 1 sample vector
// outlet 2 sample vector
// sample frames to process (vector size)
// object
dsp_add
(
binmix_perform,
6,
sig[ 0 ]->s_vec,
sig[ 1 ]->s_vec,
sig[ 2 ]->s_vec,
sig[ 3 ]->s_vec,
frames,
object
);
}
//------------------------------------------------------------------------------
// binmix_new - instantiates a copy of this object in pd
//------------------------------------------------------------------------------
static void* binmix_new( t_symbol *s, t_int argc, t_atom *argv )
{
// create a pointer to this object
t_binmix* object = ( t_binmix* )pd_new( binmix_class );
// create an additional signal inlet
signalinlet_new( &object->object, object->inlet_2 );
// create two signal outlets
outlet_new( &object->object, gensym( "signal" ) );
outlet_new( &object->object, gensym( "signal" ) );
// initialize the inlet variables
object->inlet_1 = 0;
object->inlet_2 = 0;
// initialize array pointers to null
object->a = NULL;
object->b = NULL;
object->c = NULL;
object->a_temp = NULL;
object->b_temp = NULL;
object->vector_index = NULL;
return object;
}
//------------------------------------------------------------------------------
// binmix_free - cleans up memory allocated by this object
//------------------------------------------------------------------------------
static void binmix_free( t_binmix* object )
{
// if memory is allocated
if( object->a )
{
// free the memory
free( object->a );
// set memory pointer to null
object->a = NULL;
}
// . . .
if( object->b )
{
free( object->b );
object->b = NULL;
}
if( object->c )
{
free( object->c );
object->c = NULL;
}
if( object->a_temp )
{
free( object->a_temp );
object->a_temp = NULL;
}
if( object->b_temp )
{
free( object->b_temp );
object->b_temp = NULL;
}
if( object->vector_index )
{
free( object->vector_index );
object->vector_index = NULL;
}
}
//------------------------------------------------------------------------------
// binmix_tilde_setup - describes the attributes of this object to pd so it may be properly instantiated
// (must always be named with _tilde replacing ~ in the object name)
//------------------------------------------------------------------------------
void binmix_tilde_setup( void )
{
// binmix class
//--------------------------------------------------------------------------
// creates an instance of this object and describes it to pd
binmix_class = class_new( gensym( "binmix~" ), ( t_newmethod )binmix_new, ( t_method )binmix_free, sizeof( t_binmix ), 0, A_GIMME, 0 );
// declares leftmost inlet as a signal inlet
CLASS_MAINSIGNALIN( binmix_class, t_binmix, inlet_1 );
// installs binmix_dsp so that it will be called when dsp is turned on
class_addmethod( binmix_class, ( t_method )binmix_dsp, gensym( "dsp" ), 0 );
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------