Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / recordgui.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
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
22 #include "asset.h"
23 #include "batch.h"
24 #include "bcsignals.h"
25 #include "browsebutton.h"
26 #include "channel.h"
27 #include "channelpicker.h"
28 #include "clip.h"
29 #include "condition.h"
30 #include "bchash.h"
31 #include "edl.h"
32 #include "edlsession.h"
33 #include "file.h"
34 #include "filesystem.h"
35 #include "keys.h"
36 #include "language.h"
37 #include "loadmode.h"
38 #include "meterpanel.h"
39 #include "mutex.h"
40 #include "mwindow.h"
41 #include "mwindowgui.h"
42 #include "preferences.h"
43 #include "question.h"
44 #include "recconfirmdelete.h"
45 #include "recordgui.h"
46 #include "record.h"
47 #include "recordlabel.h"
48 #include "recordmonitor.h"
49 #include "recordtransport.h"
50 #include "recordvideo.h"
51 #include "mainsession.h"
52 #include "theme.h"
53 #include "units.h"
54 #include "videodevice.h"
55
56 #include <time.h>
57
58
59
60
61 RecordGUI::RecordGUI(MWindow *mwindow, Record *record)
62  : BC_Window(_(PROGRAM_NAME ": Recording"),
63         mwindow->session->rwindow_x, mwindow->session->rwindow_y,
64         mwindow->session->rwindow_w, mwindow->session->rwindow_h,
65         xS(10), yS(10), 1, 0, 1)
66 {
67         this->mwindow = mwindow;
68         this->record = record;
69
70         current_operation = 0;
71         position_title = 0;
72         prev_label_title = 0;
73         frames_behind = 0;
74         frames_dropped = 0;
75         framerate = 0;
76         samples_clipped = 0;
77         cron_status = 0;
78         batch_bay = 0;
79         batch_path = 0;
80         status_thread = 0;
81         batch_start = 0;
82         batch_duration = 0;
83         record_transport = 0;
84         batch_browse = 0;
85         batch_source = 0;
86         batch_mode = 0;
87         new_batch = 0;
88         delete_batch = 0;
89         start_batches = 0;
90         stop_batches = 0;
91         activate_batch = 0;
92         label_button = 0;
93         drop_frames = 0;
94         fill_frames = 0;
95         monitor_video = 0;
96         monitor_audio = 0;
97         meter_audio = 0;
98         batch_flash = 0;
99         startover_thread = 0;
100         interrupt_thread = 0;
101         load_mode = 0;
102         flash_color = 0;
103         loop_hr = 0;
104         loop_min = 0;
105         loop_sec = 0;
106         reset = 0;
107         monitor_video_window = 0;
108         dc_offset_button = 0;
109         for( int i=0; i<MAXCHANNELS; ++i ) {
110                 dc_offset_text[i] = 0;
111                 meter[i] = 0;
112         }
113         total_dropped_frames = 0;
114         total_clipped_samples = 0;
115 }
116
117 RecordGUI::~RecordGUI()
118 {
119         delete status_thread;
120         delete record_transport;
121         delete batch_source;
122         delete batch_mode;
123         delete batch_flash;
124         delete startover_thread;
125         delete interrupt_thread;
126         delete batch_start;
127         delete batch_duration;
128         delete load_mode;
129 }
130
131
132 void RecordGUI::create_objects()
133 {
134         int xs5 = xS(5), xs10 = xS(10), xs20 = xS(20), xs30 = xS(30);
135         int ys5 = yS(5), ys10 = yS(10);
136         char string[BCTEXTLEN];
137         flash_color = RED;
138         Asset *asset = record->default_asset;
139         lock_window("RecordGUI::create_objects");
140         status_thread = new RecordStatusThread(mwindow, this);
141         status_thread->start();
142         set_icon(mwindow->theme->get_image("record_icon"));
143
144         mwindow->theme->get_recordgui_sizes(this, get_w(), get_h());
145 //printf("RecordGUI::create_objects 1\n");
146         mwindow->theme->draw_rwindow_bg(this);
147
148         int x = xs10;
149         int y = ys10;
150         int x1 = 0;
151         BC_Title *title;
152         int pad = max(BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1),
153                 BC_Title::calculate_h(this, "X")) + ys5;
154         int button_y = 0;
155
156 // Current batch
157         add_subwindow(title = new BC_Title(x, y, _("Path:")));
158         x1 = max(title->get_w(), x1);
159         y += pad;
160         add_subwindow(title = new BC_Title(x, y, _("Start time:")));
161         x1 = max(title->get_w(), x1);
162         y += pad;
163         add_subwindow(title = new BC_Title(x, y, _("Duration time:")));
164         x1 = max(title->get_w(), x1);
165         y += pad;
166         add_subwindow(title = new BC_Title(x, y, _("Source:")));
167         x1 = max(title->get_w(), x1);
168         y += pad;
169         add_subwindow(title = new BC_Title(x, y, _("Mode:")));
170         x1 = max(title->get_w(), x1);
171         y += pad;
172         add_subwindow(title = new BC_Title(x, y, _("Transport:")));
173         x1 = max(title->get_w(), x1);
174         y += pad;
175
176         button_y = max(y, button_y);
177
178
179
180         int x2 = 0;
181         y = ys10;
182         x = x1 + xs20;
183         add_subwindow(batch_path = new RecordPath(this, x, y));
184         add_subwindow(batch_browse = new BrowseButton(mwindow->theme,
185                 this,
186                 batch_path,
187                 batch_path->get_x() + batch_path->get_w(),
188                 y,
189                 asset->path,
190                 _(PROGRAM_NAME ": Record path"),
191                 _("Select a file to record to:"),
192                 0));
193         x2 = max(x2, batch_path->get_w() + batch_browse->get_w());
194         y += pad;
195         batch_start = new RecordStart(this, x, y);
196         batch_start->create_objects();
197         x2 = max(x2, batch_start->get_w());
198         y += pad;
199         batch_duration = new RecordDuration(this, x, y);
200         batch_duration->create_objects();
201         x2 = max(x2, batch_duration->get_w());
202         y += pad;
203         batch_source = new RecordSource(this, x, y);
204         batch_source->create_objects();
205         x2 = max(x2, batch_source->get_w());
206         y += pad;
207         batch_mode = new RecordGUIModeMenu(this, x, y, xS(200), "");
208         batch_mode->create_objects();
209         x2 = max(x2, batch_mode->get_w());
210         y += pad;
211         record_transport = new RecordTransport(mwindow,
212                 record, this, x, y);
213         record_transport->create_objects();
214         x2 = max(x2, record_transport->get_w());
215
216
217
218
219 // Compression settings
220         x = x2 + x1 + xs30;
221         y = ys10;
222         int x3 = 0;
223         pad = BC_Title::calculate_h(this, "X") + ys5;
224         add_subwindow(title = new BC_Title(x, y, _("Format:")));
225         x3 = max(title->get_w(), x3);
226         y += pad;
227
228         if(asset->audio_data)
229         {
230                 add_subwindow(title = new BC_Title(x, y, _("Audio compression:")));
231                 x3 = max(title->get_w(), x3);
232                 y += pad;
233                 add_subwindow(title = new BC_Title(x, y, _("Samplerate:")));
234                 x3 = max(title->get_w(), x3);
235                 y += pad;
236                 add_subwindow(title = new BC_Title(x, y, _("Clipped samples:")));
237                 x3 = max(title->get_w(), x3);
238                 y += pad;
239         }
240
241         if(asset->video_data)
242         {
243                 add_subwindow(title = new BC_Title(x, y, _("Video compression:")));
244                 x3 = max(title->get_w(), x3);
245                 y += pad;
246                 add_subwindow(title = new BC_Title(x, y, _("Framerate:")));
247                 x3 = max(title->get_w(), x3);
248                 y += pad;
249                 add_subwindow(title = new BC_Title(x, y, _("Frames dropped:")));
250                 x3 = max(title->get_w(), x3);
251                 y += pad;
252                 add_subwindow(title = new BC_Title(x, y, _("Frames behind:")));
253                 x3 = max(title->get_w(), x3);
254                 y += pad;
255         }
256
257         add_subwindow(title = new BC_Title(x, y, _("Position:")));
258         x3 = max(title->get_w(), x3);
259         y += pad;
260         add_subwindow(title = new BC_Title(x, y, _("Prev label:")));
261         x3 = max(title->get_w(), x3);
262         y += pad;
263
264         button_y = max(y, button_y);
265         y = ys10;
266         x = x3 + x2 + x1 + xS(40);
267
268         add_subwindow(new BC_Title(x, y,
269                 File::formattostr(asset->format),
270                 MEDIUMFONT,
271                 mwindow->theme->recordgui_fixed_color));
272         y += pad;
273
274         if(asset->audio_data) {
275                 add_subwindow(new BC_Title(x, y,
276                         File::bitstostr(asset->bits),
277                         MEDIUMFONT,
278                         mwindow->theme->recordgui_fixed_color));
279
280                 y += pad;
281                 sprintf(string, "%d", asset->sample_rate);
282                 add_subwindow(new BC_Title(x, y,
283                         string, MEDIUMFONT,
284                         mwindow->theme->recordgui_fixed_color));
285
286                 y += pad;
287                 add_subwindow(samples_clipped = new BC_Title(x, y,
288                         "0", MEDIUMFONT,
289                         mwindow->theme->recordgui_variable_color));
290                 y += pad;
291         }
292
293         if(asset->video_data) {
294                 add_subwindow(new BC_Title(x, y,
295                         asset->format == FILE_MPEG ? _("File Capture") :
296                                 File::compressiontostr(asset->vcodec),
297                         MEDIUMFONT,
298                         mwindow->theme->recordgui_fixed_color));
299
300                 y += pad;
301                 sprintf(string, "%0.2f", asset->frame_rate);
302                 add_subwindow(framerate = new BC_Title(x, y,
303                         string, MEDIUMFONT,
304                         mwindow->theme->recordgui_fixed_color));
305
306                 y += pad;
307                 add_subwindow(frames_dropped = new BC_Title(x, y,
308                         "0", MEDIUMFONT,
309                         mwindow->theme->recordgui_variable_color));
310                 y += pad;
311                 add_subwindow(frames_behind = new BC_Title(x, y,
312                         "0", MEDIUMFONT,
313                         mwindow->theme->recordgui_variable_color));
314                 y += pad;
315         }
316
317         add_subwindow(position_title = new BC_Title(x, y,
318                 "", MEDIUMFONT,
319                 mwindow->theme->recordgui_variable_color));
320
321         y += pad;
322         add_subwindow(prev_label_title = new BC_Title(x, y,
323                 _("None"), MEDIUMFONT,
324                 mwindow->theme->recordgui_variable_color));
325
326         y += pad + ys10;
327         button_y = max(y, button_y);
328
329 // Buttons
330         x = xs10;
331         y = button_y;
332
333         add_subwindow(title = new BC_Title(x,y, _("Batches:")));
334         int y_max = y + title->get_h();  x1 = x;
335         x += title->get_w() + xs5;
336         add_subwindow(activate_batch = new RecordGUIActivateBatch(this, x, y));
337         x += activate_batch->get_w();
338         y_max = max(y_max, y + activate_batch->get_h());
339         add_subwindow(start_batches = new RecordGUIStartBatches(this, x, y));
340         y_max = max(y_max, y + start_batches->get_h());  x2 = x;
341         x += start_batches->get_w();
342         add_subwindow(new_batch = new RecordGUINewBatch(this, x, y));
343         y_max = max(y_max, y + new_batch->get_h());  x3 = x;
344         x += new_batch->get_w();  int x4 = x;
345         add_subwindow(label_button = new RecordGUILabel(this, x, y));
346         y_max = max(y_max, y + label_button->get_h());
347
348         int y1 = y_max, y2 = y1 + ys5;
349         add_subwindow(title = new BC_Title(x1,y2, _("Cron:")));
350         y_max = max(y_max, y2 + title->get_h());
351         x1 += title->get_w() + xs5;
352         add_subwindow(cron_status = new BC_Title(x1,y2, _("Idle"), MEDIUMFONT,
353                 mwindow->theme->recordgui_variable_color));
354         y_max = max(y_max, y2 + cron_status->get_h());
355         add_subwindow(stop_batches = new RecordGUIStopBatches(this, x2, y1));
356         y_max = max(y_max, y1 + stop_batches->get_h());
357         add_subwindow(delete_batch = new RecordGUIDeleteBatch(this, x3, y1));
358         y_max = max(y_max, y1 + delete_batch->get_h());
359         add_subwindow(clrlbls_button = new RecordGUIClearLabels(this, x4, y1));
360         y_max = max(y_max, y1 + clrlbls_button->get_h());
361
362         x = x1 = xs10;
363         y = y_max + pad;
364         y1 = y + pad + ys5;
365
366         fill_frames = 0;
367         monitor_video = 0;
368         monitor_audio = 0;
369         meter_audio = 0;
370         if(asset->video_data) {
371                 add_subwindow(drop_frames = new RecordGUIDropFrames(this, x, y));
372                 add_subwindow(fill_frames = new RecordGUIFillFrames(this, x, y1));
373                 x += drop_frames->get_w() + xs5;  x1 = x;
374                 add_subwindow(monitor_video = new RecordGUIMonitorVideo(this, x, y));
375                 x += monitor_video->get_w() + xs5;
376         }
377
378         if(asset->audio_data) {
379                 add_subwindow(monitor_audio = new RecordGUIMonitorAudio(this, x, y));
380                 x += monitor_audio->get_w() + xs5;
381                 add_subwindow(meter_audio = new RecordGUIAudioMeters(this, x, y));
382                 x += meter_audio->get_w() + xs5;
383         }
384
385         add_subwindow(power_off = new RecordGUIPowerOff(this, x1, y1));
386         x1 += power_off->get_w() + xs10;
387         add_subwindow(commercial_check = new RecordGUICommCheck(this, x1, y1));
388         x1 += commercial_check->get_w() + xs30;
389         add_subwindow(deinterlace = new RecordGUIDeinterlace(this, x1, y1));
390         deinterlace->create_objects();
391         x1 += deinterlace->get_w() + xs5;
392         add_subwindow(new BC_Title(x1, y1, _("deinterlace")));
393
394 // Batches
395         x = xs10;
396         y += ys5;
397         if( fill_frames )
398                 y = y1 + fill_frames->get_h();
399         else if( monitor_audio )
400                 y += monitor_audio->get_h();
401
402         int bottom_margin = max(BC_OKButton::calculate_h(),
403                 LoadMode::calculate_h(this, mwindow->theme)) + ys5;
404
405
406         add_subwindow(batch_bay = new RecordGUIBatches(this, x, y,
407                 get_w() - xs20, get_h() - y - bottom_margin - ys10));
408         y += batch_bay->get_h() + ys5;
409         record->record_batches.gui = batch_bay;
410         batch_bay->update_batches(-1);
411
412 // Controls
413         int loadmode_w = LoadMode::calculate_w(this, mwindow->theme);
414         load_mode = new LoadMode(mwindow, this,
415                 get_w() / 2 - loadmode_w / 2, y, &record->load_mode);
416         load_mode->create_objects();
417         y += load_mode->get_h() + ys5;
418
419         add_subwindow(new RecordGUIOK(this));
420
421         interrupt_thread = new EndRecordThread(this);
422 //      add_subwindow(new RecordGUISave(record, this));
423         add_subwindow(new RecordGUICancel(this));
424
425         startover_thread = new RecordStartoverThread(this);
426
427         enable_batch_buttons();
428         if( batch_mode->value == RECORD_TIMED )
429                 batch_duration->enable();
430         else
431                 batch_duration->disable();
432         show_window(1);
433         unlock_window();
434 }
435
436 void RecordGUI::update_batches()
437 {
438         lock_window("void RecordGUI::Update_batches");
439         batch_bay->update_batches();
440         unlock_window();
441 }
442
443
444 Batch *RecordGUI::get_current_batch()
445 {
446         return record->get_editing_batch();
447 }
448
449 Batch *RecordGUI::get_editing_batch()
450 {
451         return record->get_editing_batch();
452 }
453
454 void RecordGUI::update_batch_sources()
455 {
456 //printf("RecordGUI::update_batch_sources 1\n");
457         ChannelPicker *channel_picker =
458                 record->record_monitor->window->channel_picker;
459         if(channel_picker)
460                 batch_source->update_list(&channel_picker->channel_listitems);
461 //printf("RecordGUI::update_batch_sources 2\n");
462 }
463
464 int RecordGUI::translation_event()
465 {
466         mwindow->session->rwindow_x = get_x();
467         mwindow->session->rwindow_y = get_y();
468         return 0;
469 }
470
471
472 int RecordGUI::resize_event(int w, int h)
473 {
474         int xs20 = xS(20), ys10 = yS(10);
475 // Recompute batch list based on previous extents
476         int bottom_margin = mwindow->session->rwindow_h -
477                 batch_bay->get_y() -
478                 batch_bay->get_h();
479         int mode_margin = mwindow->session->rwindow_h - load_mode->get_y();
480         mwindow->session->rwindow_x = get_x();
481         mwindow->session->rwindow_y = get_y();
482         mwindow->session->rwindow_w = w;
483         mwindow->session->rwindow_h = h;
484         mwindow->theme->get_recordgui_sizes(this, w, h);
485         mwindow->theme->draw_rwindow_bg(this);
486
487         int new_h = mwindow->session->rwindow_h - bottom_margin - batch_bay->get_y();
488         if(new_h < ys10) new_h = ys10;
489         batch_bay->reposition_window(batch_bay->get_x(),
490                 batch_bay->get_y(),
491                 mwindow->session->rwindow_w - xs20,
492                 mwindow->session->rwindow_h - bottom_margin - batch_bay->get_y());
493
494         load_mode->reposition_window(mwindow->session->rwindow_w / 2 -
495                         mwindow->theme->loadmode_w / 2,
496                 mwindow->session->rwindow_h - mode_margin);
497
498         flash();
499         return 1;
500 }
501
502 void RecordGUI::update_batch_tools()
503 {
504         lock_window("RecordGUI::update_batch_tools");
505 //printf("RecordGUI::update_batch_tools 1\n");
506         Batch *batch = get_editing_batch();
507         batch_path->update(batch->asset->path);
508
509 // File is open in editing batch
510 //      if(current_batch() == editing_batch() && record->file)
511 //              batch_path->disable();
512 //      else
513 //              batch_path->enable();
514
515         batch_start->update(&batch->start_day, &batch->start_time);
516         batch_duration->update(0, &batch->duration);
517         batch_source->update(batch->get_source_text());
518         batch_mode->update(batch->record_mode);
519         if( batch_mode->value == RECORD_TIMED )
520                 batch_duration->enable();
521         else
522                 batch_duration->disable();
523         flush();
524         unlock_window();
525 }
526
527 void RecordGUI::enable_batch_buttons()
528 {
529         lock_window("RecordGUI::enable_batch_buttons");
530         new_batch->enable();
531         delete_batch->enable();
532         start_batches->enable();
533         stop_batches->disable();
534         activate_batch->enable();
535         unlock_window();
536 }
537
538 void RecordGUI::disable_batch_buttons()
539 {
540         lock_window("RecordGUI::disable_batch_buttons");
541         new_batch->disable();
542         delete_batch->disable();
543         start_batches->disable();
544         stop_batches->enable();
545         activate_batch->disable();
546         unlock_window();
547 }
548
549 RecordGUIBatches::RecordGUIBatches(RecordGUI *gui, int x, int y, int w, int h)
550  : RecordBatchesGUI(gui->record->record_batches, x, y, w, h)
551 {
552         this->gui = gui;
553 }
554
555 // Do nothing for double clicks to protect active batch
556 int RecordGUIBatches::handle_event()
557 {
558         return 1;
559 }
560
561 int RecordGUIBatches::selection_changed()
562 {
563         RecordBatchesGUI::selection_changed();
564         gui->update_batch_tools();
565         return 1;
566 }
567
568
569 RecordGUISave::RecordGUISave(RecordGUI *gui)
570  : BC_Button(xS(10),
571         gui->get_h() - BC_WindowBase::get_resources()->ok_images[0]->get_h() - yS(10),
572         BC_WindowBase::get_resources()->ok_images)
573 {
574         set_tooltip(_("Save the recording and quit."));
575         this->gui = gui;
576 }
577
578 int RecordGUISave::handle_event()
579 {
580         gui->set_done(0);
581         return 1;
582 }
583
584 int RecordGUISave::keypress_event()
585 {
586 //      if(get_keypress() == RETURN)
587 //      {
588 //              handle_event();
589 //              return 1;
590 //      }
591         return 0;
592 }
593
594 RecordGUICancel::RecordGUICancel(RecordGUI *gui)
595  : BC_CancelButton(gui)
596 {
597         set_tooltip(_("Quit without pasting into project."));
598         this->gui = gui;
599 }
600
601 int RecordGUICancel::handle_event()
602 {
603         gui->interrupt_thread->start(0);
604         return 1;
605 }
606
607 int RecordGUICancel::keypress_event()
608 {
609         if(get_keypress() == ESC)
610         {
611                 handle_event();
612                 return 1;
613         }
614
615         return 0;
616 }
617
618
619 RecordGUIOK::RecordGUIOK(RecordGUI *gui)
620  : BC_OKButton(gui)
621 {
622         set_tooltip(_("Quit and paste into project."));
623         this->gui = gui;
624 }
625
626 int RecordGUIOK::handle_event()
627 {
628         gui->interrupt_thread->start(1);
629         return 1;
630 }
631
632
633 RecordGUIStartOver::RecordGUIStartOver(RecordGUI *gui, int x, int y)
634  : BC_GenericButton(x, y, _("Start Over"))
635 {
636         set_tooltip(_("Rewind the current file and erase."));
637         this->gui = gui;
638 }
639 RecordGUIStartOver::~RecordGUIStartOver()
640 {
641 }
642
643 int RecordGUIStartOver::handle_event()
644 {
645         if(!gui->startover_thread->running())
646                 gui->startover_thread->start();
647         return 1;
648 }
649
650
651 RecordGUIDropFrames::RecordGUIDropFrames(RecordGUI *gui, int x, int y)
652  : BC_CheckBox(x, y, gui->record->drop_overrun_frames, _("drop overrun frames"))
653 {
654         this->set_underline(0);
655         this->gui = gui;
656         set_tooltip(_("Drop input frames when behind."));
657 }
658
659 int RecordGUIDropFrames::handle_event()
660 {
661         gui->record->drop_overrun_frames = get_value();
662         return 1;
663 }
664
665 int RecordGUIDropFrames::keypress_event()
666 {
667         if( get_keypress() == caption[0] ) {
668                 set_value(get_value() ? 0 : 1);
669                 handle_event();
670                 return 1;
671         }
672         return 0;
673 }
674
675 RecordGUIFillFrames::RecordGUIFillFrames(RecordGUI *gui, int x, int y)
676  : BC_CheckBox(x, y, gui->record->fill_underrun_frames, _("fill underrun frames"))
677 {
678         this->set_underline(0);
679         this->gui = gui;
680         set_tooltip(_("Write extra frames when behind."));
681 }
682
683 int RecordGUIFillFrames::handle_event()
684 {
685         gui->record->fill_underrun_frames = get_value();
686         return 1;
687 }
688
689 int RecordGUIFillFrames::keypress_event()
690 {
691         if( get_keypress() == caption[0] ) {
692                 set_value(get_value() ? 0 : 1);
693                 handle_event();
694                 return 1;
695         }
696         return 0;
697 }
698
699 RecordGUIPowerOff::RecordGUIPowerOff(RecordGUI *gui, int x, int y)
700  : BC_CheckBox(x, y, gui->record->power_off, _("poweroff when done"))
701 {
702         this->set_underline(0);
703         this->gui = gui;
704         set_tooltip(_("poweroff system when batch record done."));
705 }
706
707 int RecordGUIPowerOff::handle_event()
708 {
709         gui->record->power_off = get_value();
710         return 1;
711 }
712
713 int RecordGUIPowerOff::keypress_event()
714 {
715         if( get_keypress() == caption[0] ) {
716                 set_value(get_value() ? 0 : 1);
717                 handle_event();
718                 return 1;
719         }
720         return 0;
721 }
722
723
724 RecordGUICommCheck::RecordGUICommCheck(RecordGUI *gui, int x, int y)
725  : BC_CheckBox(x, y, gui->record->commercial_check, _("check for ads"))
726 {
727         this->set_underline(0);
728         this->gui = gui;
729         set_tooltip(_("check for commercials."));
730 }
731
732 int RecordGUICommCheck::handle_event()
733 {
734         gui->record->update_skimming(get_value());
735         return 1;
736 }
737
738 int RecordGUICommCheck::keypress_event()
739 {
740         if( get_keypress() == caption[0] ) {
741                 set_value(get_value() ? 0 : 1);
742                 gui->record->update_skimming(get_value());
743                 handle_event();
744                 return 1;
745         }
746         return 0;
747 }
748
749
750 RecordGUIDelaceItem::RecordGUIDelaceItem(RecordGUIDeinterlace *popup,
751                 const char *text, int id)
752  : BC_MenuItem(text)
753 {
754         this->popup = popup;
755         this->id = id;
756 }
757 int RecordGUIDelaceItem::handle_event()
758 {
759         popup->gui->record->deinterlace = id;
760         popup->update();
761         return 1;
762 }
763
764 RecordGUIDeinterlace::RecordGUIDeinterlace(RecordGUI *gui, int x, int y)
765  : BC_PopupMenu(x, y, xS(24), "", 1, 0, xS(3))
766 {
767         this->gui = gui;
768 }
769
770 void RecordGUIDeinterlace::create_objects()
771 {
772         add_item(new RecordGUIDelaceItem(this, _("None"), RECORD_LACE_NONE));
773         add_item(new RecordGUIDelaceItem(this, _("Even"), RECORD_LACE_EVEN));
774         add_item(new RecordGUIDelaceItem(this, _("Odd"), RECORD_LACE_ODD));
775         update();
776 }
777
778 void RecordGUIDeinterlace::update()
779 {
780         int v = gui->record->deinterlace;
781         for( int i=0,n=total_items(); i<n; ++i ) {
782                 RecordGUIDelaceItem *item = (RecordGUIDelaceItem *)get_item(i);
783                 item->set_checked(item->id == v);
784         }
785 }
786
787
788 RecordGUIMonitorVideo::RecordGUIMonitorVideo(RecordGUI *gui, int x, int y)
789  : BC_CheckBox(x, y, gui->record->monitor_video, _("Monitor video"))
790 {
791         this->set_underline(8);
792         this->gui = gui;
793 }
794
795 int RecordGUIMonitorVideo::handle_event()
796 {
797 // Video capture constitutively, just like audio, but only flash on screen if 1
798         int mode = get_value();
799         Record *record = gui->record;
800         record->set_video_monitoring(mode);
801         if(record->monitor_video) {
802                 unlock_window();
803                 BC_Window *window = record->record_monitor->window;
804                 window->lock_window("RecordGUIMonitorVideo::handle_event");
805                 window->show_window();
806                 window->raise_window();
807                 window->flush();
808                 window->unlock_window();
809                 lock_window("RecordGUIMonitorVideo::handle_event");
810                 record->video_window_open = 1;
811         }
812         else {
813                 unlock_window();
814                 BC_Window *window = record->record_monitor->window;
815                 window->lock_window("RecordGUIMonitorVideo::handle_event");
816                 window->hide_window();
817                 window->flush();
818                 window->unlock_window();
819                 lock_window("RecordGUIMonitorVideo::handle_event");
820                 record->video_window_open = 0;
821         }
822         return 1;
823 }
824
825
826 int RecordGUIMonitorVideo::keypress_event()
827 {
828         if(get_keypress() == 'v') {
829                 set_value(get_value() ? 0 : 1);
830                 handle_event();
831                 return 1;
832         }
833         return 0;
834 }
835
836
837
838 RecordGUIMonitorAudio::RecordGUIMonitorAudio(RecordGUI *gui, int x, int y)
839  : BC_CheckBox(x, y, gui->record->monitor_audio, _("Monitor audio"))
840 {
841         this->set_underline(8);
842         this->gui = gui;
843 }
844
845 int RecordGUIMonitorAudio::handle_event()
846 {
847         int mode = get_value();
848         Record *record = gui->record;
849         record->set_audio_monitoring(mode);
850         if(record->monitor_audio) {
851                 unlock_window();
852                 BC_Window *window = record->record_monitor->window;
853                 window->lock_window("RecordGUIMonitorAudio::handle_event");
854                 window->show_window();
855                 window->raise_window();
856                 window->flush();
857                 window->unlock_window();
858                 lock_window("RecordGUIMonitorAudio::handle_event");
859                 record->video_window_open = 1;
860         }
861         return 1;
862 }
863
864 int RecordGUIMonitorAudio::keypress_event()
865 {
866         if(get_keypress() == 'a') {
867                 set_value(get_value() ? 0 : 1);
868                 handle_event();
869                 return 1;
870         }
871         return 0;
872 }
873
874
875 RecordGUIAudioMeters::RecordGUIAudioMeters(RecordGUI *gui, int x, int y)
876  : BC_CheckBox(x, y, gui->record->metering_audio, _("Audio meters"))
877 {
878         this->set_underline(6);
879         this->gui = gui;
880 }
881
882 int RecordGUIAudioMeters::handle_event()
883 {
884         int mode = get_value();
885         Record *record = gui->record;
886         record->set_audio_metering(mode);
887         if(record->metering_audio) {
888                 unlock_window();
889                 BC_Window *window = record->record_monitor->window;
890                 window->lock_window("RecordGUIAudioMeters::handle_event");
891                 window->show_window();
892                 window->raise_window();
893                 window->flush();
894                 window->unlock_window();
895                 lock_window("RecordGUIAudioMeters::handle_event");
896                 record->video_window_open = 1;
897         }
898         return 1;
899 }
900
901 int RecordGUIAudioMeters::keypress_event()
902 {
903         if(get_keypress() == 'm') {
904                 set_value(get_value() ? 0 : 1);
905                 handle_event();
906                 return 1;
907         }
908         return 0;
909 }
910
911 RecordPath::RecordPath(RecordGUI *gui, int x, int y)
912  : RecordBatchesGUI::Path(gui->record->record_batches, x, y)
913 {
914         this->gui = gui;
915 }
916
917 int RecordPath::handle_event()
918 {
919         return RecordBatchesGUI::Path::handle_event();
920 }
921
922
923 RecordStart::RecordStart(RecordGUI *gui, int x, int y)
924  : RecordBatchesGUI::StartTime(gui, gui->record->record_batches, x, y)
925 {
926         this->gui = gui;
927 }
928
929 int RecordStart::handle_event()
930 {
931         return RecordBatchesGUI::StartTime::handle_event();
932 }
933
934 RecordDuration::RecordDuration(RecordGUI *gui, int x, int y)
935  : RecordBatchesGUI::Duration(gui, gui->record->record_batches, x, y)
936 {
937         this->gui = gui;
938 }
939
940 int RecordDuration::handle_event()
941 {
942         return RecordBatchesGUI::Duration::handle_event();
943 }
944
945
946 RecordSource::RecordSource(RecordGUI *gui, int x, int y)
947  : RecordBatchesGUI::Source(gui, gui->record->record_batches, x, y)
948 {
949         this->gui = gui;
950 }
951
952 int RecordSource::handle_event()
953 {
954         gui->record->set_batch_channel_no(get_number());
955         return RecordBatchesGUI::Source::handle_event();
956 }
957
958
959 RecordNews::RecordNews(RecordGUI *gui, int x, int y)
960  : RecordBatchesGUI::News(gui->record->record_batches, x, y)
961 {
962         this->gui = gui;
963 }
964
965 int RecordNews::handle_event()
966 {
967         return RecordBatchesGUI::News::handle_event();
968 }
969
970
971 RecordGUINewBatch::RecordGUINewBatch(RecordGUI *gui, int x, int y)
972  : RecordBatchesGUI::NewBatch(gui->record->record_batches, x, y)
973 {
974         this->gui = gui;
975         set_tooltip(_("Create new clip."));
976 }
977 int RecordGUINewBatch::handle_event()
978 {
979         gui->record->new_batch();
980         return RecordBatchesGUI::NewBatch::handle_event();
981 }
982
983
984 RecordGUIDeleteBatch::RecordGUIDeleteBatch(RecordGUI *gui, int x, int y)
985  : RecordBatchesGUI::DeleteBatch(gui->record->record_batches, x, y)
986 {
987         this->gui = gui;
988         set_tooltip(_("Delete clip."));
989 }
990
991 int RecordGUIDeleteBatch::handle_event()
992 {
993         gui->record->delete_batch();
994         return RecordBatchesGUI::DeleteBatch::handle_event();
995 }
996
997
998 RecordGUIStartBatches::RecordGUIStartBatches(RecordGUI *gui, int x, int y)
999  : RecordBatchesGUI::StartBatches(gui->record->record_batches, x, y)
1000 {
1001         this->gui = gui;
1002         set_tooltip(_("Start batch recording\nfrom the current position."));
1003 }
1004
1005 int RecordGUIStartBatches::handle_event()
1006 {
1007         Record *record = gui->record;
1008         record->start_cron_thread();
1009         return RecordBatchesGUI::StartBatches::handle_event();
1010 }
1011
1012
1013 RecordGUIStopBatches::RecordGUIStopBatches(RecordGUI *gui, int x, int y)
1014  : RecordBatchesGUI::StopBatches(gui->record->record_batches, x, y)
1015 {
1016         this->gui = gui;
1017 }
1018
1019 int RecordGUIStopBatches::handle_event()
1020 {
1021         Record *record = gui->record;
1022         unlock_window();
1023         record->stop_cron_thread(_("Stopped"));
1024         lock_window();
1025         return RecordBatchesGUI::StopBatches::handle_event();
1026 }
1027
1028
1029 RecordGUIActivateBatch::RecordGUIActivateBatch(RecordGUI *gui, int x, int y)
1030  : RecordBatchesGUI::ActivateBatch(gui->record->record_batches, x, y)
1031 {
1032         this->gui = gui;
1033         set_tooltip(_("Make the highlighted\nclip active."));
1034 }
1035 int RecordGUIActivateBatch::handle_event()
1036 {
1037         gui->record->activate_batch(gui->record->editing_batch());
1038         gui->update_cron_status(_("Idle"));
1039         return RecordBatchesGUI::ActivateBatch::handle_event();
1040 }
1041
1042
1043 RecordGUILabel::RecordGUILabel(RecordGUI *gui, int x, int y)
1044  : BC_GenericButton(x, y, _("Label"))
1045 {
1046         this->gui = gui;
1047         set_underline(0);
1048 }
1049
1050
1051 RecordGUILabel::~RecordGUILabel()
1052 {
1053 }
1054
1055 int RecordGUILabel::handle_event()
1056 {
1057         gui->record->toggle_label();
1058         return 1;
1059 }
1060
1061 int RecordGUILabel::keypress_event()
1062 {
1063         if( get_keypress() == *get_text() ) {
1064                 handle_event();
1065                 return 1;
1066         }
1067         return 0;
1068 }
1069
1070
1071 RecordGUIClearLabels::RecordGUIClearLabels(RecordGUI *gui, int x, int y)
1072  : BC_GenericButton(x, y, _("ClrLbls"))
1073 {
1074         this->gui = gui;
1075 }
1076
1077
1078 RecordGUIClearLabels::~RecordGUIClearLabels()
1079 {
1080 }
1081
1082 int RecordGUIClearLabels::handle_event()
1083 {
1084         gui->record->clear_labels();
1085         return 1;
1086 }
1087
1088
1089 EndRecordThread::EndRecordThread(RecordGUI *gui)
1090  : Thread(1, 0, 0)
1091 {
1092         this->gui = gui;
1093         is_ok = 0;
1094 }
1095
1096 EndRecordThread::~EndRecordThread()
1097 {
1098         if(Thread::running()) {
1099                 window->lock_window("EndRecordThread::~EndRecordThread");
1100                 window->set_done(1);
1101                 window->unlock_window();
1102         }
1103         Thread::join();
1104 }
1105
1106 void EndRecordThread::start(int is_ok)
1107 {
1108         this->is_ok = is_ok;
1109         if( gui->record->writing_file ) {
1110                 if(!running())
1111                         Thread::start();
1112         }
1113         else {
1114                 gui->set_done(!is_ok);
1115         }
1116 }
1117
1118 void EndRecordThread::run()
1119 {
1120         window = new QuestionWindow(gui->record->mwindow);
1121         window->create_objects(_("Interrupt recording in progress?"), 0);
1122         int result = window->run_window();
1123         delete window;
1124         if(result == 2) gui->set_done(!is_ok);
1125 }
1126
1127
1128 RecordStartoverThread::RecordStartoverThread(RecordGUI *gui)
1129  : Thread(1, 0, 0)
1130 {
1131         this->gui = gui;
1132 }
1133 RecordStartoverThread::~RecordStartoverThread()
1134 {
1135         if(Thread::running()) {
1136                 window->lock_window("RecordStartoverThread::~RecordStartoverThread");
1137                 window->set_done(1);
1138                 window->unlock_window();
1139         }
1140         Thread::join();
1141 }
1142
1143 void RecordStartoverThread::run()
1144 {
1145         Record *record = gui->record;
1146         window = new QuestionWindow(record->mwindow);
1147         window->create_objects(_("Rewind batch and overwrite?"), 0);
1148         int result = window->run_window();
1149         if(result == 2) record->start_over();
1150         delete window;
1151 }
1152
1153
1154 int RecordGUI::set_translation(int x, int y, float z)
1155 {
1156         record->video_x = x;
1157         record->video_y = y;
1158         record->video_zoom = z;
1159         return 0;
1160 }
1161
1162 void RecordGUI::reset_video()
1163 {
1164         total_dropped_frames = 0;
1165         status_thread->reset_video();
1166         update_framerate(record->default_asset->frame_rate);
1167 }
1168
1169 void RecordGUI::update_dropped_frames(long value)
1170 {
1171         status_thread->update_dropped_frames(value);
1172 }
1173
1174 void RecordGUI::update_frames_behind(long value)
1175 {
1176         status_thread->update_frames_behind(value);
1177 }
1178
1179 void RecordGUI::update_position(double value)
1180 {
1181         status_thread->update_position(value);
1182 }
1183
1184 void RecordGUI::update_framerate(double value)
1185 {
1186         status_thread->update_framerate(value);
1187 }
1188
1189 void RecordGUI::update_video(int dropped, int behind)
1190 {
1191         total_dropped_frames += dropped;
1192         update_dropped_frames(total_dropped_frames);
1193         update_frames_behind(behind);
1194         status_thread->update_position(record->current_display_position());
1195 }
1196
1197 void RecordGUI::reset_audio()
1198 {
1199 //      gui->lock_window("RecordAudio::run 2");
1200 // reset meter
1201         total_clipped_samples = 0;
1202         status_thread->reset_audio();
1203         AudioDevice *adevice = record->adevice;
1204         RecordMonitorGUI *window = record->record_monitor->window;
1205         window->lock_window("RecordAudio::run 2");
1206         MeterPanel *meters = window->meters;
1207         if( meters ) {
1208                 int dmix = adevice && (adevice->get_idmix() || adevice->get_odmix());
1209                 meters->init_meters(dmix);
1210         }
1211         window->unlock_window();
1212 //      gui->unlock_window();
1213 }
1214
1215 void RecordGUI::update_clipped_samples(long value)
1216 {
1217         status_thread->update_clipped_samples(value);
1218 }
1219
1220 void RecordGUI::update_audio(int channels, double *max, int *over)
1221 {
1222 // Get clipping status
1223         int clipped = 0;
1224         for( int ch=0; ch<channels && !clipped; ++ch )
1225                 if( over[ch] ) clipped = 1;
1226         if( clipped ) {
1227                 update_clipped_samples(++total_clipped_samples);
1228         }
1229 // Update meters if monitoring
1230         if( record->metering_audio ) {
1231                 RecordMonitorGUI *window = record->record_monitor->window;
1232                 window->lock_window("RecordAudio::run 1");
1233                 MeterPanel *meters = window->meters;
1234                 int nmeters = meters->meters.total;
1235                 for( int ch=0; ch<nmeters; ++ch ) {
1236                         double vmax = ch < channels ? max[ch] : 0.;
1237                         int   vover = ch < channels ? over[ch] : 0;
1238                         meters->meters.values[ch]->update(vmax, vover);
1239                 }
1240                 window->unlock_window();
1241         }
1242 // update position, if no video
1243         if( !record->default_asset->video_data )
1244                 update_position(record->current_display_position());
1245 }
1246
1247
1248 int RecordGUI::keypress_event()
1249 {
1250         return record_transport->keypress_event();
1251 }
1252
1253 void RecordGUI::update_labels(double new_position)
1254 {
1255         RecordLabel *prev, *next;
1256
1257         for(prev = record->get_current_batch()->labels->last;
1258                 prev;
1259                 prev = prev->previous) {
1260                 if(prev->position <= new_position) break;
1261         }
1262
1263         for(next = record->get_current_batch()->labels->first;
1264                 next;
1265                 next = next->next)
1266         {
1267                 if(next->position > new_position) break;
1268         }
1269
1270         if(prev)
1271                 update_title(prev_label_title, prev->position);
1272         else
1273                 update_title(prev_label_title, -1);
1274
1275 //      if(next)
1276 //              update_title(next_label_title, (double)next->position / record->default_asset->sample_rate);
1277 //      else
1278 //              update_title(next_label_title, -1);
1279 }
1280
1281
1282 int RecordGUI::update_prev_label(long new_position)
1283 {
1284         update_title(prev_label_title, new_position);
1285         return 0;
1286 }
1287
1288 // int RecordGUI::update_next_label(long new_position)
1289 // {
1290 //      update_title(next_label_title, new_position);
1291 // }
1292 //
1293 int RecordGUI::update_title(BC_Title *title, double position)
1294 {
1295         static char string[256];
1296
1297         if(position >= 0) {
1298                 Units::totext(string,
1299                                 position,
1300                                 mwindow->edl->session->time_format,
1301                                 record->default_asset->sample_rate,
1302                                 record->default_asset->frame_rate,
1303                                 mwindow->edl->session->frames_per_foot);
1304         }
1305         else {
1306                 sprintf(string, "-");
1307         }
1308         title->update(string);
1309         return 0;
1310 }
1311
1312
1313 void RecordGUI::update_cron_status(const char *status)
1314 {
1315         lock_window("RecordGUI::update_cron_status");
1316         cron_status->update(status);
1317         unlock_window();
1318 }
1319
1320 void RecordGUI::update_power_off(int value)
1321 {
1322         lock_window("RecordGUI::update_power_off");
1323         power_off->update(value);
1324         unlock_window();
1325 }
1326
1327
1328
1329
1330 // ===================================== GUI
1331 // ================================================== modes
1332
1333 RecordGUIModeTextBox::RecordGUIModeTextBox(RecordGUIModeMenu *mode_menu,
1334                 int x, int y, int w,const char *text)
1335  : BC_TextBox(x, y, w, 1, text)
1336 {
1337         this->mode_menu = mode_menu;
1338 }
1339
1340 RecordGUIModeTextBox::~RecordGUIModeTextBox()
1341 {
1342 }
1343
1344 int RecordGUIModeTextBox::handle_event()
1345 {
1346         return 0;
1347 }
1348
1349 RecordGUIModeListBox::RecordGUIModeListBox(RecordGUIModeMenu *mode_menu)
1350  : BC_ListBox(mode_menu->textbox->get_x() + mode_menu->textbox->get_w(),
1351                 mode_menu->textbox->get_y(), xS(100), yS(50), LISTBOX_TEXT,
1352                 &mode_menu->modes, 0, 0, 1, 0, 1)
1353 {
1354         this->mode_menu = mode_menu;
1355 }
1356
1357 RecordGUIModeListBox::~RecordGUIModeListBox()
1358 {
1359 }
1360
1361 int RecordGUIModeListBox::handle_event()
1362 {
1363         return mode_menu->handle_event();
1364 }
1365
1366 RecordGUIModeMenu::RecordGUIModeMenu(RecordGUI *record_gui,
1367                 int x, int y, int w,const char *text)
1368 {
1369         this->record_gui = record_gui;
1370         textbox = new RecordGUIModeTextBox(this,x, y, w, "");
1371         record_gui->add_subwindow(textbox);
1372         listbox = new RecordGUIModeListBox(this);
1373         record_gui->add_subwindow(listbox);
1374 }
1375
1376 RecordGUIModeMenu::~RecordGUIModeMenu()
1377 {
1378         for( int i=0; i<modes.total; ++i )
1379                 delete modes.values[i];
1380         delete listbox;
1381         delete textbox;
1382 }
1383
1384 void RecordGUIModeMenu::create_objects()
1385 {
1386         value = RECORD_UNTIMED;
1387         modes.append(new BC_ListBoxItem(Batch::mode_to_text(RECORD_UNTIMED)));
1388         modes.append(new BC_ListBoxItem(Batch::mode_to_text(RECORD_TIMED)));
1389         textbox->update(modes.values[value]->get_text());
1390 }
1391
1392 int RecordGUIModeMenu::handle_event()
1393 {
1394         value = listbox->get_selection_number(0, 0);
1395         textbox->update(modes.values[value]->get_text());
1396         textbox->handle_event();
1397         record_gui->record->set_record_mode(value);
1398         if( value == RECORD_TIMED )
1399                 record_gui->batch_duration->enable();
1400         else
1401                 record_gui->batch_duration->disable();
1402         return 0;
1403 }
1404
1405 void RecordGUIModeMenu::update(int value)
1406 {
1407         this->value = value;
1408         textbox->update(modes.values[value]->get_text());
1409 }
1410
1411 int RecordGUIModeMenu::get_w()
1412 {
1413         return textbox->get_w() + listbox->get_w();
1414 }
1415
1416 int RecordGUIModeMenu::get_h()
1417 {
1418         return MAX(textbox->get_h(), listbox->get_h());
1419 }
1420
1421
1422 RecordStatusThread::RecordStatusThread(MWindow *mwindow, RecordGUI *gui)
1423  : Thread(1, 0, 0)
1424 {
1425         this->mwindow = mwindow;
1426         this->gui = gui;
1427         input_lock = new Condition(0, "RecordStatusThread::input_lock");
1428         reset_video();
1429         reset_audio();
1430         window_locked = 0;
1431         done = 0;
1432 }
1433
1434 RecordStatusThread::~RecordStatusThread()
1435 {
1436         if(Thread::running())
1437         {
1438                 done = 1;
1439                 input_lock->unlock();
1440         }
1441         Thread::join();
1442         delete input_lock;
1443 }
1444
1445 void RecordStatusThread::reset_video()
1446 {
1447         new_dropped_frames = 0;
1448         displayed_dropped_frames = -1;
1449         new_frames_behind = 0;
1450         displayed_frames_behind = -1;
1451         new_position = 0;
1452         displayed_framerate = -1.;
1453         new_framerate = 0.;
1454 }
1455
1456 void RecordStatusThread::reset_audio()
1457 {
1458         new_clipped_samples = 0;
1459         displayed_clipped_samples = -1;
1460 }
1461
1462 void RecordStatusThread::update_frames_behind(long value)
1463 {
1464         if( value != displayed_frames_behind ) {
1465                 new_frames_behind = value;
1466                 input_lock->unlock();
1467         }
1468 }
1469
1470 void RecordStatusThread::update_dropped_frames(long value)
1471 {
1472         if( value != displayed_dropped_frames ) {
1473                 new_dropped_frames = value;
1474                 input_lock->unlock();
1475         }
1476 }
1477
1478 void RecordStatusThread::update_clipped_samples(long value)
1479 {
1480         if( value != displayed_clipped_samples ) {
1481                 new_clipped_samples = value;
1482                 input_lock->unlock();
1483         }
1484 }
1485
1486 void RecordStatusThread::update_position(double value)
1487 {
1488         this->new_position = value;
1489         input_lock->unlock();
1490 }
1491
1492 void RecordStatusThread::update_framerate(double value)
1493 {
1494         if( value != displayed_framerate ) {
1495                 new_framerate = value;
1496                 input_lock->unlock();
1497         }
1498 }
1499
1500 void RecordStatusThread::get_window_lock()
1501 {
1502         if( !window_locked ) {
1503                 gui->lock_window("RecordStatusThread::run 1");
1504                 window_locked = 1;
1505         }
1506 }
1507
1508 template<class T>
1509 void RecordStatusThread::
1510 update_status_string(const char *fmt, T &new_value, T &displayed_value, BC_Title *widgit)
1511 {
1512         if( new_value >= 0 ) {
1513                 if( displayed_value != new_value ) {
1514                         displayed_value = new_value;
1515                         if( widgit ) {
1516                                 char string[64];
1517                                 sprintf(string, fmt, displayed_value);
1518                                 get_window_lock();
1519                                 widgit->update(string);
1520                         }
1521                 }
1522                 new_value = -1;
1523         }
1524 }
1525
1526 void RecordStatusThread::run()
1527 {
1528         while(!done) {
1529                 input_lock->lock("RecordStatusThread::run");
1530                 if(done) break;
1531                 update_status_string("%d", new_dropped_frames, displayed_dropped_frames,
1532                                         gui->frames_dropped);
1533                 update_status_string("%d", new_frames_behind, displayed_frames_behind,
1534                                         gui->frames_behind);
1535                 update_status_string("%d", new_clipped_samples, displayed_clipped_samples,
1536                                         gui->samples_clipped);
1537                 update_status_string("%0.2f", new_framerate, displayed_framerate,
1538                                         gui->framerate);
1539                 if( new_position >= 0 ) {
1540                         get_window_lock();
1541                         gui->update_title(gui->position_title, new_position);
1542                         gui->update_labels(new_position);
1543                         new_position = -1;
1544                 }
1545                 if( window_locked ) {
1546                         gui->unlock_window();
1547                         window_locked = 0;
1548                 }
1549         }
1550 }
1551
1552
1553 void RecordGUI::start_flash_batch()
1554 {
1555         if( batch_flash ) return;
1556         batch_flash = new RecordGUIFlash(this);
1557 }
1558
1559 void RecordGUI::stop_flash_batch()
1560 {
1561         if( !batch_flash ) return;
1562         delete batch_flash;
1563         batch_flash = 0;
1564 }
1565
1566 void RecordGUI::flash_batch()
1567 {
1568         lock_window("void RecordGUI::flash_batch");
1569         int cur_batch = record->current_batch();
1570         if( cur_batch >= 0 && cur_batch < batch_bay->count()) {
1571                 flash_color = flash_color == GREEN ? RED : GREEN;
1572 //printf("RecordGUI::flash_batch %x\n", flash_color);
1573                 batch_bay->set_row_color(cur_batch, flash_color);
1574                 batch_bay->update_batch_news(cur_batch);
1575         }
1576         unlock_window();
1577 }
1578
1579 RecordGUIFlash::
1580 RecordGUIFlash(RecordGUI *record_gui)
1581  : Thread(1, 0, 0)
1582 {
1583         this->record_gui = record_gui;
1584         flash_lock = new Condition(0,"RecordGUIFlash::flash_lock");
1585         done = 0;
1586         Thread::start();
1587 }
1588
1589 RecordGUIFlash::
1590 ~RecordGUIFlash()
1591 {
1592         if( Thread::running() ) {
1593                 done = 1;
1594                 flash_lock->unlock();
1595                 Thread::cancel();
1596         }
1597         Thread::join();
1598         delete flash_lock;
1599 }
1600
1601 void RecordGUIFlash::run()
1602 {
1603         while( !done ) {
1604                 record_gui->flash_batch();
1605                 enable_cancel();
1606                 Timer::delay(500);
1607                 disable_cancel();
1608         }
1609 }
1610
1611
1612
1613 RecordGUIDCOffset::RecordGUIDCOffset(MWindow *mwindow, int y)
1614  : BC_Button(xS(230), y, mwindow->theme->calibrate_data)
1615 {
1616 }
1617
1618 RecordGUIDCOffset::~RecordGUIDCOffset() {}
1619
1620 int RecordGUIDCOffset::handle_event()
1621 {
1622         return 1;
1623 }
1624
1625 int RecordGUIDCOffset::keypress_event() { return 0; }
1626
1627 RecordGUIDCOffsetText::RecordGUIDCOffsetText(char *text, int y, int number)
1628  : BC_TextBox(xS(30), y+yS(1), xS(67), 1, text, 0)
1629 {
1630         this->number = number;
1631 }
1632
1633 RecordGUIDCOffsetText::~RecordGUIDCOffsetText()
1634 {
1635 }
1636
1637 int RecordGUIDCOffsetText::handle_event()
1638 {
1639         return 1;
1640 }
1641
1642 RecordGUIReset::RecordGUIReset(MWindow *mwindow, RecordGUI *gui, int y)
1643  : BC_Button(xS(400), y, mwindow->theme->over_button)
1644 { this->gui = gui; }
1645
1646 RecordGUIReset::~RecordGUIReset()
1647 {
1648 }
1649
1650 int RecordGUIReset::handle_event()
1651 {
1652         return 1;
1653 }
1654
1655 RecordGUIResetTranslation::RecordGUIResetTranslation(MWindow *mwindow, RecordGUI *gui, int y)
1656  : BC_Button(xS(250), y, mwindow->theme->reset_data)
1657 {
1658         this->gui = gui;
1659 }
1660
1661 RecordGUIResetTranslation::~RecordGUIResetTranslation()
1662 {
1663 }
1664
1665 int RecordGUIResetTranslation::handle_event()
1666 {
1667         gui->set_translation(0, 0, 1);
1668         return 1;
1669 }
1670