4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "audioconfig.h"
24 #include "audiodevice.h"
29 #include "playbackengine.h"
30 #include "preferences.h"
31 #include "recconfirmdelete.h"
33 #include "recordengine.h"
34 #include "recordgui.h"
35 #include "recordlabel.h"
36 #include "recordpreview.h"
37 #include "recordthread.h"
38 #include "recordmonitor.h"
40 #include "videodevice.h"
45 #define _(String) gettext(String)
46 #define gettext_noop(String) String
47 #define N_(String) gettext_noop (String)
49 RecordEngine::RecordEngine(MWindow *mwindow, Record *record)
51 this->mwindow = mwindow;
52 this->record = record;
59 RecordEngine::RecordEngine(MWindow *mwindow,
65 this->mwindow = mwindow;
66 this->record = record;
68 this->labels = labels;
78 adevice = new AudioDevice;
83 vdevice = new VideoDevice(mwindow);
88 RecordEngine::~RecordEngine()
90 delete monitor_thread;
92 delete preview_thread;
93 if(adevice) delete adevice;
94 if(vdevice) delete vdevice;
97 int RecordEngine::initialize()
99 // monitor_thread = new RecordThread(mwindow, record, this);
100 monitor_thread->create_objects();
102 // record_thread = new RecordThread(mwindow, record, this);
103 record_thread->create_objects();
105 preview_thread = new RecordPreview(record, this);
106 preview_thread->initialize();
108 // put at end of file
110 if(record->do_audio) current_position = file->get_audio_length();
112 if(record->do_video) current_position = Units::tosamples((float)(file->get_video_length(record->get_framerate())), record->get_samplerate(), record->get_framerate());
116 duplex_thread = mwindow->playback_engine;
118 // initialize seek buttons
125 current_jump_jumps[0] = 20;
126 current_jump_jumps[1] = 40;
127 current_jump_jumps[2] = 60;
128 current_jump_jumps[3] = 80;
129 current_jump_jumps[4] = 100;
133 int RecordEngine::run_script(FileXML *script)
135 int result = 0, script_result = 0;
138 while(!result && !script_result)
140 result = script->read_tag();
144 if(script->tag.title_is("set_mode"))
146 set_record_mode(script->tag.get_property_text(0));
147 mode_to_text(string, get_record_mode());
148 gui->rec_mode_menu->set_text(string);
151 if(script->tag.title_is("set_duration"))
153 record->set_loop_duration((long)record->get_samplerate() * script->tag.get_property_int(0));
154 gui->update_duration_boxes();
157 if(script->tag.title_is("start_recording"))
159 gui->unlock_window();
164 if(script->tag.title_is("set_monitor_video"))
166 set_monitor_video(script->tag.get_property_int(0));
167 if(!script->tag.get_property_int(0) && record->video_window_open)
169 record->video_window_open = 0;
170 gui->monitor_video_window->window->hide_window();
174 if(script->tag.title_is("set_monitor_audio"))
176 set_monitor_audio(script->tag.get_property_int(0));
179 if(script->tag.title_is("quit_when_completed"))
181 record_thread->quit_when_completed = 1;
184 if(script->tag.title_is("ok"))
190 return script_result;
193 // ============================================= accounting
195 long RecordEngine::get_dc_offset(int offset)
197 return record->dc_offset[offset];
200 int RecordEngine::set_dc_offset(long new_offset, int number)
202 adevice->set_dc_offset(new_offset, number);
206 long int RecordEngine::get_dc_offset(long *dc_offset, RecordGUIDCOffsetText **dc_offset_text)
208 return adevice->get_dc_offset(dc_offset, dc_offset_text);
211 int RecordEngine::set_gui(RecordGUI *gui)
214 update_position(current_position);
218 int RecordEngine::get_duplex_enable()
220 return record->enable_duplex();
225 // ================================================ operations
227 int RecordEngine::open_input_devices(int duplex)
229 int audio_opened = 0;
230 int video_opened = 0;
231 AudioConfig *aconfig /* = mwindow->preferences->aconfig */;
233 // Initialize sharing
234 if(record->do_audio && record->do_video)
236 vdevice->set_adevice(adevice);
237 adevice->set_vdevice(vdevice);
243 if(record->get_software_positioning())
244 adevice->set_software_positioning();
246 for(int i = 0; i < asset->channels; i++)
248 adevice->set_dc_offset(record->dc_offset[i], i);
253 // Duplex is only needed if the timeline and the recording have audio
256 mwindow->patches->total_playable_atracks())
258 // duplex device is identical to input device
259 if(aconfig->audio_in_driver == aconfig->audio_duplex_driver &&
260 !strcmp(aconfig->oss_in_device, aconfig->oss_duplex_device) &&
261 aconfig->oss_in_bits == aconfig->oss_duplex_bits &&
262 aconfig->oss_in_channels == aconfig->oss_duplex_channels)
264 // adevice->open_duplex(mwindow->preferences->aconfig,
265 // record->get_samplerate(),
270 // two separate devices
272 // adevice->open_output(mwindow->preferences->aconfig,
273 // record->get_samplerate(),
274 // record->get_out_length());
278 if(record->do_audio && !audio_opened)
280 // adevice->open_input(mwindow->preferences->aconfig,
281 // record->get_samplerate(),
288 // vdevice->open_input(mwindow->preferences->vconfig,
293 // record->video_zoom,
294 // get_frame_rate());
295 // vdevice->set_field_order(record->reverse_interlace);
296 // if(record->get_current_channel())
297 // vdevice->set_channel(record->get_current_channel());
298 // set_video_picture();
305 int RecordEngine::close_input_devices()
308 adevice->close_all();
310 vdevice->close_all();
315 int RecordEngine::start_monitor()
317 monitor_timer.update();
318 open_input_devices(0);
319 monitor_thread->start_recording(0, 0);
324 int RecordEngine::stop_monitor()
328 // is_monitoring = 0;
329 // monitor_thread->stop_recording();
334 int RecordEngine::pause_monitor()
339 monitor_thread->pause_recording();
344 int RecordEngine::resume_monitor()
349 monitor_timer.update();
350 open_input_devices(0);
351 monitor_thread->resume_recording();
356 int RecordEngine::start_saving(int duplex)
361 record_timer.update();
362 open_input_devices(duplex);
364 duplex = record->enable_duplex() && duplex;
366 // start the duplex engine if necessary
367 // OSS < 3.9 crashes if recording starts before playback
368 // OSS >= 3.9 crashes if playback starts before recording
372 record->get_duplex_range(&start, &end);
373 duplex_thread->reset_parameters();
374 duplex_thread->arm_playback(0, 0, 1, adevice);
375 duplex_thread->start_playback();
379 // record_thread->start_recording();
386 int RecordEngine::save_frame()
391 record_timer.update();
392 record->do_audio = 0;
393 open_input_devices(0);
395 // start the duplex engine if necessary
396 record_thread->start_recording(0, 0);
402 int RecordEngine::stop_saving(int no_monitor)
406 // automatically stops duplex here and resumes monitor
407 record_thread->stop_recording(no_monitor);
412 int RecordEngine::stop_duplex()
417 duplex_thread->stop_playback(0);
418 // OSS can't resume recording if buffers underrun
419 // so stop playback first
424 int RecordEngine::start_preview()
431 preview_timer.update();
432 open_output_devices();
433 preview_thread->start_preview(current_position, file);
440 int RecordEngine::stop_preview(int no_monitor)
444 preview_thread->stop_preview(no_monitor);
445 // preview engine automatically triggers monitor when finished
450 int RecordEngine::stop_operation(int no_monitor)
452 // Resumes monitoring after stopping
453 if(is_saving) stop_saving(no_monitor);
455 if(is_previewing) stop_preview(no_monitor);
459 int RecordEngine::set_video_picture()
461 if(record->do_video && vdevice)
462 vdevice->set_picture(record->video_brightness,
465 record->video_contrast,
466 record->video_whiteness);
470 int RecordEngine::open_output_devices()
474 // adevice->open_output(mwindow->preferences->aconfig,
475 // record->get_samplerate(),
476 // record->get_out_length());
477 if(record->get_software_positioning()) adevice->set_software_positioning();
480 // Video is already open for monitoring
484 int RecordEngine::close_output_devices()
487 adevice->close_all();
488 // Video is already open for monitoring
494 int RecordEngine::lock_window()
500 int RecordEngine::unlock_window()
502 gui->unlock_window();
506 int RecordEngine::update_position(long new_position)
508 if(new_position < 0) new_position = 0; // fread error in filepcm
509 current_position = new_position;
511 gui->update_position(new_position);
513 if(new_position > total_length)
515 total_length = new_position;
516 // gui->update_total_length(new_position);
519 if(prev_label != labels->get_prev_label(new_position))
521 prev_label = labels->get_prev_label(new_position);
522 gui->update_prev_label(prev_label);
525 if(next_label != labels->get_next_label(new_position))
527 next_label = labels->get_next_label(new_position);
529 gui->update_next_label(next_label);
534 int RecordEngine::goto_prev_label()
541 new_position = labels->goto_prev_label(current_position);
542 if(new_position != -1)
544 // if(record->do_audio) file->set_audio_position(new_position);
545 if(record->do_video) file->set_video_position(Units::toframes(new_position, record->get_samplerate(), record->get_framerate()), record->get_framerate());
546 update_position(new_position);
552 int RecordEngine::goto_next_label()
559 new_position = labels->goto_next_label(current_position);
560 if(new_position != -1 && new_position <= total_length)
562 // if(record->do_audio) file->set_audio_position(new_position);
563 if(record->do_video) file->set_video_position(Units::toframes(new_position, record->get_samplerate(), record->get_framerate()), record->get_framerate());
564 update_position(new_position);
570 int RecordEngine::toggle_label()
572 labels->toggle_label(current_position);
573 update_position(current_position);
577 int RecordEngine::calibrate_dc_offset()
581 get_dc_offset(record->dc_offset, gui->dc_offset_text);
586 int RecordEngine::calibrate_dc_offset(long new_value, int channel)
590 set_dc_offset(new_value, channel);
591 record->dc_offset[channel] = new_value;
596 int RecordEngine::reset_over()
601 int RecordEngine::set_done(int value)
605 gui->set_done(value);
609 int RecordEngine::start_over()
611 if((record->do_audio && file->get_audio_length() > 0) ||
612 (record->do_video && file->get_video_length(record->get_framerate()) > 0))
614 RecConfirmDelete dialog(mwindow);
615 dialog.create_objects(_("start over"));
616 int result = dialog.run_window();
625 // start the engine over
626 labels->delete_new_labels();
629 // gui->update_total_length(0);
631 record->startsource_sample = 0;
632 record->startsource_frame = 0;
638 int RecordEngine::change_channel(Channel *channel)
640 if(record->do_video && vdevice)
641 return vdevice->set_channel(channel);
646 ArrayList<char*>* RecordEngine::get_video_inputs()
648 if(record->do_video && vdevice)
649 return vdevice->get_inputs();
654 int RecordEngine::get_vu_format() { return record->get_vu_format(); }
655 int RecordEngine::get_dither() { return record->default_asset->dither * record->default_asset->bits; }
656 int RecordEngine::get_input_channels() { return asset->channels; }
657 int RecordEngine::get_format(char *string)
660 strcpy(string, file.formattostr(mwindow->plugindb, asset->format));
663 int RecordEngine::get_samplerate() { return asset->rate; }
664 int RecordEngine::get_bits() { return asset->bits; }
665 int RecordEngine::get_time_format() { return record->get_time_format(); }
666 float RecordEngine::get_frame_rate() { return record->get_frame_rate(); }
667 int RecordEngine::get_loop_hr() { return record->loop_duration / asset->rate / 3600; }
668 int RecordEngine::get_loop_min() { return record->loop_duration / asset->rate / 60 - (long)get_loop_hr() * 60; }
669 int RecordEngine::get_loop_sec() { return record->loop_duration / asset->rate - (long)get_loop_hr() * 3600 - (long)get_loop_min() * 60; }
670 long RecordEngine::get_loop_duration() { return record->loop_duration; }
671 float RecordEngine::get_min_db() { return record->get_min_db(); }
672 int RecordEngine::get_meter_over_hold(int divisions) { return divisions * 15; }
673 int RecordEngine::get_meter_peak_hold(int divisions) { return divisions * 2; }
674 int RecordEngine::get_meter_speed() { return record->get_meter_speed(); }
675 float RecordEngine::get_frames_per_foot() { /* return mwindow->preferences->frames_per_foot; */ }
677 int RecordEngine::set_monitor_video(int value)
682 int RecordEngine::set_monitor_audio(int value)
687 int RecordEngine::set_record_mode(char *text)
689 record->record_mode = text_to_mode(text);
693 int RecordEngine::get_record_mode(char *text)
695 mode_to_text(text, record->record_mode);
699 int RecordEngine::get_record_mode()
701 return record->record_mode;
705 int RecordEngine::mode_to_text(char *string, int mode)
709 case 0: sprintf(string, _("Untimed")); break;
710 case 1: sprintf(string, _("Timed")); break;
711 case 2: sprintf(string, _("Loop")); break;
716 int RecordEngine::text_to_mode(char *string)
718 if(!strcasecmp(string, _("Untimed"))) return 0;
719 if(!strcasecmp(string, _("Timed"))) return 1;
720 if(!strcasecmp(string, _("Loop"))) return 2;
724 long RecordEngine::get_current_delay()
726 if(current_jump_jump > 0) current_jump_jump--;
727 if(current_jump_jump == 0 && current_jump_delay < /*JUMP_DELAYS*/ 1)
729 current_jump_delay++;
730 current_jump_jump = current_jump_jumps[current_jump_delay];
732 return jump_delay[current_jump_delay];
735 int RecordEngine::reset_current_delay()
737 current_jump_delay = 0;
738 current_jump_jump = current_jump_jumps[current_jump_delay];
742 int RecordEngine::set_loop_duration()
744 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));
749 // Remember to change meters if you change this.
750 // Return the size of the fragments to read from the audio device.
751 int RecordEngine::get_in_length()
753 long fragment_size = 1;
754 while(fragment_size < asset->rate / record->get_meter_speed()) fragment_size *= 2;
756 return fragment_size;
759 // Different absolute positions are defined for each operation so threads
760 // can end at different times without screwing up the frame synchronization.
761 long RecordEngine::absolute_monitor_position()
767 // return monitor_thread->absolute_position();
771 return (long)((float)monitor_timer.get_difference() / 1000 * record->get_samplerate());
778 long RecordEngine::absolute_preview_position()
784 return preview_thread->absolute_position();
788 return (long)((float)preview_timer.get_difference() / 1000 * record->get_samplerate());
795 long RecordEngine::absolute_record_position()
801 // return record_thread->absolute_position();
805 return (long)((float)record_timer.get_difference() / 1000 * record->get_samplerate());