missing commit in generator.h
[galan.git] / plugins / libseqnote.c
blob28b1a0982266c3bc2aa9ba3d5d8aa1df48376f69
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 FREQ_C0 16.351598
34 #define FREQ_A4 440
35 #define NOTE_C4 48
36 #define NOTE_A4 57
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 */
51 /* Forward refs. */
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];
67 typedef struct Data {
68 int edit, play;
69 int pattern[NUM_PATTERNS][SEQUENCE_LENGTH];
70 gboolean note[NUM_PATTERNS][SEQUENCE_LENGTH];
71 } Data;
73 PRIVATE int init_instance(Generator *g) {
74 Data *data = safe_malloc(sizeof(Data));
75 int i, j;
77 g->data = 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;
87 return 1;
90 PRIVATE void destroy_instance(Generator *g) {
91 free(g->data);
94 PRIVATE void unpickle_instance(Generator *g, ObjectStoreItem *item, ObjectStore *db) {
95 Data *data = safe_malloc(sizeof(Data));
96 ObjectStoreDatum *array;
97 ObjectStoreDatum *notes;
98 int i, j;
100 g->data = data;
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)
113 data->note[i][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);
124 int i, j;
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) {
165 char text[20];
166 int octave = note / 12;
167 int tone = note % 12;
168 int sharp =
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;
214 int i, end, offset;
216 switch( action ) {
217 case 0:
218 i=0; end=SEQUENCE_LENGTH;
219 break;
220 case 1:
221 i=0; end=SEQUENCE_LENGTH/2;
222 break;
223 case 2:
224 i=SEQUENCE_LENGTH/2; end=SEQUENCE_LENGTH;
225 break;
226 case 3:
227 i=0; end=SEQUENCE_LENGTH/4;
228 break;
229 case 4:
230 i=SEQUENCE_LENGTH/4; end=SEQUENCE_LENGTH*2/4;
231 break;
232 case 5:
233 i=SEQUENCE_LENGTH*2/4; end=SEQUENCE_LENGTH*3/4;
234 break;
235 case 6:
236 i=SEQUENCE_LENGTH*3/4; end=SEQUENCE_LENGTH*4/4;
237 break;
238 default:
239 i=0; end=SEQUENCE_LENGTH;
240 break;
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;
251 int i, end, offset;
253 switch( action ) {
254 case 0:
255 i=0; end=SEQUENCE_LENGTH;
256 break;
257 case 1:
258 i=0; end=SEQUENCE_LENGTH/2;
259 break;
260 case 2:
261 i=SEQUENCE_LENGTH/2; end=SEQUENCE_LENGTH;
262 break;
263 case 3:
264 i=0; end=SEQUENCE_LENGTH/4;
265 break;
266 case 4:
267 i=SEQUENCE_LENGTH/4; end=SEQUENCE_LENGTH*2/4;
268 break;
269 case 5:
270 i=SEQUENCE_LENGTH*2/4; end=SEQUENCE_LENGTH*3/4;
271 break;
272 case 6:
273 i=SEQUENCE_LENGTH*3/4; end=SEQUENCE_LENGTH*4/4;
274 break;
275 default:
276 i=0; end=SEQUENCE_LENGTH;
277 break;
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;
320 GtkWidget *result;
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);
329 return result;
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) {
340 GtkWidget *hb;
341 int i;
342 GtkWidget **widgets = safe_malloc(sizeof(GtkWidget *) * (SEQUENCE_LENGTH * 2 + 1));
343 Data *data = control->g->data;
344 GtkWidget *label, *menu;
345 GtkWidget *rightvb;
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;
360 adj->lower = 0;
361 adj->upper = 127;
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);
373 gtk_widget_show(b);
374 widgets[i] = b;
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);
381 gtk_widget_show(t);
382 widgets[i + SEQUENCE_LENGTH] = t;
384 gtk_box_pack_start(GTK_BOX(hb), vb, FALSE, FALSE, 0);
385 gtk_widget_show(vb);
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) {
409 GtkWidget *hb;
410 int i;
411 GtkWidget **widgets = safe_malloc(sizeof(GtkWidget *) * (SEQUENCE_LENGTH * 2 + 1));
412 Data *data = control->g->data;
413 GtkWidget *label, *menu;
414 GtkWidget *rightvb;
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);
442 gtk_widget_show(b);
443 widgets[i] = b;
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);
450 gtk_widget_show(t);
451 widgets[i + SEQUENCE_LENGTH] = t;
453 gtk_box_pack_start(GTK_BOX(hb), vb, FALSE, FALSE, 0);
454 gtk_widget_show(vb);
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) {
478 free(control->data);
481 PRIVATE void refresh_pattern(Control *control) {
482 Data *data = control->g->data;
483 GtkWidget **widgets = control->data;
484 int i;
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) {
495 int i;
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;
511 clipnote[i] = FALSE;
515 PUBLIC void init_plugin(void) {
516 setup_class();