2021-12-15 21:48:10 -05:00
/*
* Copyright ( C ) 2011 - 2017 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2021 Ben Loftis < ben @ harrisonconsoles . com >
*
* 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 .
*/
# include "pbd/compose.h"
# include <algorithm>
2022-01-11 17:27:44 -05:00
# include <gtkmm/menu.h>
# include <gtkmm/menuitem.h>
2021-12-15 21:48:10 -05:00
# include "gtkmm2ext/actions.h"
# include "gtkmm2ext/gui_thread.h"
# include "gtkmm2ext/utils.h"
2022-01-11 17:27:44 -05:00
# include "gtkmm2ext/menu_elems.h"
2021-12-15 21:48:10 -05:00
2022-01-14 00:19:59 -05:00
# include "widgets/tooltips.h"
2021-12-15 21:48:10 -05:00
# include "ardour/location.h"
# include "ardour/profile.h"
# include "ardour/session.h"
# include "audio_clock.h"
2024-09-20 22:00:46 -04:00
# include "editor_automation_line.h"
2021-12-15 21:48:10 -05:00
# include "control_point.h"
# include "editor.h"
# include "region_view.h"
# include "audio_trigger_properties_box.h"
# include "pbd/i18n.h"
using namespace Gtk ;
using namespace ARDOUR ;
using namespace ArdourWidgets ;
using std : : max ;
using std : : min ;
AudioTriggerPropertiesBox : : AudioTriggerPropertiesBox ( )
2021-12-17 09:48:58 -05:00
: _length_clock ( X_ ( " regionlength " ) , true , " " , true , false , true )
, _start_clock ( X_ ( " regionstart " ) , true , " " , false , false )
2022-01-26 11:17:53 -05:00
, _beat_adjustment ( 1 , 0.001 , 1000.0 , 1.0 , 4.0 , 0 )
, _beat_spinner ( _beat_adjustment )
2021-12-17 09:48:58 -05:00
, _stretch_toggle ( ArdourButton : : led_default_elements )
2022-01-14 00:19:59 -05:00
, _abpm_label ( ArdourButton : : Text )
2022-01-17 19:04:28 -05:00
, _ignore_changes ( false )
2021-12-15 21:48:10 -05:00
{
Gtk : : Label * label ;
int row = 0 ;
2022-01-17 20:01:53 -05:00
_abpm_label . set_sizing_text ( " 200.00 " ) ;
2022-01-14 13:55:51 -05:00
/* ------- Stretching and Tempo stuff ----------------------------- */
2021-12-15 21:48:10 -05:00
Gtk : : Table * bpm_table = manage ( new Gtk : : Table ( ) ) ;
bpm_table - > set_homogeneous ( false ) ;
bpm_table - > set_spacings ( 4 ) ;
2022-01-14 13:55:51 -05:00
bpm_table - > set_border_width ( 8 ) ;
_stretch_toggle . set_text ( _ ( " Stretch " ) ) ;
2022-01-17 20:01:53 -05:00
bpm_table - > attach ( _stretch_toggle , 0 , 1 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
bpm_table - > attach ( _stretch_selector , 1 , 4 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ; row + + ;
2022-01-14 13:55:51 -05:00
2022-01-18 09:12:17 -05:00
_bpm_label . set_text ( _ ( " BPM: " ) ) ;
_bpm_label . set_alignment ( 1.0 , 0.5 ) ;
bpm_table - > attach ( _bpm_label , 0 , 1 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
2022-01-14 13:55:51 -05:00
bpm_table - > attach ( _abpm_label , 1 , 2 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
2022-01-14 00:19:59 -05:00
2022-01-18 09:12:17 -05:00
_half_button . set_text ( _ ( " /2 " ) ) ;
_half_button . signal_clicked . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : MultiplyTempo ) , 0.5 ) ) ;
bpm_table - > attach ( _half_button , 2 , 3 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
_dbl_button . set_text ( _ ( " x2 " ) ) ;
_dbl_button . signal_clicked . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : MultiplyTempo ) , 2.0 ) ) ;
bpm_table - > attach ( _dbl_button , 3 , 4 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
2022-01-14 00:19:59 -05:00
2021-12-15 21:48:10 -05:00
row + + ;
2022-01-18 09:12:17 -05:00
_length_label . set_text ( _ ( " Clip Length: " ) ) ;
_length_label . set_alignment ( 1.0 , 0.5 ) ;
2022-01-26 11:17:53 -05:00
_beat_label . set_text ( _ ( " (beats) " ) ) ;
_beat_label . set_alignment ( 0.0 , 0.5 ) ;
2022-01-18 09:12:17 -05:00
bpm_table - > attach ( _length_label , 0 , 1 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
2022-01-26 11:17:53 -05:00
bpm_table - > attach ( _beat_spinner , 1 , 2 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
bpm_table - > attach ( _beat_label , 2 , 4 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
2021-12-15 21:48:10 -05:00
2022-01-26 12:18:41 -05:00
row + + ;
_bars_label . set_text ( _ ( " Length in Bars: " ) ) ;
_bars_label . set_alignment ( 1.0 , 0.5 ) ;
bpm_table - > attach ( _bars_label , 0 , 1 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
_bars_display . set_alignment ( 0.0 , 0.5 ) ;
bpm_table - > attach ( _bars_display , 1 , 4 , row , row + 1 , Gtk : : FILL , Gtk : : SHRINK ) ;
2022-01-16 17:04:12 -05:00
ArdourWidgets : : Frame * eTempoBox = manage ( new ArdourWidgets : : Frame ) ;
2022-09-30 02:04:56 -04:00
eTempoBox - > set_label ( _ ( " Stretch Options " ) ) ;
2022-01-14 13:55:51 -05:00
eTempoBox - > set_name ( " EditorDark " ) ;
2022-01-16 17:04:12 -05:00
eTempoBox - > set_edge_color ( 0x000000ff ) ; // black
2022-01-14 13:55:51 -05:00
eTempoBox - > add ( * bpm_table ) ;
2021-12-15 21:48:10 -05:00
2022-01-14 13:55:51 -05:00
/* -------------- Clip start&length (redundant with the trimmer gui handles?) ----------*/
2021-12-15 21:48:10 -05:00
row = 0 ;
label = manage ( new Gtk : : Label ( _ ( " Start: " ) ) ) ;
label - > set_alignment ( 1.0 , 0.5 ) ;
2021-12-17 09:48:58 -05:00
_table . attach ( * label , 0 , 1 , row , row + 1 , Gtk : : SHRINK , Gtk : : SHRINK ) ;
_table . attach ( _start_clock , 1 , 2 , row , row + 1 , Gtk : : SHRINK , Gtk : : SHRINK ) ;
2021-12-15 21:48:10 -05:00
row + + ;
2022-01-10 19:24:49 -05:00
label = manage ( new Gtk : : Label ( _ ( " Clip Length: " ) ) ) ;
2021-12-15 21:48:10 -05:00
label - > set_alignment ( 1.0 , 0.5 ) ;
2021-12-17 09:48:58 -05:00
_table . attach ( * label , 0 , 1 , row , row + 1 , Gtk : : SHRINK , Gtk : : SHRINK ) ;
_table . attach ( _length_clock , 1 , 2 , row , row + 1 , Gtk : : SHRINK , Gtk : : SHRINK ) ;
2021-12-15 21:48:10 -05:00
row + + ;
2021-12-17 09:48:58 -05:00
_table . set_homogeneous ( false ) ;
_table . set_spacings ( 4 ) ;
_table . set_border_width ( 2 ) ;
2021-12-15 21:48:10 -05:00
2022-01-24 13:28:58 -05:00
attach ( * eTempoBox , 0 , 1 , 0 , 1 , Gtk : : FILL , Gtk : : EXPAND | Gtk : : FILL ) ;
2022-01-16 17:56:59 -05:00
#if 0
2022-01-14 13:55:51 -05:00
attach ( _table , 0 , 1 , 1 , 2 , Gtk : : FILL , Gtk : : SHRINK ) ;
2022-01-16 17:56:59 -05:00
# endif
2021-12-17 09:48:58 -05:00
2022-01-17 19:04:28 -05:00
_start_clock . ValueChanged . connect ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : start_clock_changed ) ) ;
_length_clock . ValueChanged . connect ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : length_clock_changed ) ) ;
2022-01-11 17:27:44 -05:00
using namespace Menu_Helpers ;
_stretch_selector . set_text ( " ?? " ) ;
_stretch_selector . set_name ( " generic button " ) ;
_stretch_selector . set_sizing_text ( TriggerUI : : longest_stretch_mode ) ;
_stretch_selector . AddMenuElem ( MenuElem ( TriggerUI : : stretch_mode_to_string ( Trigger : : Crisp ) , sigc : : bind ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : set_stretch_mode ) , Trigger : : Crisp ) ) ) ;
_stretch_selector . AddMenuElem ( MenuElem ( TriggerUI : : stretch_mode_to_string ( Trigger : : Mixed ) , sigc : : bind ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : set_stretch_mode ) , Trigger : : Mixed ) ) ) ;
_stretch_selector . AddMenuElem ( MenuElem ( TriggerUI : : stretch_mode_to_string ( Trigger : : Smooth ) , sigc : : bind ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : set_stretch_mode ) , Trigger : : Smooth ) ) ) ;
2021-12-17 09:48:58 -05:00
_stretch_toggle . signal_clicked . connect ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : toggle_stretch ) ) ;
2022-01-17 19:04:28 -05:00
2022-01-26 11:17:53 -05:00
_beat_spinner . set_can_focus ( false ) ;
_beat_spinner . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & AudioTriggerPropertiesBox : : beats_changed ) ) ;
2022-02-18 20:25:43 -05:00
2022-04-05 12:45:40 -04:00
set_tooltip ( _stretch_toggle , _ ( " <b>If enabled</b>, the clip will be stretched to match the current timeline tempo " ) ) ;
2022-02-18 20:25:43 -05:00
set_tooltip ( _stretch_selector , _ ( " Select Crisp for drum loops, Smooth for sustained notes, or Mixed if the clip has both " ) ) ;
set_tooltip ( _beat_spinner , _ ( " Length of the clip, in beats. Changing this will change the tempo " ) ) ;
set_tooltip ( _half_button , _ ( " Click to halve the tempo for the clip. This will result in it playing faster when stretched on the timeline " ) ) ;
set_tooltip ( _dbl_button , _ ( " Click to double the tempo for the clip. This will result in it playing slower when stretched on the timeline " ) ) ;
2021-12-15 21:48:10 -05:00
}
AudioTriggerPropertiesBox : : ~ AudioTriggerPropertiesBox ( )
{
}
2022-01-14 00:19:59 -05:00
void
AudioTriggerPropertiesBox : : MultiplyTempo ( float mult )
{
TriggerPtr trigger ( tref . trigger ( ) ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < AudioTrigger > at = std : : dynamic_pointer_cast < AudioTrigger > ( trigger ) ;
2022-01-17 19:04:28 -05:00
if ( at ) {
at - > set_segment_tempo ( at - > segment_tempo ( ) * mult ) ;
2022-01-14 00:19:59 -05:00
}
}
2021-12-15 21:48:10 -05:00
void
AudioTriggerPropertiesBox : : toggle_stretch ( )
{
2021-12-24 16:13:36 -05:00
TriggerPtr trigger ( tref . trigger ( ) ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < AudioTrigger > at = std : : dynamic_pointer_cast < AudioTrigger > ( trigger ) ;
2022-01-17 19:04:28 -05:00
if ( at ) {
at - > set_stretchable ( ! at - > stretchable ( ) ) ;
2021-12-24 16:13:36 -05:00
}
2021-12-15 21:48:10 -05:00
}
2022-01-11 17:27:44 -05:00
void
AudioTriggerPropertiesBox : : set_stretch_mode ( Trigger : : StretchMode sm )
{
TriggerPtr trigger ( tref . trigger ( ) ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < AudioTrigger > at = std : : dynamic_pointer_cast < AudioTrigger > ( trigger ) ;
2022-01-17 19:04:28 -05:00
if ( at ) {
at - > set_stretch_mode ( sm ) ;
2022-01-11 17:27:44 -05:00
}
}
2021-12-15 21:48:10 -05:00
void
AudioTriggerPropertiesBox : : set_session ( Session * s )
{
SessionHandlePtr : : set_session ( s ) ;
2024-11-07 11:23:42 -05:00
if ( ! s ) {
return ;
}
2021-12-17 09:48:58 -05:00
_length_clock . set_session ( s ) ;
_start_clock . set_session ( s ) ;
2021-12-15 21:48:10 -05:00
}
void
2022-01-17 19:04:28 -05:00
AudioTriggerPropertiesBox : : on_trigger_changed ( const PBD : : PropertyChange & pc )
2021-12-15 21:48:10 -05:00
{
2021-12-24 16:13:36 -05:00
TriggerPtr trigger ( tref . trigger ( ) ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < AudioTrigger > at = std : : dynamic_pointer_cast < AudioTrigger > ( trigger ) ;
2022-01-17 19:04:28 -05:00
if ( ! at ) {
2022-01-14 00:33:05 -05:00
return ;
}
2021-12-24 16:13:36 -05:00
2022-01-17 19:04:28 -05:00
_ignore_changes = true ;
2021-12-15 21:48:10 -05:00
2022-02-12 12:14:40 -05:00
bool set_sensitivities = false ;
if ( pc . contains ( Properties : : running ) ) {
set_sensitivities = true ; //can't change stretch params while we are playing so we must watch active state
}
2022-01-17 19:04:28 -05:00
if ( pc . contains ( Properties : : start ) | | pc . contains ( Properties : : length ) ) { /* NOT REACHED from current code */
AudioClock : : Mode mode = at - > box ( ) . data_type ( ) = = ARDOUR : : DataType : : AUDIO ? AudioClock : : Samples : AudioClock : : BBT ;
2021-12-15 21:48:10 -05:00
2022-01-17 19:04:28 -05:00
_start_clock . set_mode ( mode ) ;
_length_clock . set_mode ( mode ) ;
2021-12-15 21:48:10 -05:00
2022-01-17 19:04:28 -05:00
_start_clock . set ( at - > start_offset ( ) ) ;
_length_clock . set ( at - > current_length ( ) ) ; // set_duration() ?
}
2022-01-10 19:24:49 -05:00
2022-01-26 11:17:53 -05:00
if ( pc . contains ( Properties : : tempo_meter ) | | pc . contains ( Properties : : follow_length ) ) {
2022-01-17 20:01:53 -05:00
2022-01-26 12:18:41 -05:00
char buf [ 64 ] ;
2022-01-17 20:01:53 -05:00
sprintf ( buf , " %3.2f " , at - > segment_tempo ( ) ) ;
_abpm_label . set_text ( buf ) ;
2022-12-28 09:54:13 -05:00
ArdourWidgets : : set_tooltip ( _abpm_label , string_compose ( _ ( " Clip Tempo, used for stretching. Estimated tempo (from file) was: %1 " ) , trigger - > estimated_tempo ( ) ) ) ;
2022-01-14 00:19:59 -05:00
2022-02-12 10:04:00 -05:00
int beats = round ( at - > segment_beatcnt ( ) ) ;
2022-01-26 12:18:41 -05:00
_beat_adjustment . set_value ( beats ) ;
sprintf ( buf , " %3.2f(4/4) - %3.2f(3/4) " , ( double ) beats / 4.0 , ( double ) beats / 3.0 ) ;
_bars_display . set_text ( buf ) ;
2022-01-17 19:04:28 -05:00
}
if ( pc . contains ( Properties : : stretch_mode ) | | pc . contains ( Properties : : stretchable ) ) {
_stretch_toggle . set_active ( at - > stretchable ( ) ? Gtkmm2ext : : ExplicitActive : Gtkmm2ext : : Off ) ;
_stretch_selector . set_text ( stretch_mode_to_string ( at - > stretch_mode ( ) ) ) ;
2022-02-12 12:14:40 -05:00
set_sensitivities = true ;
}
if ( set_sensitivities ) {
_stretch_toggle . set_sensitive ( ! at - > active ( ) ) ;
2022-01-18 09:12:17 -05:00
2022-02-12 12:14:40 -05:00
/* set remaining widget sensitivity based on stretchable button state & running state */
bool stretch_widgets_sensitive = at - > stretchable ( ) & & ! at - > active ( ) ;
2022-01-18 09:12:17 -05:00
2022-02-12 12:14:40 -05:00
if ( stretch_widgets_sensitive ) {
2022-01-18 09:12:17 -05:00
_stretch_selector . set_sensitive ( true ) ;
2022-01-26 11:17:53 -05:00
_beat_spinner . set_sensitive ( true ) ;
_beat_label . set_sensitive ( true ) ;
2022-01-18 09:12:17 -05:00
_length_label . set_sensitive ( true ) ;
_bpm_label . set_sensitive ( true ) ;
_half_button . set_sensitive ( true ) ;
_dbl_button . set_sensitive ( true ) ;
_abpm_label . set_sensitive ( true ) ;
2022-02-12 12:14:40 -05:00
_bars_display . set_sensitive ( true ) ;
2022-01-18 09:12:17 -05:00
} else {
_stretch_selector . set_sensitive ( false ) ;
2022-01-26 11:17:53 -05:00
_beat_spinner . set_sensitive ( false ) ;
_beat_label . set_sensitive ( false ) ;
2022-01-18 09:12:17 -05:00
_length_label . set_sensitive ( false ) ;
_bpm_label . set_sensitive ( false ) ;
_half_button . set_sensitive ( false ) ;
_dbl_button . set_sensitive ( false ) ;
_abpm_label . set_sensitive ( false ) ;
2022-02-12 12:14:40 -05:00
_bars_display . set_sensitive ( false ) ;
2022-01-18 09:12:17 -05:00
}
2022-01-17 19:04:28 -05:00
}
2022-01-10 20:33:30 -05:00
2022-01-17 19:04:28 -05:00
_ignore_changes = false ;
}
void
2022-01-26 11:17:53 -05:00
AudioTriggerPropertiesBox : : beats_changed ( )
2022-01-17 19:04:28 -05:00
{
if ( _ignore_changes ) {
return ;
}
TriggerPtr trigger ( tref . trigger ( ) ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < AudioTrigger > at = std : : dynamic_pointer_cast < AudioTrigger > ( trigger ) ;
2022-01-17 19:04:28 -05:00
if ( at ) {
2022-01-26 11:17:53 -05:00
at - > set_segment_beatcnt ( _beat_adjustment . get_value ( ) ) ;
2022-01-17 19:04:28 -05:00
}
2021-12-15 21:48:10 -05:00
}
2022-01-10 19:24:49 -05:00
void
AudioTriggerPropertiesBox : : start_clock_changed ( )
{
2022-11-14 09:52:15 -05:00
trigger ( ) - > set_start ( _start_clock . last_when ( ) ) ;
2022-01-10 19:24:49 -05:00
}
void
AudioTriggerPropertiesBox : : length_clock_changed ( )
{
2022-01-14 00:33:05 -05:00
trigger ( ) - > set_length ( _length_clock . current_duration ( ) ) ; //?
2022-01-10 19:24:49 -05:00
}