r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / virtualaconsole.C
blob9dd4b62160a574342994030d4658c39c8172dc48
1 #include "aedit.h"
2 #include "amodule.h"
3 #include "arender.h"
4 #include "assets.h"
5 #include "atrack.h"
6 #include "audiodevice.h"
7 #include "cache.h"
8 #include "edit.h"
9 #include "edits.h"
10 #include "edl.h"
11 #include "edlsession.h"
12 #include "file.h"
13 #include "levelwindow.h"
14 #include "playabletracks.h"
15 #include "plugin.h"
16 #include "preferences.h"
17 #include "renderengine.h"
18 #include "thread.h"
19 #include "tracks.h"
20 #include "transportque.h"
21 #include "virtualaconsole.h"
22 #include "virtualanode.h"
23 #include "virtualnode.h"
26 VirtualAConsole::VirtualAConsole(RenderEngine *renderengine, ARender *arender)
27  : VirtualConsole(renderengine, arender, TRACK_AUDIO)
29         this->arender = arender;
32 VirtualAConsole::~VirtualAConsole()
34 //printf("VirtualAConsole::~VirtualAConsole 1\n");
37 int VirtualAConsole::total_ring_buffers()
39         return renderengine->command->realtime ? 2 : 1;
42 void VirtualAConsole::get_playable_tracks()
44         if(!playable_tracks)
45                 playable_tracks = new PlayableTracks(renderengine, 
46                         commonrender->current_position, 
47                         TRACK_AUDIO);
50 void VirtualAConsole::new_input_buffer(int ring_buffer)
52         buffer_in[ring_buffer] = new double*[total_tracks];
53         for(int i = 0; i < total_tracks; i++)
54         {
55                 buffer_in[ring_buffer][i] = new double[renderengine->edl->session->audio_read_length];
56         }
59 void VirtualAConsole::delete_input_buffer(int ring_buffer)
61         for(int i = 0; i < total_tracks; i++)
62         {
63                 delete [] buffer_in[ring_buffer][i];
64         }
65         delete [] buffer_in[ring_buffer];
68 VirtualNode* VirtualAConsole::new_toplevel_node(Track *track, 
69         Module *module,
70         int track_number)
72         double *track_buffer[RING_BUFFERS];
73 //printf("VirtualAConsole::new_toplevel_node %p\n", module);
74         for(int i = 0; i < total_ring_buffers(); i++)
75                 track_buffer[i] = buffer_in[i][track_number];
76         return new VirtualANode(renderengine,
77                 this, 
78                 module,
79                 0,
80                 track,
81                 0,
82                 track_buffer,
83                 track_buffer,
84                 1,
85                 1,
86                 1,
87                 1);
88         return 0;
91 int VirtualAConsole::stop_rendering(int duplicate)
93         if(renderengine->command->realtime)
94         {
95                 Thread::join();
96         }
97         return 0;
101 int VirtualAConsole::process_buffer(int64_t input_len,
102         int64_t input_position,
103         int last_buffer,
104         int64_t absolute_position)
106         int result = 0;
107 // wait for an input_buffer to become available
108         if(renderengine->command->realtime)
109                 output_lock[current_input_buffer]->lock();
111         if(!interrupt)
112         {
113 // Load tracks
114                 double **buffer_in = this->buffer_in[current_input_buffer];
116                 for(int i = 0; i < total_tracks; i++)
117                 {
118                         result |= ((AModule*)virtual_modules[i]->real_module)->render(buffer_in[i],
119                                 input_len, 
120                                 input_position,
121                                 renderengine->command->get_direction());
122                 }
126                 this->input_len[current_input_buffer] = input_len;
127                 this->input_position[current_input_buffer] = input_position;
128                 this->last_playback[current_input_buffer] = last_buffer;
129                 this->last_reconfigure[current_input_buffer] = 0;
130                 this->absolute_position[current_input_buffer] = absolute_position;
132                 if(renderengine->command->realtime)
133                         input_lock[current_input_buffer]->unlock();
134                 else
135                         process_console();
138 //printf("VirtualAConsole::process_buffer 5 %p\n", buffer_in[0]);
139 // for(int i = 0; i < input_len; i++)
140 // {
141 // int16_t value = (int16_t)(buffer_in[0][i] * 32767);
142 // fwrite(&value, 2, 1, stdout);
143 // }
146                 swap_input_buffer();
147         }
148         return result;
151 void VirtualAConsole::process_console()
153         int i, j, k;
154 // length and lowest numbered sample of fragment in input buffer
155         int buffer = current_vconsole_buffer;
156         int64_t fragment_len, fragment_position;        
157 // generic buffer
158         double *current_buffer;
159 // starting sample of fragment in project
160         int64_t real_position;
161 // info for meters
162         double min, max, peak;
163         int64_t meter_render_end;    // end of current meter fragment for getting levels
164         int64_t current_fragment_peak; // first meter peak in fragment
165         int64_t input_len = this->input_len[buffer];
166         int64_t input_position = this->input_position[buffer];
167         int64_t absolute_position = this->absolute_position[buffer];
171 //printf("VirtualAConsole::process_console 1 %p\n", this->buffer_in[buffer][0]);
173 // process entire input buffer by filling one output buffer at a time
174         for(fragment_position = 0; 
175                 fragment_position < input_len && !interrupt; )
176         {
178 // test for end of input buffer
179                 fragment_len = renderengine->edl->session->audio_module_fragment;
180                 if(fragment_position + fragment_len > input_len)
181                         fragment_len = input_len - fragment_position;
186 // clear output buffers
187                 for(i = 0; i < MAX_CHANNELS; i++)
188                 {
189                         if(arender->audio_out[i])
190                         {
191                                 bzero(arender->audio_out[i], fragment_len * sizeof(double));
192                         }
193                 }
199 // get the start of the fragment in the project
200                 real_position = 
201                         (renderengine->command->get_direction() == PLAY_REVERSE) ? 
202                                 input_position - fragment_position : 
203                                 input_position + fragment_position;
205 // render nodes in sorted list
206                 for(i = 0; i < render_list.total; i++)
207                 {
208 //printf("VirtualAConsole::process_console 1 %p\n", this->buffer_in[buffer][i] + fragment_position);
209                         ((VirtualANode*)render_list.values[i])->render(arender->audio_out, 
210                                         0, 
211                                         buffer,
212                                         fragment_position,
213                                         fragment_len, 
214                                         real_position, 
215                                         arender->source_length,
216                                         renderengine->reverse,
217                                         arender);
218                 }
220 // get peaks and limit volume in the fragment
221                 for(i = 0; i < MAX_CHANNELS; i++)
222                 {
223                         current_buffer = arender->audio_out[i];
224                         if(current_buffer)
225                         {
227                                 for(j = 0; j < fragment_len; )
228                                 {
229 // Get length to test for meter
230                                         if(renderengine->command->realtime)
231                                                 meter_render_end = j + arender->meter_render_fragment;
232                                         else
233                                                 meter_render_end = fragment_len;
235                                         if(meter_render_end > fragment_len) 
236                                                 meter_render_end =  fragment_len;
238                                         min = max = 0;
240                                         for( ; j < meter_render_end; j++)
241                                         {
242 // Level history comes before clipping to get over status
243                                                 if(current_buffer[j] > max) max = current_buffer[j];
244                                                 else
245                                                 if(current_buffer[j] < min) min = current_buffer[j];
247                                                 if(current_buffer[j] > 1) current_buffer[j] = 1;
248                                                 else
249                                                 if(current_buffer[j] < -1) current_buffer[j] = -1;
250                                         }
253                                         if(fabs(max) > fabs(min))
254                                                 peak = fabs(max);
255                                         else
256                                                 peak = fabs(min);
258                                         if(renderengine->command->realtime)
259                                         {
260                                                 arender->level_history[i][arender->current_level[i]] = peak;
261                                                 arender->level_samples[arender->current_level[i]] = 
262                                                         (renderengine->command->get_direction() == PLAY_REVERSE) ? 
263                                                         real_position - j : 
264                                                         real_position + j;
265                                                 arender->current_level[i] = arender->get_next_peak(arender->current_level[i]);
266                                         }
267                                 }
269                         }
270                 }
273 // advance fragment
274                 fragment_position += fragment_len;
276 // Pack channels, fix speed and send to device.
277                 if(renderengine->command->realtime && !interrupt)
278                 {
279 // speed parameters
280                         int64_t real_output_len; // length compensated for speed
281                         double sample;       // output sample
282                         int k;
283                         double *audio_out_packed[MAX_CHANNELS];
285                         for(i = 0, j = 0; i < MAX_CHANNELS; i++)
286                         {
287                                 if(renderengine->config->aconfig->do_channel[i])
288                                 {
289                                         audio_out_packed[j++] = arender->audio_out[i];
290                                 }
291                         }
293                         for(i = 0; 
294                                 i < renderengine->config->aconfig->total_playable_channels(); 
295                                 i++)
296                         {
297                                 int64_t in, out;
298                                 int64_t fragment_end;
300                                 current_buffer = audio_out_packed[i];
302 // Time stretch the fragment to the real_output size
303                                 if(renderengine->command->get_speed() > 1)
304                                 {
305 // Number of samples in real output buffer for each to sample rendered.
306                                         int interpolate_len = (int)renderengine->command->get_speed();
307                                         for(in = 0, out = 0; in < fragment_len; )
308                                         {
309                                                 sample = 0;
310                                                 for(k = 0; k < interpolate_len; k++)
311                                                 {
312                                                         sample += current_buffer[in++];
313                                                 }
314                                                 sample /= renderengine->command->get_speed();
315                                                 current_buffer[out++] = sample;
316                                         }
317                                         real_output_len = out;
318                                 }
319                                 else
320                                 if(renderengine->command->get_speed() < 1)
321                                 {
322                                         int interpolate_len = (int)(1 / renderengine->command->get_speed()); // number of samples to skip
323                                         real_output_len = fragment_len * interpolate_len;
325                                         for(in = fragment_len - 1, out = real_output_len - 1; in >= 0; )
326                                         {
327                                                 for(k = 0; k < interpolate_len; k++)
328                                                 {
329                                                         current_buffer[out--] = current_buffer[in];
330                                                 }
331                                                 in--;
332                                         }
333                                 }
334                                 else
335                                         real_output_len = fragment_len;
336                         }
338                         if(!renderengine->audio->get_interrupted())
339                         {
340                                 renderengine->audio->write_buffer(audio_out_packed, 
341                                         real_output_len, 
342                                         renderengine->config->aconfig->total_playable_channels());
343                         }
345                         if(renderengine->audio->get_interrupted()) interrupt = 1;
346                 }
349 // for(int i = 0; i < fragment_len; i++)
350 // {
351 // int16_t value = (int16_t)(arender->audio_out[0][i] * 32767);
352 // fwrite(&value, 2, 1, stdout);
353 // }
354         }
358 void VirtualAConsole::run()
360         startup_lock->unlock();
362         while(!done && !interrupt)
363         {
364 // wait for a buffer to render through console
365                 input_lock[current_vconsole_buffer]->lock();
367                 if(!done && !interrupt && !last_reconfigure[current_vconsole_buffer])
368                 {
369 // render it if not last buffer
370 // send to output device or the previously set output buffer
371                         process_console();
373 // test for exit conditions tied to the buffer
374                         if(last_playback[current_vconsole_buffer]) done = 1;
376 // free up buffer for reading from disk
377                         output_lock[current_vconsole_buffer]->unlock();
379 // get next buffer
380                         if(!done) swap_thread_buffer();
381                 }
382                 else
383                 if(last_reconfigure[current_vconsole_buffer])
384                         done = 1;
385         }
387         if(interrupt)
388         {
389                 for(int i = 0; i < total_ring_buffers(); i++)
390                 {
391                         output_lock[i]->unlock();
392                 }
393         }
394         else
395         if(!last_reconfigure[current_vconsole_buffer])
396         {
397                 if(renderengine->command->realtime)
398                         send_last_output_buffer();
399         }
427 int VirtualAConsole::init_rendering(int duplicate)
429         return 0;
433 int VirtualAConsole::send_last_output_buffer()
435         renderengine->audio->set_last_buffer();
436         return 0;