r1009: Move the dependencies to newer package names
[cinelerra_cv/mob.git] / cinelerra / recordaudio.C
blob740ea949dae6a29470d144697ec35a7922e96cfe
1 #include "asset.h"
2 #include "audiodevice.h"
3 #include "batch.h"
4 #include "bcsignals.h"
5 #include "clip.h"
6 #include "condition.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "errorbox.h"
10 #include "file.h"
11 #include "filethread.h"
12 #include "language.h"
13 #include "meterpanel.h"
14 #include "mutex.h"
15 #include "mwindow.h"
16 #include "mwindowgui.h"
17 #include "preferences.h"
18 #include "record.h"
19 #include "recordaudio.h"
20 #include "recordgui.h"
21 #include "recordengine.h"
22 #include "recordmonitor.h"
23 #include "recordthread.h"
24 #include "renderengine.h"
28 RecordAudio::RecordAudio(MWindow *mwindow,
29                                 Record *record, 
30                                 RecordThread *record_thread)
31  : Thread(1, 0, 0)
33         this->mwindow = mwindow;
34         this->record = record;
35         this->record_thread = record_thread; 
36         this->gui = record->record_gui;
37         fragment_position = 0;
38         timer_lock = new Mutex("RecordAudio::timer_lock");
39         trigger_lock = new Condition(1, "RecordAudio::trigger_lock");
42 RecordAudio::~RecordAudio()
44         delete timer_lock;
45         delete trigger_lock;
48 void RecordAudio::reset_parameters()
50         fragment_position = 0;
51         batch_done = 0;
55 int RecordAudio::arm_recording()
57         reset_parameters();
58 // Fudge buffer sizes
59         record->get_audio_write_length(buffer_size, fragment_size);
60         record_channels = record->default_asset->channels;
62 // Realtime is set in the audio driver
63 //      if(mwindow->edl->session->real_time_record) Thread::set_realtime();
65         timer.update();
66         trigger_lock->lock("RecordAudio::arm_recording");
67         Thread::start();
70 void RecordAudio::start_recording()
72         trigger_lock->unlock();
75 int RecordAudio::stop_recording()
77 // Device won't exist if interrupting a cron job
78         if(record->adevice)
79         {
80                 record->adevice->interrupt_crash();
81 // Joined in RecordThread
82                 //Thread::join();
83         }
84         return 0;
87 void RecordAudio::run()
89         int channel, buffer;
90         Timer delayer;
91         int total_clipped_samples = 0;
92         int clipped_sample = 0;
93         write_result = 0;
94         grab_result = 0;
96 //printf("RecordAudio::run 1 %d\n", Thread::calculate_realtime());
97         over = new int[record_channels];
98         max = new double[record_channels];
100 // thread out I/O
101         if(!record_thread->monitor)
102         {
103 // Get a buffer from the file to record into.
104                 input = record->file->get_audio_buffer();
105         }
106         else
107         {
108 // Make up a fake buffer.
109                 input = new double*[record_channels];
111                 for(int i = 0; i < record_channels; i++)
112                 {
113                         input[i] = new double[buffer_size];
114                 }
115         }
117 //printf("RecordAudio::run 1\n");
118         gui->total_clipped_samples = 0;
119         gui->update_clipped_samples(0);
122 // Wait for trigger
123         trigger_lock->lock("RecordAudio::run");
124         trigger_lock->unlock();
127 //printf("RecordAudio::run 2\n");
128         while(!batch_done && 
129                 !write_result)
130         {
131 // Handle data from the audio device.
132 //printf("RecordAudio::run 3\n");
133                         if(!record_thread->monitor)
134                         {
135 // Read into file's buffer for recording.
136 // device needs to write buffer starting at fragment position
137 //printf("RecordAudio::run 2.1\n");
138                                 grab_result = record->adevice->read_buffer(input, 
139                                         fragment_size, 
140                                         over, 
141                                         max, 
142                                         fragment_position);
143 //printf("RecordAudio::run 2.2\n");
144                         }
145                         else
146                         {
147 // Read into monitor buffer for monitoring.
148 //printf("RecordAudio::run 1\n");
149                                 grab_result = record->adevice->read_buffer(input, 
150                                         fragment_size, 
151                                         over, 
152                                         max, 
153                                         0);
154 //printf("RecordAudio::run 2 %d\n", grab_result);
155                         }
156 //printf("RecordAudio::run 3 %d %f\n", fragment_size, max);
158 // Update timer for synchronization
159                         timer_lock->lock("RecordAudio::run");
160                         
161                         if(!record_thread->monitor)
162                         {
163                                 record->get_current_batch()->current_sample += fragment_size;
164                                 record->get_current_batch()->total_samples = 
165                                         MAX(record->get_current_batch()->current_sample, record->get_current_batch()->total_samples);
166                         }
168                         record->get_current_batch()->session_samples += fragment_size;
169                         timer.update();
170                         timer_lock->unlock();
172 //printf("RecordAudio::run 2\n");
173 // Get clipping status
174                         if(record->monitor_audio || !record_thread->monitor)
175                         {
176                                 clipped_sample = 0;
177                                 for(channel = 0; channel < record_channels; channel++)
178                                 {
179                                         if(over[channel]) clipped_sample = 1;
180                                 }
181                         }
183 // Update meters if monitoring
184 //printf("RecordAudio::run 2 %d %d %d %d\n", record->monitor_audio, record_thread->batch_done(), record_thread->loop_done(), grab_result);
185                         if(record->monitor_audio && 
186                                 !batch_done && 
187                                 !grab_result)
188                         {
189                                 record->record_monitor->window->lock_window("RecordAudio::run 1");
190                                 for(channel = 0; channel < record_channels; channel++)
191                                 {
192                                         record->record_monitor->window->meters->meters.values[channel]->update(
193                                                 max[channel], 
194                                                 over[channel]);
195                                 }
196                                 record->record_monitor->window->unlock_window();
197                         }
200 //printf("RecordAudio::run 2\n");
201 // Write file if writing
202                         if(!record_thread->monitor)
203                         {
204                                 fragment_position += fragment_size;
206                                 if(fragment_position >= buffer_size)
207                                 {
208                                         write_buffer(0);
209                                 }
212 //printf("RecordAudio::run 2 %f\n", record->current_display_position());
213                                 if(!record->default_asset->video_data) 
214                                         gui->update_position(record->current_display_position());
215                                 if(clipped_sample) 
216                                         gui->update_clipped_samples(++total_clipped_samples);
218                                 if(!record_thread->monitor && 
219                                         !batch_done && 
220                                         !write_result && 
221                                         !record->default_asset->video_data)
222                                 {
223 // handle different recording modes
224                                         switch(record->get_current_batch()->record_mode)
225                                         {
226                                                 case RECORD_TIMED:
227                                                         if(record->current_display_position() > *record->current_duration())
228                                                                 batch_done = 1;
229                                                         break;
230                                                 case RECORD_LOOP:
231                                                         if(record->current_display_position() > *record->current_duration())
232                                                                 batch_done = 1;
233                                                         break;
234                                                 case RECORD_SCENETOSCENE:
235                                                         break;
236                                         }
237                                 }
238                         }
239 //printf("RecordAudio::run 4 %d %d\n", batch_done, write_result);
240         }
242 TRACE("RecordAudio::run 4");
243         if(write_result && !record->default_asset->video_data)
244         {
245                 ErrorBox error_box(PROGRAM_NAME ": Error",
246                         mwindow->gui->get_abs_cursor_x(1),
247                         mwindow->gui->get_abs_cursor_y(1));
248                 error_box.create_objects(_("No space left on disk."));
249                 error_box.run_window();
250                 batch_done = 1;
251         }
252 TRACE("RecordAudio::run 10");
254         if(!record_thread->monitor)
255         {
256 // write last buffer
257                 write_buffer(1);
258         }
259         else
260         {
261 // Delete the fake buffer.
262                 for(int i = 0; i < record_channels; i++)
263                 {
264                         record->record_monitor->window->meters->meters.values[i]->reset();
265                         delete [] input[i];
266                 }
267                 delete [] input;
268                 input = 0;
269         }
270 TRACE("RecordAudio::run 11");
272 // reset meter
273         gui->lock_window("RecordAudio::run 2");
274         for(channel = 0; channel < record_channels; channel++)
275         {
276                 record->record_monitor->window->meters->meters.values[channel]->reset();
277         }
278 TRACE("RecordAudio::run 12");
280         gui->unlock_window();
281         delete [] max;
282         delete [] over;
283 TRACE("RecordAudio::run 100");
286 void RecordAudio::write_buffer(int skip_new)
288 // block until buffer is ready for writing
289         write_result = record->file->write_audio_buffer(fragment_position);
290 // Defeat errors if video
291         if(record->default_asset->video_data) write_result = 0;
292         fragment_position = 0;
293         if(!skip_new && !write_result) input = record->file->get_audio_buffer();
296 int64_t RecordAudio::sync_position()
298         int64_t result;
299         if(!batch_done)
300         {
301 //printf("RecordAudio::sync_position 1\n");
302                 timer_lock->lock("RecordAudio::sync_position");
303                 if(!mwindow->edl->session->record_software_position)
304                 {
305 //printf("RecordAudio::sync_position 1\n");
306                         result = record->adevice->current_position();
307                 }
308                 else
309                 {
310 //printf("RecordAudio::sync_position 1 %d\n", record->get_current_batch()->session_samples);
311                         result = record->get_current_batch()->session_samples +
312                                 timer.get_scaled_difference(record->default_asset->sample_rate);
313                 }
314                 timer_lock->unlock();
315 //printf("RecordAudio::sync_position 2\n");
316                 return result;
317         }
318         else
319         return -1;