Skip to content

Commit

Permalink
wip(amplimix): New Pipeline architecture.
Browse files Browse the repository at this point in the history
Signed-off-by: Axel Nana <[email protected]>
  • Loading branch information
na2axl committed Aug 25, 2024
1 parent 301eb2d commit 19e7231
Show file tree
Hide file tree
Showing 7 changed files with 582 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ set(SA_SOURCE
include/SparkyStudios/Audio/Amplitude/Math/SplitComplex.h
include/SparkyStudios/Audio/Amplitude/Math/Utils.h
include/SparkyStudios/Audio/Amplitude/Mixer/Amplimix.h
include/SparkyStudios/Audio/Amplitude/Mixer/Node.h
include/SparkyStudios/Audio/Amplitude/Mixer/Pipeline.h
include/SparkyStudios/Audio/Amplitude/Mixer/SoundProcessor.h
include/SparkyStudios/Audio/Amplitude/Sound/Attenuation.h
Expand Down Expand Up @@ -319,8 +320,10 @@ set(SA_SOURCE
src/Mixer/Pipeline/OcclusionProcessor.h
src/Mixer/Pipeline/PassThroughProcessor.h
src/Mixer/Pipeline/SilenceProcessor.h

src/Mixer/Amplimix.h
src/Mixer/Amplimix.cpp
src/Mixer/Node.cpp
src/Mixer/Pipeline.cpp
src/Mixer/RealChannel.cpp
src/Mixer/RealChannel.h
Expand Down
1 change: 1 addition & 0 deletions include/SparkyStudios/Audio/Amplitude/Amplitude.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include <SparkyStudios/Audio/Amplitude/Math/Utils.h>

#include <SparkyStudios/Audio/Amplitude/Mixer/Amplimix.h>
#include <SparkyStudios/Audio/Amplitude/Mixer/Pipeline.h>
#include <SparkyStudios/Audio/Amplitude/Mixer/SoundProcessor.h>

#include <SparkyStudios/Audio/Amplitude/Sound/Attenuation.h>
Expand Down
352 changes: 352 additions & 0 deletions include/SparkyStudios/Audio/Amplitude/Mixer/Node.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
// Copyright (c) 2024-present Sparky Studios. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#ifndef _AM_MIXER_NODE_H
#define _AM_MIXER_NODE_H

#include <SparkyStudios/Audio/Amplitude/Core/AudioBuffer.h>
#include <SparkyStudios/Audio/Amplitude/Core/Common.h>

namespace SparkyStudios::Audio::Amplitude
{
class AmplimixLayer;
class Pipeline;

/**
* @brief An instance of an Amplimix pipeline node.
*
* This class represents the actual node executed within the
* Amplimix pipeline. Each node instance has a unique ID assigned
* to it, that matches the one provided in the pipeline asset.
*/
class AM_API_PUBLIC NodeInstance
{
public:
/**
* @brief NodeInstance constructor.
*
* @param id Unique identifier for the node instance.
*/
NodeInstance(AmObjectID id);

/**
* @brief NodeInstance destructor.
*/
virtual ~NodeInstance() = default;

/**
* @brief Returns the unique identifier for the node instance.
*/
[[nodiscard]] AmObjectID GetId() const;

protected:
AmObjectID m_id; /// The unique identifier for the node instance in the pipeline.
};

/**
* @brief Interface for Amplimix pipeline nodes that can consume
* audio data from an input buffer.
*/
class AM_API_PUBLIC ConsumerNodeInstance
{
public:
/**
* @brief Consumes audio data from the provider node
* specified with the call of @c ConsumerNodeInstance::Connect().
*/
virtual void Consume() = 0;

/**
* @brief Set the input provider node ID for this node.
*
* @param provider The provider node for this node.
*/
virtual void Connect(AmObjectID provider) = 0;
};

/**
* @brief Interface for Amplimix pipeline nodes that can provide
* audio data to an output buffer.
*/
class AM_API_PUBLIC ProviderNodeInstance
{
public:
/**
* @brief Produces audio data ready to be taken as input of
* a consumer node.
*
* @return The output audio data.
*/
virtual AudioBuffer Provide() = 0;
};

/**
* @brief Base class for Amplimix pipeline nodes that can process
* audio data in-place.
*/
class AM_API_PUBLIC ProcessorNodeInstance
: public NodeInstance
, public ConsumerNodeInstance
, public ProviderNodeInstance
{
public:
/**
* @brief ProcessorNodeInstance constructor.
*/
ProcessorNodeInstance(AmObjectID id, Pipeline* pipeline);

/**
* @brief ProcessorNodeInstance destructor.
*/
~ProcessorNodeInstance() override = default;

/**
* @brief Process input audio data and returns the output audio data.
*
* @param input The input audio data to process.
*
* @return The output audio data.
*/
virtual AudioBuffer Process(const AudioBuffer& input) = 0;

/**
* @copydoc ConsumerNodeInstance::Consume()
*/
void Consume() final;

/**
* @copydoc ConsumerNodeInstance::Connect()
*/
void Connect(AmObjectID provider) final;

/**
* @copydoc ProviderNodeInstance::Provide()
*/
AudioBuffer Provide() final;

protected:
AmObjectID m_provider;
Pipeline* m_pipeline; ///< The pipeline this node instance belongs to.

private:
AudioBuffer _processingBuffer;
};

/**
* @brief Base class for Amplimix pipeline nodes that can mix
* audio data from multiple input buffers, and outputs the result
* of the mix.
*/
class AM_API_PUBLIC MixerNodeInstance
: public NodeInstance
, public ConsumerNodeInstance
, public ProviderNodeInstance
{
public:
/**
* @brief MixerNodeInstance constructor.
*/
MixerNodeInstance(AmObjectID id, Pipeline* pipeline);

/**
* @brief MixerNodeInstance destructor.
*/
~MixerNodeInstance() override = default;

/**
* @brief Mixes audio data from multiple inputs, and outputs the result
* of the mix.
*
* @param inputs The list of input audio data to mix.
*
* @return The output audio data.
*/
virtual AudioBuffer Mix(const std::vector<AudioBuffer>& inputs) = 0;

/**
* @copydoc ConsumerNodeInstance::Consume()
*/
void Consume() final;

/**
* @copydoc ConsumerNodeInstance::Connect()
*
* @note This method appends the given provider to the list of input
* provider nodes. If the provider node already exists in the list, it
* will not be added again.
*/
void Connect(AmObjectID provider) final;

/**
* @brief Set the input provider nodes for this mixer node.
*
* @param providers The provider nodes for this mixer node.
*
* @note This method clears the existing input provider nodes,
* and replaces them with the provided ones.
*/
void In(const std::vector<AmObjectID>& providers);

/**
* @copydoc ProviderNodeInstance::Provide()
*/
AudioBuffer Provide() final;

protected:
std::vector<AmObjectID> m_providers;
Pipeline* m_pipeline; ///< The pipeline this node instance belongs to.

private:
std::vector<AudioBuffer> _processingBuffers;
};

class AM_API_PUBLIC InputNodeInstance final
: public NodeInstance
, public ProviderNodeInstance
{
friend class Pipeline;

/**
* @brief Class used to marks the input of the pipeline.
*
* This node is automatically added to the pipeline when created. And thus
* should not be manually added to the pipeline asset.
*/
public:
/**
* @brief InputNodeInstance constructor.
*/
InputNodeInstance(AmObjectID id, Pipeline* pipeline);

/**
* @brief InputNodeInstance destructor.
*/
~InputNodeInstance() override = default;

/**
* @brief Set the input of the pipeline.
*
* @param layer The layer to which this input belongs.
* @param buffer The buffer to set as the input.
*/
void SetInput(const AmplimixLayer* layer, const AudioBuffer* buffer);

/**
* @copydoc ProviderNodeInstance::Provide()
*/
AudioBuffer Provide() final;

private:
const AmplimixLayer* _layer;
const AudioBuffer* _buffer;
};

/**
* @brief Class used to marks the output of the pipeline.
*
* This node is automatically added to the pipeline when created. And thus
* should not be manually added to the pipeline asset.
*/
class AM_API_PUBLIC OutputNodeInstance final
: public NodeInstance
, public ConsumerNodeInstance
{
friend class Pipeline;

public:
/**
* @brief OutputNodeInstance constructor.
*/
OutputNodeInstance(AmObjectID id, Pipeline* pipeline);

/**
* @brief OutputNodeInstance destructor.
*/
~OutputNodeInstance() override = default;

/**
* @brief Set the output of the pipeline.
*
* @param buffer The buffer to set as the output.
*/
void SetOutput(AudioBuffer* buffer);

/**
* @copydoc ConsumerNodeInstance::Consume()
*/
void Consume() final;

/**
* @copydoc ConsumerNodeInstance::Connect()
*/
void Connect(AmObjectID provider) final;

private:
AmObjectID _provider;
Pipeline* _pipeline; ///< The pipeline this node instance belongs to.
AudioBuffer* _buffer;
};

/**
* @brief Base class for Amplimix pipeline nodes.
*
* This class presents the basic structure to create Amplimix
* pipeline nodes. Each @c Node must be derived from this class
* and implement the @c Node::CreateInstance() and
* @c Node::DestroyInstance() methods.
*/
class AM_API_PUBLIC Node
{
public:
/**
* @brief Node constructor.
*
* @param name Name of the node. Should be unique within the pipeline.
*/
Node(AmString name);

/**
* @brief Node destructor.
*/
virtual ~Node() = default;

/**
* @brief Returns the name of the node.
*/
[[nodiscard]] const AmString& GetName() const;

/**
* @brief Creates a new instance of the node.
*
* @param id Unique identifier for the new instance.
*
* @return A new instance of the node.
*/
virtual NodeInstance* CreateInstance(AmObjectID id) const = 0;

/**
* @brief Destroys the specified instance of the node.
*
* @param instance Pointer to the instance to be destroyed.
*/
virtual void DestroyInstance(NodeInstance* instance) const = 0;

private:
AmString _name;
};
} // namespace SparkyStudios::Audio::Amplitude

#endif // _AM_MIXER_NODE_H
Loading

0 comments on commit 19e7231

Please sign in to comment.