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", &note_x0,
554 		   "x1", &note_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