1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2021 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/X/machine/ags_cell_pattern_callbacks.h>
21
22 #include <ags/X/ags_ui_provider.h>
23 #include <ags/X/ags_window.h>
24 #include <ags/X/ags_machine.h>
25
26 #include <gdk/gdkkeysyms.h>
27
28 #include <math.h>
29
30 void ags_cell_pattern_start_channel_launch_callback(AgsTask *task, AgsNote *note);
31
32 gboolean
ags_cell_pattern_draw_callback(GtkWidget * drawing_area,cairo_t * cr,AgsCellPattern * cell_pattern)33 ags_cell_pattern_draw_callback(GtkWidget *drawing_area, cairo_t *cr, AgsCellPattern *cell_pattern)
34 {
35 // cairo_surface_flush(cairo_get_target(cr));
36
37 cairo_push_group(cr);
38
39 /* the grid */
40 ags_cell_pattern_draw_grid(cell_pattern, cr);
41
42 /* the pattern */
43 ags_cell_pattern_draw_matrix(cell_pattern, cr);
44
45 ags_cell_pattern_draw_cursor(cell_pattern, cr);
46
47 /* paint */
48 cairo_pop_group_to_source(cr);
49
50 cairo_paint(cr);
51
52 // cairo_surface_mark_dirty(cairo_get_target(cr));
53
54 return(FALSE);
55 }
56
57 gboolean
ags_cell_pattern_focus_in_callback(GtkWidget * widget,GdkEvent * event,AgsCellPattern * cell_pattern)58 ags_cell_pattern_focus_in_callback(GtkWidget *widget, GdkEvent *event, AgsCellPattern *cell_pattern)
59 {
60 //TODO:JK: implement me, blink cursor
61
62 return(TRUE);
63 }
64
65 gboolean
ags_cell_pattern_drawing_area_button_press_callback(GtkWidget * widget,GdkEventButton * event,AgsCellPattern * cell_pattern)66 ags_cell_pattern_drawing_area_button_press_callback(GtkWidget *widget, GdkEventButton *event, AgsCellPattern *cell_pattern)
67 {
68 if(event->button == 1){
69 AgsMachine *machine;
70
71 AgsAudio *audio;
72 AgsChannel *start_input, *nth_channel;
73
74 GList *start_pattern;
75
76 guint input_lines;
77 guint i, j;
78 guint index1;
79
80 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) cell_pattern,
81 AGS_TYPE_MACHINE);
82
83 audio = machine->audio;
84
85 /* get some audio fields */
86 g_object_get(audio,
87 "input-lines", &input_lines,
88 "input", &start_input,
89 NULL);
90
91 /* get pattern position */
92 i = (guint) floor((double) event->y / (double) cell_pattern->cell_height);
93 j = (guint) floor((double) event->x / (double) cell_pattern->cell_width);
94
95 index1 = machine->bank_1;
96
97 nth_channel = ags_channel_nth(start_input,
98 input_lines - ((guint) gtk_range_get_value(GTK_RANGE(cell_pattern->vscrollbar)) + i) - 1);
99
100 if(nth_channel != NULL){
101 /* toggle pattern */
102 g_object_get(nth_channel,
103 "pattern", &start_pattern,
104 NULL);
105
106 ags_pattern_toggle_bit(start_pattern->data,
107 0, index1,
108 j);
109
110 g_object_unref(nth_channel);
111
112 g_list_free_full(start_pattern,
113 g_object_unref);
114 }
115
116 /* unref */
117 if(start_input != NULL){
118 g_object_unref(start_input);
119 }
120
121 /* queue draw */
122 gtk_widget_queue_draw((GtkWidget *) cell_pattern->drawing_area);
123 }
124
125 return(FALSE);
126 }
127
128 gboolean
ags_cell_pattern_drawing_area_key_press_event(GtkWidget * widget,GdkEventKey * event,AgsCellPattern * cell_pattern)129 ags_cell_pattern_drawing_area_key_press_event(GtkWidget *widget, GdkEventKey *event, AgsCellPattern *cell_pattern)
130 {
131 if(event->keyval == GDK_KEY_Tab){
132 return(FALSE);
133 }
134
135 switch(event->keyval){
136 case GDK_KEY_Control_L:
137 {
138 cell_pattern->key_mask |= AGS_CELL_PATTERN_KEY_L_CONTROL;
139 }
140 break;
141 case GDK_KEY_Control_R:
142 {
143 cell_pattern->key_mask |= AGS_CELL_PATTERN_KEY_R_CONTROL;
144 }
145 break;
146 case GDK_KEY_c:
147 {
148 /* copy notes */
149 if((AGS_CELL_PATTERN_KEY_L_CONTROL & (cell_pattern->key_mask)) != 0 || (AGS_CELL_PATTERN_KEY_R_CONTROL & (cell_pattern->key_mask)) != 0){
150 AgsMachine *machine;
151
152 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) cell_pattern,
153 AGS_TYPE_MACHINE);
154
155 ags_machine_copy_pattern(machine);
156 }
157 }
158 break;
159 }
160
161 return(TRUE);
162 }
163
164 gboolean
ags_cell_pattern_drawing_area_key_release_event(GtkWidget * widget,GdkEventKey * event,AgsCellPattern * cell_pattern)165 ags_cell_pattern_drawing_area_key_release_event(GtkWidget *widget, GdkEventKey *event, AgsCellPattern *cell_pattern)
166 {
167 AgsMachine *machine;
168
169 AgsAudio *audio;
170 AgsChannel *start_input;
171 AgsChannel *channel, *nth_channel;
172
173 guint input_lines;
174
175 if(event->keyval == GDK_KEY_Tab){
176 return(FALSE);
177 }
178
179 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) cell_pattern,
180 AGS_TYPE_MACHINE);
181
182 audio = machine->audio;
183
184 /* get some fields */
185 g_object_get(audio,
186 "input", &start_input,
187 "input-lines", &input_lines,
188 NULL);
189
190 switch(event->keyval){
191 case GDK_KEY_Control_L:
192 {
193 cell_pattern->key_mask &= (~AGS_CELL_PATTERN_KEY_L_CONTROL);
194 }
195 break;
196 case GDK_KEY_Control_R:
197 {
198 cell_pattern->key_mask &= (~AGS_CELL_PATTERN_KEY_R_CONTROL);
199 }
200 break;
201 case GDK_KEY_Left:
202 case GDK_KEY_leftarrow:
203 {
204 if(cell_pattern->cursor_x > 0){
205 GList *start_pattern;
206
207 gboolean bit_is_on;
208
209 cell_pattern->cursor_x -= 1;
210
211 /* audible feedback */
212 nth_channel = ags_channel_nth(start_input,
213 input_lines - cell_pattern->cursor_y - 1);
214
215 channel = nth_channel;
216
217 if(channel != NULL){
218 /* check bit */
219 g_object_get(channel,
220 "pattern", &start_pattern,
221 NULL);
222
223 bit_is_on = (ags_pattern_get_bit(start_pattern->data,
224 0, machine->bank_1, cell_pattern->cursor_x)) ? TRUE: FALSE;
225
226 if(bit_is_on){
227 AgsPlayback *playback;
228
229 g_object_get(channel,
230 "playback", &playback,
231 NULL);
232
233 ags_machine_playback_set_active(machine,
234 playback,
235 TRUE);
236
237 g_object_unref(playback);
238 }
239
240 /* unref */
241 g_object_unref(channel);
242
243 g_list_free_full(start_pattern,
244 g_object_unref);
245 }
246 }
247 }
248 break;
249 case GDK_KEY_Right:
250 case GDK_KEY_rightarrow:
251 {
252 if(cell_pattern->cursor_x < cell_pattern->n_cols){
253 GList *start_pattern;
254
255 gboolean bit_is_on;
256
257 cell_pattern->cursor_x += 1;
258
259 /* audible feedback */
260 nth_channel = ags_channel_nth(start_input,
261 input_lines - cell_pattern->cursor_y - 1);
262
263 channel = nth_channel;
264
265 if(channel != NULL){
266 /* check bit */
267 g_object_get(channel,
268 "pattern", &start_pattern,
269 NULL);
270
271 bit_is_on = ags_pattern_get_bit(start_pattern->data,
272 0, machine->bank_1, cell_pattern->cursor_x);
273
274 if(bit_is_on){
275 AgsPlayback *playback;
276
277 g_object_get(channel,
278 "playback", &playback,
279 NULL);
280
281 ags_machine_playback_set_active(machine,
282 playback,
283 TRUE);
284
285 g_object_unref(playback);
286 }
287
288 /* unref */
289 g_object_unref(channel);
290
291 g_list_free_full(start_pattern,
292 g_object_unref);
293 }
294 }
295 }
296 break;
297 case GDK_KEY_Up:
298 case GDK_KEY_uparrow:
299 {
300 if(cell_pattern->cursor_y > 0){
301 GList *start_pattern;
302
303 gboolean bit_is_on;
304
305 cell_pattern->cursor_y -= 1;
306
307 /* audible feedback */
308 nth_channel = ags_channel_nth(start_input,
309 input_lines - cell_pattern->cursor_y - 1);
310
311 channel = nth_channel;
312
313 if(channel != NULL){
314 /* check bit */
315 g_object_get(channel,
316 "pattern", &start_pattern,
317 NULL);
318
319 bit_is_on = (ags_pattern_get_bit(start_pattern->data,
320 0, machine->bank_1, cell_pattern->cursor_x)) ? TRUE: FALSE;
321
322 if(bit_is_on){
323 AgsPlayback *playback;
324
325 g_object_get(channel,
326 "playback", &playback,
327 NULL);
328
329 ags_machine_playback_set_active(machine,
330 playback,
331 TRUE);
332
333 g_object_unref(playback);
334 }
335
336 /* unref */
337 g_object_unref(channel);
338
339 g_list_free_full(start_pattern,
340 g_object_unref);
341 }
342 }
343
344 if(cell_pattern->cursor_y < gtk_range_get_value(GTK_RANGE(cell_pattern->vscrollbar))){
345 gtk_range_set_value(GTK_RANGE(cell_pattern->vscrollbar),
346 gtk_range_get_value(GTK_RANGE(cell_pattern->vscrollbar)) - 1.0);
347 }
348 }
349 break;
350 case GDK_KEY_Down:
351 case GDK_KEY_downarrow:
352 {
353 if(cell_pattern->cursor_y < cell_pattern->n_rows){
354 GList *start_pattern;
355
356 gboolean bit_is_on;
357
358 cell_pattern->cursor_y += 1;
359
360 /* audible feedback */
361 nth_channel = ags_channel_nth(start_input,
362 input_lines - cell_pattern->cursor_y - 1);
363
364 channel = nth_channel;
365
366 if(channel != NULL){
367 /* check bit */
368 g_object_get(channel,
369 "pattern", &start_pattern,
370 NULL);
371
372 bit_is_on = ags_pattern_get_bit(start_pattern->data,
373 0, machine->bank_1, cell_pattern->cursor_x);
374
375 if(bit_is_on){
376 AgsPlayback *playback;
377
378 g_object_get(channel,
379 "playback", &playback,
380 NULL);
381
382 ags_machine_playback_set_active(machine,
383 playback,
384 TRUE);
385
386 g_object_unref(playback);
387 }
388
389 /* unref */
390 g_object_unref(channel);
391
392 g_list_free_full(start_pattern,
393 g_object_unref);
394 }
395 }
396
397 if(cell_pattern->cursor_y >= gtk_range_get_value(GTK_RANGE(cell_pattern->vscrollbar)) + AGS_CELL_PATTERN_MAX_CONTROLS_SHOWN_VERTICALLY){
398 gtk_range_set_value(GTK_RANGE(cell_pattern->vscrollbar),
399 gtk_range_get_value(GTK_RANGE(cell_pattern->vscrollbar)) + 1.0);
400 }
401 }
402 break;
403 case GDK_KEY_space:
404 {
405 GList *start_pattern;
406
407 guint i, j;
408 guint index1;
409
410 i = cell_pattern->cursor_y;
411 j = cell_pattern->cursor_x;
412
413 index1 = machine->bank_1;
414
415 nth_channel = ags_channel_nth(start_input,
416 input_lines - i - 1);
417
418 channel = nth_channel;
419
420 if(channel != NULL){
421 /* toggle pattern */
422 g_object_get(channel,
423 "pattern", &start_pattern,
424 NULL);
425
426 ags_pattern_toggle_bit(start_pattern->data,
427 0, index1,
428 j);
429
430 /* play pattern */
431 if(ags_pattern_get_bit(start_pattern->data,
432 0, index1, j)){
433 AgsPlayback *playback;
434
435 g_object_get(channel,
436 "playback", &playback,
437 NULL);
438
439 ags_machine_playback_set_active(machine,
440 playback,
441 TRUE);
442
443 g_object_unref(playback);
444 }
445
446 /* unref */
447 g_object_unref(channel);
448
449 g_list_free_full(start_pattern,
450 g_object_unref);
451 }
452
453 /* queue draw */
454 gtk_widget_queue_draw((GtkWidget *) cell_pattern->drawing_area);
455 }
456 break;
457 }
458
459 /* unref */
460 if(start_input != NULL){
461 g_object_unref(start_input);
462 }
463
464 return(TRUE);
465 }
466
467 void
ags_cell_pattern_adjustment_value_changed_callback(GtkWidget * widget,AgsCellPattern * cell_pattern)468 ags_cell_pattern_adjustment_value_changed_callback(GtkWidget *widget, AgsCellPattern *cell_pattern)
469 {
470 gtk_widget_queue_draw((GtkWidget *) cell_pattern->drawing_area);
471 }
472
473 void
ags_cell_pattern_start_channel_launch_callback(AgsTask * task,AgsNote * note)474 ags_cell_pattern_start_channel_launch_callback(AgsTask *task, AgsNote *note)
475 {
476 AgsAudio *audio;
477 AgsChannel *channel;
478 AgsRecycling *first_recycling, *last_recycling;
479 AgsRecycling *recycling, *next_recycling, *end_recycling;
480 AgsAudioSignal *audio_signal;
481 AgsPlayback *playback;
482 AgsRecallID *recall_id;
483
484 GObject *output_soundcard;
485
486 gdouble delay;
487 guint samplerate;
488
489 channel = AGS_START_CHANNEL(task)->channel;
490
491 /* get some fields */
492 g_object_get(channel,
493 "audio", &audio,
494 "output-soundcard", &output_soundcard,
495 "playback", &playback,
496 NULL);
497
498 g_object_unref(audio);
499
500 g_object_unref(output_soundcard);
501
502 if(playback != NULL){
503 g_object_unref(playback);
504 }
505
506 recall_id = ags_playback_get_recall_id(playback, AGS_SOUND_SCOPE_PLAYBACK);
507
508 #ifdef AGS_DEBUG
509 g_message("launch");
510 #endif
511
512 if(playback == NULL ||
513 recall_id == NULL){
514 return;
515 }
516
517 /* get presets */
518 ags_soundcard_get_presets(AGS_SOUNDCARD(output_soundcard),
519 NULL,
520 &samplerate,
521 NULL,
522 NULL);
523
524 delay = ags_soundcard_get_delay(AGS_SOUNDCARD(output_soundcard));
525
526 /* get some fields */
527 g_object_get(channel,
528 "first-recycling", &first_recycling,
529 "last-recycling", &last_recycling,
530 NULL);
531
532 end_recycling = ags_recycling_next(last_recycling);
533
534 /* add audio signal */
535 recycling = first_recycling;
536 g_object_ref(recycling);
537
538 next_recycling = NULL;
539
540 while(recycling != end_recycling){
541 if(!ags_recall_global_get_rt_safe()){
542 guint note_x0, note_x1;
543
544 audio_signal = ags_audio_signal_new((GObject *) output_soundcard,
545 (GObject *) recycling,
546 (GObject *) recall_id);
547 g_object_set(audio_signal,
548 "note", note,
549 NULL);
550
551 /* add audio signal */
552 g_object_get(note,
553 "x0", ¬e_x0,
554 "x1", ¬e_x1,
555 NULL);
556
557 ags_recycling_create_audio_signal_with_frame_count(recycling,
558 audio_signal,
559 (note_x1 - note_x0) * ((gdouble) samplerate / delay),
560 0.0, 0);
561 audio_signal->stream_current = audio_signal->stream;
562 ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
563
564 /*
565 * emit add_audio_signal on AgsRecycling
566 */
567 ags_recycling_add_audio_signal(recycling,
568 audio_signal);
569 }else{
570 GList *start_list, *list;
571
572 g_object_get(recycling,
573 "audio-signal", &start_list,
574 NULL);
575
576 audio_signal = NULL;
577 list = ags_audio_signal_find_by_recall_id(start_list,
578 (GObject *) recall_id);
579
580 if(list != NULL){
581 audio_signal = list->data;
582
583 g_object_set(audio_signal,
584 "note", note,
585 NULL);
586 }
587
588 g_list_free_full(start_list,
589 g_object_unref);
590
591 g_object_set(note,
592 "rt-offset", 0,
593 NULL);
594 }
595
596 /* iterate */
597 next_recycling = ags_recycling_next(recycling);
598
599 g_object_unref(recycling);
600
601 recycling = next_recycling;
602 }
603
604 if(first_recycling != NULL){
605 g_object_unref(first_recycling);
606 g_object_unref(last_recycling);
607 }
608
609 if(end_recycling != NULL){
610 g_object_unref(end_recycling);
611 }
612
613 if(next_recycling != NULL){
614 g_object_unref(next_recycling);
615 }
616 }
617