aboutsummaryrefslogtreecommitdiff
path: root/cyclone/hammer/midiparse.c
blob: 9a79a3922879eda1c0e54ae63b2ebbd851e27557 (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
131
132
/* 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.  */

#include "m_pd.h"

typedef struct _midiparse
{
    t_object       x_ob;
    unsigned char  x_ready;
    unsigned char  x_status;
    unsigned char  x_channel;
    unsigned char  x_data1;
    t_outlet      *x_polyout;
    t_outlet      *x_ctlout;
    t_outlet      *x_pgmout;
    t_outlet      *x_touchout;
    t_outlet      *x_bendout;
    t_outlet      *x_chanout;
} t_midiparse;

static t_class *midiparse_class;

static void midiparse_clear(t_midiparse *x)
{
    x->x_status = 0;
    x->x_ready = 0;
}

static void midiparse_float(t_midiparse *x, t_float f)
{
    int ival = (int)f;  /* CHECKED */
    if (ival < 0)
    {
	/* CHECKME */
	return;
    }
    if (ival < 256)  /* CHECKED clear if input over 255 */
    {
	unsigned char bval = ival;
	if (bval & 0x80)
	{
	    unsigned char status = bval & 0xF0;
	    if (status == 0xF0)
	    {
		/* CHECKED no such test in max -- this is incompatible,
		   but real-time messages are out-of-band, and they
		   should be ignored here.  LATER rethink the 0xFE case. */
		if (bval < 0xF8)
		    midiparse_clear(x);
	    }
	    else
	    {
		x->x_status = status;
		x->x_channel = bval & 0x0F;
		x->x_ready = (status == 0xC0 || status == 0xD0);
	    }
	}
	else if (x->x_ready)
	{
	    t_atom at[2];
	    x->x_ready = 0;
	    outlet_float(x->x_chanout, x->x_channel + 1);
	    switch (x->x_status)
	    {
	    case 0x80:
		SETFLOAT(&at[0], x->x_data1);
		SETFLOAT(&at[1], 0);
		outlet_list(((t_object *)x)->ob_outlet, 0, 2, at);
		break;
	    case 0x90:
		SETFLOAT(&at[0], x->x_data1);
		SETFLOAT(&at[1], bval);
		outlet_list(((t_object *)x)->ob_outlet, 0, 2, at);
		break;
	    case 0xA0:
		SETFLOAT(&at[0], bval);
		SETFLOAT(&at[1], x->x_data1);
		outlet_list(x->x_polyout, 0, 2, at);
		break;
	    case 0xB0:
		SETFLOAT(&at[0], bval);
		SETFLOAT(&at[1], x->x_data1);
		outlet_list(x->x_ctlout, 0, 2, at);
		break;
	    case 0xC0:
		outlet_float(x->x_pgmout, bval);
		x->x_ready = 1;
		break;
	    case 0xD0:
		outlet_float(x->x_touchout, bval);
		x->x_ready = 1;
		break;
	    case 0xE0:
		/* CHECKED: ignores data1 */
		outlet_float(x->x_bendout, bval);
		break;
	    default:;
	    }
	}
	else if (x->x_status)
	{
	    x->x_data1 = bval;  /* CHECKED key #0 accepted */
	    x->x_ready = 1;
	}
    }
    else midiparse_clear(x);
}

static void *midiparse_new(void)
{
    t_midiparse *x = (t_midiparse *)pd_new(midiparse_class);
    outlet_new((t_object *)x, &s_list);
    x->x_polyout = outlet_new((t_object *)x, &s_list);
    x->x_ctlout = outlet_new((t_object *)x, &s_list);
    x->x_pgmout = outlet_new((t_object *)x, &s_float);
    x->x_touchout = outlet_new((t_object *)x, &s_float);
    x->x_bendout = outlet_new((t_object *)x, &s_float);
    x->x_chanout = outlet_new((t_object *)x, &s_float);
    midiparse_clear(x);
    return (x);
}

void midiparse_setup(void)
{
    midiparse_class = class_new(gensym("midiparse"), 
				(t_newmethod)midiparse_new, 0,
				sizeof(t_midiparse), 0, 0);
    class_addbang(midiparse_class, midiparse_clear);
    class_addfloat(midiparse_class, midiparse_float);
    /* CHECKED autocasting lists to floats */
}