Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / virtualaconsole.C
blob844a7a52dd83bf42e92e17ac7dc134f84d47c89c
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 "condition.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;
30         output_temp = 0;
31         output_allocation = 0;
34 VirtualAConsole::~VirtualAConsole()
36         if(output_temp) delete [] output_temp;
40 void VirtualAConsole::get_playable_tracks()
42         if(!playable_tracks)
43                 playable_tracks = new PlayableTracks(renderengine, 
44                         commonrender->current_position, 
45                         TRACK_AUDIO,
46                         1);
50 VirtualNode* VirtualAConsole::new_entry_node(Track *track, 
51         Module *module,
52         int track_number)
54         return new VirtualANode(renderengine,
55                 this, 
56                 module,
57                 0,
58                 track,
59                 0);
60         return 0;
65 int VirtualAConsole::process_buffer(int64_t len,
66         int64_t start_position,
67         int last_buffer,
68         int64_t absolute_position)
70         int result = 0;
73 // clear output buffers
74         for(int i = 0; i < MAX_CHANNELS; i++)
75         {
76 // printf("VirtualAConsole::process_buffer 2 %d %p %lld\n", 
77 // i, 
78 // arender->audio_out[i],
79 // len);
80                 if(arender->audio_out[i])
81                 {
82                         bzero(arender->audio_out[i], len * sizeof(double));
83                 }
84         }
86 // Create temporary output
87         if(output_temp && output_allocation < len)
88         {
89                 delete [] output_temp;
90                 output_temp = 0;
91         }
93         if(!output_temp)
94         {
95                 output_temp = new double[len];
96                 output_allocation = len;
97         }
99 // Reset plugin rendering status
100         reset_attachments();
101 //printf("VirtualAConsole::process_buffer 1 %p\n", output_temp);
103 // Render exit nodes
104         for(int i = 0; i < exit_nodes.total; i++)
105         {
106                 VirtualANode *node = (VirtualANode*)exit_nodes.values[i];
107                 Track *track = node->track;
109 //printf("VirtualAConsole::process_buffer 2 %d %p\n", i, output_temp);
110                 result |= node->render(output_temp, 
111                         start_position + track->nudge,
112                         len,
113                         renderengine->edl->session->sample_rate);
114 //printf("VirtualAConsole::process_buffer 3 %p\n", output_temp);
115         }
116 //printf("VirtualAConsole::process_buffer 4\n");
119 // get peaks and limit volume in the fragment
120         for(int i = 0; i < MAX_CHANNELS; i++)
121         {
122                 double *current_buffer = arender->audio_out[i];
124                 if(current_buffer)
125                 {
127                         for(int j = 0; j < len; )
128                         {
129                                 int meter_render_end;
130 // Get length to test for meter and limit
131                                 if(renderengine->command->realtime)
132                                         meter_render_end = j + arender->meter_render_fragment;
133                                 else
134                                         meter_render_end = len;
136                                 if(meter_render_end > len) 
137                                         meter_render_end =  len;
139                                 double peak = 0;
141                                 for( ; j < meter_render_end; j++)
142                                 {
143 // Level history comes before clipping to get over status
144                                         double *sample = &current_buffer[j];
147                                         if(fabs(*sample) > peak) peak = fabs(*sample);
148 // Make the output device clip it
149 //                                      if(*sample > 1) *sample = 1;
150 //                                      else
151 //                                      if(*sample < -1) *sample = -1;
152                                 }
155                                 if(renderengine->command->realtime)
156                                 {
157                                         arender->level_history[i][arender->current_level[i]] = peak;
158                                         arender->level_samples[arender->current_level[i]] = 
159                                                 renderengine->command->get_direction() == PLAY_REVERSE ? 
160                                                 start_position - j : 
161                                                 start_position + j;
162                                         arender->current_level[i] = arender->get_next_peak(arender->current_level[i]);
163                                 }
164                         }
165                 }
166         }
170 //printf("VirtualAConsole::process_buffer 5\n");
173 // Pack channels, fix speed and send to device.
174         if(renderengine->command->realtime && !interrupt)
175         {
176 // speed parameters
177 // length compensated for speed
178                 int real_output_len;
179 // output sample
180                 double sample;
181                 int k;
182                 double *audio_out_packed[MAX_CHANNELS];
183                 int audio_channels = renderengine->edl->session->audio_channels;
185                 for(int i = 0, j = 0; 
186                         i < audio_channels; 
187                         i++)
188                 {
189                         audio_out_packed[j++] = arender->audio_out[i];
190                 }
192                 for(int i = 0; 
193                         i < audio_channels; 
194                         i++)
195                 {
196                         int in, out;
197                         int fragment_end;
199                         double *current_buffer = audio_out_packed[i];
201 // Time stretch the fragment to the real_output size
202                         if(renderengine->command->get_speed() > 1)
203                         {
204 // Number of samples in real output buffer for each to sample rendered.
205                                 int interpolate_len = (int)renderengine->command->get_speed();
206                                 for(in = 0, out = 0; in < len; )
207                                 {
208                                         sample = 0;
209                                         for(k = 0; k < interpolate_len; k++)
210                                         {
211                                                 sample += current_buffer[in++];
212                                         }
213                                         sample /= renderengine->command->get_speed();
214                                         current_buffer[out++] = sample;
215                                 }
216                                 real_output_len = out;
217                         }
218                         else
219                         if(renderengine->command->get_speed() < 1)
220                         {
221 // number of samples to skip
222                                 int interpolate_len = (int)(1.0 / renderengine->command->get_speed());
223                                 real_output_len = len * interpolate_len;
225                                 for(in = len - 1, out = real_output_len - 1; in >= 0; )
226                                 {
227                                         for(k = 0; k < interpolate_len; k++)
228                                         {
229                                                 current_buffer[out--] = current_buffer[in];
230                                         }
231                                         in--;
232                                 }
233                         }
234                         else
235                                 real_output_len = len;
236                 }
238 // Wait until video is ready
239                 if(arender->first_buffer)
240                 {
241                         renderengine->first_frame_lock->lock("VirtualAConsole::process_buffer");
242                         arender->first_buffer = 0;
243                 }
244                 if(!renderengine->audio->get_interrupted())
245                 {
246                         renderengine->audio->write_buffer(audio_out_packed, 
247                                 real_output_len);
248                 }
250                 if(renderengine->audio->get_interrupted()) interrupt = 1;
251         }
256 //printf("VirtualAConsole::process_buffer 100\n");
261         return result;
288 int VirtualAConsole::init_rendering(int duplicate)
290         return 0;
294 int VirtualAConsole::send_last_output_buffer()
296         renderengine->audio->set_last_buffer();
297         return 0;
301 //      Local Variables:
302 //      mode: C++
303 //      c-file-style: "linux"
304 //      End: