fix delete_edit optimize segv, add dump submenu/dump_undo, add dbl edge drag/drop...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / virtualaconsole.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "aedit.h"
23 #include "amodule.h"
24 #include "arender.h"
25 #include "assets.h"
26 #include "atrack.h"
27 #include "audiodevice.h"
28 #include "bcsignals.h"
29 #include "condition.h"
30 #include "edit.h"
31 #include "edits.h"
32 #include "edl.h"
33 #include "edlsession.h"
34 #include "file.h"
35 #include "levelwindow.h"
36 #include "playabletracks.h"
37 #include "plugin.h"
38 #include "preferences.h"
39 #include "renderengine.h"
40 #include "samples.h"
41 #include "thread.h"
42 #include "tracks.h"
43 #include "transportque.h"
44 #include "virtualaconsole.h"
45 #include "virtualanode.h"
46 #include "virtualnode.h"
47
48
49 VirtualAConsole::VirtualAConsole(RenderEngine *renderengine, ARender *arender)
50  : VirtualConsole(renderengine, arender, TRACK_AUDIO)
51 {
52         this->arender = arender;
53         output_temp = 0;
54         output_allocation = 0;
55 }
56
57 VirtualAConsole::~VirtualAConsole()
58 {
59         if(output_temp) delete output_temp;
60 }
61
62
63 void VirtualAConsole::get_playable_tracks()
64 {
65         if(!playable_tracks)
66                 playable_tracks = new PlayableTracks(renderengine->get_edl(),
67                         commonrender->current_position,
68                         renderengine->command->get_direction(),
69                         TRACK_AUDIO,
70                         1);
71 }
72
73
74 VirtualNode* VirtualAConsole::new_entry_node(Track *track,
75         Module *module,
76         int track_number)
77 {
78         return new VirtualANode(renderengine,
79                 this, module, 0, track, 0);
80         return 0;
81 }
82
83
84
85 int VirtualAConsole::process_buffer(int64_t len,
86         int64_t start_position)
87 {
88         int result = 0;
89         const int debug = 0;
90 if(debug) printf("VirtualAConsole::process_buffer %d this=%p len=%jd\n",
91   __LINE__, this, len);
92
93
94 // clear output buffers
95         for(int i = 0; i < MAX_CHANNELS; i++)
96         {
97 // if(debug) printf("VirtualAConsole::process_buffer 2 %d %p %jd\n",
98 // i,
99 // arender->audio_out[i],
100 // len);
101
102                 if(arender->audio_out[i])
103                 {
104                         bzero(arender->audio_out[i]->get_data(), len * sizeof(double));
105                 }
106         }
107
108 // Create temporary output
109         if(output_temp && output_allocation < len)
110         {
111                 delete output_temp;
112                 output_temp = 0;
113         }
114
115         if(!output_temp)
116         {
117                 output_temp = new Samples(len);
118                 output_allocation = len;
119         }
120 if(debug) printf("VirtualAConsole::process_buffer %d\n", __LINE__);
121
122
123 // Reset plugin rendering status
124         reset_attachments();
125 //printf("VirtualAConsole::process_buffer 1 %p\n", output_temp);
126
127 if(debug) printf("VirtualAConsole::process_buffer %d\n", __LINE__);
128
129
130 // Render exit nodes
131         for(int i = 0; i < exit_nodes.total; i++)
132         {
133                 VirtualANode *node = (VirtualANode*)exit_nodes.values[i];
134                 Track *track = node->track;
135
136                 result |= node->render(output_temp,
137                         len,
138                         start_position + track->nudge,
139                         renderengine->get_edl()->session->sample_rate);
140         }
141 if(debug) printf("VirtualAConsole::process_buffer %d\n", __LINE__);
142
143
144
145 // get peaks and limit volume in the fragment
146         for(int i = 0; i < MAX_CHANNELS; i++)
147         {
148                 if(arender->audio_out[i])
149                 {
150                         double *current_buffer = arender->audio_out[i]->get_data();
151
152
153                         for(int j = 0; j < len; )
154                         {
155                                 int meter_render_end;
156 // Get length to test for meter and limit
157                                 if(renderengine->command->realtime)
158                                         meter_render_end = j + arender->meter_render_fragment;
159                                 else
160                                         meter_render_end = len;
161
162                                 if(meter_render_end > len)
163                                         meter_render_end =  len;
164
165                                 double peak = 0;
166                                 while( j < meter_render_end ) {
167 // Level history comes before clipping to get over status
168                                         double *sample = &current_buffer[j++];
169                                         if( fabs(*sample) > peak ) peak = fabs(*sample);
170 // Make the output device clip it
171 //                                      if(*sample > 1) *sample = 1;
172 //                                      else
173 //                                      if(*sample < -1) *sample = -1;
174                                 }
175
176                                 if( renderengine->command->realtime ) {
177                                         int direction = renderengine->command->get_direction();
178                                         int64_t pos = direction == PLAY_REVERSE ?
179                                                 start_position - j :
180                                                 start_position + j ;
181                                         arender->meter_history->set_peak(i, peak, pos);
182                                 }
183                         }
184                 }
185         }
186
187 if(debug) printf("VirtualAConsole::process_buffer %d\n", __LINE__);
188
189
190
191
192
193 // Pack channels, fix speed and send to device.
194         if(!renderengine->is_nested &&
195                 renderengine->command->realtime &&
196                 !interrupt)
197         {
198 // speed parameters
199 // length compensated for speed
200                 int real_output_len = 0;
201 // output sample
202                 double sample;
203                 int k;
204                 double *audio_out_packed[MAX_CHANNELS];
205                 int audio_channels = renderengine->get_edl()->session->audio_channels;
206
207                 for(int i = 0, j = 0;
208                         i < audio_channels;
209                         i++)
210                 {
211                         audio_out_packed[j++] = arender->audio_out[i]->get_data();
212                 }
213                 for(int i = 0;
214                         i < audio_channels;
215                         i++)
216                 {
217                         int in, out;
218
219                         double *current_buffer = audio_out_packed[i];
220
221 // Time stretch the fragment to the real_output size
222                         if(renderengine->command->get_speed() > 1)
223                         {
224 // Number of samples in real output buffer for each to sample rendered.
225                                 int interpolate_len = (int)renderengine->command->get_speed();
226                                 for(in = 0, out = 0; in < len; )
227                                 {
228                                         sample = 0;
229                                         for(k = 0; k < interpolate_len; k++)
230                                         {
231                                                 sample += current_buffer[in++];
232                                         }
233
234                                         sample /= renderengine->command->get_speed();
235                                         current_buffer[out++] = sample;
236                                 }
237                                 real_output_len = out;
238                         }
239                         else
240                         if(renderengine->command->get_speed() < 1)
241                         {
242 // number of samples to skip
243                                 int interpolate_len = (int)(1.0 / renderengine->command->get_speed());
244                                 real_output_len = len * interpolate_len;
245
246                                 for(in = len - 1, out = real_output_len - 1; in >= 0; )
247                                 {
248                                         for(k = 0; k < interpolate_len; k++)
249                                         {
250                                                 current_buffer[out--] = current_buffer[in];
251                                         }
252                                         in--;
253                                 }
254                         }
255                         else
256                                 real_output_len = len;
257                 }
258
259 // Wait until video is ready
260                 if(arender->first_buffer)
261                 {
262                         renderengine->first_frame_lock->lock("VirtualAConsole::process_buffer");
263                         arender->first_buffer = 0;
264                 }
265                 if(!renderengine->audio->get_interrupted())
266                 {
267                         renderengine->audio->write_buffer(audio_out_packed, audio_channels,
268                                 real_output_len);
269                 }
270
271                 if(renderengine->audio->get_interrupted()) interrupt = 1;
272         }
273
274 if(debug) printf("VirtualAConsole::process_buffer %d\n", __LINE__);
275
276
277
278
279
280         return result;
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 int VirtualAConsole::init_rendering(int duplicate)
308 {
309         return 0;
310 }
311
312
313 int VirtualAConsole::send_last_output_buffer()
314 {
315         renderengine->audio->set_last_buffer();
316         return 0;
317 }
318