missing commit in generator.h
[galan.git] / plugins / libtrigseq.c
blobbd91184750da9627e2b0de049286bb2c66afaa27
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
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdint.h>
24 #include <gdk/gdk.h>
25 #include <gtk/gtk.h>
27 #include "global.h"
28 #include "generator.h"
29 #include "comp.h"
30 #include "control.h"
31 #include "gencomp.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 */
44 /* Forward refs. */
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, }
55 typedef struct Data {
56 int edit, play;
57 gboolean pattern[NUM_PATTERNS][SEQUENCE_LENGTH];
58 } Data;
60 PRIVATE gboolean clipseq[SEQUENCE_LENGTH];
62 PRIVATE int init_instance(Generator *g) {
63 Data *data = safe_malloc(sizeof(Data));
64 int i, j;
66 g->data = 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;
74 return 1;
77 PRIVATE void destroy_instance(Generator *g) {
78 free(g->data);
81 PRIVATE void unpickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
82 Data *data = safe_malloc(sizeof(Data));
83 ObjectStoreDatum *array;
84 int i, j;
86 g->data = data;
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++)
94 data->pattern[i][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);
103 int i, j;
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;
150 int i, end, offset;
152 switch( action ) {
153 case 0:
154 i=0; end=SEQUENCE_LENGTH;
155 break;
156 case 1:
157 i=0; end=SEQUENCE_LENGTH/2;
158 break;
159 case 2:
160 i=SEQUENCE_LENGTH/2; end=SEQUENCE_LENGTH;
161 break;
162 case 3:
163 i=0; end=SEQUENCE_LENGTH/4;
164 break;
165 case 4:
166 i=SEQUENCE_LENGTH/4; end=SEQUENCE_LENGTH*2/4;
167 break;
168 case 5:
169 i=SEQUENCE_LENGTH*2/4; end=SEQUENCE_LENGTH*3/4;
170 break;
171 case 6:
172 i=SEQUENCE_LENGTH*3/4; end=SEQUENCE_LENGTH*4/4;
173 break;
174 default:
175 i=0; end=SEQUENCE_LENGTH;
176 break;
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;
186 int i, end, offset;
188 switch( action ) {
189 case 0:
190 i=0; end=SEQUENCE_LENGTH;
191 break;
192 case 1:
193 i=0; end=SEQUENCE_LENGTH/2;
194 break;
195 case 2:
196 i=SEQUENCE_LENGTH/2; end=SEQUENCE_LENGTH;
197 break;
198 case 3:
199 i=0; end=SEQUENCE_LENGTH/4;
200 break;
201 case 4:
202 i=SEQUENCE_LENGTH/4; end=SEQUENCE_LENGTH*2/4;
203 break;
204 case 5:
205 i=SEQUENCE_LENGTH*2/4; end=SEQUENCE_LENGTH*3/4;
206 break;
207 case 6:
208 i=SEQUENCE_LENGTH*3/4; end=SEQUENCE_LENGTH*4/4;
209 break;
210 default:
211 i=0; end=SEQUENCE_LENGTH;
212 break;
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;
254 GtkWidget *result;
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);
263 return result;
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) {
274 GtkWidget *hb;
275 int i;
276 GtkWidget **widgets = safe_malloc(sizeof(GtkWidget *) * SEQUENCE_LENGTH);
277 GtkWidget *menu;
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);
287 gtk_widget_show(b);
288 widgets[i] = b;
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) {
303 free(control->data);
306 PRIVATE void refresh_pattern(Control *control) {
307 Data *data = control->g->data;
308 GtkWidget **widgets = control->data;
309 int i;
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) {
332 setup_class();