1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "generator.h"
33 #define FREQ_C0 16.351598
37 #define NOTE_TO_FREQ(n) (FREQ_A4 * pow(2, ((n) - NOTE_A4) / 12.0))
39 #define SEQUENCE_LENGTH 32
40 #define NUM_PATTERNS 16
42 #define GENERATOR_CLASS_NAME "seqnote"
43 #define GENERATOR_CLASS_PATH "Pattern/Note Sequence"
45 #define EVT_SEL_EDIT 0 /* input */
46 #define EVT_SEL_PLAY 1 /* input */
47 #define EVT_STEP 2 /* input */
48 #define EVT_OUTPUT 0 /* output */
49 #define EVT_NOTE_OUT 1 /* output */
52 PRIVATE
void init_pattern(Control
*control
);
53 PRIVATE
void init_2oct_pattern(Control
*control
);
54 PRIVATE
void done_pattern(Control
*control
);
55 PRIVATE
void refresh_pattern(Control
*control
);
57 #define SEQNOTE_CONTROL_PATTERN 0
58 PRIVATE ControlDescriptor seqnote_controls
[] = {
59 { CONTROL_KIND_USERDEF
, "pattern", 0,0,0,0, 0,FALSE
, 0,0, init_pattern
, done_pattern
, refresh_pattern
},
60 { CONTROL_KIND_USERDEF
, "2 Octaves Pattern", 0,0,0,0, 0,FALSE
, 0,0, init_2oct_pattern
, done_pattern
, refresh_pattern
},
61 { CONTROL_KIND_NONE
, }
64 PRIVATE
int clipseq
[SEQUENCE_LENGTH
];
65 PRIVATE gboolean clipnote
[SEQUENCE_LENGTH
];
69 int pattern
[NUM_PATTERNS
][SEQUENCE_LENGTH
];
70 gboolean note
[NUM_PATTERNS
][SEQUENCE_LENGTH
];
73 PRIVATE
int init_instance(Generator
*g
) {
74 Data
*data
= safe_malloc(sizeof(Data
));
79 data
->edit
= data
->play
= 0;
81 for (i
= 0; i
< NUM_PATTERNS
; i
++)
82 for (j
= 0; j
< SEQUENCE_LENGTH
; j
++) {
83 data
->pattern
[i
][j
] = NOTE_A4
;
84 data
->note
[i
][j
] = FALSE
;
90 PRIVATE
void destroy_instance(Generator
*g
) {
94 PRIVATE
void unpickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
95 Data
*data
= safe_malloc(sizeof(Data
));
96 ObjectStoreDatum
*array
;
97 ObjectStoreDatum
*notes
;
102 data
->edit
= objectstore_item_get_integer(item
, "seqnote_edit", 0);
103 data
->play
= objectstore_item_get_integer(item
, "seqnote_play", 0);
104 array
= objectstore_item_get(item
, "seqnote_patterns");
105 notes
= objectstore_item_get(item
, "seqnote_notes");
107 for (i
= 0; i
< NUM_PATTERNS
; i
++)
108 for (j
= 0; j
< SEQUENCE_LENGTH
; j
++) {
109 data
->pattern
[i
][j
] =
110 objectstore_datum_integer_value(
111 objectstore_datum_array_get(array
, i
* SEQUENCE_LENGTH
+ j
)
114 objectstore_datum_integer_value(
115 objectstore_datum_array_get(notes
, i
* SEQUENCE_LENGTH
+ j
)
120 PRIVATE
void pickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
121 Data
*data
= g
->data
;
122 ObjectStoreDatum
*array
= objectstore_datum_new_array(NUM_PATTERNS
* SEQUENCE_LENGTH
);
123 ObjectStoreDatum
*notes
= objectstore_datum_new_array(NUM_PATTERNS
* SEQUENCE_LENGTH
);
126 objectstore_item_set_integer(item
, "seqnote_edit", data
->edit
);
127 objectstore_item_set_integer(item
, "seqnote_play", data
->play
);
128 objectstore_item_set(item
, "seqnote_patterns", array
);
129 objectstore_item_set(item
, "seqnote_notes", notes
);
131 for (i
= 0; i
< NUM_PATTERNS
; i
++)
132 for (j
= 0; j
< SEQUENCE_LENGTH
; j
++) {
133 objectstore_datum_array_set(array
, i
* SEQUENCE_LENGTH
+ j
,
134 objectstore_datum_new_integer(data
->pattern
[i
][j
]));
135 objectstore_datum_array_set(notes
, i
* SEQUENCE_LENGTH
+ j
,
136 objectstore_datum_new_integer(data
->note
[i
][j
]));
140 PRIVATE
void evt_sel_edit_handler(Generator
*g
, AEvent
*event
) {
141 Data
*data
= g
->data
;
143 data
->edit
= GEN_DOUBLE_TO_INT(event
->d
.number
) % NUM_PATTERNS
;
144 gen_update_controls(g
, -1);
147 PRIVATE
void evt_sel_play_handler(Generator
*g
, AEvent
*event
) {
148 ((Data
*) g
->data
)->play
= GEN_DOUBLE_TO_INT(event
->d
.number
) % NUM_PATTERNS
;
151 PRIVATE
void evt_step_handler(Generator
*g
, AEvent
*event
) {
152 Data
*data
= g
->data
;
153 int step
= GEN_DOUBLE_TO_INT(event
->d
.number
) % SEQUENCE_LENGTH
;
155 if (data
->note
[data
->play
][step
]) {
156 gen_init_aevent(event
, AE_NUMBER
, NULL
, 0, NULL
, 0, event
->time
);
157 event
->d
.number
= NOTE_TO_FREQ(data
->pattern
[data
->play
][step
]);
158 gen_send_events(g
, EVT_OUTPUT
, -1, event
);
159 event
->d
.number
= data
->pattern
[data
->play
][step
];
160 gen_send_events(g
, EVT_NOTE_OUT
, -1, event
);
164 PRIVATE
void update_label(GtkWidget
*label
, int note
) {
166 int octave
= note
/ 12;
167 int tone
= note
% 12;
169 (tone
== 1) || (tone
== 3) ||
170 (tone
== 6) || (tone
== 8) || (tone
== 10);
172 sprintf(text
, "%c%s%d\n(%d)", "CCDDEFFGGAAB"[tone
], sharp
? "#" : "", octave
, note
);
173 gtk_label_set_text(GTK_LABEL(label
), text
);
176 PRIVATE
void value_changed_handler(GtkAdjustment
*adj
, gpointer userdata
) {
177 int step
= (intptr_t) userdata
;
178 Control
*c
= gtk_object_get_data(GTK_OBJECT(adj
), "Control");
179 GtkWidget
**widgets
= c
->data
;
180 Data
*data
= c
->g
->data
;
182 if (c
->events_flow
) {
183 int note
= 127 - adj
->value
;
184 data
->pattern
[data
->edit
][step
] = note
;
185 update_label(widgets
[SEQUENCE_LENGTH
* 2], note
);
186 gen_update_controls(c
->g
, -1);
190 PRIVATE
void focus_in_handler(GtkRange
*b
, GdkEventFocus
*event
, gpointer userdata
) {
191 Control
*c
= userdata
;
192 GtkAdjustment
*adj
= gtk_range_get_adjustment(b
);
193 GtkWidget
**widgets
= c
->data
;
195 if (c
->events_flow
) {
196 int note
= 127 - adj
->value
;
197 update_label(widgets
[SEQUENCE_LENGTH
* 2], note
);
201 PRIVATE
void toggle_changed_handler(GtkWidget
*widget
, gpointer userdata
) {
202 int step
= (intptr_t) userdata
;
203 Control
*c
= gtk_object_get_data(GTK_OBJECT(widget
), "Control");
204 Data
*data
= c
->g
->data
;
206 if (c
->events_flow
) {
207 data
->note
[data
->edit
][step
] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
208 gen_update_controls(c
->g
, -1);
212 PRIVATE
void do_copy(Control
*c
, guint action
, GtkWidget
*widget
) {
213 Data
*data
= c
->g
->data
;
218 i
=0; end
=SEQUENCE_LENGTH
;
221 i
=0; end
=SEQUENCE_LENGTH
/2;
224 i
=SEQUENCE_LENGTH
/2; end
=SEQUENCE_LENGTH
;
227 i
=0; end
=SEQUENCE_LENGTH
/4;
230 i
=SEQUENCE_LENGTH
/4; end
=SEQUENCE_LENGTH
*2/4;
233 i
=SEQUENCE_LENGTH
*2/4; end
=SEQUENCE_LENGTH
*3/4;
236 i
=SEQUENCE_LENGTH
*3/4; end
=SEQUENCE_LENGTH
*4/4;
239 i
=0; end
=SEQUENCE_LENGTH
;
243 for( offset
=i
; i
<end
; i
++ ) {
244 clipseq
[i
-offset
] = data
->pattern
[data
->edit
][i
];
245 clipnote
[i
-offset
] = data
->note
[data
->edit
][i
];
249 PRIVATE
void do_paste(Control
*c
, guint action
, GtkWidget
*widget
) {
250 Data
*data
= c
->g
->data
;
255 i
=0; end
=SEQUENCE_LENGTH
;
258 i
=0; end
=SEQUENCE_LENGTH
/2;
261 i
=SEQUENCE_LENGTH
/2; end
=SEQUENCE_LENGTH
;
264 i
=0; end
=SEQUENCE_LENGTH
/4;
267 i
=SEQUENCE_LENGTH
/4; end
=SEQUENCE_LENGTH
*2/4;
270 i
=SEQUENCE_LENGTH
*2/4; end
=SEQUENCE_LENGTH
*3/4;
273 i
=SEQUENCE_LENGTH
*3/4; end
=SEQUENCE_LENGTH
*4/4;
276 i
=0; end
=SEQUENCE_LENGTH
;
280 for( offset
=i
; i
<end
; i
++ ) {
281 data
->pattern
[data
->edit
][i
] = clipseq
[i
-offset
];
282 data
->note
[data
->edit
][i
] = clipnote
[i
-offset
];
284 if (c
->events_flow
) {
285 gen_update_controls(c
->g
, -1);
289 PRIVATE GtkItemFactoryEntry popup_items
[] = {
290 /* Path, accelerator, callback, extra-numeric-argument, kind */
291 { "/Full", NULL
, NULL
, 0, "<Branch>" },
292 { "/Full/Copy", NULL
, do_copy
, 0, NULL
},
293 { "/Full/Paste", NULL
, do_paste
, 0, NULL
},
294 { "/1st Half", NULL
, NULL
, 0, "<Branch>" },
295 { "/1st Half/Copy", NULL
, do_copy
, 1, NULL
},
296 { "/1st Half/Paste", NULL
, do_paste
, 1, NULL
},
297 { "/2nd Half", NULL
, NULL
, 0, "<Branch>" },
298 { "/2nd Half/Copy", NULL
, do_copy
, 2, NULL
},
299 { "/2nd Half/Paste", NULL
, do_paste
, 2, NULL
},
300 { "/1st Quarter", NULL
, NULL
, 0, "<Branch>" },
301 { "/1st Quarter/Copy", NULL
, do_copy
, 3, NULL
},
302 { "/1st Quarter/Paste", NULL
, do_paste
, 3, NULL
},
303 { "/2nd Quarter", NULL
, NULL
, 0, "<Branch>" },
304 { "/2nd Quarter/Copy", NULL
, do_copy
, 4, NULL
},
305 { "/2nd Quarter/Paste", NULL
, do_paste
, 4, NULL
},
306 { "/3rd Quarter", NULL
, NULL
, 0, "<Branch>" },
307 { "/3rd Quarter/Copy", NULL
, do_copy
, 5, NULL
},
308 { "/3rd Quarter/Paste", NULL
, do_paste
, 5, NULL
},
309 { "/4th Quarter", NULL
, NULL
, 0, "<Branch>" },
310 { "/4th Quarter/Copy", NULL
, do_copy
, 6, NULL
},
311 { "/4th Quarter/Paste", NULL
, do_paste
, 6, NULL
},
314 PRIVATE
void kill_popup(GtkWidget
*popup
, GtkItemFactory
*ifact
) {
315 gtk_object_unref(GTK_OBJECT(ifact
));
318 PRIVATE GtkWidget
*build_popup(Control
*c
) {
319 GtkItemFactory
*ifact
;
321 int nitems
= sizeof(popup_items
) / sizeof(popup_items
[0]);
323 ifact
= gtk_item_factory_new(GTK_TYPE_MENU
, "<seqnote-popup>", NULL
);
325 gtk_item_factory_create_items(ifact
, nitems
, popup_items
, c
);
326 result
= gtk_item_factory_get_widget(ifact
, "<seqnote-popup>");
328 gtk_signal_connect(GTK_OBJECT(result
), "destroy", GTK_SIGNAL_FUNC(kill_popup
), ifact
);
332 PRIVATE
void popup_handler(GtkWidget
*widget
, Control
*c
) {
333 //Data *data = c->g->data;
334 GtkWidget
*popup
= build_popup(c
);
336 gtk_menu_popup(GTK_MENU(popup
), NULL
, NULL
, NULL
, NULL
, 1, 0);
339 PRIVATE
void init_pattern(Control
*control
) {
342 GtkWidget
**widgets
= safe_malloc(sizeof(GtkWidget
*) * (SEQUENCE_LENGTH
* 2 + 1));
343 Data
*data
= control
->g
->data
;
344 GtkWidget
*label
, *menu
;
347 hb
= gtk_hbox_new(FALSE
, 5);
349 for (i
= 0; i
< SEQUENCE_LENGTH
; i
++) {
350 GtkWidget
*vb
= gtk_vbox_new(FALSE
, 5);
351 GtkWidget
*b
= gtk_vscale_new(NULL
);
352 GtkWidget
*t
= gtk_toggle_button_new();
353 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(b
));
355 gtk_scale_set_draw_value(GTK_SCALE(b
), FALSE
);
356 gtk_scale_set_digits(GTK_SCALE(b
), 2);
358 adj
->step_increment
= 1;
359 adj
->page_increment
= 1;
362 adj
->value
= 127 - data
->pattern
[data
->edit
][i
];
364 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t
), data
->note
[data
->edit
][i
]);
366 gtk_object_set_data(GTK_OBJECT(adj
), "Control", control
);
367 gtk_signal_connect(GTK_OBJECT(adj
), "value_changed",
368 GTK_SIGNAL_FUNC(value_changed_handler
), (gpointer
) (intptr_t) i
);
369 gtk_signal_connect(GTK_OBJECT(b
), "focus_in_event",
370 GTK_SIGNAL_FUNC(focus_in_handler
), control
);
371 gtk_widget_set_usize(b
, 12, 100);
372 gtk_box_pack_start(GTK_BOX(vb
), b
, FALSE
, FALSE
, 0);
376 gtk_object_set_data(GTK_OBJECT(t
), "Control", control
);
377 gtk_signal_connect(GTK_OBJECT(t
), "toggled",
378 GTK_SIGNAL_FUNC(toggle_changed_handler
), (gpointer
)(intptr_t) i
);
379 gtk_widget_set_usize(t
, 12, 16);
380 gtk_box_pack_start(GTK_BOX(vb
), t
, FALSE
, FALSE
, 0);
382 widgets
[i
+ SEQUENCE_LENGTH
] = t
;
384 gtk_box_pack_start(GTK_BOX(hb
), vb
, FALSE
, FALSE
, 0);
387 rightvb
= gtk_vbox_new( FALSE
, 5 );
389 label
= gtk_label_new("--");
390 gtk_box_pack_start(GTK_BOX(rightvb
), label
, FALSE
, FALSE
, 0);
391 menu
= gtk_button_new_with_label( "M" );
392 gtk_box_pack_start(GTK_BOX(rightvb
), menu
, TRUE
, FALSE
, 0);
395 gtk_signal_connect( GTK_OBJECT(menu
), "clicked",
396 GTK_SIGNAL_FUNC( popup_handler
), control
);
398 gtk_box_pack_start(GTK_BOX(hb
), rightvb
, FALSE
, FALSE
, 0);
399 gtk_widget_show(label
);
400 gtk_widget_show(menu
);
401 gtk_widget_show(rightvb
);
402 widgets
[SEQUENCE_LENGTH
* 2] = label
;
404 control
->widget
= hb
;
405 control
->data
= widgets
;
408 PRIVATE
void init_2oct_pattern(Control
*control
) {
411 GtkWidget
**widgets
= safe_malloc(sizeof(GtkWidget
*) * (SEQUENCE_LENGTH
* 2 + 1));
412 Data
*data
= control
->g
->data
;
413 GtkWidget
*label
, *menu
;
416 hb
= gtk_hbox_new(FALSE
, 5);
418 for (i
= 0; i
< SEQUENCE_LENGTH
; i
++) {
419 GtkWidget
*vb
= gtk_vbox_new(FALSE
, 5);
420 GtkWidget
*b
= gtk_vscale_new(NULL
);
421 GtkWidget
*t
= gtk_toggle_button_new();
422 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(b
));
424 gtk_scale_set_draw_value(GTK_SCALE(b
), FALSE
);
425 gtk_scale_set_digits(GTK_SCALE(b
), 2);
427 adj
->step_increment
= 1;
428 adj
->page_increment
= 1;
429 adj
->lower
= 127 - 48;
430 adj
->upper
= 127 - 24;
431 adj
->value
= 127 - data
->pattern
[data
->edit
][i
];
433 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t
), data
->note
[data
->edit
][i
]);
435 gtk_object_set_data(GTK_OBJECT(adj
), "Control", control
);
436 gtk_signal_connect(GTK_OBJECT(adj
), "value_changed",
437 GTK_SIGNAL_FUNC(value_changed_handler
), (gpointer
) (intptr_t) i
);
438 gtk_signal_connect(GTK_OBJECT(b
), "focus_in_event",
439 GTK_SIGNAL_FUNC(focus_in_handler
), control
);
440 gtk_widget_set_usize(b
, 12, 100);
441 gtk_box_pack_start(GTK_BOX(vb
), b
, FALSE
, FALSE
, 0);
445 gtk_object_set_data(GTK_OBJECT(t
), "Control", control
);
446 gtk_signal_connect(GTK_OBJECT(t
), "toggled",
447 GTK_SIGNAL_FUNC(toggle_changed_handler
), (gpointer
) (intptr_t) i
);
448 gtk_widget_set_usize(t
, 12, 16);
449 gtk_box_pack_start(GTK_BOX(vb
), t
, FALSE
, FALSE
, 0);
451 widgets
[i
+ SEQUENCE_LENGTH
] = t
;
453 gtk_box_pack_start(GTK_BOX(hb
), vb
, FALSE
, FALSE
, 0);
456 rightvb
= gtk_vbox_new( FALSE
, 5 );
458 label
= gtk_label_new("--");
459 gtk_box_pack_start(GTK_BOX(rightvb
), label
, FALSE
, FALSE
, 0);
460 menu
= gtk_button_new_with_label( "M" );
461 gtk_box_pack_start(GTK_BOX(rightvb
), menu
, TRUE
, FALSE
, 0);
464 gtk_signal_connect( GTK_OBJECT(menu
), "clicked",
465 GTK_SIGNAL_FUNC( popup_handler
), control
);
467 gtk_box_pack_start(GTK_BOX(hb
), rightvb
, FALSE
, FALSE
, 0);
468 gtk_widget_show(label
);
469 gtk_widget_show(menu
);
470 gtk_widget_show(rightvb
);
471 widgets
[SEQUENCE_LENGTH
* 2] = label
;
473 control
->widget
= hb
;
474 control
->data
= widgets
;
477 PRIVATE
void done_pattern(Control
*control
) {
481 PRIVATE
void refresh_pattern(Control
*control
) {
482 Data
*data
= control
->g
->data
;
483 GtkWidget
**widgets
= control
->data
;
486 for (i
= 0; i
< SEQUENCE_LENGTH
; i
++) {
487 gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(widgets
[i
])),
488 127 - data
->pattern
[data
->edit
][i
]);
489 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widgets
[i
+ SEQUENCE_LENGTH
]),
490 data
->note
[data
->edit
][i
]);
494 PRIVATE
void setup_class(void) {
496 GeneratorClass
*k
= gen_new_generatorclass(GENERATOR_CLASS_NAME
, FALSE
, 3, 2,
497 NULL
, NULL
, seqnote_controls
,
498 init_instance
, destroy_instance
,
499 unpickle_instance
, pickle_instance
);
501 gen_configure_event_input(k
, EVT_SEL_EDIT
, "Edit Seq", evt_sel_edit_handler
);
502 gen_configure_event_input(k
, EVT_SEL_PLAY
, "Play Seq", evt_sel_play_handler
);
503 gen_configure_event_input(k
, EVT_STEP
, "Step", evt_step_handler
);
504 gen_configure_event_output(k
, EVT_OUTPUT
, "Freq");
505 gen_configure_event_output(k
, EVT_NOTE_OUT
, "Note");
507 gencomp_register_generatorclass(k
, FALSE
, GENERATOR_CLASS_PATH
, NULL
, NULL
);
509 for( i
=0; i
<SEQUENCE_LENGTH
; i
++ ) {
510 clipseq
[i
] = NOTE_A4
;
515 PUBLIC
void init_plugin(void) {