Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / recordengine.C
blob96de11c99d7ac214d8a12652c3e1f27ecd91f95c
1 #include "assets.h"
2 #include "audioconfig.h"
3 #include "audiodevice.h"
4 #include "file.h"
5 #include "filexml.h"
6 #include "mwindow.h"
7 #include "patchbay.h"
8 #include "playbackengine.h"
9 #include "preferences.h"
10 #include "recconfirmdelete.h"
11 #include "record.h"
12 #include "recordengine.h"
13 #include "recordgui.h"
14 #include "recordlabel.h"
15 #include "recordpreview.h"
16 #include "recordthread.h"
17 #include "recordmonitor.h"
18 #include "units.h"
19 #include "videodevice.h"
21 #include <ctype.h>
23 #include <libintl.h>
24 #define _(String) gettext(String)
25 #define gettext_noop(String) String
26 #define N_(String) gettext_noop (String)
28 RecordEngine::RecordEngine(MWindow *mwindow, Record *record)
30         this->mwindow = mwindow;
31         this->record = record;
38 RecordEngine::RecordEngine(MWindow *mwindow, 
39                         Record *record, 
40                         File *file, 
41                         Asset_GC asset, 
42                         RecordLabels *labels)
44         this->mwindow = mwindow;
45         this->record = record; 
46         this->file = file; 
47         this->labels = labels; 
48         this->asset = asset;
49         is_saving = 0;
50         is_previewing = 0;
51         is_duplexing = 0;
52         is_monitoring = 0;
53         prev_label = -1;
54         next_label = -1;
56         if(record->do_audio)
57                 adevice = new AudioDevice; 
58         else 
59                 adevice = 0;
61         if(record->do_video)
62                 vdevice = new VideoDevice(mwindow); 
63         else 
64                 vdevice = 0;
67 RecordEngine::~RecordEngine()
69         delete monitor_thread;
70         delete record_thread;
71         delete preview_thread;
72         if(adevice) delete adevice;
73         if(vdevice) delete vdevice;
76 int RecordEngine::initialize()
78 //      monitor_thread = new RecordThread(mwindow, record, this);
79         monitor_thread->create_objects();
80         
81 //      record_thread = new RecordThread(mwindow, record, this);
82         record_thread->create_objects();
84         preview_thread = new RecordPreview(record, this);
85         preview_thread->initialize();
87 // put at end of file
88         total_length = -1;
89         if(record->do_audio) current_position = file->get_audio_length();
90         else
91         if(record->do_video) current_position = Units::tosamples((float)(file->get_video_length(record->get_framerate())), record->get_samplerate(), record->get_framerate());
93         file->seek_end();
95         duplex_thread = mwindow->playback_engine;
97 // initialize seek buttons
98         jump_delay[0] = 100;
99         jump_delay[1] = 50;
100         jump_delay[2] = 25;
101         jump_delay[3] = 10;
102         jump_delay[4] = 5;
104         current_jump_jumps[0] = 20;
105         current_jump_jumps[1] = 40;
106         current_jump_jumps[2] = 60;
107         current_jump_jumps[3] = 80;
108         current_jump_jumps[4] = 100;
111 int RecordEngine::run_script(FileXML *script)
113         int result = 0, script_result = 0;
114         char string[1024];
116         while(!result && !script_result)
117         {
118                 result = script->read_tag();
120                 if(!result)
121                 {
122                         if(script->tag.title_is("set_mode"))
123                         {
124                                 set_record_mode(script->tag.get_property_text(0));
125                                 mode_to_text(string, get_record_mode());
126                                 gui->rec_mode_menu->set_text(string);
127                         }
128                         else
129                         if(script->tag.title_is("set_duration"))
130                         {
131                                 record->set_loop_duration((long)record->get_samplerate() * script->tag.get_property_int(0));
132                                 gui->update_duration_boxes();
133                         }
134                         else
135                         if(script->tag.title_is("start_recording"))
136                         {
137                                 gui->unlock_window();
138                                 start_saving();
139                                 gui->lock_window();
140                         }
141                         else
142                         if(script->tag.title_is("set_monitor_video"))
143                         {
144                                 set_monitor_video(script->tag.get_property_int(0));
145                                 if(!script->tag.get_property_int(0) && record->video_window_open)
146                                 {
147                                         record->video_window_open = 0;
148                                         gui->monitor_video_window->window->hide_window();
149                                 }
150                         }
151                         else
152                         if(script->tag.title_is("set_monitor_audio"))
153                         {
154                                 set_monitor_audio(script->tag.get_property_int(0));
155                         }
156                         else
157                         if(script->tag.title_is("quit_when_completed"))
158                         {
159                                 record_thread->quit_when_completed = 1;
160                         }
161                         else
162                         if(script->tag.title_is("ok"))
163                         {
164                                 script_result = 1;
165                         }
166                 }
167         }
168         return script_result;
171 // ============================================= accounting
173 long RecordEngine::get_dc_offset(int offset)
175         return record->dc_offset[offset];
178 int RecordEngine::set_dc_offset(long new_offset, int number)
180         adevice->set_dc_offset(new_offset, number);
183 long int RecordEngine::get_dc_offset(long *dc_offset, RecordGUIDCOffsetText **dc_offset_text)
185         return adevice->get_dc_offset(dc_offset, dc_offset_text);
188 int RecordEngine::set_gui(RecordGUI *gui)
190         this->gui = gui;
191         update_position(current_position);
194 int RecordEngine::get_duplex_enable()
196         return record->enable_duplex();
201 // ================================================ operations
203 int RecordEngine::open_input_devices(int duplex)
205         int audio_opened = 0;
206         int video_opened = 0;
207         AudioConfig *aconfig /* = mwindow->preferences->aconfig */;
209 // Initialize sharing
210         if(record->do_audio && record->do_video)
211         {
212                 vdevice->set_adevice(adevice);
213                 adevice->set_vdevice(vdevice);
214         }
216 // Initialize audio
217         if(record->do_audio)
218         {
219                 if(record->get_software_positioning()) 
220                         adevice->set_software_positioning();
222                 for(int i = 0; i < asset->channels; i++)
223                 {
224                         adevice->set_dc_offset(record->dc_offset[i], i);
225                 }
226         }
229 // Duplex is only needed if the timeline and the recording have audio
230         if(duplex &&
231                 record->do_audio && 
232                 mwindow->patches->total_playable_atracks())
233         {
234 // duplex device is identical to input device
235                 if(aconfig->audio_in_driver == aconfig->audio_duplex_driver &&
236                         !strcmp(aconfig->oss_in_device, aconfig->oss_duplex_device) &&
237                         aconfig->oss_in_bits == aconfig->oss_duplex_bits &&
238                         aconfig->oss_in_channels == aconfig->oss_duplex_channels)
239                 {
240 //                      adevice->open_duplex(mwindow->preferences->aconfig, 
241 //                                              record->get_samplerate(), 
242 //                                              get_in_length());
243                         audio_opened = 1;
244                 }
245                 else
246 // two separate devices
247                 {
248 //                      adevice->open_output(mwindow->preferences->aconfig, 
249 //                                      record->get_samplerate(), 
250 //                                      record->get_out_length());
251                 }
252         }
254         if(record->do_audio && !audio_opened)
255         {
256 //              adevice->open_input(mwindow->preferences->aconfig, 
257 //                              record->get_samplerate(), 
258 //                              get_in_length());
259         }
261 // Initialize video
262         if(record->do_video)
263         {
264 //              vdevice->open_input(mwindow->preferences->vconfig, 
265 //                      record->frame_w, 
266 //                      record->frame_h,
267 //                      record->video_x, 
268 //                      record->video_y, 
269 //                      record->video_zoom,
270 //                      get_frame_rate());
271 //              vdevice->set_field_order(record->reverse_interlace);
272 //              if(record->get_current_channel())
273 //                      vdevice->set_channel(record->get_current_channel());
274 //              set_video_picture();
275         }
277         return 0;
281 int RecordEngine::close_input_devices()
283         if(record->do_audio)
284                 adevice->close_all();
285         if(record->do_video)
286                 vdevice->close_all();
288         return 0;
291 int RecordEngine::start_monitor()
293         monitor_timer.update();
294         open_input_devices(0);
295         monitor_thread->start_recording(0, 0);
296         is_monitoring = 1;
297         return 0;
300 int RecordEngine::stop_monitor()
302 //      if(is_monitoring)
303 //      {
304 //              is_monitoring = 0;
305 //              monitor_thread->stop_recording();
306 //      }
307         return 0;
310 int RecordEngine::pause_monitor()
312         if(is_monitoring)
313         {
314                 is_monitoring = 0;
315                 monitor_thread->pause_recording();
316         }
317         return 0;
320 int RecordEngine::resume_monitor()
322         if(!is_monitoring)
323         {
324                 is_monitoring = 1;
325                 monitor_timer.update();
326                 open_input_devices(0);
327                 monitor_thread->resume_recording();
328         }
329         return 0;
332 int RecordEngine::start_saving(int duplex)
334         if(!is_saving)
335         {
336                 pause_monitor();
337                 record_timer.update();
338                 open_input_devices(duplex);
340                 duplex = record->enable_duplex() && duplex;
342 // start the duplex engine if necessary
343 // OSS < 3.9 crashes if recording starts before playback
344 // OSS >= 3.9 crashes if playback starts before recording
345                 if(duplex)
346                 {
347                         long start, end;
348                         record->get_duplex_range(&start, &end);
349                         duplex_thread->reset_parameters();
350                         duplex_thread->arm_playback(0, 0, 1, adevice);
351                         duplex_thread->start_playback();
352                         is_duplexing = 1;
353                 }
355 //              record_thread->start_recording();
357                 is_saving = 1;
358         }
359         return 0;
362 int RecordEngine::save_frame()
364         if(!is_saving)
365         {
366                 pause_monitor();
367                 record_timer.update();
368                 record->do_audio = 0;
369                 open_input_devices(0);
371 // start the duplex engine if necessary
372                 record_thread->start_recording(0, 0);
373                 is_saving = 1;
374         }
375         return 0;
378 int RecordEngine::stop_saving(int no_monitor)
380         if(is_saving)
381         {
382 // automatically stops duplex here and resumes monitor
383                 record_thread->stop_recording(no_monitor); 
384         }
385         return 0;
388 int RecordEngine::stop_duplex()
390         if(is_duplexing)
391         {
392                 is_duplexing = 0;
393                 duplex_thread->stop_playback(0);
394 // OSS can't resume recording if buffers underrun
395 // so stop playback first
396         }
397         return 0;
400 int RecordEngine::start_preview()
402         if(!is_previewing)
403         {
404                 stop_operation();
405                 pause_monitor();
407                 preview_timer.update();
408                 open_output_devices();
409                 preview_thread->start_preview(current_position, file);
411                 is_previewing = 1;
412         }
413         return 0;
416 int RecordEngine::stop_preview(int no_monitor)
418         if(is_previewing)
419         {
420                 preview_thread->stop_preview(no_monitor);
421 // preview engine automatically triggers monitor when finished
422         }
423         return 0;
426 int RecordEngine::stop_operation(int no_monitor)
428 // Resumes monitoring after stopping
429         if(is_saving) stop_saving(no_monitor);
430         else
431         if(is_previewing) stop_preview(no_monitor);
432         return 0;
435 int RecordEngine::set_video_picture()
437         if(record->do_video && vdevice) 
438                 vdevice->set_picture(record->video_brightness,
439                         record->video_hue,
440                         record->video_color,
441                         record->video_contrast,
442                         record->video_whiteness);
443         return 0;
446 int RecordEngine::open_output_devices()
448         if(record->do_audio)
449         {
450 //              adevice->open_output(mwindow->preferences->aconfig, 
451 //                              record->get_samplerate(), 
452 //                              record->get_out_length());
453                 if(record->get_software_positioning()) adevice->set_software_positioning();
454         }
456 // Video is already open for monitoring
457         return 0;
460 int RecordEngine::close_output_devices()
462         if(record->do_audio)
463                 adevice->close_all();
464 // Video is already open for monitoring
465         return 0;
470 int RecordEngine::lock_window()
472         gui->lock_window();
475 int RecordEngine::unlock_window()
477         gui->unlock_window();
480 int RecordEngine::update_position(long new_position)
482         if(new_position < 0) new_position = 0;      // fread error in filepcm
483         current_position = new_position;
484         
485         gui->update_position(new_position);
487         if(new_position > total_length) 
488         {
489                 total_length = new_position;
490 //              gui->update_total_length(new_position);
491         }
492         
493         if(prev_label != labels->get_prev_label(new_position))
494         {
495                 prev_label = labels->get_prev_label(new_position);
496                 gui->update_prev_label(prev_label);
497         }
498         
499         if(next_label != labels->get_next_label(new_position))
500         {
501                 next_label = labels->get_next_label(new_position);
503                 gui->update_next_label(next_label);
504         }
507 int RecordEngine::goto_prev_label()
509         if(!is_saving)
510         {
511                 stop_operation();
512                 long new_position;
514                 new_position = labels->goto_prev_label(current_position);
515                 if(new_position != -1)
516                 {
517 //                      if(record->do_audio) file->set_audio_position(new_position);
518                         if(record->do_video) file->set_video_position(Units::toframes(new_position, record->get_samplerate(), record->get_framerate()), record->get_framerate());
519                         update_position(new_position);
520                 }
521         }
524 int RecordEngine::goto_next_label()
526         if(!is_saving)
527         {
528                 stop_operation();
529                 long new_position;
531                 new_position = labels->goto_next_label(current_position);
532                 if(new_position != -1 && new_position <= total_length)
533                 {
534 //                      if(record->do_audio) file->set_audio_position(new_position);
535                         if(record->do_video) file->set_video_position(Units::toframes(new_position, record->get_samplerate(), record->get_framerate()), record->get_framerate());
536                         update_position(new_position);
537                 }
538         }
539         return 0;
542 int RecordEngine::toggle_label()
544         labels->toggle_label(current_position);
545         update_position(current_position);
546         return 0;
549 int RecordEngine::calibrate_dc_offset()
551         if(record->do_audio)
552         {
553                 get_dc_offset(record->dc_offset, gui->dc_offset_text);
554         }
555         return 0;
558 int RecordEngine::calibrate_dc_offset(long new_value, int channel)
560         if(record->do_audio)
561         {
562                 set_dc_offset(new_value, channel);
563                 record->dc_offset[channel] = new_value;
564         }
565         return 0;
568 int RecordEngine::reset_over()
572 int RecordEngine::set_done(int value)
574         stop_operation(1);
575         stop_monitor();
576         gui->set_done(value);
579 int RecordEngine::start_over()
581         if((record->do_audio && file->get_audio_length() > 0) ||
582                 (record->do_video && file->get_video_length(record->get_framerate()) > 0))
583         {
584                 RecConfirmDelete dialog(mwindow);
585                 dialog.create_objects("start over");
586                 int result = dialog.run_window();
587                 if(!result)
588                 {
589                         stop_operation();
590 // remove file
591                         file->close_file();
592                         remove(asset->path);
594 // reopen file
595 //                      file->set_processors(mwindow->preferences->smp ? 2: 1);
596 //                      file->set_preload(mwindow->preferences->playback_preload);
597 //                      file->try_to_open_file(mwindow->plugindb, asset, 1, 1);
599 // start the engine over
600                         labels->delete_new_labels();
601                         update_position(0);
602                         total_length = 0;
603 //                      gui->update_total_length(0);
605                         record->startsource_sample = 0;
606                         record->startsource_frame = 0;
607                 }
608         }
611 int RecordEngine::change_channel(Channel *channel)
613         if(record->do_video && vdevice) 
614                 return vdevice->set_channel(channel);
615         else
616                 return 0;
619 ArrayList<char*>* RecordEngine::get_video_inputs() 
621         if(record->do_video && vdevice) 
622                 return vdevice->get_inputs();
623         else
624                 return 0;
627 int RecordEngine::get_vu_format() { return record->get_vu_format(); }
628 int RecordEngine::get_dither() { return record->default_asset->dither * record->default_asset->bits; }
629 int RecordEngine::get_input_channels() { return asset->channels; }
630 int RecordEngine::get_format(char *string)
632         File file;
633         strcpy(string, file.formattostr(mwindow->plugindb, asset->format)); 
635 int RecordEngine::get_samplerate() { return asset->rate; }
636 int RecordEngine::get_bits() { return asset->bits; }
637 int RecordEngine::get_time_format() { return record->get_time_format(); }
638 float RecordEngine::get_frame_rate() { return record->get_frame_rate(); }
639 int RecordEngine::get_loop_hr() { return record->loop_duration / asset->rate / 3600; }
640 int RecordEngine::get_loop_min() { return record->loop_duration / asset->rate / 60 - (long)get_loop_hr() * 60; }
641 int RecordEngine::get_loop_sec() { return record->loop_duration / asset->rate - (long)get_loop_hr() * 3600 - (long)get_loop_min() * 60; }
642 long RecordEngine::get_loop_duration() { return record->loop_duration; }
643 float RecordEngine::get_min_db() { return record->get_min_db(); }
644 int RecordEngine::get_meter_over_hold(int divisions) { return divisions * 15; }
645 int RecordEngine::get_meter_peak_hold(int divisions) { return divisions * 2; }
646 int RecordEngine::get_meter_speed() { return record->get_meter_speed(); }
647 float RecordEngine::get_frames_per_foot() { /* return mwindow->preferences->frames_per_foot; */ }
649 int RecordEngine::set_monitor_video(int value)
653 int RecordEngine::set_monitor_audio(int value)
657 int RecordEngine::set_record_mode(char *text)
659         record->record_mode = text_to_mode(text);
662 int RecordEngine::get_record_mode(char *text)
664         mode_to_text(text, record->record_mode);
667 int RecordEngine::get_record_mode()
669         return record->record_mode;
672 int RecordEngine::mode_to_text(char *string, int mode)
674         switch(mode)
675         {
676                 case 0:        sprintf(string, _("Untimed"));       break;
677                 case 1:        sprintf(string, _("Timed"));         break;
678                 case 2:        sprintf(string, _("Loop"));          break;
679         }
682 int RecordEngine::text_to_mode(char *string)
684         if(!strcasecmp(string, _("Untimed"))) return 0;
685         if(!strcasecmp(string, _("Timed")))   return 1;
686         if(!strcasecmp(string, _("Loop")))    return 2;
689 long RecordEngine::get_current_delay()
691         if(current_jump_jump > 0) current_jump_jump--;
692         if(current_jump_jump == 0 && current_jump_delay < /*JUMP_DELAYS*/ 1)
693         {
694                 current_jump_delay++;
695                 current_jump_jump = current_jump_jumps[current_jump_delay];
696         }
697         return jump_delay[current_jump_delay];
700 int RecordEngine::reset_current_delay()
702         current_jump_delay = 0;
703         current_jump_jump = current_jump_jumps[current_jump_delay];
706 int RecordEngine::set_loop_duration() 
708         record->set_loop_duration((long)record->get_samplerate() * (atol(gui->loop_sec->get_text()) + atol(gui->loop_min->get_text()) * 60 + atol(gui->loop_hr->get_text()) * 3600)); 
712 // Remember to change meters if you change this.
713 // Return the size of the fragments to read from the audio device.
714 int RecordEngine::get_in_length() 
716         long fragment_size = 1;
717         while(fragment_size < asset->rate / record->get_meter_speed()) fragment_size *= 2;
718         fragment_size /= 2;
719         return fragment_size;
722 // Different absolute positions are defined for each operation so threads
723 // can end at different times without screwing up the frame synchronization.
724 long RecordEngine::absolute_monitor_position()
726         if(is_monitoring)
727         {
728                 if(record->do_audio)
729                 {
730 //                      return monitor_thread->absolute_position();
731                 }
732                 else
733                 {
734                         return (long)((float)monitor_timer.get_difference() / 1000 * record->get_samplerate());
735                 }
736         }
737         else
738         return -1;
741 long RecordEngine::absolute_preview_position()
743         if(is_previewing)
744         {
745                 if(record->do_audio)
746                 {
747                         return preview_thread->absolute_position();
748                 }
749                 else
750                 {
751                         return (long)((float)preview_timer.get_difference() / 1000 * record->get_samplerate());
752                 }
753         }
754         else
755         return -1;
758 long RecordEngine::absolute_record_position()
760         if(is_saving)
761         {
762                 if(record->do_audio)
763                 {
764 //                      return record_thread->absolute_position();
765                 }
766                 else
767                 {
768                         return (long)((float)record_timer.get_difference() / 1000 * record->get_samplerate());
769                 }
770         }
771         else
772         return -1;
776 //      Local Variables:
777 //      mode: C++
778 //      c-file-style: "linux"
779 //      End: