Initial Commit
This commit is contained in:
50
CMakeLists.txt
Normal file
50
CMakeLists.txt
Normal file
@@ -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)
|
24
cmake/CPM.cmake
Normal file
24
cmake/CPM.cmake
Normal file
@@ -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})
|
10
include/ReMixer/ReMixer.h
Normal file
10
include/ReMixer/ReMixer.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <ReMixer/stream.h>
|
||||
#include <ReMixer/sound.h>
|
||||
|
||||
namespace ReMixer {
|
||||
uint16_t createStream(const std::string& application_name, const std::string& stream_name, SampleRate sample_rate, StreamMode mode);
|
||||
}
|
||||
|
||||
// this dick
|
48
include/ReMixer/StreamManager.h
Normal file
48
include/ReMixer/StreamManager.h
Normal file
@@ -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 <map>
|
||||
#include "stream.h"
|
||||
|
||||
class TakenStreamIDException : public std::exception
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
class StreamManager {
|
||||
public:
|
||||
static std::map<uint16_t, Stream *> 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(); };
|
||||
|
||||
};
|
43
include/ReMixer/sound.h
Normal file
43
include/ReMixer/sound.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
class PlaybackDevice {};
|
||||
class InputDevice {};
|
||||
|
||||
class Sound {
|
||||
private:
|
||||
std::vector<uint8_t> audio_data;
|
||||
public:
|
||||
std::vector<uint8_t> getAudioData();
|
||||
void setAudioData(const std::vector<uint8_t>& 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<uint8_t>& 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)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
50
include/ReMixer/stream.h
Normal file
50
include/ReMixer/stream.h
Normal file
@@ -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 <string>
|
||||
#include <vector>
|
||||
#include <pulse/simple.h>
|
||||
|
||||
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<char> 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<Stream*> streamList;
|
||||
|
||||
|
81
main.cpp
Normal file
81
main.cpp
Normal file
@@ -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 <iostream>
|
||||
#include <ReMixer/stream.h>
|
||||
#include <ReMixer/sound.h>
|
||||
|
||||
#include <vorbis/codec.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
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
|
7
src/linux/ReMixer.cpp
Normal file
7
src/linux/ReMixer.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <ReMixer/ReMixer.h>
|
||||
|
||||
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;
|
||||
|
||||
}
|
1
src/linux/StreamManager.cpp
Normal file
1
src/linux/StreamManager.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "ReMixer/StreamManager.h"
|
12
src/linux/sound.cpp
Normal file
12
src/linux/sound.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <ReMixer/sound.h>
|
||||
std::vector<uint8_t> Sound::getAudioData() {
|
||||
return audio_data;
|
||||
}
|
||||
|
||||
void Sound::setAudioData(const std::vector<uint8_t>& audioData) {
|
||||
audio_data = audioData;
|
||||
}
|
||||
|
||||
Sound::Sound(const std::vector<uint8_t>& audioData) {
|
||||
setAudioData(audioData);
|
||||
}
|
34
src/linux/stream.cpp
Normal file
34
src/linux/stream.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <ReMixer/stream.h>
|
||||
#include <ReMixer/sound.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
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);
|
||||
}
|
Reference in New Issue
Block a user