CoriEngine
Loading...
Searching...
No Matches
Track.hpp
Go to the documentation of this file.
1#pragma once
3#include "Mixer.hpp"
4#include "Sound.hpp"
5
6struct MIX_Track;
7
8namespace Cori {
9 namespace Audio {
10 using TrackStopCallbackFn = std::function<void()>;
11 using SoundWithParams = std::pair<std::shared_ptr<Sound>, PlayParams>;
12
13 template<typename T>
14 concept IsSoundWithParams = std::is_same_v<T, SoundWithParams>;
15
19 class Track : public Profiling::Trackable<Track> {
20 public:
27 std::expected<void, Core::CoriError<>> SetSound(const std::shared_ptr<Sound>& sound);
28
29
36 std::expected<void, Core::CoriError<>> Start(const PlayParams& params = PlayParams{});
37
38
49 std::expected<void, Core::CoriError<>> Play(const IsSoundWithParams auto&... sequence) {
50 if (m_Valid) {
51 if (!m_ActiveSequence) {
52 m_SoundSequence.clear();
53 m_SoundSequence.reserve(sizeof...(sequence));
54 (..., m_SoundSequence.push_back(sequence));
55 m_EraseLastInSequence = false;
56 m_SequenceIntroFinished = false;
57
58 m_CurrentLoopedSequenceIndex = 0;
59 auto& initialPart = m_SoundSequence.back();
60
61 const auto success = PlaySoundWithParams(initialPart);
62 if (!success) {
63 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Audio::Self, Logger::Tags::Audio::Track }, "An error occurred when trying to play a part of sequence. Details: {}", success.error().what());
64 }
65
66 m_ActiveSequence = true;
67 if constexpr (sizeof...(sequence) > 2) {
68 if (!initialPart.second.LoopedInSequence) {
69 m_EraseLastInSequence = true;
70 }
71 else {
72 m_SequenceIntroFinished = true;
73 m_CurrentLoopedSequenceIndex = m_SoundSequence.size() - 2;
74 }
75
76 SetTrackStopCallbackInternal([this] {
77 if (m_EraseLastInSequence) {
78 m_SoundSequence.pop_back();
79 m_EraseLastInSequence = false;
80 }
81 if (!m_SoundSequence.empty()) {
82 SoundWithParams* part;
83
84 if (m_SequenceIntroFinished) {
85 part = &m_SoundSequence.at(m_CurrentLoopedSequenceIndex);
86 }
87 else {
88 part = &m_SoundSequence.back();
89 }
90
91 m_ActiveSequence = false;
92 const auto success_ = PlaySoundWithParams(*part);
93 if (!success_) {
94 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Audio::Self, Logger::Tags::Audio::Track }, "An error occurred when trying to play a part of sequence. Details: {}", success_.error().what());
95 }
96 m_ActiveSequence = true;
97
98 if (!part->second.LoopedInSequence && !m_SequenceIntroFinished) {
99 m_EraseLastInSequence = true;
100 }
101 else {
102 if (m_SequenceIntroFinished) {
103 if (m_CurrentLoopedSequenceIndex == 0) {
104 m_CurrentLoopedSequenceIndex = m_SoundSequence.size() - 1;
105 }
106 else {
107 --m_CurrentLoopedSequenceIndex;
108 }
109 }
110 else {
111 m_SequenceIntroFinished = true;
112 if (m_CurrentLoopedSequenceIndex == 0) {
113 m_CurrentLoopedSequenceIndex = m_SoundSequence.size() - 2;
114 }
115 else {
116 --m_CurrentLoopedSequenceIndex;
117 }
118 }
119 }
120 }
121 else {
122 const auto success_ = Stop(false);
123 if (!success_) {
124 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Audio::Self, Logger::Tags::Audio::Track }, "An error occurred when trying to stop a sequence inside of Engine side Callback. Details: {}", success_.error().what());
125 }
126 }
127 });
128 return {};
129 }
130 else {
131 if (initialPart.second.LoopedInSequence) {
132 SetTrackStopCallbackInternal([this] {
133 SoundWithParams* part = &m_SoundSequence.at(0);
134 m_ActiveSequence = false;
135 const auto success_ = PlaySoundWithParams(*part);
136 if (!success_) {
137 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Audio::Self, Logger::Tags::Audio::Track }, "An error occurred when trying to play a part of sequence. Details: {}", success_.error().what());
138 }
139 m_ActiveSequence = true;
140 });
141 return {};
142 }
143
144 m_ActiveSequence = false;
145 return {};
146 }
147 }
148
149 return std::unexpected(Core::CoriError(std::format("Failed to play sequence on Track '{} (TrackID: {})'. A sequence is already playing on this track.", m_Name, m_ID)));
150 }
151
152 return std::unexpected(Core::CoriError(std::format("Failed to play sequence on Track '{} (TrackID: {})'. Track object is invalid.", m_Name, m_ID)));
153 }
154
163 std::expected<void, Core::CoriError<>> Stop(const bool abruptStop, const int64_t fadeOutMS = 0);
164
165
171 std::expected<void, Core::CoriError<>> Pause();
172
173
178 std::expected<void, Core::CoriError<>> Resume();
179
184 [[nodiscard]] bool IsPaused() const;
185
186
191 [[nodiscard]] bool IsPlaying() const;
192
200 std::expected<void, Core::CoriError<>> SetGain(const float gain);
201
202
207 [[nodiscard]] float GetGain() const;
208
214 std::expected<void, Core::CoriError<>> SetTag(const char* tag);
215
222 void RemoveTag(const char* tag, const bool preserveCachedTag = false);
223
228 [[nodiscard]] std::string_view GetTag() const;
229
235 [[nodiscard]] bool IsValid() const;
236
240 [[nodiscard]] TrackID GetID() const;
241
248
254 [[nodiscard]] static std::shared_ptr<Track> Create(std::string name);
255
256 ~Track();
257
258 const std::string m_Name;
259
263 static void TrackStopCallback(void* userdata, MIX_Track* track);
264
265 private:
266 explicit Track(std::string name);
267
268 std::expected<void, Core::CoriError<>> PlaySoundWithParams(SoundWithParams& object);
269
270 std::expected<void, Core::CoriError<>> StopInternal(const int64_t fadeOutMS) const;
271
272 TrackStopCallbackFn m_EngineCallBack;
273 TrackStopCallbackFn m_ClientCallBack;
274
275 std::expected<void, Core::CoriError<>> ProcessSequencePart(const SoundWithParams& part);
276
277 void SetTrackStopCallbackInternal(TrackStopCallbackFn callback);
278
279 const TrackID m_ID{ 0 };
280 bool m_Valid{ false };
281 bool m_ActiveSequence{ false };
282 bool m_EraseLastInSequence{ false };
283 bool m_SequenceIntroFinished{ false };
284 uint32_t m_CurrentLoopedSequenceIndex{ 0 };
285 std::string m_CurrentTag{};
286 std::vector<SoundWithParams> m_SoundSequence;
287 inline static std::atomic<TrackID> s_NextIndex{ 1 };
288 };
289 }
290}
#define CORI_CORE_ERROR_TAGGED(...)
Definition Logger.hpp:1039
const std::string m_Name
Definition Track.hpp:258
void RemoveTag(const char *tag, const bool preserveCachedTag=false)
Removes the tag from the Track.
Definition Track.cpp:123
static void TrackStopCallback(void *userdata, MIX_Track *track)
For internal use only!
Definition Track.cpp:162
std::string_view GetTag() const
Gets the active/cached Track tag.
Definition Track.cpp:134
std::expected< void, Core::CoriError<> > Start(const PlayParams &params=PlayParams{})
Starts the Track that has a preassigned Sound asset.
Definition Track.cpp:29
std::expected< void, Core::CoriError<> > Resume()
Resumes the Track.
Definition Track.cpp:71
std::expected< void, Core::CoriError<> > Stop(const bool abruptStop, const int64_t fadeOutMS=0)
Stops the Track.
Definition Track.cpp:42
bool IsValid() const
Check if the Track is valid.
Definition Track.cpp:142
float GetGain() const
Returns the current Track gain. The default gain for a Track is 1.0f.
Definition Track.cpp:105
TrackID GetID() const
Returns the TrackID associated with Track.
Definition Track.cpp:146
std::expected< void, Core::CoriError<> > SetSound(const std::shared_ptr< Sound > &sound)
Assigns the Sound asset to the Track.
Definition Track.cpp:6
bool IsPaused() const
Checks if the Track is paused.
Definition Track.cpp:80
std::expected< void, Core::CoriError<> > SetGain(const float gain)
Sets the Track gain.
Definition Track.cpp:96
void SetTrackStopCallback(TrackStopCallbackFn callback)
Sets a callback to be run when the Track stops playing.
Definition Track.cpp:150
std::expected< void, Core::CoriError<> > SetTag(const char *tag)
Assigns the tag to the Track.
Definition Track.cpp:113
static std::shared_ptr< Track > Create(std::string name)
Creates a Track object.
Definition Track.cpp:154
std::expected< void, Core::CoriError<> > Pause()
Pauses the Track.
Definition Track.cpp:62
bool IsPlaying() const
Checks if the Track is playing.
Definition Track.cpp:88
std::expected< void, Core::CoriError<> > Play(const IsSoundWithParams auto &... sequence)
Plays a single or a sequence of SoundWithParams objects.
Definition Track.hpp:49
Custom error class mainly used in std::expected.
Definition Error.hpp:27
For InstanceMetrics to work with a type it should derive from this.
Definition Trackable.hpp:29
Everything connected to audio is in this namespace.
Definition IDDefs.hpp:4
std::pair< std::shared_ptr< Sound >, PlayParams > SoundWithParams
Definition Track.hpp:11
uint16_t TrackID
Definition IDDefs.hpp:5
std::function< void()> TrackStopCallbackFn
Definition Track.hpp:10
Global engine namespace.
Parameters to be used when playing sound, you can mix your audio playback however you want with these...
Definition Mixer.hpp:20
static constexpr char Self[]
Definition Logger.hpp:75
static constexpr char Track[]
Definition Logger.hpp:78