WIP Edits

This commit is contained in:
2025-07-18 12:25:25 -05:00
parent 6501c6b0e8
commit 9bd6dc956f
8 changed files with 65 additions and 119 deletions

View File

@@ -38,9 +38,7 @@ endif()
include_directories("include") include_directories("include")
add_library(ReMixer ${SOURCES} add_library(ReMixer ${SOURCES})
src/linux/PulseSubsystem.cpp
src/linux/SoundSubsystem.cpp)
add_executable(ReMixer-Test main.cpp) add_executable(ReMixer-Test main.cpp)
@@ -65,7 +63,7 @@ target_link_libraries(ReMixer-Test PUBLIC ReMixer)
add_executable(pacat pacat_simple.cpp add_executable(pacat pacat_simple.cpp
src/windows/ReMixer.cpp src/windows/ReMixer.cpp
include/ReMixer/PulseSubsystem.h) include/ReMixer/PulseDevice.h)
target_link_libraries(pacat pulse-simple pulse) target_link_libraries(pacat pulse-simple pulse)
add_executable(vorbis_decode vorbis_decode.cpp) add_executable(vorbis_decode vorbis_decode.cpp)

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "AudioFormat.hpp"
#include "ReMixer.h" #include "ReMixer.h"
namespace ReMixer { namespace ReMixer {
@@ -15,6 +16,12 @@ namespace ReMixer {
std::set<AudioFormat> supported_formats; std::set<AudioFormat> supported_formats;
}; };
class IAudioDevice;
using PlaybackCallback = std::;
using CaptureCallback = 0;
using DeviceStateCallback = 0;
class IAudioDevice { class IAudioDevice {
public: public:
virtual ~IAudioDevice() = default; virtual ~IAudioDevice() = default;
@@ -25,6 +32,15 @@ namespace ReMixer {
virtual bool Stop() = 0; virtual bool Stop() = 0;
virtual bool IsRunning() const = 0; virtual bool IsRunning() const = 0;
virtual AudioDeviceInfo GetInfo() const = 0;
virtual AudioFormat GetActualFormat() const = 0;
virtual uint32_t GetActualBufferSizeFrames() const = 0;
virtual double GetLatencyMilliseconds() const = 0;
template <typename T>
T* AsPlatformSpecific() { return dynamic_cast<T>(*this); }
}; };
} }

View File

