aboutsummaryrefslogtreecommitdiff
path: root/cyclone/sickle/bitshift.c
blob: db30fcdad910380648eb4f8ad4c5293f49620628 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* Copyright (c) 2002-2003 krzYszcz and others.
 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
 * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* When bit-shifting 32-bit values, gcc (intel?) bashes the second operand
   modulo 32.  In msp x << 32 gives 0, x >> 32 gives a propagated sign bit
   (as expected).  Mimicking that is clumsy.  LATER consider making the calcs
   more generic (use long long values?) */

#include "m_pd.h"
#include "sickle/sic.h"

//#define BITSHIFT_DEBUG

typedef struct _bitshift
{
    t_sic  x_sic;
    int    x_convert1;
    int    x_lshift;
    int    x_rshift;
    int    x_lover;
} t_bitshift;

static t_class *bitshift_class;

static t_int *bitshift_perform(t_int *w)
{
    t_bitshift *x = (t_bitshift *)(w[1]);
    int nblock = (int)(w[2]);
    t_float *in = (t_float *)(w[3]);
    t_float *out = (t_float *)(w[4]);
    /* LATER think about performance */
    if (x->x_lshift)
    {
	unsigned int shift = x->x_lshift;
	if (x->x_convert1) while (nblock--)
	{
	    /* CHECKED */
	    t_int i = ((t_int)*in++ << shift);
	    *out++ = (t_float)i;
	}
	else while (nblock--)
	{
	    /* CHECKED */
	    t_int i = (*(t_int *)(t_float *)in++ << shift);
	    *out++ = *(t_float *)&i;
	}
    }
    else if (x->x_rshift)
    {
	unsigned int shift = x->x_rshift;
	if (x->x_convert1) while (nblock--)
	{
	    /* CHECKME */
	    t_int i = ((t_int)*in++ >> shift);
	    *out++ = (t_float)i;
	}
	else while (nblock--)
	{
	    /* CHECKME */
	    t_int i = (*(t_int *)(t_float *)in++ >> shift);
	    *out++ = *(t_float *)&i;
	}
    }
    else if (x->x_lover)
	while (nblock--) *out++ = 0;  /* CHECKED both modes */
    else
	while (nblock--) *out++ = *in++;  /* CHECKED both modes */
    return (w + 5);
}

static void bitshift_dsp(t_bitshift *x, t_signal **sp)
{
    dsp_add(bitshift_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
}

static void bitshift_mode(t_bitshift *x, t_floatarg f)
{
    int i = (int)f;
    x->x_convert1 = (i > 0);  /* CHECKED */
}

static void bitshift_shift(t_bitshift *x, t_floatarg f)
{
    int i = (int)f;
    int nbits = sizeof(t_int) * 8;
    x->x_lshift = x->x_rshift = 0;
    x->x_lover = 0;
    if (i > 0)
    {
#ifdef BITSHIFT_DEBUG
	post("%.8x << %d == %.8x, %.8x << %d == %.8x",
	     1, i, 1 << i, -1, i, -1 << i);
#endif
	if (i < nbits)
	    x->x_lshift = i;
	else
	    x->x_lover = 1;
    }
    else if (i < 0)
    {
#ifdef BITSHIFT_DEBUG
	post("%.8x >> %d == %.8x, %.8x >> %d == %.8x",
	     0x7fffffff, -i, 0x7fffffff >> -i, -1, -i, -1 >> -i);
#endif
	x->x_rshift = (i <= -nbits ? nbits - 1 : -i);
    }
}

static void *bitshift_new(t_floatarg f1, t_floatarg f2)
{
    t_bitshift *x = (t_bitshift *)pd_new(bitshift_class);
    outlet_new((t_object *)x, &s_signal);
    bitshift_shift(x, f1);
    bitshift_mode(x, f2);
    return (x);
}

void bitshift_tilde_setup(void)
{
    bitshift_class = class_new(gensym("bitshift~"),
			       (t_newmethod)bitshift_new, 0,
			       sizeof(t_bitshift), 0,
			       A_DEFFLOAT, A_DEFFLOAT, 0);
    sic_setup(bitshift_class, bitshift_dsp, SIC_FLOATTOSIGNAL);
    class_addmethod(bitshift_class, (t_method)bitshift_mode,
		    gensym("mode"), A_FLOAT, 0);
    class_addmethod(bitshift_class, (t_method)bitshift_shift,
		    gensym("shift"), A_FLOAT, 0);
}