2005-09-25 14:42:24 -04:00
/*
2019-08-02 17:26:43 -04:00
* Copyright ( C ) 2006 - 2012 David Robillard < d @ drobilla . net >
* Copyright ( C ) 2006 - 2015 Tim Mayberry < mojofunk @ gmail . com >
* Copyright ( C ) 2006 - 2016 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2009 - 2011 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2014 - 2016 Robin Gareus < robin @ gareus . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2005-09-25 14:42:24 -04:00
2012-05-24 02:09:29 -04:00
# include <cmath>
# include <gtkmm2ext/utils.h>
2009-02-25 13:26:51 -05:00
# include "pbd/memento_command.h"
2010-03-02 13:05:26 -05:00
# include "pbd/stateful_diff_command.h"
2010-10-28 16:01:26 -04:00
# include "pbd/pthread_utils.h"
2006-11-12 19:50:28 -05:00
2022-07-05 21:27:50 -04:00
# include "temporal/tempo.h"
2009-02-25 13:26:51 -05:00
# include "ardour/audioregion.h"
2012-05-24 02:09:29 -04:00
# include "ardour/session_event.h"
2009-10-23 19:21:55 -04:00
# include "ardour/dB.h"
2024-04-16 21:53:30 -04:00
# include "ardour/region_fx_plugin.h"
2005-09-25 14:42:24 -04:00
2006-07-31 23:23:35 -04:00
# include "audio_region_editor.h"
# include "audio_region_view.h"
2006-01-03 09:16:27 -05:00
# include "gui_thread.h"
2024-04-16 21:53:30 -04:00
# include "public_editor.h"
2005-09-25 14:42:24 -04:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2005-09-25 14:42:24 -04:00
using namespace ARDOUR ;
2006-06-21 19:01:03 -04:00
using namespace PBD ;
2005-09-25 14:42:24 -04:00
using namespace std ;
2007-03-18 12:45:43 -04:00
using namespace Gtkmm2ext ;
2005-09-25 14:42:24 -04:00
2010-10-28 16:01:26 -04:00
static void *
_peak_amplitude_thread ( void * arg )
{
static_cast < AudioRegionEditor * > ( arg ) - > peak_amplitude_thread ( ) ;
return 0 ;
}
2024-04-16 21:53:30 -04:00
AudioRegionEditor : : AudioRegionEditor ( Session * s , AudioRegionView * arv )
: RegionEditor ( s , arv )
, _arv ( arv )
, _audio_region ( arv - > audio_region ( ) )
2022-12-17 06:37:32 -05:00
, gain_adjustment ( accurate_coefficient_to_dB ( fabsf ( _audio_region - > scale_amplitude ( ) ) ) , - 40.0 , + 40.0 , 0.1 , 1.0 , 0 )
, _polarity_toggle ( _ ( " Invert " ) )
2024-09-07 10:42:40 -04:00
, _fade_before_fx_toggle ( _ ( " Fade before Fx " ) )
2024-04-16 21:53:30 -04:00
, _show_on_touch ( _ ( " Show on Touch " ) )
2011-04-04 08:21:26 -04:00
, _peak_channel ( false )
2005-09-25 14:42:24 -04:00
{
2010-10-28 16:01:26 -04:00
Gtk : : HBox * b = Gtk : : manage ( new Gtk : : HBox ) ;
b - > set_spacing ( 6 ) ;
b - > pack_start ( gain_entry ) ;
b - > pack_start ( * Gtk : : manage ( new Gtk : : Label ( _ ( " dB " ) ) ) , false , false ) ;
2008-12-12 09:43:24 -05:00
2009-10-23 19:21:55 -04:00
gain_label . set_name ( " AudioRegionEditorLabel " ) ;
2010-04-23 20:29:28 -04:00
gain_label . set_text ( _ ( " Region gain: " ) ) ;
2010-10-28 16:01:26 -04:00
gain_label . set_alignment ( 1 , 0.5 ) ;
2009-10-23 19:21:55 -04:00
gain_entry . configure ( gain_adjustment , 0.0 , 1 ) ;
2010-10-27 17:18:44 -04:00
_table . attach ( gain_label , 0 , 1 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
2010-10-28 16:01:26 -04:00
_table . attach ( * b , 1 , 2 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
+ + _table_row ;
2010-02-19 13:09:08 -05:00
2010-10-28 16:01:26 -04:00
b = Gtk : : manage ( new Gtk : : HBox ) ;
b - > set_spacing ( 6 ) ;
b - > pack_start ( _peak_amplitude ) ;
b - > pack_start ( * Gtk : : manage ( new Gtk : : Label ( _ ( " dBFS " ) ) ) , false , false ) ;
2011-06-01 13:00:29 -04:00
2010-10-28 16:01:26 -04:00
_peak_amplitude_label . set_name ( " AudioRegionEditorLabel " ) ;
_peak_amplitude_label . set_text ( _ ( " Peak amplitude: " ) ) ;
_peak_amplitude_label . set_alignment ( 1 , 0.5 ) ;
_table . attach ( _peak_amplitude_label , 0 , 1 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
_table . attach ( * b , 1 , 2 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
+ + _table_row ;
2011-06-01 13:00:29 -04:00
2022-12-17 06:37:32 -05:00
_polarity_label . set_name ( " AudioRegionEditorLabel " ) ;
_polarity_label . set_text ( _ ( " Polarity: " ) ) ;
2024-04-16 21:53:30 -04:00
_polarity_label . set_alignment ( 1 , 0.5 ) ;
2022-12-17 06:37:32 -05:00
_table . attach ( _polarity_label , 0 , 1 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
_table . attach ( _polarity_toggle , 1 , 2 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
2024-09-07 10:42:40 -04:00
_table . attach ( _fade_before_fx_toggle , 2 , 3 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
2022-12-17 06:37:32 -05:00
+ + _table_row ;
2024-04-16 21:53:30 -04:00
_region_line_label . set_name ( " AudioRegionEditorLabel " ) ;
_region_line_label . set_text ( _ ( " Region Line: " ) ) ;
_region_line_label . set_alignment ( 1 , 0.5 ) ;
_table . attach ( _region_line_label , 0 , 1 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
_table . attach ( _region_line , 1 , 2 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
_table . attach ( _show_on_touch , 2 , 3 , _table_row , _table_row + 1 , Gtk : : FILL , Gtk : : FILL ) ;
+ + _table_row ;
2024-08-18 19:00:31 -04:00
UI : : instance ( ) - > set_tip ( _polarity_toggle , _ ( " Invert the signal polarity (180deg phase shift) " ) ) ;
2024-09-07 10:42:40 -04:00
UI : : instance ( ) - > set_tip ( _fade_before_fx_toggle , _ ( " Apply region effects after the region fade. \n This is useful if the effect(s) have tail, which would otherwise be faded out by the region fade (e.g. reverb, delay) " ) ) ;
2024-08-18 19:00:31 -04:00
UI : : instance ( ) - > set_tip ( _show_on_touch , _ ( " When touching a control in a region effect plugin UI, the corresponding region-automation line is shown the editor, and edit mode is set to 'draw'. " ) ) ;
2009-10-23 19:21:55 -04:00
gain_changed ( ) ;
2024-09-07 10:42:40 -04:00
fade_before_fx_changed ( ) ;
2024-04-16 21:53:30 -04:00
refill_region_line ( ) ;
2005-09-25 14:42:24 -04:00
2010-05-21 20:26:26 -04:00
gain_adjustment . signal_value_changed ( ) . connect ( sigc : : mem_fun ( * this , & AudioRegionEditor : : gain_adjustment_changed ) ) ;
2022-12-17 06:37:32 -05:00
_polarity_toggle . signal_toggled ( ) . connect ( sigc : : mem_fun ( * this , & AudioRegionEditor : : gain_adjustment_changed ) ) ;
2024-09-07 10:42:40 -04:00
_fade_before_fx_toggle . signal_toggled ( ) . connect ( sigc : : mem_fun ( * this , & AudioRegionEditor : : fade_before_fx_toggle_changed ) ) ;
2024-04-16 21:53:30 -04:00
_show_on_touch . signal_toggled ( ) . connect ( sigc : : mem_fun ( * this , & AudioRegionEditor : : show_on_touch_changed ) ) ;
arv - > region_line_changed . connect ( ( sigc : : mem_fun ( * this , & AudioRegionEditor : : refill_region_line ) ) ) ;
2010-10-28 16:01:26 -04:00
_peak_amplitude . property_editable ( ) = false ;
_peak_amplitude . set_text ( _ ( " Calculating... " ) ) ;
2024-10-18 19:51:44 -04:00
PeakAmplitudeFound . connect ( _peak_amplitude_connection , invalidator ( * this ) , std : : bind ( & AudioRegionEditor : : peak_amplitude_found , this , _1 ) , gui_context ( ) ) ;
2016-05-15 20:49:18 -04:00
char name [ 64 ] ;
snprintf ( name , 64 , " peak amplitude-%p " , this ) ;
pthread_create_and_store ( name , & _peak_amplitude_thread_handle , _peak_amplitude_thread , this ) ;
2013-07-13 08:27:56 -04:00
signal_peak_thread ( ) ;
2024-04-16 21:53:30 -04:00
2024-08-18 19:00:31 -04:00
2010-10-28 16:01:26 -04:00
}
AudioRegionEditor : : ~ AudioRegionEditor ( )
{
void * v ;
2016-05-15 20:49:18 -04:00
_peak_channel . deliver ( ' t ' ) ;
2011-09-30 13:55:14 -04:00
pthread_join ( _peak_amplitude_thread_handle , & v ) ;
2005-09-25 14:42:24 -04:00
}
void
2010-02-19 13:09:08 -05:00
AudioRegionEditor : : region_changed ( const PBD : : PropertyChange & what_changed )
2005-09-25 14:42:24 -04:00
{
2010-05-21 20:26:26 -04:00
RegionEditor : : region_changed ( what_changed ) ;
2011-06-01 13:00:29 -04:00
2010-02-19 13:09:08 -05:00
if ( what_changed . contains ( ARDOUR : : Properties : : scale_amplitude ) ) {
2009-10-23 19:21:55 -04:00
gain_changed ( ) ;
}
2011-04-04 08:21:26 -04:00
2024-08-13 13:43:36 -04:00
if ( what_changed . contains ( ARDOUR : : Properties : : fade_before_fx ) ) {
2024-09-07 10:42:40 -04:00
fade_before_fx_changed ( ) ;
2024-08-13 13:43:36 -04:00
}
2011-04-04 08:21:26 -04:00
if ( what_changed . contains ( ARDOUR : : Properties : : start ) | | what_changed . contains ( ARDOUR : : Properties : : length ) ) {
/* ask the peak thread to run again */
2013-07-13 08:27:56 -04:00
signal_peak_thread ( ) ;
2011-04-04 08:21:26 -04:00
}
2005-09-25 14:42:24 -04:00
}
2024-04-16 21:53:30 -04:00
void
AudioRegionEditor : : region_fx_changed ( )
{
RegionEditor : : region_fx_changed ( ) ;
refill_region_line ( ) ;
}
2009-10-23 19:21:55 -04:00
void
AudioRegionEditor : : gain_changed ( )
{
2022-12-17 06:37:32 -05:00
const gain_t scale_amplitude = _audio_region - > scale_amplitude ( ) ;
float const region_gain_dB = accurate_coefficient_to_dB ( fabsf ( scale_amplitude ) ) ;
2009-10-23 19:21:55 -04:00
if ( region_gain_dB ! = gain_adjustment . get_value ( ) ) {
gain_adjustment . set_value ( region_gain_dB ) ;
}
2022-12-17 06:37:32 -05:00
_polarity_toggle . set_active ( scale_amplitude < 0 ) ;
2009-10-23 19:21:55 -04:00
}
void
AudioRegionEditor : : gain_adjustment_changed ( )
{
2022-12-17 06:37:32 -05:00
float gain = dB_to_coefficient ( gain_adjustment . get_value ( ) ) ;
if ( _polarity_toggle . get_active ( ) ) {
gain * = - 1 ;
}
2010-05-21 20:26:26 -04:00
if ( _audio_region - > scale_amplitude ( ) ! = gain ) {
_audio_region - > set_scale_amplitude ( gain ) ;
2009-10-23 19:21:55 -04:00
}
}
2010-10-28 16:01:26 -04:00
2024-08-13 13:43:36 -04:00
void
2024-09-07 10:42:40 -04:00
AudioRegionEditor : : fade_before_fx_changed ( )
2024-08-13 13:43:36 -04:00
{
2024-09-07 10:42:40 -04:00
_fade_before_fx_toggle . set_active ( _audio_region - > fade_before_fx ( ) ) ;
2024-08-13 13:43:36 -04:00
}
void
2024-09-07 10:42:40 -04:00
AudioRegionEditor : : fade_before_fx_toggle_changed ( )
2024-08-13 13:43:36 -04:00
{
2024-09-07 10:42:40 -04:00
_audio_region - > set_fade_before_fx ( _fade_before_fx_toggle . get_active ( ) ) ;
2024-08-13 13:43:36 -04:00
}
2013-07-13 08:27:56 -04:00
void
AudioRegionEditor : : signal_peak_thread ( )
{
_peak_channel . deliver ( ' c ' ) ;
}
2010-10-28 16:01:26 -04:00
void
AudioRegionEditor : : peak_amplitude_thread ( )
{
2011-04-04 08:21:26 -04:00
while ( 1 ) {
2016-05-15 20:49:18 -04:00
char msg ;
2011-04-04 08:21:26 -04:00
/* await instructions to run */
2016-05-15 20:49:18 -04:00
_peak_channel . receive ( msg ) ;
if ( msg = = ' t ' ) {
break ;
}
2011-04-04 08:21:26 -04:00
2022-07-05 21:27:50 -04:00
/* update thread-local tempo map */
Temporal : : TempoMap : : fetch ( ) ;
2011-04-04 08:21:26 -04:00
/* compute peak amplitude and signal the fact */
PeakAmplitudeFound ( accurate_coefficient_to_dB ( _audio_region - > maximum_amplitude ( ) ) ) ; /* EMIT SIGNAL */
}
2010-10-28 16:01:26 -04:00
}
void
AudioRegionEditor : : peak_amplitude_found ( double p )
{
2010-11-03 21:56:56 -04:00
stringstream s ;
s . precision ( 2 ) ;
s . setf ( ios : : fixed , ios : : floatfield ) ;
s < < p ;
_peak_amplitude . set_text ( s . str ( ) ) ;
2010-10-28 16:01:26 -04:00
}
2024-04-16 21:53:30 -04:00
void
AudioRegionEditor : : show_touched_automation ( std : : weak_ptr < PBD : : Controllable > wac )
{
if ( ! _arv - > set_region_fx_line ( wac ) ) {
return ;
}
switch ( PublicEditor : : instance ( ) . current_mouse_mode ( ) ) {
case Editing : : MouseObject :
case Editing : : MouseTimeFX :
case Editing : : MouseGrid :
case Editing : : MouseCut :
PublicEditor : : instance ( ) . set_mouse_mode ( Editing : : MouseDraw , false ) ;
break ;
default :
break ;
}
}
void
AudioRegionEditor : : show_on_touch_changed ( )
{
if ( ! _show_on_touch . get_active ( ) ) {
_ctrl_touched_connection . disconnect ( ) ;
return ;
}
2024-10-18 19:51:44 -04:00
Controllable : : ControlTouched . connect ( _ctrl_touched_connection , invalidator ( * this ) , std : : bind ( & AudioRegionEditor : : show_touched_automation , this , _1 ) , gui_context ( ) ) ;
2024-04-16 21:53:30 -04:00
}
void
AudioRegionEditor : : refill_region_line ( )
{
using namespace Gtk : : Menu_Helpers ;
_region_line . clear_items ( ) ;
MenuList & rm_items ( _region_line . items ( ) ) ;
int nth = 0 ;
PBD : : ID rfx_id ( 0 ) ;
uint32_t param_id = 0 ;
string active_text = _ ( " Gain Envelope " ) ;
_arv - > get_region_fx_line ( rfx_id , param_id ) ;
_arv - > set_ignore_line_change ( true ) ;
Gtk : : RadioMenuItem : : Group grp ;
AudioRegionView * arv = _arv ;
rm_items . push_back ( RadioMenuElem ( grp , _ ( " Gain Envelope " ) ) ) ;
Gtk : : CheckMenuItem * cmi = static_cast < Gtk : : CheckMenuItem * > ( & rm_items . back ( ) ) ;
cmi - > set_active ( rfx_id = = 0 | | param_id = = UINT32_MAX ) ;
cmi - > signal_activate ( ) . connect ( [ cmi , arv ] ( ) { if ( cmi - > get_active ( ) ) { arv - > set_region_gain_line ( ) ; } } ) ;
_audio_region - > foreach_plugin ( [ & rm_items , arv , & nth , & grp , & active_text , rfx_id , param_id ] ( std : : weak_ptr < RegionFxPlugin > wfx )
{
std : : shared_ptr < RegionFxPlugin > fx ( wfx . lock ( ) ) ;
if ( ! fx ) {
return ;
}
std : : shared_ptr < Plugin > plugin = fx - > plugin ( ) ;
2024-08-20 14:01:06 -04:00
if ( ! plugin ) {
return ;
}
2024-04-16 21:53:30 -04:00
Gtk : : Menu * acm = manage ( new Gtk : : Menu ) ;
MenuList & acm_items ( acm - > items ( ) ) ;
for ( size_t i = 0 ; i < plugin - > parameter_count ( ) ; + + i ) {
if ( ! plugin - > parameter_is_control ( i ) | | ! plugin - > parameter_is_input ( i ) ) {
continue ;
}
const Evoral : : Parameter param ( PluginAutomation , 0 , i ) ;
std : : string label = plugin - > describe_parameter ( param ) ;
if ( label = = X_ ( " latency " ) | | label = = X_ ( " hidden " ) ) {
continue ;
}
std : : shared_ptr < ARDOUR : : AutomationControl > c ( std : : dynamic_pointer_cast < ARDOUR : : AutomationControl > ( fx - > control ( param ) ) ) ;
if ( c & & c - > flags ( ) & ( Controllable : : HiddenControl | Controllable : : NotAutomatable ) ) {
continue ;
}
bool active = fx - > id ( ) = = rfx_id & & param_id = = i ;
acm_items . push_back ( RadioMenuElem ( grp , label ) ) ;
Gtk : : CheckMenuItem * cmi = static_cast < Gtk : : CheckMenuItem * > ( & acm_items . back ( ) ) ;
cmi - > set_active ( active ) ;
cmi - > signal_activate ( ) . connect ( [ cmi , arv , nth , i ] ( ) { if ( cmi - > get_active ( ) ) { arv - > set_region_fx_line ( nth , i ) ; } } ) ;
if ( active ) {
active_text = fx - > name ( ) + " : " + label ;
}
}
if ( ! acm_items . empty ( ) ) {
rm_items . push_back ( MenuElem ( fx - > name ( ) , * acm ) ) ;
} else {
delete acm ;
}
+ + nth ;
} ) ;
if ( rm_items . size ( ) > 1 ) {
_show_on_touch . set_sensitive ( true ) ;
} else {
_show_on_touch . set_active ( false ) ;
_show_on_touch . set_sensitive ( false ) ;
}
_region_line . set_text ( active_text ) ;
_arv - > set_ignore_line_change ( false ) ;
}
void
AudioRegionEditor : : on_unmap ( )
{
_show_on_touch . set_active ( false ) ;
ArdourDialog : : on_unmap ( ) ;
}