no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / patchbay.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 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 "apatchgui.h"
23 #include "automation.h"
24 #include "floatauto.h"
25 #include "floatautos.h"
26 #include "clip.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "filexml.h"
30 #include "intauto.h"
31 #include "intautos.h"
32 #include "language.h"
33 #include "localsession.h"
34 #include "mainundo.h"
35 #include "mwindow.h"
36 #include "mwindowgui.h"
37 #include "patchbay.h"
38 #include "patchgui.h"
39 #include "mainsession.h"
40 #include "strack.h"
41 #include "theme.h"
42 #include "timelinepane.h"
43 #include "track.h"
44 #include "trackcanvas.h"
45 #include "tracks.h"
46 #include "vpatchgui.h"
47
48
49
50
51
52
53 NudgePopup::NudgePopup(MWindow *mwindow, PatchBay *patchbay)
54  : BC_PopupMenu(0,
55                 0,
56                 0,
57                 "",
58                 0)
59 {
60         this->mwindow = mwindow;
61         this->patchbay = patchbay;
62 }
63
64 NudgePopup::~NudgePopup()
65 {
66 }
67
68
69 void NudgePopup::create_objects()
70 {
71         add_item(seconds_item = new NudgePopupSeconds(this));
72         add_item(native_item = new NudgePopupNative(this));
73 }
74
75 void NudgePopup::activate_menu(PatchGUI *gui)
76 {
77 // Set checked status
78         seconds_item->set_checked(mwindow->edl->session->nudge_format ? 1 : 0);
79         native_item->set_checked(mwindow->edl->session->nudge_format ? 0 : 1);
80
81 // Set native units to track format
82         native_item->set_text(gui->track->data_type == TRACK_AUDIO ?
83                 (char*)_("Samples") :
84                 (char*)_("Frames"));
85
86 // Show it
87         BC_PopupMenu::activate_menu();
88 }
89
90
91
92 NudgePopupSeconds::NudgePopupSeconds(NudgePopup *popup)
93  : BC_MenuItem(_("Seconds"))
94 {
95         this->popup = popup;
96 }
97
98 int NudgePopupSeconds::handle_event()
99 {
100         popup->mwindow->edl->session->nudge_format = 1;
101         popup->mwindow->gui->update_patchbay();
102         return 1;
103 }
104
105
106
107
108
109 NudgePopupNative::NudgePopupNative(NudgePopup *popup)
110  : BC_MenuItem("")
111 {
112         this->popup = popup;
113 }
114
115 int NudgePopupNative::handle_event()
116 {
117         popup->mwindow->edl->session->nudge_format = 0;
118         popup->mwindow->gui->update_patchbay();
119         return 1;
120 }
121
122
123
124
125
126
127
128
129
130 PatchBay::PatchBay(MWindow *mwindow, MWindowGUI *gui)
131  : BC_SubWindow(mwindow->theme->patchbay_x,
132         mwindow->theme->patchbay_y,
133         mwindow->theme->patchbay_w,
134         mwindow->theme->patchbay_h)
135 {
136         this->mwindow = mwindow;
137         this->gui = gui;
138         this->pane = 0;
139         drag_operation = Tracks::NONE;
140         for(int i = 0; i < TRANSFER_TYPES; i++) mode_icons[i] = 0;
141 // *** CONTEXT_HELP ***
142         context_help_set_keyword("The Patchbay");
143 }
144
145 PatchBay::PatchBay(MWindow *mwindow,
146         TimelinePane *pane,
147         int x,
148         int y,
149         int w,
150         int h)
151  : BC_SubWindow(x,
152         y,
153         w,
154         h)
155 {
156         this->mwindow = mwindow;
157         this->gui = mwindow->gui;
158         this->pane = pane;
159         drag_operation = Tracks::NONE;
160         for(int i = 0; i < TRANSFER_TYPES; i++) mode_icons[i] = 0;
161 // *** CONTEXT_HELP ***
162         context_help_set_keyword("The Patchbay");
163 // printf("PatchBay::PatchBay %d %d %d %d %d\n",
164 // __LINE__,
165 // x,
166 // y,
167 // w,
168 // h);
169 }
170
171 PatchBay::~PatchBay()
172 {
173         delete_all_patches();
174         for(int i = 0; i < TRANSFER_TYPES; i++) delete mode_icons[i];
175 }
176
177
178 int PatchBay::delete_all_patches()
179 {
180     patches.remove_all_objects();
181     return 0;
182 }
183
184 void PatchBay::create_objects()
185 {
186         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
187         flash(0);
188
189 // Create icons for mode types
190         static const char *mode_types[] = {
191                 "mode_normal",
192                 "mode_add",
193                 "mode_subtract",
194                 "mode_multiply",
195                 "mode_divide",
196                 "mode_replace",
197                 "mode_max",
198                 "mode_min",
199                 "mode_darken",
200                 "mode_lighten",
201                 "mode_dst",
202                 "mode_dstatop",
203                 "mode_dstin",
204                 "mode_dstout",
205                 "mode_dstover",
206                 "mode_src",
207                 "mode_srcatop",
208                 "mode_srcin",
209                 "mode_srcout",
210                 "mode_srcover",
211                 "mode_and",
212                 "mode_or",
213                 "mode_xor",
214                 "mode_overlay",
215                 "mode_screen",
216                 "mode_burn",
217                 "mode_dodge",
218                 "mode_hardlight",
219                 "mode_softlight",
220                 "mode_difference",
221         };
222         for( int mode=0; mode<TRANSFER_TYPES; ++mode ) {
223                 mode_icons[mode] = new BC_Pixmap(this,
224                         mwindow->theme->get_image(mode_types[mode]),
225                         PIXMAP_ALPHA);
226         }
227
228         add_subwindow(nudge_popup = new NudgePopup(mwindow, this));
229         nudge_popup->create_objects();
230         update();
231 }
232
233 BC_Pixmap* PatchBay::mode_to_icon(int mode)
234 {
235         return mode_icons[mode];
236 }
237
238 int PatchBay::icon_to_mode(BC_Pixmap *icon)
239 {
240         for(int i = 0; i < TRANSFER_TYPES; i++)
241                 if(icon == mode_icons[i]) return i;
242         return TRANSFER_NORMAL;
243 }
244
245 void PatchBay::resize_event()
246 {
247         reposition_window(mwindow->theme->patchbay_x,
248                 mwindow->theme->patchbay_y,
249                 mwindow->theme->patchbay_w,
250                 mwindow->theme->patchbay_h);
251         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
252         update();
253         flash(0);
254 }
255
256 void PatchBay::resize_event(int x, int y, int w, int h)
257 {
258         reposition_window(x,
259                 y,
260                 w,
261                 h);
262         draw_top_background(get_parent(), 0, 0, w, h);
263         update();
264         flash(0);
265 }
266
267 int PatchBay::button_press_event()
268 {
269         int result = 0;
270 // Too much junk to support the wheel
271         return result;
272 }
273
274 int PatchBay::cursor_motion_event()
275 {
276         //int cursor_x = get_relative_cursor_x();
277         int cursor_y = get_relative_cursor_y();
278         int update_gui = 0;
279
280         if(drag_operation != Tracks::NONE)
281         {
282                 if(cursor_y >= 0 &&
283                         cursor_y < get_h())
284                 {
285 // Get track we're inside of
286                         for(Track *track = mwindow->edl->tracks->first;
287                                 track;
288                                 track = track->next)
289                         {
290                                 if( track->is_hidden() ) continue;
291                                 int y = track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
292                                 int h = track->vertical_span(mwindow->theme);
293                                 if(cursor_y >= y && cursor_y < y + h)
294                                 {
295                                         switch(drag_operation)
296                                         {
297                                                 case Tracks::PLAY:
298                                                         if(track->play != new_status)
299                                                         {
300                                                                 track->play = new_status;
301                                                                 mwindow->gui->unlock_window();
302                                                                 mwindow->restart_brender();
303                                                                 mwindow->sync_parameters(CHANGE_EDL);
304                                                                 mwindow->gui->lock_window();
305                                                                 update_gui = 1;
306                                                         }
307                                                         break;
308                                                 case Tracks::RECORD:
309                                                         if(track->armed != new_status)
310                                                         {
311                                                                 track->armed = new_status;
312                                                                 update_gui = 1;
313                                                         }
314                                                         break;
315                                                 case Tracks::GANG:
316                                                         if(track->ganged != new_status)
317                                                         {
318                                                                 track->ganged = new_status;
319                                                                 update_gui = 1;
320                                                         }
321                                                         break;
322                                                 case Tracks::DRAW:
323                                                         if(track->draw != new_status)
324                                                         {
325                                                                 track->draw = new_status;
326                                                                 update_gui = 1;
327                                                         }
328                                                         break;
329                                                 case Tracks::EXPAND:
330                                                         if(track->expand_view != new_status)
331                                                         {
332                                                                 track->expand_view = new_status;
333                                                                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
334                                                                 gui->draw_trackmovement();
335                                                                 update_gui = 0;
336                                                         }
337                                                         break;
338                                                 case Tracks::MUTE:
339                                                 {
340                                                         IntAuto *current = 0;
341                                                         Auto *keyframe = 0;
342                                                         double position = mwindow->edl->local_session->get_selectionstart(1);
343                                                         Autos *mute_autos = track->automation->autos[AUTOMATION_MUTE];
344
345                                                         current = (IntAuto*)mute_autos->get_prev_auto(PLAY_FORWARD,
346                                                                 keyframe);
347
348                                                         if(current->value != new_status)
349                                                         {
350
351 //                                                              mwindow->undo->update_undo_before(_("keyframe"), this);
352                                                                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
353
354                                                                 current->value = new_status;
355
356 //                                                              mwindow->undo->update_undo_after(_("keyframe"), LOAD_AUTOMATION);
357
358                                                                 mwindow->gui->unlock_window();
359                                                                 mwindow->restart_brender();
360                                                                 mwindow->sync_parameters(CHANGE_PARAMS);
361                                                                 mwindow->gui->lock_window();
362
363                                                                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
364                                                                 {
365                                                                         gui->draw_overlays(1);
366                                                                 }
367                                                                 update_gui = 1;
368                                                         }
369                                                         break;
370                                                 }
371                                         }
372                                 }
373                         }
374                 }
375         }
376
377         if(update_gui)
378         {
379                 gui->update_patchbay();
380         }
381         return 0;
382 }
383
384 void PatchBay::set_meter_format(int mode, int min, int max)
385 {
386         for(int i = 0; i < patches.total; i++)
387         {
388                 PatchGUI *patchgui = patches.values[i];
389                 if(patchgui->data_type == TRACK_AUDIO)
390                 {
391                         APatchGUI *apatchgui = (APatchGUI*)patchgui;
392                         if(apatchgui->meter)
393                         {
394                                 apatchgui->meter->change_format(mode, min, max);
395                         }
396                 }
397         }
398 }
399
400 void PatchBay::update_meters(ArrayList<double> *module_levels)
401 {
402         for(int level_number = 0, patch_number = 0;
403                 patch_number < patches.total && level_number < module_levels->total;
404                 patch_number++)
405         {
406                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
407
408                 if(patchgui->data_type == TRACK_AUDIO)
409                 {
410                         if(patchgui->meter)
411                         {
412                                 double level = module_levels->values[level_number];
413                                 patchgui->meter->update(level, level > 1);
414                         }
415
416                         level_number++;
417                 }
418         }
419 }
420
421 void PatchBay::reset_meters()
422 {
423         for(int patch_number = 0;
424                 patch_number < patches.total;
425                 patch_number++)
426         {
427                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
428                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
429                 {
430                         patchgui->meter->reset_over();
431                 }
432         }
433 }
434
435 void PatchBay::stop_meters()
436 {
437         for(int patch_number = 0;
438                 patch_number < patches.total;
439                 patch_number++)
440         {
441                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
442                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
443                 {
444                         patchgui->meter->reset();
445                 }
446         }
447 }
448
449
450 #define PATCH_X 3
451
452 int PatchBay::update()
453 {
454         int patch_count = 0;
455
456 // Every patch has a GUI regardless of whether or not it is visible.
457 // Make sure GUI's are allocated for every patch and deleted for non-existant
458 // patches.
459         for(Track *current = mwindow->edl->tracks->first; current; current = NEXT)
460         {
461                 if( current->is_hidden() ) continue;
462                 PatchGUI *patchgui = 0;
463                 int y = current->y_pixel;
464                 y -= mwindow->edl->local_session->track_start[pane->number];
465
466 //printf("PatchBay::update %d %d\n", __LINE__, y);
467                 if(patches.total > patch_count)
468                 {
469                         if(patches.values[patch_count]->track_id != current->get_id())
470                         {
471                                 delete patches.values[patch_count];
472
473                                 switch(current->data_type)
474                                 {
475                                         case TRACK_AUDIO:
476                                                 patchgui = patches.values[patch_count] = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
477                                                 break;
478                                         case TRACK_VIDEO:
479                                                 patchgui = patches.values[patch_count] = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
480                                                 break;
481                                         case TRACK_SUBTITLE:
482                                                 patchgui = patches.values[patch_count] = new SPatchGUI(mwindow, this, (STrack*)current, PATCH_X, y);
483                                                 break;
484                                 }
485                                 patchgui->create_objects();
486                         }
487                         else
488                         {
489                                 patches.values[patch_count]->update(PATCH_X, y);
490                         }
491                 }
492                 else
493                 {
494                         switch(current->data_type)
495                         {
496                                 case TRACK_AUDIO:
497                                         patchgui = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
498                                         break;
499                                 case TRACK_VIDEO:
500                                         patchgui = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
501                                         break;
502                                 case TRACK_SUBTITLE:
503                                         patchgui = new SPatchGUI(mwindow, this, (STrack*)current, PATCH_X, y);
504                                         break;
505                         }
506                         patches.append(patchgui);
507                         patchgui->create_objects();
508                 }
509                 ++patch_count;
510         }
511
512         while(patches.total > patch_count)
513         {
514                 delete patches.values[patches.total - 1];
515                 patches.remove_number(patches.total - 1);
516         }
517
518         show_window(0);
519         return 0;
520 }
521
522 void PatchBay::synchronize_faders(float dv, int data_type, Track *skip, int edge, int span)
523 {
524         for( Track *current=mwindow->edl->tracks->first; current; current=NEXT ) {
525                 if( current == skip ) continue;
526                 if( skip && !current->armed_gang(skip) ) continue;
527                 if( current->data_type != data_type ) continue;
528                 if( !current->is_armed() ) continue;
529                 FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
530                 double position = mwindow->edl->local_session->get_selectionstart(1);
531                 FloatAuto *float_auto = (FloatAuto*)fade_autos->get_auto_for_editing(position);
532                 int64_t pos = float_auto->position;
533                 float_auto->bump_update(pos, dv, edge, span);
534                 PatchGUI *patch = get_patch_of(current);
535                 if( patch ) patch->update(patch->x, patch->y);
536         }
537 }
538
539 void PatchBay::synchronize_nudge(int64_t value, Track *skip)
540 {
541         Track *current = mwindow->edl->tracks->first;
542         for( ; current; current = NEXT ) {
543                 if( current->data_type == skip->data_type &&
544                     current->armed_gang(skip) && current->is_armed() &&
545                     current != skip ) {
546                         current->nudge = value;
547                         PatchGUI *patch = get_patch_of(current);
548                         if(patch) patch->update(patch->x, patch->y);
549                 }
550         }
551 }
552
553 PatchGUI* PatchBay::get_patch_of(Track *track)
554 {
555         for(int i = 0; i < patches.total; i++)
556         {
557                 if(patches.values[i]->track == track)
558                         return patches.values[i];
559         }
560         return 0;
561 }
562
563 int PatchBay::resize_event(int top, int bottom)
564 {
565         reposition_window(mwindow->theme->patchbay_x,
566                 mwindow->theme->patchbay_y,
567                 mwindow->theme->patchbay_w,
568                 mwindow->theme->patchbay_h);
569         return 0;
570 }
571
572