1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  *
6  * This program 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 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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 this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 
29 #include <gtk/gtk.h>
30 
31 #include <sweep/sweep_i18n.h>
32 #include <sweep/sweep_types.h>
33 #include <sweep/sweep_typeconvert.h>
34 #include "sweep_app.h"
35 
36 #include "head.h"
37 #include "callbacks.h"
38 #include "interface.h"
39 #include "print.h"
40 #include "play.h"
41 #include "record.h"
42 #include "sample.h"
43 
44 #include "../pixmaps/playrev.xpm"
45 #include "../pixmaps/loop.xpm"
46 #include "../pixmaps/recpausesel.xpm"
47 #include "../pixmaps/stop.xpm"
48 #include "../pixmaps/prevtrk.xpm"
49 #include "../pixmaps/nexttrk.xpm"
50 #include "../pixmaps/ff.xpm"
51 #include "../pixmaps/rew.xpm"
52 #include "../pixmaps/upleft.xpm"
53 #include "../pixmaps/lowleft.xpm"
54 #include "../pixmaps/upright.xpm"
55 #include "../pixmaps/lowright.xpm"
56 
57 #define FRAMERATE 10
58 
59 extern GtkStyle * style_wb;
60 extern GtkStyle * style_LCD;
61 extern GtkStyle * style_light_grey;
62 extern GtkStyle * style_red_grey;
63 extern GtkStyle * style_green_grey;
64 extern GtkStyle * style_red;
65 
66 static void
head_init_repeater(sw_head * head,GtkFunction function,gpointer data)67 head_init_repeater (sw_head * head, GtkFunction function, gpointer data)
68 {
69   function (data);
70 
71   g_mutex_lock (head->head_mutex);
72 
73   if (head->repeater_tag > 0) {
74     g_source_remove (head->repeater_tag);
75   }
76 
77   head->repeater_tag = g_timeout_add ((guint32)1000/FRAMERATE,
78 					function, data);
79 
80   g_mutex_unlock (head->head_mutex);
81 }
82 
83 void
hctl_repeater_released_cb(GtkWidget * widget,gpointer data)84 hctl_repeater_released_cb (GtkWidget * widget, gpointer data)
85 {
86   sw_head_controller * hctl = (sw_head_controller *)data;
87   sw_head * head = hctl->head;
88 
89   g_mutex_lock (head->head_mutex);
90 
91   if (head->repeater_tag > 0) {
92     g_source_remove (head->repeater_tag);
93     head->repeater_tag = 0;
94   }
95 
96   g_mutex_unlock (head->head_mutex);
97 }
98 
99 void
hctl_loop_toggled_cb(GtkWidget * widget,gpointer data)100 hctl_loop_toggled_cb (GtkWidget * widget, gpointer data)
101 {
102   sw_head_controller * hctl = (sw_head_controller *)data;
103   sw_head * head = hctl->head;
104   gboolean active;
105 
106   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
107   head_set_looping (head, active);
108 }
109 
110 void
hctl_reverse_toggled_cb(GtkWidget * widget,gpointer data)111 hctl_reverse_toggled_cb (GtkWidget * widget, gpointer data)
112 {
113   sw_head_controller * hctl = (sw_head_controller *)data;
114   sw_head * head = hctl->head;
115   gboolean active;
116 
117   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
118   head_set_reverse (head, active);
119 }
120 
121 void
hctl_reverse_toggle_cb(GtkWidget * widget,gpointer data)122 hctl_reverse_toggle_cb (GtkWidget * widget, gpointer data)
123 {
124   sw_head_controller * hctl = (sw_head_controller *)data;
125   sw_head * head = hctl->head;
126 
127   head_set_reverse (head, !head->reverse);
128 }
129 
130 void
hctl_mute_toggled_cb(GtkWidget * widget,gpointer data)131 hctl_mute_toggled_cb (GtkWidget * widget, gpointer data)
132 {
133   sw_head_controller * hctl = (sw_head_controller *)data;
134   sw_head * head = hctl->head;
135   gboolean active;
136 
137   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
138   head_set_mute (head, active);
139 }
140 
141 void
hctl_mute_toggle_cb(GtkWidget * widget,gpointer data)142 hctl_mute_toggle_cb (GtkWidget * widget, gpointer data)
143 {
144   sw_head_controller * hctl = (sw_head_controller *)data;
145   sw_head * head = hctl->head;
146 
147   head_set_mute (head, !head->mute);
148 }
149 
150 void
hctl_record_cb(GtkWidget * widget,gpointer data)151 hctl_record_cb (GtkWidget * widget, gpointer data)
152 {
153   sw_head_controller * hctl = (sw_head_controller *)data;
154   sw_head * head = hctl->head;
155 
156   record_cb (widget, head);
157 }
158 
159 void
hctl_record_stop_cb(GtkWidget * widget,gpointer data)160 hctl_record_stop_cb (GtkWidget * widget, gpointer data)
161 {
162   sw_head_controller * hctl = (sw_head_controller *)data;
163   sw_head * head = hctl->head;
164 
165   stop_recording (head->sample);
166 }
167 
168 void
hctl_refresh_looping(sw_head_controller * hctl)169 hctl_refresh_looping (sw_head_controller * hctl)
170 {
171   sw_head * head = hctl->head;
172 
173   if (hctl->loop_toggle) {
174   g_signal_handlers_block_matched (GTK_OBJECT(hctl->loop_toggle), G_SIGNAL_MATCH_DATA, 0,
175 									0, 0, 0, hctl);
176   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(hctl->loop_toggle),
177 				head->looping);
178   g_signal_handlers_unblock_matched (GTK_OBJECT(hctl->loop_toggle), G_SIGNAL_MATCH_DATA, 0,
179 									0, 0, 0, hctl);
180   }
181 }
182 
183 void
hctl_refresh_reverse(sw_head_controller * hctl)184 hctl_refresh_reverse (sw_head_controller * hctl)
185 {
186   sw_head * head = hctl->head;
187 
188   if (hctl->reverse_toggle) {
189   g_signal_handlers_block_matched (GTK_OBJECT(hctl->reverse_toggle), G_SIGNAL_MATCH_DATA, 0,
190 									0, 0, 0, hctl);
191 
192   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(hctl->reverse_toggle),
193 				head->reverse);
194   g_signal_handlers_unblock_matched (GTK_OBJECT(hctl->reverse_toggle), G_SIGNAL_MATCH_DATA, 0,
195 									0, 0, 0, hctl);
196   }
197 }
198 
199 void
hctl_refresh_mute(sw_head_controller * hctl)200 hctl_refresh_mute (sw_head_controller * hctl)
201 {
202   sw_head * head = hctl->head;
203 
204   if (hctl->mute_toggle) {
205   g_signal_handlers_block_matched (GTK_OBJECT(hctl->mute_toggle), G_SIGNAL_MATCH_DATA, 0,
206 									0, 0, 0, hctl);
207   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(hctl->mute_toggle),
208 				head->mute);
209   g_signal_handlers_unblock_matched (GTK_OBJECT(hctl->mute_toggle), G_SIGNAL_MATCH_DATA, 0,
210 									0, 0, 0, hctl);
211   }
212 }
213 
214 void
hctl_refresh_going(sw_head_controller * hctl)215 hctl_refresh_going (sw_head_controller * hctl)
216 {
217   sw_head * head = hctl->head;
218 
219   if (hctl->go_toggle) {
220   g_signal_handlers_block_matched (GTK_OBJECT(hctl->go_toggle), G_SIGNAL_MATCH_DATA, 0,
221 									0, 0, 0, hctl);
222   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(hctl->go_toggle),
223 				head->going);
224   g_signal_handlers_unblock_matched (GTK_OBJECT(hctl->go_toggle), G_SIGNAL_MATCH_DATA, 0,
225 									0, 0, 0, hctl);
226   }
227 }
228 
229 void
hctl_refresh_offset(sw_head_controller * hctl)230 hctl_refresh_offset (sw_head_controller * hctl)
231 {
232   sw_head * head = hctl->head;
233   sw_sample * sample = head->sample;
234   sw_framecount_t offset = head->offset;
235 
236 #define BUF_LEN 16
237   char buf[BUF_LEN];
238 
239   snprint_time (buf, BUF_LEN,
240 		frames_to_time (sample->sounddata->format, offset));
241 
242   gtk_label_set_text (GTK_LABEL(hctl->pos_label), buf);
243 }
244 
245 void
hctl_refresh_gain(sw_head_controller * hctl)246 hctl_refresh_gain (sw_head_controller * hctl)
247 {
248 }
249 
250 static gboolean
h_rewind_step(gpointer data)251 h_rewind_step (gpointer data)
252 {
253   sw_head * head = (sw_head *)data;
254   sw_sample * sample = head->sample;
255   gint step;
256 
257   step = sample->sounddata->format->rate; /* 1 second */
258   head_set_offset (head, head->offset - step);
259 
260   return TRUE;
261 }
262 
263 static gboolean
h_ffwd_step(gpointer data)264 h_ffwd_step (gpointer data)
265 {
266   sw_head * head = (sw_head *)data;
267   sw_sample * sample = head->sample;
268   gint step;
269 
270   step = sample->sounddata->format->rate; /* 1 second */
271   head_set_offset (head, head->offset + step);
272 
273   return TRUE;
274 }
275 
276 void
hctl_rewind_pressed_cb(GtkWidget * widget,gpointer data)277 hctl_rewind_pressed_cb (GtkWidget * widget, gpointer data)
278 {
279   sw_head_controller * hctl = (sw_head_controller *)data;
280   sw_head * head = hctl->head;
281 
282   head_init_repeater (head, (GtkFunction)h_rewind_step, head);
283 }
284 
285 void
hctl_ffwd_pressed_cb(GtkWidget * widget,gpointer data)286 hctl_ffwd_pressed_cb (GtkWidget * widget, gpointer data)
287 {
288   sw_head_controller * hctl = (sw_head_controller *)data;
289   sw_head * head = hctl->head;
290 
291   head_init_repeater (head, (GtkFunction)h_ffwd_step, head);
292 }
293 
294 void
hctl_goto_start_cb(GtkWidget * widget,gpointer data)295 hctl_goto_start_cb (GtkWidget * widget, gpointer data)
296 {
297   sw_head_controller * hctl = (sw_head_controller *)data;
298   sw_head * head = hctl->head;
299 
300   /*head_set_scrubbing (head, FALSE);*/
301   head_set_offset (head, 0);
302 }
303 
304 void
hctl_goto_end_cb(GtkWidget * widget,gpointer data)305 hctl_goto_end_cb (GtkWidget * widget, gpointer data)
306 {
307   sw_head_controller * hctl = (sw_head_controller *)data;
308   sw_head * head = hctl->head;
309   sw_sample * sample = head->sample;
310 
311   /*head_set_scrubbing (head, FALSE);*/
312   head_set_offset (head, sample->sounddata->nr_frames);
313 }
314 
315 void
hctl_destroy_cb(GtkWidget * widget,gpointer data)316 hctl_destroy_cb (GtkWidget * widget, gpointer data)
317 {
318   sw_head_controller * hctl = (sw_head_controller *)data;
319 
320   hctl->head->controllers = g_list_remove (hctl->head->controllers, hctl);
321 
322   g_free (hctl);
323 }
324 
325 void
head_controller_set_head(sw_head_controller * hctl,sw_head * head)326 head_controller_set_head (sw_head_controller * hctl, sw_head * head)
327 {
328   sw_head * old_head = hctl->head;
329 
330   if (old_head != NULL) {
331     old_head->controllers = g_list_remove (old_head->controllers, hctl);
332   }
333 
334   hctl->head = head;
335 
336   if (g_list_find (head->controllers, hctl) == 0) {
337     head->controllers = g_list_append (head->controllers, hctl);
338   }
339 
340   hctl_refresh_looping (hctl);
341   hctl_refresh_reverse (hctl);
342   hctl_refresh_mute (hctl);
343   hctl_refresh_going (hctl);
344   hctl_refresh_offset (hctl);
345   hctl_refresh_gain (hctl);
346 }
347 
348 GtkWidget *
head_controller_create(sw_head * head,GtkWidget * window,sw_head_controller ** hctl_ret)349 head_controller_create (sw_head * head, GtkWidget * window,
350 			sw_head_controller ** hctl_ret)
351 {
352   sw_head_controller * hctl;
353 
354   GtkWidget * handlebox;
355   GtkWidget * hbox;
356   GtkWidget * tool_hbox;
357   GtkWidget * frame;
358   GtkWidget * lcdbox;
359   GtkWidget * imagebox;
360   GtkWidget * pixmap;
361   GtkWidget * button;
362   GtkWidget * label;
363 
364   GtkStyle * style;
365 
366   GtkTooltips * tooltips;
367 
368   g_assert (head != NULL);
369 
370   hctl = g_malloc0 (sizeof (sw_head_controller));
371   hctl->head = head;
372 
373 
374   if (head->type == SWEEP_HEAD_RECORD) {
375       style = style_red_grey;
376   } else {
377       style = style_green_grey;
378   }
379 
380     handlebox = gtk_handle_box_new ();
381     /*    gtk_box_pack_start (GTK_BOX (main_vbox), handlebox, FALSE, TRUE, 0);
382     gtk_widget_show (handlebox);
383     */
384 
385     gtk_widget_set_style (handlebox, style);
386 
387     g_signal_connect (G_OBJECT (handlebox), "destroy",
388 			G_CALLBACK (hctl_destroy_cb), hctl);
389 
390     hbox = gtk_hbox_new (FALSE, 8);
391     gtk_container_add (GTK_CONTAINER (handlebox), hbox);
392     gtk_widget_show (hbox);
393 
394     gtk_widget_set_size_request(hbox, -1, 24);
395 
396     frame = gtk_frame_new (NULL);
397     gtk_widget_set_style (frame, style_light_grey);
398     gtk_box_pack_start (GTK_BOX(hbox), frame, TRUE, TRUE, 0);
399     gtk_widget_show (frame);
400 
401     lcdbox = gtk_event_box_new ();
402     gtk_widget_set_style (lcdbox, style_LCD);
403     gtk_container_add (GTK_CONTAINER(frame), lcdbox);
404     gtk_widget_show (lcdbox);
405 
406     tooltips = gtk_tooltips_new ();
407     gtk_tooltips_set_tip (tooltips, lcdbox,
408 			  _("Cursor position (indicator)"), NULL);
409 
410     tool_hbox = gtk_hbox_new (FALSE, 0);
411     gtk_container_add (GTK_CONTAINER(lcdbox), tool_hbox);
412     gtk_widget_show (tool_hbox);
413 
414     imagebox = gtk_vbox_new (FALSE, 0);
415     gtk_box_pack_start (GTK_BOX(tool_hbox), imagebox, FALSE, FALSE, 0);
416     gtk_widget_show (imagebox);
417 
418     pixmap = create_widget_from_xpm (window, upleft_xpm);
419     gtk_widget_show (pixmap);
420     gtk_box_pack_start (GTK_BOX(imagebox), pixmap, FALSE, FALSE, 0);
421 
422     pixmap = create_widget_from_xpm (window, lowleft_xpm);
423     gtk_widget_show (pixmap);
424     gtk_box_pack_end (GTK_BOX(imagebox), pixmap, FALSE, FALSE, 0);
425 
426     label = gtk_label_new ("00:00:00.000");
427     gtk_box_pack_start (GTK_BOX(tool_hbox), label, TRUE, TRUE, 0);
428     gtk_widget_show (label);
429 
430     hctl->pos_label = label;
431 
432     imagebox = gtk_vbox_new (FALSE, 0);
433     gtk_box_pack_start (GTK_BOX(tool_hbox), imagebox, FALSE, FALSE, 0);
434     gtk_widget_show (imagebox);
435 
436     pixmap = create_widget_from_xpm (window, upright_xpm);
437     gtk_widget_show (pixmap);
438     gtk_box_pack_start (GTK_BOX(imagebox), pixmap, FALSE, FALSE, 0);
439 
440     pixmap = create_widget_from_xpm (window, lowright_xpm);
441     gtk_widget_show (pixmap);
442     gtk_box_pack_end (GTK_BOX(imagebox), pixmap, FALSE, FALSE, 0);
443 
444     tool_hbox = gtk_hbox_new (TRUE, 0);
445     gtk_box_pack_start (GTK_BOX (hbox), tool_hbox, FALSE, TRUE, 0);
446     gtk_widget_show (tool_hbox);
447 
448     button = create_pixmap_button (window, playrev_xpm,
449 				   _("Reverse mode (toggle)"),
450 				   style, SW_TOOLBAR_TOGGLE_BUTTON,
451 				   G_CALLBACK (hctl_reverse_toggled_cb), NULL, NULL, hctl);
452 
453 	g_signal_handlers_block_matched (GTK_OBJECT(button), G_SIGNAL_MATCH_DATA, 0,
454 									0, 0, 0, hctl);
455     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button),
456 				  head->reverse);
457 
458 	g_signal_handlers_unblock_matched (GTK_OBJECT(button), G_SIGNAL_MATCH_DATA, 0,
459 									0, 0, 0, hctl);
460 
461     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
462     gtk_widget_show (button);
463 
464     hctl->reverse_toggle = button;
465 
466     button = create_pixmap_button (window, loop_xpm,
467 				   _("Loop mode recording (toggle)"),
468 				   style, SW_TOOLBAR_TOGGLE_BUTTON,
469 				   G_CALLBACK (hctl_loop_toggled_cb), NULL, NULL, hctl);
470     g_signal_handlers_block_matched (GTK_OBJECT(button), G_SIGNAL_MATCH_DATA, 0,
471 									0, 0, 0, hctl);
472     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button),
473 				  head->looping);
474     g_signal_handlers_unblock_matched (GTK_OBJECT(button), G_SIGNAL_MATCH_DATA, 0,
475 									0, 0, 0, hctl);
476     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
477     gtk_widget_show (button);
478 
479     hctl->loop_toggle = button;
480 
481     tool_hbox = gtk_hbox_new (TRUE, 0);
482     gtk_box_pack_start (GTK_BOX (hbox), tool_hbox, TRUE, TRUE, 0);
483     gtk_widget_show (tool_hbox);
484 
485     button = create_pixmap_button (window, recpausesel_xpm,
486 				   _("Record into selection"),
487 				   style, SW_TOOLBAR_TOGGLE_BUTTON,
488 				   G_CALLBACK (hctl_record_cb), NULL, NULL, hctl);
489     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
490     gtk_widget_show (button);
491 #if 0
492     gtk_widget_add_accelerator (button, "clicked", accel_group,
493 				GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
494 #endif
495 g_signal_handlers_block_matched (GTK_OBJECT(button), G_SIGNAL_MATCH_DATA, 0,
496 									0, 0, 0, hctl);
497     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), head->going);
498     g_signal_handlers_unblock_matched (GTK_OBJECT(button), G_SIGNAL_MATCH_DATA, 0,
499 									0, 0, 0, hctl);
500 
501     hctl->go_toggle = button;
502 
503     button = create_pixmap_button (window, stop_xpm, _("Stop"),
504 				   style, SW_TOOLBAR_BUTTON,
505 				   G_CALLBACK (hctl_record_stop_cb), NULL, NULL, hctl);
506     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
507     gtk_widget_show (button);
508 
509 
510     tool_hbox = gtk_hbox_new (TRUE, 0);
511     gtk_box_pack_start (GTK_BOX (hbox), tool_hbox, FALSE, TRUE, 0);
512     gtk_widget_show (tool_hbox);
513 
514     button
515       = create_pixmap_button (window, prevtrk_xpm,
516 			      _("Go to beginning"),
517 			      style, SW_TOOLBAR_BUTTON,
518 			      G_CALLBACK (hctl_goto_start_cb), NULL, NULL, hctl);
519     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
520     gtk_widget_show (button);
521 
522     /*NOALLOC(button);*/
523 
524     /* Rewind */
525 
526     button
527       = create_pixmap_button (window, rew_xpm, _("Rewind"),
528 			      style, SW_TOOLBAR_BUTTON,
529 			      NULL,
530 			      G_CALLBACK (hctl_rewind_pressed_cb),
531 			      G_CALLBACK (hctl_repeater_released_cb), hctl);
532     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
533     gtk_widget_show (button);
534 
535     /*    NOALLOC(button);*/
536 
537     /* Fast forward */
538 
539     button
540       = create_pixmap_button (window, ff_xpm, _("Fast forward"),
541 			      style, SW_TOOLBAR_BUTTON,
542 			      NULL,
543 			      G_CALLBACK (hctl_ffwd_pressed_cb),
544 			      G_CALLBACK (hctl_repeater_released_cb),
545 			      hctl);
546     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
547     gtk_widget_show (button);
548 
549     /*NOALLOC(button);*/
550 
551     /* End */
552 
553     button
554       = create_pixmap_button (window, nexttrk_xpm,
555 			      _("Go to the end"),
556 			      style, SW_TOOLBAR_BUTTON,
557 			      G_CALLBACK (hctl_goto_end_cb), NULL, NULL, hctl);
558     gtk_box_pack_start (GTK_BOX (tool_hbox), button, FALSE, TRUE, 0);
559     gtk_widget_show (button);
560 
561     /*NOALLOC(button);*/
562 
563     head->controllers = g_list_append (head->controllers, hctl);
564 
565     *hctl_ret = hctl;
566 
567     return handlebox;
568 }
569 
570 /* head functions */
571 
572 #define PBOOL(p) ((p) ? "TRUE" : "FALSE" )
573 
574 int
head_dump(sw_head * head)575 head_dump (sw_head * head)
576 {
577   printf ("head %p\toffset: %f", head, head->offset);
578   printf ("\tstop:\t%d\n", head->stop_offset);
579   printf ("\tgoing:\t%s\n", PBOOL(head->going));
580   printf ("\trestricted:\t%s\n", PBOOL(head->restricted));
581   printf ("\tlooping:\t%s\n", PBOOL(head->looping));
582   printf ("\tpreviewing:\t%s\n", PBOOL(head->previewing));
583   printf ("\treverse:\t%s\n", PBOOL(head->reverse));
584   printf ("\tmute:\t%s\n", PBOOL(head->mute));
585   printf ("\tgain:\t%f\n", head->gain);
586   printf ("\trate:\t%f\n", head->rate);
587   printf ("\tmix:\t%f\n", head->mix);
588   return 0;
589 }
590 
591 sw_head *
head_new(sw_sample * sample,sw_head_t head_type)592 head_new (sw_sample * sample, sw_head_t head_type)
593 {
594   sw_head * head;
595 
596   head = g_malloc0 (sizeof (sw_head));
597 
598   head->sample = sample;
599 
600   head->head_mutex = g_mutex_new ();
601   head->type = head_type;
602   head->stop_offset = 0;
603   head->offset = 0;
604   head->going = FALSE;
605   head->restricted = FALSE;
606   head->looping = FALSE;
607   head->previewing = FALSE;
608   head->reverse = FALSE;
609   head->mute = FALSE;
610   head->gain = (head->type == SWEEP_HEAD_PLAY ? 0.7 : 1.0);
611   head->rate = 1.0;
612   head->mix = 0.0;
613 
614   head->repeater_tag = -1;
615   head->controllers = NULL;
616 
617   return head;
618 }
619 
620 void
head_set_scrubbing(sw_head * h,gboolean scrubbing)621 head_set_scrubbing (sw_head * h, gboolean scrubbing)
622 {
623   g_mutex_lock (h->head_mutex);
624 
625   h->scrubbing = scrubbing;
626 
627   g_mutex_unlock (h->head_mutex);
628 }
629 
630 void
head_set_previewing(sw_head * h,gboolean previewing)631 head_set_previewing (sw_head * h, gboolean previewing)
632 {
633   g_mutex_lock (h->head_mutex);
634 
635   h->previewing = previewing;
636 
637   g_mutex_unlock (h->head_mutex);
638 }
639 
640 void
head_set_looping(sw_head * h,gboolean looping)641 head_set_looping (sw_head * h, gboolean looping)
642 {
643   GList * gl;
644   sw_head_controller * hctl;
645 
646   g_mutex_lock (h->head_mutex);
647 
648   h->looping = looping;
649 
650   for (gl = h->controllers; gl; gl = gl->next) {
651     hctl = (sw_head_controller *)gl->data;
652     hctl_refresh_looping (hctl);
653   }
654 
655   g_mutex_unlock (h->head_mutex);
656 }
657 
658 void
head_set_reverse(sw_head * h,gboolean reverse)659 head_set_reverse (sw_head * h, gboolean reverse)
660 {
661   GList * gl;
662   sw_head_controller * hctl;
663 
664   g_mutex_lock (h->head_mutex);
665 
666   h->reverse = reverse;
667 
668   for (gl = h->controllers; gl; gl = gl->next) {
669     hctl = (sw_head_controller *)gl->data;
670     hctl_refresh_reverse (hctl);
671   }
672 
673   g_mutex_unlock (h->head_mutex);
674 }
675 
676 void
head_set_mute(sw_head * h,gboolean mute)677 head_set_mute (sw_head * h, gboolean mute)
678 {
679   GList * gl;
680   sw_head_controller * hctl;
681 
682   g_mutex_lock (h->head_mutex);
683 
684   h->mute = mute;
685 
686   for (gl = h->controllers; gl; gl = gl->next) {
687     hctl = (sw_head_controller *)gl->data;
688     hctl_refresh_mute (hctl);
689   }
690 
691   g_mutex_unlock (h->head_mutex);
692 }
693 
694 void
head_set_going(sw_head * h,gboolean going)695 head_set_going (sw_head * h, gboolean going)
696 {
697   GList * gl;
698   sw_head_controller * hctl;
699 
700   g_mutex_lock (h->head_mutex);
701 
702   h->going = going;
703 
704   for (gl = h->controllers; gl; gl = gl->next) {
705     hctl = (sw_head_controller *)gl->data;
706     hctl_refresh_going (hctl);
707   }
708 
709   g_mutex_unlock (h->head_mutex);
710 }
711 
712 void
head_set_restricted(sw_head * h,gboolean restricted)713 head_set_restricted (sw_head * h, gboolean restricted)
714 {
715   GList * gl;
716   sw_head_controller * hctl;
717 
718   g_mutex_lock (h->head_mutex);
719 
720   h->restricted = restricted;
721 
722   for (gl = h->controllers; gl; gl = gl->next) {
723     hctl = (sw_head_controller *)gl->data;
724     hctl_refresh_going (hctl);
725   }
726 
727   g_mutex_unlock (h->head_mutex);
728 }
729 
730 void
head_set_stop_offset(sw_head * h,sw_framecount_t offset)731 head_set_stop_offset (sw_head * h, sw_framecount_t offset)
732 {
733   g_mutex_lock (h->head_mutex);
734 
735   h->stop_offset = offset;
736 
737   g_mutex_unlock (h->head_mutex);
738 }
739 
740 void
head_set_offset(sw_head * h,sw_framecount_t offset)741 head_set_offset (sw_head * h, sw_framecount_t offset)
742 {
743   GList * gl;
744   sw_head_controller * hctl;
745 
746   g_mutex_lock (h->head_mutex);
747 
748   offset = CLAMP (offset, 0, h->sample->sounddata->nr_frames);
749 
750   h->offset = offset;
751 
752   for (gl = h->controllers; gl; gl = gl->next) {
753     hctl = (sw_head_controller *)gl->data;
754     hctl_refresh_offset (hctl);
755   }
756 
757   if (h == h->sample->rec_head)
758     sample_refresh_rec_marker (h->sample);
759 
760   g_mutex_unlock (h->head_mutex);
761 }
762 
763 void
head_set_gain(sw_head * h,gfloat gain)764 head_set_gain (sw_head * h, gfloat gain)
765 {
766   GList * gl;
767   sw_head_controller * hctl;
768 
769   g_mutex_lock (h->head_mutex);
770 
771   h->gain = gain;
772 
773   for (gl = h->controllers; gl; gl = gl->next) {
774     hctl = (sw_head_controller *)gl->data;
775     hctl_refresh_gain (hctl);
776   }
777 
778   g_mutex_unlock (h->head_mutex);
779 }
780 
781 void
head_set_rate(sw_head * h,gfloat rate)782 head_set_rate (sw_head * h, gfloat rate)
783 {
784   g_mutex_lock (h->head_mutex);
785 
786   h->rate = rate;
787 
788   g_mutex_unlock (h->head_mutex);
789 }
790 
791 void
head_set_monitor(sw_head * h,gboolean monitor)792 head_set_monitor (sw_head * h, gboolean monitor)
793 {
794   g_mutex_lock (h->head_mutex);
795 
796   h->monitor = monitor;
797 
798   g_mutex_unlock (h->head_mutex);
799 
800   sample_update_device (h->sample);
801 }
802 
803 static sw_framecount_t
head_write_unrestricted(sw_head * head,sw_audio_t * buf,sw_framecount_t count)804 head_write_unrestricted (sw_head * head, sw_audio_t * buf,
805 			 sw_framecount_t count)
806 {
807   sw_sample * sample = head->sample;
808   sw_sounddata * sounddata = sample->sounddata;
809   sw_format * f = sounddata->format;
810   gpointer d;
811   sw_audio_t * rd;
812   sw_framecount_t i, j, t, b;
813 
814   d = sounddata->data +
815     (int)frames_to_bytes (f, head->offset);
816   rd = (sw_audio_t *)d;
817 
818   if (head->reverse) {
819     b = 0;
820 
821     for (i = 0; i < count; i++) {
822       for (j = 0; j < f->channels; j++) {
823 	t = (count-1 - i) * f->channels + j;
824 	rd[t] *= head->mix;
825 	rd[t] += (buf[b] * head->gain);
826 	b++;
827       }
828     }
829 
830     head->offset -= count;
831 
832   } else {
833     for (i = 0; i < count * f->channels; i++) {
834       rd[i] *= head->mix;
835       rd[i] += (buf[i] * head->gain);
836     }
837 
838     head->offset += count;
839 
840   }
841 
842   return count;
843 }
844 
845 sw_framecount_t
head_write(sw_head * head,sw_audio_t * buf,sw_framecount_t count)846 head_write (sw_head * head, sw_audio_t * buf, sw_framecount_t count)
847 {
848   sw_sample * sample = head->sample;
849   sw_sounddata * sounddata = sample->sounddata;
850   sw_format * f = sounddata->format;
851   sw_framecount_t remaining = count, written = 0, n = 0;
852   GList * gl;
853   sw_sel * sel;
854 
855   while (head->restricted && remaining > 0) {
856     g_mutex_lock (sounddata->sels_mutex);
857 
858     /* Find selection region that offset is or should be in */
859     if (head->reverse) {
860       for (gl = g_list_last (sounddata->sels); gl; gl = gl->prev) {
861 	sel = (sw_sel *)gl->data;
862 
863 	if (head->offset > sel->sel_end)
864 	  head->offset = sel->sel_end;
865 
866 	if (head->offset > sel->sel_start) {
867 	  n = MIN (remaining, head->offset - sel->sel_start);
868 	  break;
869 	}
870       }
871     } else {
872       for (gl = sounddata->sels; gl; gl = gl->next) {
873 	sel = (sw_sel *)gl->data;
874 
875 	if (head->offset < sel->sel_start)
876 	  head->offset = sel->sel_start;
877 
878 	if (head->offset < sel->sel_end) {
879 	  n = MIN (remaining, sel->sel_end - head->offset);
880 	  break;
881 	}
882       }
883     }
884 
885     g_mutex_unlock (sounddata->sels_mutex);
886 
887     if (gl == NULL) {
888       if (head->looping) {
889 	head->offset = head->reverse ? sounddata->nr_frames : 0;
890       } else {
891 	head->going = FALSE;
892 	return written;
893       }
894     } else {
895       written += head_write_unrestricted (head, buf, n);
896       buf += (int)frames_to_samples (f, n);
897       remaining -= n;
898     }
899   }
900 
901   if (remaining > 0) {
902     written += head_write_unrestricted (head, buf, remaining);
903   }
904 
905   return written;
906 }
907