r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / cinelerra / arender.C
blob3b719a60d38003763dbe6e32bb547c6483091a3f
1 #include "amodule.h"
2 #include "arender.h"
3 #include "atrack.h"
4 #include "atrack.h"
5 #include "audiodevice.h"
6 #include "auto.h"
7 #include "autos.h"
8 #include "cache.h"
9 #include "condition.h"
10 #include "edit.h"
11 #include "edl.h"
12 #include "edlsession.h"
13 #include "levelwindow.h"
14 #include "mainsession.h"
15 #include "playabletracks.h"
16 #include "playbackengine.h"
17 #include "preferences.h"
18 #include "renderengine.h"
19 #include "tracks.h"
20 #include "transportque.h"
21 #include "virtualaconsole.h"
22 #include "virtualconsole.h"
23 #include "virtualnode.h"
25 ARender::ARender(RenderEngine *renderengine)
26  : CommonRender(renderengine)
28 // Clear output buffers
29         for(int i = 0; i < MAXCHANNELS; i++)
30         {
31                 audio_out[i] = 0;
32                 level_history[i] = 0;
33         }
34         level_samples = 0;
35         total_peaks = 0;
37         data_type = TRACK_AUDIO;
40 ARender::~ARender()
42         for(int i = 0; i < MAXCHANNELS; i++)
43         {
44                 if(audio_out[i]) delete [] audio_out[i];
45                 if(level_history[i]) delete [] level_history[i];
46         }
47         if(level_samples) delete [] level_samples;
50 void ARender::arm_command()
52 // Need the meter history now so AModule can allocate its own history
53         calculate_history_size();
54         CommonRender::arm_command();
55         asynchronous = 1;
56         init_meters();
60 int ARender::get_total_tracks()
62         return renderengine->edl->tracks->total_audio_tracks();
65 Module* ARender::new_module(Track *track)
67         return new AModule(renderengine, this, 0, track);
70 int ARender::calculate_history_size()
72         if(total_peaks > 0)
73                 return total_peaks;
74         else
75         {
76                 meter_render_fragment = renderengine->fragment_len;
77 // This number and the timer in tracking.C determine the rate
78                 while(meter_render_fragment > 
79                         renderengine->edl->session->sample_rate / TRACKING_RATE) 
80                         meter_render_fragment /= 2;
81                 total_peaks = 16 * 
82                         renderengine->fragment_len / 
83                         meter_render_fragment;
84                 return total_peaks;
85         }
88 int ARender::init_meters()
90 // not providing enough peaks results in peaks that are ahead of the sound
91         if(level_samples) delete [] level_samples;
92         calculate_history_size();
93         level_samples = new int64_t[total_peaks];
94         for(int i = 0; i < MAXCHANNELS;i++)
95         {
96                 current_level[i] = 0;
97                 if(audio_out[i] && !level_history[i]) level_history[i] = new double[total_peaks];
98         }
100         for(int i = 0; i < total_peaks; i++)
101         {
102                 level_samples[i] = -1;
103         }
104         
105         for(int j = 0; j < MAXCHANNELS; j++)
106         {
107                 if(audio_out[j]) 
108                         for(int i = 0; i < total_peaks; i++)
109                                 level_history[j][i] = 0;
110         }
111         return 0;
114 void ARender::init_output_buffers()
116         if(renderengine->command->realtime)
117         {
118                 for(int i = 0; i < MAXCHANNELS; i++)
119                 {
120 // Reset the output buffers in case speed changed
121                         if(audio_out[i])
122                         {
123                                 delete [] audio_out[i];
124                                 audio_out[i] = 0;
125                         }
127                         if(renderengine->config->aconfig->do_channel[i])
128                         {
129                                 audio_out[i] = new double[renderengine->adjusted_fragment_len];
130                         }
131                 }
132         }
136 VirtualConsole* ARender::new_vconsole_object() 
138         return new VirtualAConsole(renderengine, this);
141 int64_t ARender::tounits(double position, int round)
143         if(round)
144                 return Units::round(position * renderengine->edl->session->sample_rate);
145         else
146                 return (int64_t)(position * renderengine->edl->session->sample_rate);
149 double ARender::fromunits(int64_t position)
151         return (double)position / renderengine->edl->session->sample_rate;
155 int ARender::process_buffer(double **buffer_out, 
156         int64_t input_len, 
157         int64_t input_position, 
158         int last_buffer)
160         int result = 0;
162         this->last_playback = last_buffer;
163         int64_t fragment_position = 0;
164         int64_t fragment_len = input_len;
165         int reconfigure = 0;
166         current_position = input_position;
168         while(fragment_position < input_len)
169         {
170                 for(int i = 0; i < MAXCHANNELS; i++)
171                 {
172                         if(buffer_out[i])
173                                 this->audio_out[i] = buffer_out[i] + fragment_position;
174                         else
175                                 this->audio_out[i] = 0;
176                 }
178                 fragment_len = input_len;
179                 if(fragment_position + fragment_len > input_len)
180                         fragment_len = input_len - fragment_position;
182                 reconfigure = vconsole->test_reconfigure(input_position, 
183                         fragment_len,
184                         last_playback);
186 //printf("ARender::process_buffer 1 %lld %d\n", input_position, reconfigure);
188                 if(reconfigure) restart_playback();
190                 result = process_buffer(fragment_len, input_position);
192                 fragment_position += fragment_len;
193                 input_position += fragment_len;
194                 current_position = input_position;
195         }
197 // Don't delete audio_out on completion
198         bzero(this->audio_out, sizeof(double*) * MAXCHANNELS);
202         return result;
203         return 0;
207 int ARender::process_buffer(int64_t input_len, int64_t input_position)
209         int result = ((VirtualAConsole*)vconsole)->process_buffer(input_len,
210                 input_position,
211                 last_playback,
212                 session_position);
216 // advance counters
217         session_position += input_len;
218         return result;
221 // int ARender::restart_playback()
222 // {
223 // // Use for rebuilding the virtual console during playback.
224 // // Send last buffer to old thread.
225 //      if(vconsole)
226 //      {
227 //              send_reconfigure_buffer();
228 //              vconsole->wait_for_completion();
229 //      }
230 // 
231 //      CommonRender::restart_playback();
232 //      return 0;
233 // }
235 int ARender::get_history_number(int64_t *table, int64_t position)
237 // Get the entry closest to position
238         int result = 0;
239         int64_t min_difference = 0x7fffffff;
240         for(int i = 0; i < total_peaks; i++)
241         {
242 //printf("%d %d ", i, table[i]);
243                 if(labs(table[i] - position) < min_difference)
244                 {
245 //printf("\n");
246                         min_difference = labs(table[i] - position);
247                         result = i;
248                 }
249         }
250 //printf("\n");
251 //printf("ARender::get_history_number %ld %d %d\n", position, result, min_difference);
252         return result;
255 void ARender::send_last_buffer()
257         renderengine->audio->set_last_buffer();
260 int ARender::wait_device_completion()
262 // audio device should be entirely cleaned up by vconsole
263         renderengine->audio->wait_for_completion();
264         return 0;
267 void ARender::run()
269         int64_t current_input_length;
270         int reconfigure = 0;
272         first_buffer = 1;
274         start_lock->unlock();
276         while(!done && !interrupt && !last_playback)
277         {
278                 current_input_length = renderengine->fragment_len;
280 //printf("ARender::run 1 %p\n", renderengine->edl);
281                 get_boundaries(current_input_length);
283 //printf("ARender::run 10 %lld %lld\n", current_position, current_input_length);
284                 if(current_input_length)
285                 {
286                         reconfigure = vconsole->test_reconfigure(current_position, 
287                                 current_input_length,
288                                 last_playback);
289                         if(reconfigure) restart_playback();
290                 }
291 //printf("ARender::run 20 %lld %lld\n", current_position, current_input_length);
294 // Update tracking if no video is playing.
295                 if(renderengine->command->realtime && 
296                         renderengine->playback_engine &&
297                         !renderengine->do_video)
298                 {
299                         double position = (double)renderengine->audio->current_position() / 
300                                 renderengine->edl->session->sample_rate * 
301                                 renderengine->command->get_speed();
303                         if(renderengine->command->get_direction() == PLAY_FORWARD) 
304                                 position += renderengine->command->playbackstart;
305                         else
306                                 position = renderengine->command->playbackstart - position;
308 // This number is not compensated for looping.  It's compensated in 
309 // PlaybackEngine::get_tracking_position when interpolation also happens.
310                         renderengine->playback_engine->update_tracking(position);
311                 }
315 //printf("ARender::run 30 %lld\n", current_input_length);
319                 process_buffer(current_input_length, current_position);
320 //printf("ARender::run 40\n");
323                 advance_position(get_render_length(current_input_length));
324 //printf("ARender::run 50\n");
327                 if(vconsole->interrupt) interrupt = 1;
328         }
330         if(!interrupt) send_last_buffer();
331         if(renderengine->command->realtime) wait_device_completion();
332         vconsole->stop_rendering(0);
352 int ARender::get_datatype()
354         return TRACK_AUDIO;
357 int ARender::arm_playback(int64_t current_position,
358                         int64_t input_length, 
359                         int64_t amodule_render_fragment, 
360                         int64_t playback_buffer, 
361                         int64_t output_length)
363         this->current_position = current_position;
364         this->input_length = input_length;
365         session_position = 0;
367         source_length = renderengine->end_position - renderengine->start_position;
370         if(renderengine->command->realtime)
371         {
372                 Thread::set_realtime(renderengine->edl->session->real_time_playback);
373                 init_meters();
374         }
377 // start reading input and sending to arenderthread
378 // only if there's an audio device
379         if(renderengine->command->realtime)     
380         {
381                 set_synchronous(1);
382                 start();
383         }
384         return 0;
387 // int ARender::send_reconfigure_buffer()
388 // {
389 //      if(renderengine->command->realtime)
390 //      {
391 //              vconsole->output_lock[vconsole->current_input_buffer]->lock("ARender::send_reconfigure_buffer");
392 // 
393 //              vconsole->input_len[vconsole->current_input_buffer] = 0;
394 //              vconsole->input_position[vconsole->current_input_buffer] = 0;
395 //              vconsole->last_playback[vconsole->current_input_buffer] = 0;
396 //              vconsole->last_reconfigure[vconsole->current_input_buffer] = 1;
397 // 
398 //              vconsole->input_lock[vconsole->current_input_buffer]->unlock();
399 //              vconsole->swap_input_buffer();
400 //      }
401 //      return 0;
402 // }
404 int ARender::reverse_buffer(double *buffer, int64_t len)
406         register int64_t start, end;
407         double temp;
409         for(start = 0, end = len - 1; end > start; start++, end--)
410         {
411                 temp = buffer[start];
412                 buffer[start] = buffer[end];
413                 buffer[end] = temp;
414         }
417 int ARender::get_next_peak(int current_peak)
419         current_peak++;
420         if(current_peak >= total_peaks) current_peak = 0;
421         return current_peak;
424 int64_t ARender::get_render_length(int64_t current_render_length)
426         return current_render_length;