20 #include "ext_common.h"
21 #include "jpatcher_api.h"
22 #include "jgraphics.h"
26 #include "TTClassWrapperMax.h"
30 const double kPollIntervalDefault = 150;
31 const double kPollIntervalMinimum = 50;
32 const double kPollIntervalMaximum = 5000;
33 const double kHeightDefault = 13;
34 const double kHeightMinimum = 1;
35 const double kHeightMaximum = 400;
36 const double kWidthDefault = 80;
37 const double kWidthMinimum = 1;
38 const double kWidthMaximum = 1200;
39 const double kOrientationVertical = 1;
40 const double kOrientationHorizontal = 0;
41 const double kMinimumChangeForRedraw = 0.00001;
46 ORIENTATION_AUTOMATIC = 0,
47 ORIENTATION_HORIZONTAL = 1,
48 ORIENTATION_VERTICAL = 2
53 typedef struct _meter{
60 t_jrgba attrBorderColor;
63 long effectOrientation;
67 t_jsurface* gradientSurface;
75 void* meter_new(t_symbol *s,
long argc, t_atom *argv);
76 void meter_free(t_meter *x);
77 t_max_err meter_notify(t_meter *x, t_symbol *s, t_symbol *msg,
void *sender,
void *data);
78 void meter_assist(t_meter *x,
void *b,
long m,
long a,
char *s);
79 void meter_bang(t_meter *x);
80 void meter_int(t_meter *x,
long value);
81 void meter_float(t_meter *x,
double value);
82 void meter_set(t_meter *x,
double value);
83 void meter_clock(t_meter *x);
84 t_int* meter_perform(t_int *w);
85 void meter_perform64(t_meter *x, t_object *dsp64,
double **ins,
long numins,
double **outs,
long numouts,
long sampleframes,
long flags,
void *userparam);
86 void meter_dsp(t_meter *x, t_signal **sp,
short *count);
87 void meter_dsp64(t_meter *x, t_object *dsp64,
short *count,
double samplerate,
long maxvectorsize,
long flags);
88 void meter_paint(t_meter *x, t_object *view);
89 void meter_dopaint_horizontal(t_meter *x, t_object *view);
90 void meter_dopaint_vertical(t_meter *x, t_object *view);
91 void* meter_oksize(t_meter *x, t_rect *newrect);
92 void meterEffectOrientation(t_meter* x);
93 void meterCacheSurface(t_meter* x);
96 static t_class* s_meter_class;
102 #pragma mark Class Definition
107 t_class *c = class_new(
"j.meter~", (method)meter_new, (method)meter_free,
sizeof(t_meter), (method)NULL, A_GIMME, 0L);
109 c->c_flags |= CLASS_FLAG_NEWDICTIONARY;
110 jbox_initclass(c, 0);
111 class_dspinitjbox(c);
114 common_symbols_init();
116 class_addmethod(c, (method)meter_bang,
"bang", 0);
117 class_addmethod(c, (method)meter_int,
"int", A_LONG, 0);
118 class_addmethod(c, (method)meter_float,
"float", A_FLOAT, 0);
119 class_addmethod(c, (method)meter_set,
"set", A_FLOAT, 0);
120 class_addmethod(c, (method)meter_dsp,
"dsp", A_CANT, 0);
121 class_addmethod(c, (method)meter_dsp64,
"dsp64", A_CANT, 0);
122 class_addmethod(c, (method)meter_paint,
"paint", A_CANT, 0);
123 class_addmethod(c, (method)meter_oksize,
"oksize", A_CANT, 0);
124 class_addmethod(c, (method)meter_bang,
"mousedown", A_CANT, 0);
125 class_addmethod(c, (method)meter_notify,
"notify", A_CANT, 0);
126 class_addmethod(c, (method)meter_assist,
"assist", A_CANT, 0);
137 CLASS_ATTR_LONG(c,
"orientation", 0, t_meter, attrOrientation);
138 CLASS_ATTR_LABEL(c,
"orientation", 0,
"Orientation");
139 CLASS_ATTR_CATEGORY(c,
"orientation", 0,
"Appearance");
140 CLASS_ATTR_ENUMINDEX(c,
"orientation", 0,
"Automatic Horizontal Vertical");
141 CLASS_ATTR_DEFAULT_SAVE_PAINT(c,
"orientation", 0,
"0");
143 CLASS_ATTR_RGBA(c,
"bgcolor", 0, t_meter, attrBgColor);
144 CLASS_ATTR_DEFAULTNAME_SAVE_PAINT(c,
"bgcolor", 0,
"0.1 0.1 0.1 1.0");
145 CLASS_ATTR_STYLE(c,
"bgcolor", 0,
"rgba");
146 CLASS_ATTR_LABEL(c,
"bgcolor", 0,
"Background Color");
148 CLASS_ATTR_LONG(c,
"defeat", 0, t_meter, attrDefeat);
149 CLASS_ATTR_LABEL(c,
"defeat", 0,
"defeat");
150 CLASS_ATTR_DEFAULT(c,
"defeat", 0,
"0");
151 CLASS_ATTR_SAVE(c,
"defeat", 0);
152 CLASS_ATTR_STYLE(c,
"defeat", 0,
"onoff");
153 CLASS_ATTR_CATEGORY(c,
"defeat", 0,
"Behavior");
155 CLASS_ATTR_DEFAULT(c,
"patching_rect", 0,
"0. 0. 100. 12.");
156 CLASS_ATTR_MIN(c,
"patching_size", 0,
"1. 1.");
160 class_register(CLASS_BOX, c);
170 #pragma mark Life Cycle
173 void *meter_new(t_symbol *s,
long argc, t_atom *argv)
179 t_dictionary *d=NULL;
181 if (!(d=object_dictionaryarg(argc,argv)))
184 x = (t_meter *)object_alloc(s_meter_class);
204 jbox_new(box, flags, argc, argv);
205 x->obj.z_box.b_firstin = (t_object*)x;
206 dsp_setupjbox((t_pxjbox *)x, 1);
207 x->clock = clock_new(x, (method)meter_clock);
208 meterEffectOrientation(x);
209 x->outlet = outlet_new(x, 0);
210 attr_dictionary_process(x,d);
211 jbox_ready((t_jbox *)x);
216 void meter_free(t_meter *x)
218 dsp_freejbox((t_pxjbox *)x);
219 jgraphics_surface_destroy(x->gradientSurface);
220 object_free((t_object *)x->clock);
221 jbox_free((t_jbox *)x);
230 t_max_err meter_notify(t_meter *x, t_symbol *s, t_symbol *msg,
void *sender,
void *data)
234 if (msg == _sym_attr_modified) {
236 name = (t_symbol *)object_method((t_object *)data, _sym_getname);
238 if (name == _sym_bgcolor)
239 jbox_redraw((t_jbox*)x);
240 if (name == _sym_patching_rect || name == gensym(
"orientation"))
241 meterEffectOrientation(x);
242 if (name == gensym(
"defeat")) {
243 if (sys_getdspstate()) {
244 if (x->attrDefeat == 0)
245 clock_delay(x->clock, kPollIntervalDefault);
249 return jbox_notify((t_jbox*)x, s, msg, sender, data);
254 void meter_assist(t_meter *x,
void *b,
long msg,
long arg,
char *dst)
257 strcpy(dst,
"Input");
260 case 0: strcpy(dst,
"Output");
break;
268 void meter_bang(t_meter *x)
271 jbox_redraw((t_jbox*)x);
275 void meter_int(t_meter *x,
long value)
277 meter_float(x,(
double)value);
280 void meter_float(t_meter *x,
double value)
283 outlet_float(x->outlet, x->envelope);
284 jbox_redraw((t_jbox*)x);
289 void meter_set(t_meter *x,
double value)
292 jbox_redraw((t_jbox*)x);
298 void meter_clock(t_meter *x)
300 double delta = fabs(x->newEnvelope - x->envelope);
301 x->envelope = x->newEnvelope;
304 if (delta > kMinimumChangeForRedraw)
305 jbox_redraw((t_jbox *)x);
307 outlet_float(x->outlet, x->envelope);
308 if (sys_getdspstate()) {
309 if (x->attrDefeat == 0)
310 clock_delay(x->clock, kPollIntervalDefault);
317 #pragma mark Signal Processing
320 t_int *meter_perform(t_int *w)
322 t_meter *x = (t_meter *)(w[1]);
323 t_float *input = (
float *)(w[2]);
324 long n = (long)(w[3]);
327 if (x->obj.z_disabled)
331 currentvalue = ((*input) < 0)?-(*input):*input;
332 if (currentvalue > x->newEnvelope)
333 x->newEnvelope = currentvalue;
342 void meter_perform64(t_meter *x, t_object *dsp64,
double **ins,
long numins,
double **outs,
long numouts,
long sampleframes,
long flags,
void *userparam)
345 int n = sampleframes;
349 currentvalue = ((*in) < 0)?-(*in):*in;
350 if (currentvalue > x->newEnvelope)
351 x->newEnvelope = currentvalue;
357 void meter_dsp(t_meter *x, t_signal **sp,
short *count)
360 dsp_add(meter_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
361 clock_delay(x->clock, kPollIntervalDefault);
367 void meter_dsp64(t_meter *x, t_object *dsp64,
short *count,
double samplerate,
long maxvectorsize,
long flags)
370 object_method(dsp64, gensym(
"dsp_add64"), x, meter_perform64, 0, NULL);
372 clock_delay(x->clock, kPollIntervalDefault);
380 #pragma mark User Interface
383 void *meter_oksize(t_meter *x, t_rect *newrect)
385 TTLimit(newrect->width, kWidthMinimum, kWidthMaximum);
386 TTLimit(newrect->height, kHeightMinimum, kHeightMaximum);
387 meterCacheSurface(x);
392 void meterEffectOrientation(t_meter* x) {
394 t_jbox* box = (t_jbox*)x;
395 long lastEffectOrientation = x->effectOrientation;
397 switch(x->attrOrientation) {
399 x->effectOrientation = box->b_patching_rect.width > box->b_patching_rect.height;
403 x->effectOrientation = 1;
407 x->effectOrientation = 0;
413 if (x->effectOrientation != lastEffectOrientation)
414 jbox_redraw((t_jbox*)x);
418 void meterCacheSurface(t_meter* x)
421 t_jbox* box = (t_jbox*)x;
424 x->gradientRect.x = 0;
425 x->gradientRect.y = 0;
427 if (x->effectOrientation) {
428 x->gradientRect.width = box->b_patching_rect.width * 0.96;
429 x->gradientRect.height = box->b_patching_rect.height;
433 x->gradientRect.width = box->b_patching_rect.width;
434 x->gradientRect.height = box->b_patching_rect.height * 0.96;
437 if (x->gradientSurface)
438 jgraphics_surface_destroy(x->gradientSurface);
440 x->gradientSurface = jgraphics_image_surface_create(JGRAPHICS_FORMAT_ARGB32, x->gradientRect.width, x->gradientRect.height);
448 if (x->effectOrientation) {
449 for (i=0; i < x->gradientRect.width; i++) {
450 color.red = i / x->gradientRect.width;
451 for (j=0; j < x->gradientRect.height; j++)
452 jgraphics_image_surface_set_pixel(x->gradientSurface, i, j, color);
456 for (j=0; j < x->gradientRect.height; j++) {
457 color.red = 1. - (j / x->gradientRect.height);
458 for (i=0; i < x->gradientRect.width; i++)
459 jgraphics_image_surface_set_pixel(x->gradientSurface, i, j, color);
465 void meter_paint(t_meter *x, t_object *view)
467 if (x->effectOrientation)
468 meter_dopaint_horizontal(x,view);
470 meter_dopaint_vertical(x,view);
474 void meter_dopaint_horizontal(t_meter *x, t_object *view) {
478 double level = TTClip(x->envelope, 0.0f, 1.0f);
486 g = (t_jgraphics*) patcherview_get_jgraphics(view);
487 jbox_get_rect_for_view((t_object *)x, view, &rect);
490 position = rect.width * level * 0.96;
491 peakPosition = rect.width * x->peak * 0.96;
498 jgraphics_image_surface_draw(g, x->gradientSurface, x->gradientRect, rect);
500 jgraphics_set_source_jrgba(g, &x->attrBgColor);
501 jgraphics_rectangle_fill_fast(g, position, 0, rect.width-position, rect.height);
503 if (x->envelope > 1.0 || x->peak > 1.0) {
505 c.green = c.blue = 0.0;
507 jgraphics_set_source_jrgba(g, &c);
508 jgraphics_rectangle_fill_fast(g, rect.width - (rect.width * .04), 0, rect.width * .04, rect.height);
511 c.red = peakPosition / x->gradientRect.width;
515 jgraphics_set_source_jrgba(g, &c);
518 jgraphics_move_to(g, peakPosition, 0.0);
519 jgraphics_line_to(g, peakPosition, rect.height);
520 jgraphics_set_line_width(g, 1.0);
525 void meter_dopaint_vertical(t_meter *x, t_object *view) {
529 double level = TTClip(x->envelope, 0.0f, 1.0f);
537 g = (t_jgraphics*) patcherview_get_jgraphics(view);
538 jbox_get_rect_for_view((t_object *)x, view, &rect);
541 position = rect.height * level * 0.96;
542 peakPosition = rect.height * x->peak * 0.96;
549 jgraphics_image_surface_draw(g, x->gradientSurface, x->gradientRect, rect);
551 jgraphics_set_source_jrgba(g, &x->attrBgColor);
552 jgraphics_rectangle_fill_fast(g, 0, 0, rect.width, rect.height-position);
554 if (x->envelope > 1.0 || x->peak > 1.0) {
556 c.green = c.blue = 0.0;
558 jgraphics_set_source_jrgba(g, &c);
559 jgraphics_rectangle_fill_fast(g, 0, 0, rect.width, rect.height * .04);
562 c.red = peakPosition / x->gradientRect.height;
566 jgraphics_set_source_jrgba(g, &c);
569 jgraphics_move_to(g, 0.0, rect.height - peakPosition);
570 jgraphics_line_to(g, rect.width, rect.height - peakPosition);
571 jgraphics_set_line_width(g, 1.0);
int C74_EXPORT main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
double TTFloat64
64 bit floating point number
TTFOUNDATION_EXPORT const TTFloat64 kTTGainMidiPowerInv
Invverse power constant used when calculating MID gain.
float TTFloat32
32 bit floating point number