diff --git a/libs/temporal/debug.cc b/libs/temporal/debug.cc index 478f40f0a2..4e260ec22e 100644 --- a/libs/temporal/debug.cc +++ b/libs/temporal/debug.cc @@ -27,4 +27,5 @@ PBD::DebugBits PBD::DEBUG::Grid = PBD::new_debug_bit ("Grid"); PBD::DebugBits PBD::DEBUG::SnapBBT = PBD::new_debug_bit ("SnapBBT"); PBD::DebugBits PBD::DEBUG::Beats = PBD::new_debug_bit ("Beats"); PBD::DebugBits PBD::DEBUG::MapReset = PBD::new_debug_bit ("MapReset"); +PBD::DebugBits PBD::DEBUG::ScopedTempoMap = PBD::new_debug_bit ("scopedtempomap"); diff --git a/libs/temporal/tempo.cc b/libs/temporal/tempo.cc index 1708f99d87..8d9a10d1f6 100644 --- a/libs/temporal/tempo.cc +++ b/libs/temporal/tempo.cc @@ -825,6 +825,7 @@ GridIterator::valid_for (TempoMap const & m, superclock_t start, uint32_t bmod, /* TEMPOMAP */ TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter) + : _scope_owner (nullptr) { TempoPoint* tp = new TempoPoint (*this, initial_tempo, 0, Beats(), BBT_Time()); MeterPoint* mp = new MeterPoint (*this, initial_meter, 0, Beats(), BBT_Time()); @@ -841,15 +842,23 @@ TempoMap::~TempoMap() } TempoMap::TempoMap (XMLNode const & node, int version) + : _scope_owner (nullptr) { set_state (node, version); } TempoMap::TempoMap (TempoMap const & other) + : _scope_owner (nullptr) { copy_points (other); } +void +TempoMap::set_scope_owner (ScopedTempoMapOwner& sco) +{ + _scope_owner = &sco; +} + TempoMap& TempoMap::operator= (TempoMap const & other) { diff --git a/libs/temporal/temporal/debug.h b/libs/temporal/temporal/debug.h index d8153dd000..88b3e5a4db 100644 --- a/libs/temporal/temporal/debug.h +++ b/libs/temporal/temporal/debug.h @@ -30,6 +30,7 @@ namespace PBD { LIBTEMPORAL_API extern DebugBits SnapBBT; LIBTEMPORAL_API extern DebugBits Beats; LIBTEMPORAL_API extern DebugBits MapReset; + LIBTEMPORAL_API extern DebugBits ScopedTempoMap; } } diff --git a/libs/temporal/temporal/scope.h b/libs/temporal/temporal/scope.h new file mode 100644 index 0000000000..71d2170ed9 --- /dev/null +++ b/libs/temporal/temporal/scope.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2025 Paul Davis + * + * 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. + */ + +#pragma once + +#include +#include + +#include "pbd/compose.h" + +#include "temporal/debug.h" +#include "temporal/tempo.h" + +namespace Temporal { + +class ScopedTempoMapOwner +{ + public: + ScopedTempoMapOwner () : local_tempo_map_depth (0) {} + virtual ~ScopedTempoMapOwner () {} + + void start_local_tempo_map (std::shared_ptr map) { + _local_tempo_map = map; + in (); + DEBUG_TRACE (PBD::DEBUG::ScopedTempoMap, string_compose ("%1: starting local tempo scope\n", scope_name())); + } + + void end_local_tempo_map () { + DEBUG_TRACE (PBD::DEBUG::ScopedTempoMap, string_compose ("%1: ending local tempo scope\n", scope_name())); + local_tempo_map_depth = 1; /* force exit in out() */ + out (); + _local_tempo_map.reset (); + } + + uint64_t depth() const { return local_tempo_map_depth; } + + virtual std::string scope_name() const = 0; + + protected: + mutable std::shared_ptr _local_tempo_map; + mutable uint64_t local_tempo_map_depth; + + private: + friend class TempoMapScope; + + void in () const { + if (_local_tempo_map && local_tempo_map_depth++ == 0 ) { + DEBUG_TRACE (PBD::DEBUG::ScopedTempoMap, string_compose ("%1: in to local tempo %2\n", scope_name(), local_tempo_map_depth)); + Temporal::TempoMap::set (_local_tempo_map); + } + } + + void out () const { + DEBUG_TRACE (PBD::DEBUG::ScopedTempoMap, string_compose ("%1: out with local tempo %2\n", scope_name(), local_tempo_map_depth)); + if (local_tempo_map_depth && --local_tempo_map_depth == 0) { + DEBUG_TRACE (PBD::DEBUG::ScopedTempoMap, string_compose ("%1: done with local tempo, depth now %2\n", scope_name(), local_tempo_map_depth)); + Temporal::TempoMap::fetch (); /* get current global map into thread-local pointer */ + } + } + +}; + + +struct TempoMapScope { + TempoMapScope (ScopedTempoMapOwner const & sco) + : scope (sco) + { + scope.in (); + } + + ~TempoMapScope () { + scope.out (); + } + + ScopedTempoMapOwner const & scope; +}; + +} // namespace + +#define EC_LOCAL_TEMPO_SCOPE Temporal::TempoMapScope __tms (*this); diff --git a/libs/temporal/temporal/tempo.h b/libs/temporal/temporal/tempo.h index cd006edec5..2638d46e5e 100644 --- a/libs/temporal/temporal/tempo.h +++ b/libs/temporal/temporal/tempo.h @@ -62,6 +62,7 @@ namespace Temporal { class Meter; class TempoMap; class TempoMapCutBuffer; +class ScopedTempoMapOwner; class MapOwned { protected: @@ -1009,11 +1010,15 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible static void map_assert (bool expr, char const * exprstr, char const * file, int line); + void set_scope_owner (ScopedTempoMapOwner&); + ScopedTempoMapOwner* scope_owner() const { return _scope_owner; } + private: Tempos _tempos; Meters _meters; MusicTimes _bartimes; Points _points; + ScopedTempoMapOwner* _scope_owner; int set_tempos_from_state (XMLNode const &); int set_meters_from_state (XMLNode const &);