inLimbo
TUI Music Player that keeps you in Limbo.
 
Loading...
Searching...
No Matches
audio_playback.hpp
Go to the documentation of this file.
1#ifndef AUDIO_PLAYBACK_HPP
2#define AUDIO_PLAYBACK_HPP
3
4#define MINIAUDIO_IMPLEMENTATION
5#include "miniaudio.h"
6#include <chrono>
7#include <iostream>
8#include <mutex>
9#include <stdexcept>
10#include <string>
11#include <thread>
12
23{
24private:
25 ma_engine engine;
26 ma_sound sound;
27 bool isPlaying;
28 bool wasPaused;
29 uint64_t pausePosition;
30 std::thread playbackThread;
31 std::mutex mtx;
32
33public:
41 MiniAudioPlayer() : isPlaying(false), wasPaused(false), pausePosition(0)
42 {
43 if (ma_engine_init(NULL, &engine) != MA_SUCCESS)
44 {
45 throw std::runtime_error("Failed to initialize MiniAudio engine.");
46 }
47 }
48
56 {
57 stop();
58 ma_sound_uninit(&sound);
59 ma_engine_uninit(&engine);
60 }
61
73 int loadFile(const std::string& filePath)
74 {
75 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
76
77 if (isPlaying)
78 {
79 stop();
80 }
81
82 ma_sound_uninit(&sound);
83
84 if (ma_sound_init_from_file(&engine, filePath.c_str(), MA_SOUND_FLAG_STREAM, NULL, NULL,
85 &sound) != MA_SUCCESS)
86 {
87 throw std::runtime_error("Failed to load audio file: " + filePath);
88 return -1;
89 }
90 return 0;
91 }
92
101 void play()
102 {
103 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
104 if (!isPlaying)
105 {
106 if (ma_sound_start(&sound) != MA_SUCCESS)
107 {
108 throw std::runtime_error("Failed to play the sound.");
109 }
110 isPlaying = true;
111
112 // Stop any existing playback thread
113 if (playbackThread.joinable())
114 {
115 playbackThread.join();
116 }
117
118 // Start a new playback thread
119 playbackThread = std::thread(
120 [this]()
121 {
122 while (isPlaying)
123 {
124 if (!ma_sound_is_playing(&sound))
125 {
126 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
127 isPlaying = false;
128 break;
129 }
130 std::this_thread::sleep_for(std::chrono::milliseconds(100));
131 }
132 });
133 }
134 }
135
144 void pause()
145 {
146 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
147 if (isPlaying)
148 {
149 // Store the current position before stopping
150 pausePosition = ma_sound_get_time_in_pcm_frames(&sound);
151
152 if (ma_sound_stop(&sound) != MA_SUCCESS)
153 {
154 throw std::runtime_error("Failed to pause the sound.");
155 }
156 isPlaying = false;
157 wasPaused = true;
158
159 if (playbackThread.joinable())
160 {
161 playbackThread.join();
162 }
163 }
164 }
165
172 void resume()
173 {
174 if (wasPaused)
175 {
176 // Seek to the stored position and start playing again
177 ma_sound_seek_to_pcm_frame(&sound, pausePosition);
178 play(); // Call play() to resume playback from the correct position
179 wasPaused = false;
180 }
181 }
182
189 void stop()
190 {
191 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
192 if (isPlaying)
193 {
194 if (ma_sound_stop(&sound) != MA_SUCCESS)
195 {
196 throw std::runtime_error("Failed to stop the sound.");
197 }
198 isPlaying = false;
199 ma_sound_seek_to_pcm_frame(&sound, 0);
200 }
201
202 if (playbackThread.joinable())
203 {
204 playbackThread.join();
205 }
206 }
207
217 void setVolume(float volume)
218 {
219 if (volume < 0.0f || volume > 1.0f)
220 {
221 throw std::invalid_argument("Volume must be between 0.0 and 1.0.");
222 }
223 ma_sound_set_volume(&sound, volume);
224 }
225
233 float getVolume() const { return ma_sound_get_volume(&sound); }
234
243 {
244 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
245 return isPlaying;
246 }
247
257 {
258 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
259 if (ma_sound_get_time_in_milliseconds(&sound) != MA_SUCCESS)
260 {
261 throw std::runtime_error("Failed to get sound duration.");
262 }
263 float duration = 0.0f;
264 ma_result result = ma_sound_get_length_in_seconds(&sound, &duration);
265 if (result != MA_SUCCESS)
266 {
267 throw std::runtime_error("Failed to get sound duration. Result: " + std::to_string(result));
268 }
269 return duration;
270 }
271
280 double seekTime(int seconds)
281 {
282 std::unique_lock<std::mutex> lock(mtx); // Protect shared state
283
284 // Get the sample rate of the sound
285 ma_uint32 sampleRate = ma_engine_get_sample_rate(&engine);
286
287 // Get the total length of the sound in PCM frames
288 ma_uint64 totalFrames;
289 ma_result result = ma_sound_get_length_in_pcm_frames(&sound, &totalFrames);
290 if (result != MA_SUCCESS)
291 {
292 std::cerr << "Failed to get total PCM frames." << std::endl;
293 }
294
295 // Get the current position in PCM frames
296 ma_uint64 currentFrames = ma_sound_get_time_in_pcm_frames(&sound);
297
298 // Calculate the new position in PCM frames
299 ma_int64 newFrames =
300 static_cast<ma_int64>(currentFrames) + static_cast<ma_int64>(seconds) * sampleRate;
301
302 // Clamp the new position to valid bounds
303 if (newFrames < 0)
304 newFrames = seconds = 0;
305 if (static_cast<ma_uint64>(newFrames) > totalFrames)
306 newFrames = totalFrames;
307
308 result = ma_sound_seek_to_pcm_frame(&sound, static_cast<ma_uint64>(newFrames));
309 if (result != MA_SUCCESS)
310 {
311 std::cerr << "Failed to seek sound." << std::endl;
312 }
313
314 return (double)seconds;
315 }
316};
317
318#endif
float getVolume() const
Gets the current volume of the audio playback.
Definition audio_playback.hpp:233
bool isCurrentlyPlaying()
Checks if the sound is currently playing.
Definition audio_playback.hpp:242
int loadFile(const std::string &filePath)
Loads an audio file for playback.
Definition audio_playback.hpp:73
void resume()
Resumes playback from the last paused position.
Definition audio_playback.hpp:172
void stop()
Stops the playback and resets the playback position.
Definition audio_playback.hpp:189
void pause()
Pauses the current audio playback.
Definition audio_playback.hpp:144
void setVolume(float volume)
Sets the volume of the audio playback.
Definition audio_playback.hpp:217
double seekTime(int seconds)
Seeks to a specific time in the audio (in seconds).
Definition audio_playback.hpp:280
MiniAudioPlayer()
Constructs a MiniAudioPlayer object and initializes the MiniAudio engine.
Definition audio_playback.hpp:41
~MiniAudioPlayer()
Destroys the MiniAudioPlayer object, stopping any playback and cleaning up resources.
Definition audio_playback.hpp:55
float getDuration()
Gets the total duration of the sound in seconds.
Definition audio_playback.hpp:256
void play()
Starts playback of the loaded audio file.
Definition audio_playback.hpp:101