add haupauge-1657 dual usb capture support, add deinterlace to recordmonitor, asset...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / arender.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 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 "amodule.h"
23 #include "arender.h"
24 #include "atrack.h"
25 #include "audiodevice.h"
26 #include "auto.h"
27 #include "autos.h"
28 #include "bcsignals.h"
29 #include "cache.h"
30 #include "condition.h"
31 #include "edit.h"
32 #include "edl.h"
33 #include "edlsession.h"
34 #include "levelwindow.h"
35 #include "mainsession.h"
36 #include "playabletracks.h"
37 #include "playbackengine.h"
38 #include "preferences.h"
39 #include "renderengine.h"
40 #include "samples.h"
41 #include "tracks.h"
42 #include "transportque.h"
43 #include "virtualaconsole.h"
44 #include "virtualconsole.h"
45 #include "virtualnode.h"
46
47 ARender::ARender(RenderEngine *renderengine)
48  : CommonRender(renderengine)
49 {
50 // Clear output buffers
51         for( int i=0; i<MAXCHANNELS; ++i ) {
52                 buffer[i] = 0;
53                 audio_out[i] = 0;
54                 buffer_allocated[i] = 0;
55         }
56         total_peaks = 0;
57         meter_history = new MeterHistory();
58         data_type = TRACK_AUDIO;
59 }
60
61 ARender::~ARender()
62 {
63         for( int i=0; i<MAXCHANNELS; ++i ) delete buffer[i];
64         delete meter_history;
65 }
66
67 void ARender::arm_command()
68 {
69 // Need the meter history now so AModule can allocate its own history
70         calculate_history_size();
71         CommonRender::arm_command();
72         asynchronous = 1;
73         init_meters();
74 }
75
76
77 int ARender::get_total_tracks()
78 {
79         return renderengine->get_edl()->tracks->total_audio_tracks();
80 }
81
82 Module* ARender::new_module(Track *track)
83 {
84         return new AModule(renderengine, this, 0, track);
85 }
86
87 int ARender::calculate_history_size()
88 {
89         if( !total_peaks ) {
90                 meter_render_fragment = renderengine->fragment_len;
91                 int tracking_fragment = renderengine->get_edl()->session->sample_rate / TRACKING_RATE;
92 // This number and the timer in tracking.C determine the rate
93                 while( meter_render_fragment > tracking_fragment ) meter_render_fragment /= 2;
94                 total_peaks = 16 * renderengine->fragment_len / meter_render_fragment;
95         }
96         return total_peaks;
97 }
98
99 int ARender::init_meters()
100 {
101 // not providing enough peaks results in peaks that are ahead of the sound
102         meter_history->init(MAXCHANNELS, calculate_history_size());
103         for( int i=0; i<MAXCHANNELS; ++i ) {
104                 if( buffer[i] ) meter_history->reset_channel(i);
105         }
106         return 0;
107 }
108
109 void ARender::allocate_buffers(int samples)
110 {
111         for( int i=0; i<MAXCHANNELS; ++i ) {
112 // Reset the output buffers in case speed changed
113                 if( buffer_allocated[i] < samples ||
114                     i >= renderengine->get_edl()->session->audio_channels ) {
115                         delete buffer[i];  buffer[i] = 0;
116                 }
117
118                 if( !buffer[i] && i < renderengine->get_edl()->session->audio_channels ) {
119                         buffer[i] = new Samples(samples);
120                         buffer_allocated[i] = samples;
121                 }
122                 audio_out[i] = buffer[i];
123         }
124 }
125
126 void ARender::init_output_buffers()
127 {
128         allocate_buffers(renderengine->adjusted_fragment_len);
129 }
130
131
132 VirtualConsole* ARender::new_vconsole_object()
133 {
134         return new VirtualAConsole(renderengine, this);
135 }
136
137 int64_t ARender::tounits(double position, int round)
138 {
139         if(round)
140                 return Units::round(position * renderengine->get_edl()->session->sample_rate);
141         else
142                 return (int64_t)(position * renderengine->get_edl()->session->sample_rate);
143 }
144
145 double ARender::fromunits(int64_t position)
146 {
147         return (double)position / renderengine->get_edl()->session->sample_rate;
148 }
149
150
151 int ARender::process_buffer(Samples **buffer_out,
152         int64_t input_len,
153         int64_t input_position)
154 {
155         int result = 0;
156
157         int64_t fragment_position = 0;
158         int64_t fragment_len = input_len;
159         int reconfigure = 0;
160         current_position = input_position;
161
162 // Process in fragments
163         int start_offset = buffer_out[0]->get_offset();
164         while(fragment_position < input_len)
165         {
166 // Set pointers for destination data
167                 for(int i = 0; i < MAXCHANNELS; i++)
168                 {
169                         if(buffer_out[i])
170                         {
171                                 this->audio_out[i] = buffer_out[i];
172                                 this->audio_out[i]->set_offset(start_offset + fragment_position);
173                         }
174                         else
175                                 this->audio_out[i] = 0;
176                 }
177
178                 fragment_len = input_len;
179                 if(fragment_position + fragment_len > input_len)
180                         fragment_len = input_len - fragment_position;
181
182                 reconfigure = vconsole->test_reconfigure(input_position,
183                         fragment_len);
184
185 //printf("ARender::process_buffer 1 %jd %d\n", input_position, reconfigure);
186
187                 if(reconfigure) restart_playback();
188
189                 result = process_buffer(fragment_len, input_position);
190
191                 fragment_position += fragment_len;
192                 input_position += fragment_len;
193                 current_position = input_position;
194         }
195
196 // Reset offsets
197         for(int i = 0; i < MAXCHANNELS; i++)
198         {
199                 if(buffer_out[i]) buffer_out[i]->set_offset(start_offset);
200         }
201
202
203
204         return result;
205 }
206
207
208 int ARender::process_buffer(int64_t input_len, int64_t input_position)
209 {
210         int result = ((VirtualAConsole*)vconsole)->process_buffer(input_len,
211                 input_position);
212         return result;
213 }
214
215 void ARender::send_last_buffer()
216 {
217         if( renderengine->audio )
218                 renderengine->audio->set_last_buffer();
219 }
220
221 int ARender::stop_audio(int wait)
222 {
223         if( renderengine->audio )
224                 renderengine->audio->stop_audio(wait);
225         return 0;
226 }
227
228 void ARender::interrupt_playback()
229 {
230 //printf("ARender::interrupt_playback\n");
231         interrupt = 1;
232         if( renderengine->audio )
233                 renderengine->audio->interrupt_playback();
234 }
235
236 void ARender::run()
237 {
238         int64_t current_input_length;
239         int reconfigure = 0;
240 const int debug = 0;
241
242         first_buffer = 1;
243
244         start_lock->unlock();
245 if(debug) printf("ARender::run %d %d\n", __LINE__, Thread::calculate_realtime());
246
247         while(!done && !interrupt)
248         {
249                 float speed = renderengine->command->get_speed();
250                 current_input_length = (int64_t)(renderengine->fragment_len * speed +0.5) ;
251
252 if(debug) printf("ARender::run %d %jd %jd\n", __LINE__, current_position, current_input_length);
253                 get_boundaries(current_input_length);
254
255 if(debug) printf("ARender::run %d %jd %jd\n", __LINE__, current_position, current_input_length);
256                 if(current_input_length)
257                 {
258                         reconfigure = vconsole->test_reconfigure(current_position,
259                                 current_input_length);
260                         if(reconfigure) restart_playback();
261                 }
262 if(debug) printf("ARender::run %d %jd %jd\n", __LINE__, current_position, current_input_length);
263
264
265 // Update tracking if no video is playing.
266                 if(renderengine->command->realtime &&
267                         renderengine->playback_engine &&
268                         !renderengine->do_video)
269                 {
270                         double position = (double)renderengine->audio->current_position() /
271                                 renderengine->get_edl()->session->sample_rate * speed;
272
273                         if(renderengine->command->get_direction() == PLAY_FORWARD)
274                                 position += renderengine->command->playbackstart;
275                         else
276                                 position = renderengine->command->playbackstart - position;
277
278 // This number is not compensated for looping.  It's compensated in
279 // PlaybackEngine::get_tracking_position when interpolation also happens.
280                         renderengine->playback_engine->update_tracking(position);
281                 }
282
283
284 if(debug) printf("ARender::run %d %jd\n", __LINE__, current_input_length);
285
286
287
288                 process_buffer(current_input_length, current_position);
289 if(debug) printf("ARender::run %d\n", __LINE__);
290
291
292                 advance_position(current_input_length);
293 if(debug) printf("ARender::run %d\n", __LINE__);
294
295
296                 if( !interrupt ) interrupt = renderengine->interrupted;
297                 if( !interrupt ) interrupt = renderengine->audio->get_interrupted();
298                 if( !interrupt ) interrupt = vconsole->interrupt;
299         }
300
301 if(debug) printf("ARender::run %d\n", __LINE__);
302         if(!interrupt) send_last_buffer();
303         if(renderengine->command->realtime)
304                 stop_audio(interrupt ? 0 : 1);
305         vconsole->stop_rendering(0);
306         stop_plugins();
307 }
308