@@ -25,6 +25,20 @@
namespace ReMixer namespace ReMixer
{ {
namespace PulseAudio {
class PulseDevice : public IAudioDevice {
public:
PulseDevice(const AudioDeviceInfo& info);
~PulseDevice() override;
};
}
/// A PulseAudio implementation of the SoundSubsystem. /// A PulseAudio implementation of the SoundSubsystem.
class PulseAudioSubsystem : public SoundSubsystem class PulseAudioSubsystem : public SoundSubsystem
{ {

View File

@@ -7,137 +7,42 @@
namespace ReMixer { namespace ReMixer {
/// 1. Abstraction Layer: /// TODO: Support JACK
/// Define abstract base classes or interfaces that capture the common /// TOOD: Support ALSA
/// functionalities across all supported audio APIs. /// TODO: Support PulseAudio
/// 2. Platform Specific Implementations: /// TODO: Support WASAPI
/// Create conrete classes for each platform (PulseDevice, WasapiDevice)
/// that inherit from the abstract interfaces and implement the API-specific calls.
/// 3. Factory Pattern:
/// Use a factory function or class to create the correct platform-specific
/// implementation at runtime, based on the operating system.
/// 4. Resource Management:
/// Employ RAII for managing audio device handles, streams, and buffers. Utilize Smart Pointers?
/// 5. Callbacks for asynchronous operations:
/// Most low-level audio APIs use callbacks for delivering audio data (playback/capture)
/// or notifying of device state changes. Your wrapper classes should expose this through
/// C++ lambdas or std::function (or josh/Event)
/// 6. Error Handling:
/// A consistent error reporting mechanism is crucial
/// 7. Data Formats:
/// Handle common audio formats (PCM float, int16, int32) and sample rates. Provide conversion utilities if necessary.
/// 8. Device Enumeration:
/// Allow users to discover available audio input and output devices.
///
enum class SampleFormat {
Unknown,
Float16,
Float32,
Int16,
Int32,
};
unsigned operator ""_Hz(unsigned long long int frequency);
unsigned operator ""_kHz(long double frequency);
unsigned operator ""_kHz(unsigned long long int frequency);
struct AudioFormat {
uint32_t sample_rate;
uint16_t channels;
SampleFormat format;
static AudioFormat StereoFloat(uint32_t rate) {
return {rate, 2, SampleFormat::Float16};
}
static AudioFormat StereoFloat48kHz() {
return StereoFloat(48_kHz);
}
};
enum class DeviceType { // TODO: Support Recording
Unknown, Output, Input, Duplex
};
struct AudioDeviceInfo {
std::string id;
std::string name;
DeviceType type;
bool is_default;
std::set<AudioFormat> supported_formats;
};
class Sound; class Sound;
class SoundHandle;
class IAudioDevice;
class Stream; class Stream;
class SoundSubsystem; class SoundSubsystem;
class PulseAudioSubsystem; class PulseAudioSubsystem;
class PulseStream; class PulseStream;
enum class PlaybackStatus { Stopped, Playing, Paused, Finished, Error };
class SoundHandle {
friend void Init();
friend SoundHandle* PlaySoundAsync(Sound& sound);
public:
Event<> Finished;
Event<> Paused;
Event<std::string> ErrorEncountered;
void Pause();
void Resume();
void Stop();
PlaybackStatus Status() const;
bool IsPlaying() const;
bool IsPaused() const;
bool IsStopped();
float GetPlaybackPositionMs() const;
float GetPlaybackPositionPercent() const;
/// Playback speed control (e.g., 0.5 for half speed, 2.0 for double speed)
/// @note Requires sample rate conversion or similar at lower level.
void SetPlaybackSpeed(float rate);
float GetPlaybackSpeed() const;
void SetPlaybackPositionMs(float ms);
void SetPlaybackPositionPercent(float percent);
void Seek(float ms);
void SeekPercent(float percent);
/// Volume control (0.0 to 1.0)
void SetVolume(float volume);
float GetVolume() const;
protected:
SoundHandle(const Sound& sound);
private:
};
class IAudioDevice {
public:
virtual ~IAudioDevice() = default;
virtual bool Initialize(const AudioFormat& requestedFormat, uint32_t bufferSizeFrames) = 0;
virtual void Shutdown() = 0;
virtual bool Start() = 0;
virtual bool Stop() = 0;
virtual bool IsRunning() const = 0;
};
void Init(); void Init();
void Cleanup(); void Cleanup();
#pragma region Simple API
/// Simple high-level API for sound playback. /// Simple high-level API for sound playback.
/// @note Assumes you want the default device, and ideal parameters to properly play the sound. /// @note Assumes you want the default device, and ideal parameters to properly play the sound.
/// @return SoundHandle instance for managing the state of playback. (i.e. pause, seek, resume, playback speed, events.) /// @return SoundHandle instance for managing the state of playback. (i.e. pause, seek, resume, playback speed, events.)
SoundHandle* PlaySoundAsync(Sound& Sound); SoundHandle* PlaySoundAsync(Sound& Sound);
std::vector<IAudioDevice*> EnumerateDevices();
#pragma endregion
#pragma region Advanced API
#pragma endregion
} }

View File

@@ -20,6 +20,8 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include "AudioFormat.hpp"
int mix(int a, int b); int mix(int a, int b);
namespace ReMixer { namespace ReMixer {

View File

@@ -0,0 +1,8 @@
//
// Created by josh on 7/16/25.
//
#ifndef WASAPIDEVICE_HPP
#define WASAPIDEVICE_HPP
#endif //WASAPIDEVICE_HPP

View File

@@ -16,13 +16,16 @@
#include <thread> #include <thread>
#include <ReMixer/stream.h> #include <ReMixer/stream.h>
#include <ReMixer/Sound.hpp> #include <ReMixer/Sound.hpp>
#include <ReMixer/PulseSubsystem.h> #include <ReMixer/PulseDevice.h>
#include <ReMixer/ReMixer.h> #include <ReMixer/ReMixer.h>
#include "ReMixer/Frequency.hpp"
[[noreturn]] int main() { [[noreturn]] int main() {
using namespace ReMixer; using namespace ReMixer;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace ReMixer::FrequencyLiterals;
uint measurement = 44.1_kHz; uint measurement = 44.1_kHz;

View File

@@ -1,4 +1,4 @@
#include <ReMixer/PulseSubsystem.h> #include <ReMixer/PulseDevice.h>
void ReMixer::PulseAudioSubsystem::Play(ReMixer::PulseStream &stream, const ReMixer::Sound &sound) { void ReMixer::PulseAudioSubsystem::Play(ReMixer::PulseStream &stream, const ReMixer::Sound &sound) {