From 57937e322b162ff26729c6db48fd0b8ee2baddf5 Mon Sep 17 00:00:00 2001 From: Redacted Date: Tue, 6 Aug 2024 22:36:34 -0400 Subject: [PATCH] Initial Commit --- CMakeLists.txt | 50 ++++++++++++++++++++ cmake/CPM.cmake | 24 ++++++++++ include/ReMixer/ReMixer.h | 10 ++++ include/ReMixer/StreamManager.h | 48 +++++++++++++++++++ include/ReMixer/sound.h | 43 +++++++++++++++++ include/ReMixer/stream.h | 50 ++++++++++++++++++++ main.cpp | 81 +++++++++++++++++++++++++++++++++ src/linux/ReMixer.cpp | 7 +++ src/linux/StreamManager.cpp | 1 + src/linux/sound.cpp | 12 +++++ src/linux/stream.cpp | 34 ++++++++++++++ 11 files changed, 360 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/CPM.cmake create mode 100644 include/ReMixer/ReMixer.h create mode 100644 include/ReMixer/StreamManager.h create mode 100644 include/ReMixer/sound.h create mode 100644 include/ReMixer/stream.h create mode 100644 main.cpp create mode 100644 src/linux/ReMixer.cpp create mode 100644 src/linux/StreamManager.cpp create mode 100644 src/linux/sound.cpp create mode 100644 src/linux/stream.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..29a0da5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.18) +project(ReMixer + VERSION 1.0 + LANGUAGES CXX +) + +set(CMAKE_CXX_STANDARD 20) + + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(cmake/CPM.cmake) + +CPMAddPackage( + NAME uuid + URL https://git.redacted.cc/Redacted/uuid/archive/Release-1.zip +) + +if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) + message(FATAL_ERROR "In-Source builds are not allowed") +endif() + +file(GLOB_RECURSE HEADERS "include/ReMixer/*.h") + +if(UNIX AND NOT APPLE) + file(GLOB_RECURSE SOURCES "src/shared/*.cpp" "src/linux/*.cpp") +endif() + +if(WIN32) + file(GLOB_RECURSE HEADERS "include/ReMixer/*.h") + file(GLOB_RECURSE SOURCES "src/shared/*.cpp" "src/windows/*.cpp") +endif() + +include_directories("include" ${uuid_SOURCE_DIR}/include) + +add_library(ReMixer ${SOURCES}) +add_executable(ReMixer-Test main.cpp) + +set_target_properties(ReMixer PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(ReMixer-Test PROPERTIES LINKER_LANGUAGE CXX) + +if(UNIX AND NOT APPLE) + target_link_libraries(ReMixer PUBLIC vorbisfile vorbis pulse-simple pulse uuid) +endif() + +if(WIN32) + #target_link_libraries(Remixer PUBLIC) +endif() + +target_link_libraries(ReMixer-Test PUBLIC ReMixer) diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake new file mode 100644 index 0000000..d866ad7 --- /dev/null +++ b/cmake/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.38.7) +set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) \ No newline at end of file diff --git a/include/ReMixer/ReMixer.h b/include/ReMixer/ReMixer.h new file mode 100644 index 0000000..788b3b3 --- /dev/null +++ b/include/ReMixer/ReMixer.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace ReMixer { + uint16_t createStream(const std::string& application_name, const std::string& stream_name, SampleRate sample_rate, StreamMode mode); +} + +// this dick \ No newline at end of file diff --git a/include/ReMixer/StreamManager.h b/include/ReMixer/StreamManager.h new file mode 100644 index 0000000..e4d2b76 --- /dev/null +++ b/include/ReMixer/StreamManager.h @@ -0,0 +1,48 @@ +/// ReMixer +/// A Public Domain C++ Audio Playback Library +/// By william @ RedactedSoftware. Thanks to Dawsh & Maxine. +/// (c) 2024 Redacted Software +/// This work is explicitly dedicated to the public domain, for the hopeful betterment of the software industry. + +/// @file StreamManager.h +/// @desc This class manages internal creation and storage of active Streams. +/// @edit 2024-08-06 + +#pragma once +#include +#include "stream.h" + +class TakenStreamIDException : public std::exception +{ + +}; + +class StreamManager { +public: + static std::map streamList; + + //StreamManager(); + //StreamManager(const StreamManager&); + // Get stream using handle + static Stream *GetStream(uint16_t handle) + { + return streamList.at(handle); + } + // Return Stream handle + // TODO: + static Stream* CreateStream() + { + + // Can we create the stream here and assign the handle on our side? + // or do you need to change it from outside + } + static void AddStream(Stream* stream) + { + streamList.emplace(stream->handle, stream); + } + // Iterator maybe? + // Fuck if I know what type is returned. + auto begin() { return streamList.begin(); }; + auto end() { return streamList.end(); }; + +}; \ No newline at end of file diff --git a/include/ReMixer/sound.h b/include/ReMixer/sound.h new file mode 100644 index 0000000..e70b9fd --- /dev/null +++ b/include/ReMixer/sound.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include + + +class PlaybackDevice {}; +class InputDevice {}; + +class Sound { +private: + std::vector audio_data; +public: + std::vector getAudioData(); + void setAudioData(const std::vector& audioData); + uint8_t* ptr() { return audio_data.data();} + [[nodiscard]] const uint8_t* ptr() const { return audio_data.data();} + Sound() = default; + explicit Sound(const std::vector& audioData); +}; + + + +/// Short (sub-10-second) audio clips via OGG vorbis format. +class SFX : public Sound { +public: + SFX() = default; + SFX(const std::filesystem::path& sfx_file_path) + { + + } +}; + +/// Longer (>10 second) audio via WAV format. +class Song : public Sound { +public: + Song() = default; + Song(const std::filesystem::path& song_file_path) + { + + } +}; \ No newline at end of file diff --git a/include/ReMixer/stream.h b/include/ReMixer/stream.h new file mode 100644 index 0000000..acb5deb --- /dev/null +++ b/include/ReMixer/stream.h @@ -0,0 +1,50 @@ +/// ReMixer +/// A Public Domain C++ Audio Playback Library +//By william @ RedactedSoftware. Thanks to Dawsh & Maxine. +/// (c) 2024 Redacted Software +/// This work is explicitly dedicated to the public domain, for the hopeful betterment of the software industry. + +/// @file stream.h +/// @desc An audio stream class that interfaces with pulseaudio, etc, to play back sounds. +/// @edit 2024-08-06 + +#pragma once + +#include +#include +#include + +enum class StreamMode : bool { + MONO = false, + STEREO = true +}; + +enum class SampleRate : unsigned int { + STANDARD = 44100, + HIGH = 48000 +}; + +class Stream { +private: + std::string application_name; + std::string stream_name; + StreamMode mode; + SampleRate sample_rate; + size_t bufferSize; + std::vector buffer; +#ifdef __linux__ + pa_simple* stream = nullptr; +#endif + +#ifdef _WIN32 +#endif +public: + uint16_t handle; + Stream(const std::string& application_name, const std::string& stream_name, SampleRate sample_rate, StreamMode mode); + unsigned int numChannels(); + void erase(); +}; + +inline std::vector streamList; + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..2c421dc --- /dev/null +++ b/main.cpp @@ -0,0 +1,81 @@ +/// ReMixer +/// A Public Domain C++ Audio Playback Library +/// By william @ RedactedSoftware. Thanks to Dawsh & Maxine. +/// (c) 2024 Redacted Software +/// This work is explicitly dedicated to the public domain, for the hopeful betterment of the software industry. + +/// @file StreamManager.h +/// @desc This class manages internal creation and storage of active Streams. +/// @edit 2024-08-06 + +#include +#include +#include + +#include +#include +#include +#include + +void decodeVorbis(const char* inputFile, const char* outputFile) +{ + OggVorbis_File vf; + FILE* inFile = fopen(inputFile, "rb"); + if (!inFile) { + std::cerr << "Error opening input file." << std::endl; return; + } + + if (ov_open(inFile, &vf, NULL, 0) < 0) { + std::cerr << "Error opening Ogg Vorbis file." << std::endl; + fclose(inFile); + return; + } + vorbis_info* vi = ov_info(&vf, -1); + + std::ofstream outFile(outputFile, std::ios::binary); + if (!outFile.is_open()) { + std::cerr << "Error opening output file." << std::endl; + ov_clear(&vf); + fclose(inFile); + return; + } + + char pcmout[4096]; + int current_section; + long bytes; + + while ((bytes = ov_read(&vf, pcmout, sizeof(pcmout), 0, 2, 1, ¤t_section)) > 0) { + outFile.write(pcmout, bytes); + } + + outFile.close(); + ov_clear(&vf); + fclose(inFile); +} + +[[noreturn]] int main() { + const char* inputFile = "input.ogg"; + const char* outputFile = "output.raw"; + + decodeVorbis(inputFile, outputFile); + + std::cout << "Decoding complete. Raw audio data saved to " << outputFile << std::endl; + + Stream stream("ReMixer-Test", "Main", SampleRate::STANDARD, StreamMode::STEREO); + + bool keep_runnin = true; + + while (keep_runnin) { + + } + return 0; +} + +//Windows :( +#ifdef _WIN32 +extern "C" { + int wmain(int argc, wchar_t* argv[]) { + return main(); + } +} +#endif \ No newline at end of file diff --git a/src/linux/ReMixer.cpp b/src/linux/ReMixer.cpp new file mode 100644 index 0000000..ef7a24c --- /dev/null +++ b/src/linux/ReMixer.cpp @@ -0,0 +1,7 @@ +#include + +uint16_t ReMixer::createStream(const std::string& application_name, const std::string& stream_name, SampleRate sample_rate, StreamMode mode) { + auto s = Stream(application_name, stream_name, sample_rate, mode); + return s.handle; + +} \ No newline at end of file diff --git a/src/linux/StreamManager.cpp b/src/linux/StreamManager.cpp new file mode 100644 index 0000000..fea7e9f --- /dev/null +++ b/src/linux/StreamManager.cpp @@ -0,0 +1 @@ +#include "ReMixer/StreamManager.h" \ No newline at end of file diff --git a/src/linux/sound.cpp b/src/linux/sound.cpp new file mode 100644 index 0000000..d415e5d --- /dev/null +++ b/src/linux/sound.cpp @@ -0,0 +1,12 @@ +#include +std::vector Sound::getAudioData() { + return audio_data; +} + +void Sound::setAudioData(const std::vector& audioData) { + audio_data = audioData; +} + +Sound::Sound(const std::vector& audioData) { + setAudioData(audioData); +} diff --git a/src/linux/stream.cpp b/src/linux/stream.cpp new file mode 100644 index 0000000..6e3f283 --- /dev/null +++ b/src/linux/stream.cpp @@ -0,0 +1,34 @@ +#include +#include +#include + +Stream::Stream(const std::string& name, const std::string& stream_name, SampleRate sample_rate, StreamMode mode) { + this->application_name = name; + this->stream_name = stream_name; + this->sample_rate = sample_rate; + this->mode = mode; + handle = UUID::dice(0, 65535); + + //50ms. + bufferSize = (unsigned int) sample_rate * numChannels() * 2 / 20; + + pa_sample_spec sample_spec = {.format = PA_SAMPLE_S16LE, .rate = (uint32_t) sample_rate, .channels = (uint8_t) numChannels()}; + + pa_buffer_attr buffer_attr = {buffer_attr.maxlength = (uint32_t) -1, buffer_attr.tlength = bufferSize, buffer_attr.prebuf = (uint32_t) -1, + buffer_attr.minreq = (uint32_t) -1, buffer_attr.fragsize = (uint32_t) -1}; + + stream = pa_simple_new(nullptr, name.c_str(), PA_STREAM_PLAYBACK, nullptr, name.c_str(), &sample_spec, nullptr, &buffer_attr, nullptr); + streamList.push_back(new Stream(*this)); +} + +unsigned int Stream::numChannels() { + return (unsigned int) mode + 1; +} + +void Stream::erase() { + pa_simple_free(stream); + + for (int i = 0; i < streamList.size(); i++) + if (this == streamList[i]) + streamList.erase(streamList.begin() + i); +}