root/sweep/trunk/src/record.c

Revision 435, 13.9 kB (checked in by kickback, 6 years ago)

sweep: make most accels editable. creates new file ~/.sweep/keybindings. removed accel info from transport bar tooltips (they could go out of sync and are static themselves)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000-2002 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 <sys/types.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/time.h>
33
34 #include <glib.h>
35 #include <gdk/gdkkeysyms.h>
36 #include <gtk/gtk.h>
37
38 #include "callbacks.h"
39
40 #include <sweep/sweep_i18n.h>
41
42 #include <sweep/sweep_types.h>
43 #include <sweep/sweep_undo.h>
44 #include <sweep/sweep_sounddata.h>
45 #include <sweep/sweep_sample.h>
46 #include <sweep/sweep_typeconvert.h>
47
48 #include "sample.h"
49 #include "interface.h"
50 #include "edit.h"
51 #include "head.h"
52 #include "levelmeter.h"
53 #include "sample-display.h"
54 #include "play.h"
55 #include "driver.h"
56 #include "undo_dialog.h"
57 #include "db_slider.h"
58
59 #define DEBUG
60
61 extern GtkStyle * style_wb;
62 extern GtkStyle * style_LCD;
63 extern GtkStyle * style_light_grey;
64 extern GtkStyle * style_red_grey;
65 extern GtkStyle * style_green_grey;
66 extern GtkStyle * style_red;
67
68 static GtkWidget * rec_dialog = NULL;
69
70 static sw_handle * rec_handle = NULL;
71
72 static gboolean rec_prepared = FALSE;
73
74 static gint update_tag = -1;
75
76 static GtkWidget * rec_ind_ebox;
77 static GtkWidget * rec_ind_label;
78 static gboolean rec_ind_state = FALSE;
79
80 static GtkWidget * combo;
81 static GtkWidget * mix_slider, * gain_slider;
82 static sw_head_controller * head_controller;
83
84 static sw_head * rec_head = NULL;
85
86 static gint
87 update_rec_ind (gpointer data)
88 {
89   sw_head * h = (sw_head *)data;
90
91   if (rec_dialog == NULL) {
92     return FALSE;
93   } else if (!h->going) {
94     gtk_label_set_text (GTK_LABEL(rec_ind_label), _("Ready to record"));
95     gtk_widget_set_style (rec_ind_ebox, style_light_grey);
96     return FALSE;
97   } else {
98     rec_ind_state = !rec_ind_state;
99
100     if (rec_ind_state) {
101       gtk_widget_set_style (rec_ind_ebox, style_red);
102     } else {
103       gtk_widget_set_style (rec_ind_ebox, style_light_grey);
104     }
105
106     return TRUE;
107   }
108 }
109
110 static gint
111 update_recmarker (gpointer data)
112 {
113   sw_head * h = (sw_head *)data;
114
115   if (rec_dialog == NULL || !h->going) {
116     update_tag = 0;
117
118     head_set_going (h, FALSE);
119
120     return FALSE;
121   } else {
122     sample_set_rec_marker (h->sample, h->offset);
123
124     head_set_offset (h, h->offset);
125     return TRUE;
126   }
127 }
128
129 static void
130 start_recmarker (sw_head * head)
131 {
132   if (update_tag > 0) {
133     g_source_remove (update_tag);
134   }
135
136   update_tag = g_timeout_add ((guint32)30,
137                                 (GSourceFunc)update_recmarker,
138                                 (gpointer)head);
139
140   gtk_label_set_text (GTK_LABEL(rec_ind_label), "RECORDING");
141   gtk_widget_set_style (rec_ind_ebox, style_red);
142   rec_ind_state = TRUE;
143
144   g_timeout_add ((guint32)500,
145                    (GSourceFunc)update_rec_ind,
146                    (gpointer)head);
147 }
148
149 static void
150 mix_value_changed_cb (GtkWidget * widget, gfloat value, gpointer data)
151 {
152   sw_head * head = (sw_head *)data;
153
154   head->mix = value;
155 }
156
157 static void
158 gain_value_changed_cb (GtkWidget * widget, gfloat value, gpointer data)
159 {
160   sw_head * head = (sw_head *)data;
161
162   head->gain = value;
163 }
164
165 void
166 stop_recording (sw_sample * sample)
167 {
168   head_set_going (sample->rec_head, FALSE);
169 }
170
171 static void
172 prepare_recording (sw_format * format)
173 {
174   rec_handle = device_open (0, O_RDONLY);
175
176   if (rec_handle == NULL) return;
177
178   device_setup (rec_handle, format);
179
180   rec_prepared = TRUE;
181 }
182
183 static struct timeval tv_instant = {0, 0};
184
185 static void
186 do_record_regions (sw_sample * sample)
187 {
188   sw_head * head = sample->rec_head;
189   sw_sounddata * sounddata = sample->sounddata;
190   sw_format * f = sounddata->format;
191   fd_set fds;
192   sw_framecount_t sel_total, run_total;
193   sw_framecount_t offset, remaining, n, count;
194   gint percent;
195   gboolean rec_mixing = FALSE;
196
197   sw_audio_t * rbuf;
198
199   gboolean active = TRUE;
200
201   if (!rec_prepared)
202     prepare_recording (f);
203
204   if (rec_handle == NULL) goto done;
205
206   head->restricted = TRUE;
207
208   sel_total = sounddata_selection_nr_frames (sounddata) / 100;
209   if (sel_total == 0) sel_total = 1;
210   run_total = 0;
211
212   rbuf = alloca (1024 * f->channels * sizeof (sw_audio_t));
213
214   rec_mixing = TRUE;
215
216   while (active) {
217      
218     FD_ZERO (&fds);
219     FD_SET (rec_handle->driver_fd, &fds);
220    
221     if (select (rec_handle->driver_fd+1, &fds, NULL, NULL, &tv_instant) == 0);
222
223     n = 1024;
224     count = n * f->channels;
225    
226     count = device_read (rec_handle, rbuf, count);
227    
228     g_mutex_lock (sample->ops_mutex);
229    
230     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL || count == -1 ||
231         !head->going) {
232       active = FALSE;
233     } else {
234       head_write (head, rbuf, n);
235      
236       remaining -= n;
237       offset += n;
238      
239       run_total += n;
240       percent = run_total / sel_total;
241       percent = MIN (100, percent);
242       sample_set_progress_percent (sample, percent);
243      
244     }
245    
246     g_mutex_unlock (sample->ops_mutex);
247   }
248  
249  done:
250   if (rec_handle != NULL) {
251     device_close (rec_handle);
252   }
253
254   gtk_widget_set_sensitive (combo, TRUE);
255
256   rec_prepared = FALSE;
257 }
258
259 static void
260 do_record_regions_thread (sw_op_instance * inst)
261 {
262   sw_sample * sample = inst->sample;
263
264   sw_edit_buffer * old_eb;
265   paste_over_data * p;
266
267   old_eb = edit_buffer_from_sample (sample);
268
269   p = paste_over_data_new (old_eb, old_eb);
270   inst->redo_data = inst->undo_data = p;
271   set_active_op (sample, inst);
272
273   do_record_regions (sample);
274
275   if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
276     p->new_eb = edit_buffer_from_sample (sample);
277    
278     register_operation (sample, inst);
279   }
280 }
281
282 static sw_operation record_regions_op = {
283   SWEEP_EDIT_MODE_FILTER,
284   (SweepCallback)do_record_regions_thread,
285   (SweepFunction)NULL,
286   (SweepCallback)undo_by_paste_over,
287   (SweepFunction)paste_over_data_destroy,
288   (SweepCallback)redo_by_paste_over,
289   (SweepFunction)paste_over_data_destroy
290 };
291
292 void
293 record_cb (GtkWidget * widget, gpointer data)
294 {
295   sw_head * head = (sw_head *)data;
296   sw_sample * sample = head->sample;
297
298   if (head->going) {
299     stop_recording (sample);
300   } else {
301     if (sounddata_selection_nr_frames (sample->sounddata) > 0) {
302       head->going = TRUE;
303       gtk_widget_set_sensitive (combo, FALSE);
304       schedule_operation (sample, "Record", &record_regions_op, NULL);
305       start_recmarker (head);
306     } else {
307       head_set_going (head, FALSE);
308       sample_set_tmp_message (sample, _("No selection to record into"));
309     }
310   }
311 }
312
313 static void
314 rec_dialog_destroy (GtkWidget * widget, gpointer data)
315 {
316   sw_head * head = (sw_head *)data;
317
318   rec_dialog = NULL;
319   rec_head = NULL;
320
321   stop_recording (head->sample);
322 }
323
324 static void
325 _rec_dialog_set_sample (sw_sample * sample, gboolean select_current)
326 {
327   sw_head * head;
328
329   gtk_entry_set_text (GTK_ENTRY(GTK_COMBO(combo)->entry),
330                       g_basename (sample->pathname));
331
332   if (sample->rec_head == NULL) {
333     sample->rec_head = head_new (sample, SWEEP_HEAD_RECORD);
334   }
335
336   head = sample->rec_head;
337
338   if (rec_head != NULL) {
339     g_signal_handlers_disconnect_matched
340                                             (GTK_OBJECT(mix_slider),
341                                              G_SIGNAL_MATCH_DATA,
342                                              0,
343                                              0,
344                                              0,
345                                              0,
346                                              rec_head);
347                                                                                                  
348         g_signal_handlers_disconnect_matched
349                                             (GTK_OBJECT(gain_slider),
350                                              G_SIGNAL_MATCH_DATA,
351                                              0,
352                                              0,
353                                              0,
354                                              0,
355                                              rec_head);
356    
357   }
358
359   db_slider_set_value (DB_SLIDER(mix_slider), head->mix);
360   g_signal_connect (G_OBJECT(mix_slider), "value-changed",
361                       G_CALLBACK(mix_value_changed_cb), head);
362
363   db_slider_set_value (DB_SLIDER(gain_slider), head->gain);
364   g_signal_connect (G_OBJECT(gain_slider), "value-changed",
365                       G_CALLBACK(gain_value_changed_cb), head);
366
367   rec_head = head;
368
369   head_controller_set_head (head_controller, rec_head);
370 }
371
372 void
373 rec_dialog_refresh_sample_list (void)
374 {
375   GList * cbitems = NULL;
376
377   if (rec_dialog == NULL)
378     return;
379
380   if ((cbitems = sample_bank_list_names ()) != NULL)
381     gtk_combo_set_popdown_strings (GTK_COMBO(combo), cbitems);
382
383   g_list_free (cbitems);
384 }
385
386 static void
387 rec_dialog_entry_changed_cb (GtkWidget * widget, gpointer data)
388 {
389   GtkEntry * entry;
390   const gchar * new_text;
391   sw_sample * sample;
392
393   entry = GTK_ENTRY(GTK_COMBO(combo)->entry);
394   new_text = gtk_entry_get_text (entry);
395
396   sample = sample_bank_find_byname (new_text);
397
398   if (sample == NULL) return;
399 g_signal_handlers_block_matched (GTK_OBJECT(entry), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, NULL);
400   _rec_dialog_set_sample (sample, TRUE);
401   g_signal_handlers_unblock_matched (GTK_OBJECT(entry), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, NULL);
402 }
403
404 void
405 rec_dialog_create (sw_sample * sample)
406 {
407   GtkWidget * window;
408   GtkWidget * main_vbox;
409   GtkWidget * separator;
410   GtkWidget * frame;
411   GtkWidget * hbox;
412   GtkWidget * label;
413   GtkWidget * slider;
414   GtkWidget * ebox;
415   GtkWidget * hctl;
416   GtkTooltips * tooltips;
417
418 #ifdef DEVEL_CODE
419   GtkWidget * levelmeter;
420 #endif
421
422   /*  GSList * group;*/
423
424   GtkAccelGroup * accel_group;
425
426   sw_head * head;
427
428   if (sample->rec_head == NULL) {
429     sample->rec_head = head_new (sample, SWEEP_HEAD_RECORD);
430   }
431
432   head = sample->rec_head;
433
434   if (rec_dialog == NULL) {
435     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
436     sweep_set_window_icon (GTK_WINDOW(window));
437
438         attach_window_close_accel(GTK_WINDOW(window));
439     rec_dialog = window;       
440          
441     main_vbox = gtk_vbox_new (FALSE, 0);
442     gtk_container_add (GTK_CONTAINER(window), main_vbox);
443     gtk_widget_show (main_vbox);
444
445     gtk_window_set_wmclass(GTK_WINDOW(rec_dialog), "rec_dialog", "Sweep");
446     gtk_window_set_title(GTK_WINDOW(rec_dialog), _("Sweep: Record"));
447     gtk_window_set_position(GTK_WINDOW(rec_dialog), GTK_WIN_POS_MOUSE);
448
449     accel_group = gtk_accel_group_new ();
450     gtk_window_add_accel_group (GTK_WINDOW(rec_dialog), accel_group);
451
452     g_signal_connect (G_OBJECT(rec_dialog), "destroy",
453                        G_CALLBACK(rec_dialog_destroy), head);
454
455     hbox = gtk_hbox_new (FALSE, 8);
456     gtk_box_pack_start (GTK_BOX(main_vbox), hbox, FALSE, TRUE, 8);
457     gtk_widget_show (hbox);
458
459     label = gtk_label_new (_("File:"));
460     gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 8);
461     gtk_widget_show (label);
462
463     combo = gtk_combo_new ();
464     gtk_box_pack_start (GTK_BOX(hbox), combo, TRUE, TRUE, 8);
465     gtk_widget_show (combo);
466
467     gtk_editable_set_editable (GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE);
468
469     g_signal_connect (G_OBJECT(GTK_COMBO(combo)->entry), "changed",
470                         G_CALLBACK(rec_dialog_entry_changed_cb), NULL);
471
472     separator = gtk_hseparator_new ();
473     gtk_box_pack_start (GTK_BOX(main_vbox), separator, FALSE, FALSE, 0);
474     gtk_widget_show (separator);
475
476     hbox = gtk_hbox_new (FALSE, 0);
477     gtk_box_pack_start (GTK_BOX(main_vbox), hbox, TRUE, TRUE, 8);
478     gtk_widget_show (hbox);
479
480     /* Old signal */
481
482     frame = gtk_frame_new (_("Previous sound"));
483     gtk_container_set_border_width (GTK_CONTAINER(frame), 8);
484     gtk_box_pack_start (GTK_BOX(hbox), frame, TRUE, TRUE, 0);
485     gtk_widget_show (frame);
486
487     tooltips = gtk_tooltips_new ();
488
489     slider = db_slider_new (_("Gain"), head->mix, 0.0, 1.0);
490     gtk_container_add (GTK_CONTAINER(frame), slider);
491     gtk_widget_show (slider);
492
493     mix_slider = slider;
494
495     gtk_tooltips_set_tip (tooltips, slider,
496                           _("This slider allows you to mix the new recording "
497                             "in with the previous contents of the buffer. "
498                             "Set it to -inf dB to overwrite the previous "
499                             "sound."), NULL);
500     /* New signal */
501
502     frame = gtk_frame_new (_("Recorded sound"));
503     gtk_container_set_border_width (GTK_CONTAINER(frame), 8);
504     gtk_box_pack_start (GTK_BOX(hbox), frame, TRUE, TRUE, 0);
505     gtk_widget_show (frame);
506
507     slider = db_slider_new (_("Gain"), head->gain, 0.0, 1.0);
508     gtk_container_add (GTK_CONTAINER(frame), slider);
509     gtk_widget_show (slider);
510
511     gain_slider = slider;
512
513     gtk_tooltips_set_tip (tooltips, slider,
514                           _("This slider allows you to reduce the level of "
515                             "the recorded sound. Set it to 0 dB to record "
516                             "without any reduction. "
517                             "Note that setting this to -inf dB will record "
518                             "silence."), NULL);
519
520     /* Level meters */
521
522 #ifdef DEVEL_CODE
523     levelmeter = levelmeter_new (7);
524     gtk_box_pack_start (GTK_BOX(hbox), levelmeter, FALSE, TRUE, 3);
525     gtk_widget_show (levelmeter);
526
527     levelmeter = levelmeter_new (7);
528     gtk_box_pack_start (GTK_BOX(hbox), levelmeter, FALSE, TRUE, 3);
529     gtk_widget_show (levelmeter);
530 #endif
531
532     hctl = head_controller_create (sample->rec_head, rec_dialog,
533                                    &head_controller);
534     gtk_box_pack_start (GTK_BOX (main_vbox), hctl, FALSE, TRUE, 0);
535     gtk_widget_show (hctl);
536
537     ebox = gtk_event_box_new ();
538     gtk_widget_set_style (ebox, style_light_grey);
539     gtk_box_pack_start (GTK_BOX(main_vbox), ebox, FALSE, TRUE, 0);
540     gtk_widget_show (ebox);
541
542     rec_ind_ebox = ebox;
543
544     label = gtk_label_new (_("Ready to record"));
545     gtk_container_add (GTK_CONTAINER(ebox), label);
546     gtk_widget_show (label);
547
548     rec_ind_label = label;
549   }
550
551   rec_dialog_refresh_sample_list ();
552   _rec_dialog_set_sample (sample, TRUE);
553
554   if (!GTK_WIDGET_VISIBLE(rec_dialog)) {
555     gtk_widget_show (rec_dialog);
556   } else {
557     gdk_window_raise (rec_dialog->window);
558   }
559
560 }
Note: See TracBrowser for help on using the browser.