Don't copy DetuningHelper in Note copy constructor (#7888)

Reworks how note detuning copying works so as not to perform a clip duplication and allocation by default in the constructors

---------

Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
This commit is contained in:
regulus79
2025-05-28 19:28:13 -04:00
committed by GitHub
parent cb84fce599
commit 7e02795f47
7 changed files with 26 additions and 119 deletions

View File

@@ -27,7 +27,6 @@
#include "AutomationNode.h"
#include "AutomationClip.h"
#include "shared_object.h"
namespace lmms
{

View File

@@ -104,12 +104,15 @@ public:
int key = DefaultKey,
volume_t volume = DefaultVolume,
panning_t panning = DefaultPanning,
DetuningHelper * detuning = nullptr );
std::shared_ptr<DetuningHelper> detuning = nullptr);
Note( const Note & note );
~Note() override;
Note& operator=(const Note& note);
//! Performs a deep copy and returns an owning raw pointer
Note* clone() const;
// Note types
enum class Type
{
@@ -237,10 +240,8 @@ public:
static TimePos quantized( const TimePos & m, const int qGrid );
DetuningHelper * detuning() const
{
return m_detuning.get();
}
const std::shared_ptr<DetuningHelper>& detuning() const { return m_detuning; }
bool hasDetuningInfo() const;
bool withinRange(int tickStart, int tickEnd) const;
@@ -265,7 +266,7 @@ private:
panning_t m_panning;
TimePos m_length;
TimePos m_pos;
std::unique_ptr<DetuningHelper> m_detuning;
std::shared_ptr<DetuningHelper> m_detuning;
Type m_type = Type::Regular;
};

View File

@@ -1,89 +0,0 @@
/*
* shared_object.h - class sharedObject for use among other objects
*
* Copyright (c) 2006-2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_SHARED_OBJECT_H
#define LMMS_SHARED_OBJECT_H
#include <atomic>
namespace lmms
{
class sharedObject
{
public:
sharedObject() :
m_referenceCount(1)
{
}
virtual ~sharedObject() = default;
template<class T>
static T* ref( T* object )
{
// Incrementing an atomic reference count can be relaxed since no action
// is ever taken as a result of increasing the count.
// Other loads and stores can be reordered around this without consequence.
object->m_referenceCount.fetch_add(1, std::memory_order_relaxed);
return object;
}
template<class T>
static void unref( T* object )
{
// When decrementing an atomic reference count, we need to provide
// two ordering guarantees:
// 1. All reads and writes to the referenced object occur before
// the count reaches zero.
// 2. Deletion occurs after the count reaches zero.
//
// To accomplish this, each decrement must be store-released,
// and the final thread (which is deleting the referenced data)
// must load-acquire those stores.
// The simplest way to do this to give the decrement acquire-release
// semantics.
//
// See https://www.boost.org/doc/libs/1_67_0/doc/html/atomic/usage_examples.html
// for further discussion, along with a slightly more complicated
// (but possibly more performant on weakly-ordered hardware like ARM)
// approach.
const bool deleteObject =
object->m_referenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1;
if ( deleteObject )
{
object->deleteLater();
}
}
private:
std::atomic_int m_referenceCount;
} ;
} // namespace lmms
#endif // LMMS_SHARED_OBJECT_H