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 SEQUENCE_LENGTH 32
34 #define NUM_PATTERNS 16
36 #define GENERATOR_CLASS_NAME "trigseq"
37 #define GENERATOR_CLASS_PATH "Pattern/Trigger Sequence"
39 #define EVT_SEL_EDIT 0 /* input */
40 #define EVT_SEL_PLAY 1 /* input */
41 #define EVT_STEP 2 /* input */
42 #define EVT_OUTPUT 0 /* output */
45 PRIVATE
void init_pattern(Control
*control
);
46 PRIVATE
void done_pattern(Control
*control
);
47 PRIVATE
void refresh_pattern(Control
*control
);
49 #define TRIGSEQ_CONTROL_PATTERN 0
50 PRIVATE ControlDescriptor trigseq_controls
[] = {
51 { CONTROL_KIND_USERDEF
, "pattern", 0,0,0,0, 0,FALSE
, 0,0, init_pattern
, done_pattern
, refresh_pattern
},
52 { CONTROL_KIND_NONE
, }
57 gboolean pattern
[NUM_PATTERNS
][SEQUENCE_LENGTH
];
60 PRIVATE gboolean clipseq
[SEQUENCE_LENGTH
];
62 PRIVATE
int init_instance(Generator
*g
) {
63 Data
*data
= safe_malloc(sizeof(Data
));
68 data
->edit
= data
->play
= 0;
70 for (i
= 0; i
< NUM_PATTERNS
; i
++)
71 for (j
= 0; j
< SEQUENCE_LENGTH
; j
++)
72 data
->pattern
[i
][j
] = FALSE
;
77 PRIVATE
void destroy_instance(Generator
*g
) {
81 PRIVATE
void unpickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
82 Data
*data
= safe_malloc(sizeof(Data
));
83 ObjectStoreDatum
*array
;
88 data
->edit
= objectstore_item_get_integer(item
, "trigseq_edit", 0);
89 data
->play
= objectstore_item_get_integer(item
, "trigseq_play", 0);
90 array
= objectstore_item_get(item
, "trigseq_patterns");
92 for (i
= 0; i
< NUM_PATTERNS
; i
++)
93 for (j
= 0; j
< SEQUENCE_LENGTH
; j
++)
95 objectstore_datum_integer_value(
96 objectstore_datum_array_get(array
, i
* SEQUENCE_LENGTH
+ j
)
100 PRIVATE
void pickle_instance(Generator
*g
, ObjectStoreItem
*item
, ObjectStore
*db
) {
101 Data
*data
= g
->data
;
102 ObjectStoreDatum
*array
= objectstore_datum_new_array(NUM_PATTERNS
* SEQUENCE_LENGTH
);
105 objectstore_item_set_integer(item
, "trigseq_edit", data
->edit
);
106 objectstore_item_set_integer(item
, "trigseq_play", data
->play
);
107 objectstore_item_set(item
, "trigseq_patterns", array
);
109 for (i
= 0; i
< NUM_PATTERNS
; i
++)
110 for (j
= 0; j
< SEQUENCE_LENGTH
; j
++)
111 objectstore_datum_array_set(array
, i
* SEQUENCE_LENGTH
+ j
,
112 objectstore_datum_new_integer(data
->pattern
[i
][j
]));
115 PRIVATE
void evt_sel_edit_handler(Generator
*g
, AEvent
*event
) {
116 Data
*data
= g
->data
;
118 data
->edit
= GEN_DOUBLE_TO_INT(event
->d
.number
) % NUM_PATTERNS
;
119 gen_update_controls(g
, TRIGSEQ_CONTROL_PATTERN
);
122 PRIVATE
void evt_sel_play_handler(Generator
*g
, AEvent
*event
) {
123 ((Data
*) g
->data
)->play
= GEN_DOUBLE_TO_INT(event
->d
.number
) % NUM_PATTERNS
;
126 PRIVATE
void evt_step_handler(Generator
*g
, AEvent
*event
) {
127 Data
*data
= g
->data
;
128 int step
= GEN_DOUBLE_TO_INT(event
->d
.number
) % SEQUENCE_LENGTH
;
130 if (data
->pattern
[data
->play
][step
]) {
131 gen_init_aevent(event
, AE_NUMBER
, NULL
, 0, NULL
, 0, event
->time
);
132 event
->d
.number
= step
;
133 gen_send_events(g
, EVT_OUTPUT
, -1, event
);
137 PRIVATE
void toggled_handler(GtkWidget
*widget
, gpointer userdata
) {
138 int step
= (intptr_t) userdata
;
139 Control
*c
= gtk_object_get_data(GTK_OBJECT(widget
), "Control");
140 Data
*data
= c
->g
->data
;
142 if (c
->events_flow
) {
143 data
->pattern
[data
->edit
][step
] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
144 gen_update_controls(c
->g
, TRIGSEQ_CONTROL_PATTERN
);
148 PRIVATE
void do_copy(Control
*c
, guint action
, GtkWidget
*widget
) {
149 Data
*data
= c
->g
->data
;
154 i
=0; end
=SEQUENCE_LENGTH
;
157 i
=0; end
=SEQUENCE_LENGTH
/2;
160 i
=SEQUENCE_LENGTH
/2; end
=SEQUENCE_LENGTH
;
163 i
=0; end
=SEQUENCE_LENGTH
/4;
166 i
=SEQUENCE_LENGTH
/4; end
=SEQUENCE_LENGTH
*2/4;
169 i
=SEQUENCE_LENGTH
*2/4; end
=SEQUENCE_LENGTH
*3/4;
172 i
=SEQUENCE_LENGTH
*3/4; end
=SEQUENCE_LENGTH
*4/4;
175 i
=0; end
=SEQUENCE_LENGTH
;
179 for( offset
=i
; i
<end
; i
++ ) {
180 clipseq
[i
-offset
] = data
->pattern
[data
->edit
][i
];
184 PRIVATE
void do_paste(Control
*c
, guint action
, GtkWidget
*widget
) {
185 Data
*data
= c
->g
->data
;
190 i
=0; end
=SEQUENCE_LENGTH
;
193 i
=0; end
=SEQUENCE_LENGTH
/2;
196 i
=SEQUENCE_LENGTH
/2; end
=SEQUENCE_LENGTH
;
199 i
=0; end
=SEQUENCE_LENGTH
/4;
202 i
=SEQUENCE_LENGTH
/4; end
=SEQUENCE_LENGTH
*2/4;
205 i
=SEQUENCE_LENGTH
*2/4; end
=SEQUENCE_LENGTH
*3/4;
208 i
=SEQUENCE_LENGTH
*3/4; end
=SEQUENCE_LENGTH
*4/4;
211 i
=0; end
=SEQUENCE_LENGTH
;
215 for( offset
=i
; i
<end
; i
++ ) {
216 data
->pattern
[data
->edit
][i
] = clipseq
[i
-offset
];
218 if (c
->events_flow
) {
219 gen_update_controls(c
->g
, TRIGSEQ_CONTROL_PATTERN
);
223 PRIVATE GtkItemFactoryEntry popup_items
[] = {
224 /* Path, accelerator, callback, extra-numeric-argument, kind */
225 { "/Full", NULL
, NULL
, 0, "<Branch>" },
226 { "/Full/Copy", NULL
, do_copy
, 0, NULL
},
227 { "/Full/Paste", NULL
, do_paste
, 0, NULL
},
228 { "/1st Half", NULL
, NULL
, 0, "<Branch>" },
229 { "/1st Half/Copy", NULL
, do_copy
, 1, NULL
},
230 { "/1st Half/Paste", NULL
, do_paste
, 1, NULL
},
231 { "/2nd Half", NULL
, NULL
, 0, "<Branch>" },
232 { "/2nd Half/Copy", NULL
, do_copy
, 2, NULL
},
233 { "/2nd Half/Paste", NULL
, do_paste
, 2, NULL
},
234 { "/1st Quarter", NULL
, NULL
, 0, "<Branch>" },
235 { "/1st Quarter/Copy", NULL
, do_copy
, 3, NULL
},
236 { "/1st Quarter/Paste", NULL
, do_paste
, 3, NULL
},
237 { "/2nd Quarter", NULL
, NULL
, 0, "<Branch>" },
238 { "/2nd Quarter/Copy", NULL
, do_copy
, 4, NULL
},
239 { "/2nd Quarter/Paste", NULL
, do_paste
, 4, NULL
},
240 { "/3rd Quarter", NULL
, NULL
, 0, "<Branch>" },
241 { "/3rd Quarter/Copy", NULL
, do_copy
, 5, NULL
},
242 { "/3rd Quarter/Paste", NULL
, do_paste
, 5, NULL
},
243 { "/4th Quarter", NULL
, NULL
, 0, "<Branch>" },
244 { "/4th Quarter/Copy", NULL
, do_copy
, 6, NULL
},
245 { "/4th Quarter/Paste", NULL
, do_paste
, 6, NULL
},
248 PRIVATE
void kill_popup(GtkWidget
*popup
, GtkItemFactory
*ifact
) {
249 gtk_object_unref(GTK_OBJECT(ifact
));
252 PRIVATE GtkWidget
*build_popup(Control
*c
) {
253 GtkItemFactory
*ifact
;
255 int nitems
= sizeof(popup_items
) / sizeof(popup_items
[0]);
257 ifact
= gtk_item_factory_new(GTK_TYPE_MENU
, "<trigseq-popup>", NULL
);
259 gtk_item_factory_create_items(ifact
, nitems
, popup_items
, c
);
260 result
= gtk_item_factory_get_widget(ifact
, "<trigseq-popup>");
262 gtk_signal_connect(GTK_OBJECT(result
), "destroy", GTK_SIGNAL_FUNC(kill_popup
), ifact
);
266 PRIVATE
void popup_handler(GtkWidget
*widget
, Control
*c
) {
267 //Data *data = c->g->data;
268 GtkWidget
*popup
= build_popup(c
);
270 gtk_menu_popup(GTK_MENU(popup
), NULL
, NULL
, NULL
, NULL
, 1, 0);
273 PRIVATE
void init_pattern(Control
*control
) {
276 GtkWidget
**widgets
= safe_malloc(sizeof(GtkWidget
*) * SEQUENCE_LENGTH
);
279 hb
= gtk_hbox_new(FALSE
, 5);
281 for (i
= 0; i
< SEQUENCE_LENGTH
; i
++) {
282 GtkWidget
*b
= gtk_toggle_button_new();
283 gtk_object_set_data(GTK_OBJECT(b
), "Control", control
);
284 gtk_signal_connect(GTK_OBJECT(b
), "toggled", GTK_SIGNAL_FUNC(toggled_handler
), (gpointer
) (intptr_t)i
);
285 gtk_box_pack_start(GTK_BOX(hb
), b
, FALSE
, FALSE
, 0);
286 gtk_widget_set_usize(b
, 12, 16);
290 menu
= gtk_button_new_with_label( "m" );
292 gtk_signal_connect( GTK_OBJECT(menu
), "clicked",
293 GTK_SIGNAL_FUNC( popup_handler
), control
);
295 gtk_box_pack_start(GTK_BOX(hb
), menu
, FALSE
, FALSE
, 0);
296 gtk_widget_show(menu
);
298 control
->widget
= hb
;
299 control
->data
= widgets
;
302 PRIVATE
void done_pattern(Control
*control
) {
306 PRIVATE
void refresh_pattern(Control
*control
) {
307 Data
*data
= control
->g
->data
;
308 GtkWidget
**widgets
= control
->data
;
311 for (i
= 0; i
< SEQUENCE_LENGTH
; i
++) {
312 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widgets
[i
]),
313 data
->pattern
[data
->edit
][i
]);
317 PRIVATE
void setup_class(void) {
318 GeneratorClass
*k
= gen_new_generatorclass(GENERATOR_CLASS_NAME
, FALSE
, 3, 1,
319 NULL
, NULL
, trigseq_controls
,
320 init_instance
, destroy_instance
,
321 unpickle_instance
, pickle_instance
);
323 gen_configure_event_input(k
, EVT_SEL_EDIT
, "Edit Seq", evt_sel_edit_handler
);
324 gen_configure_event_input(k
, EVT_SEL_PLAY
, "Play Seq", evt_sel_play_handler
);
325 gen_configure_event_input(k
, EVT_STEP
, "Step", evt_step_handler
);
326 gen_configure_event_output(k
, EVT_OUTPUT
, "Output");
328 gencomp_register_generatorclass(k
, FALSE
, GENERATOR_CLASS_PATH
, NULL
, NULL
);
331 PUBLIC
void init_plugin(void) {