Mixing Test

This commit is contained in:
2024-08-26 04:27:52 -04:00
parent 828048b882
commit 4b00f38411
4 changed files with 125 additions and 29 deletions

View File

@@ -1,8 +1,19 @@
//
// Created by dawsh on 8/23/24.
//
#pragma once
#include <ReMixer/SoundSubsystem.h>
/// A PulseAudio implementation of the SoundSubsystem.
class PulseAudioSubsystem : public SoundSubsystem
{
public:
protected:
private:
pa_threaded_mainloop* mainloop;
pa_context* context;
pa_stream_direction_t* direction;
pa_mainloop_api* api;
};
#ifndef REMIXER_PULSESUBSYSTEM_H
#define REMIXER_PULSESUBSYSTEM_H
#endif //REMIXER_PULSESUBSYSTEM_H

View File

@@ -8,4 +8,3 @@ namespace ReMixer {
SFX* loadSFX(const std::string& file);
}
// this dick

View File

@@ -90,13 +90,6 @@ private:
};
/// A PulseAudio implementation of the SoundSubsystem.
class PulseAudioSubsystem : public SoundSubsystem
{
public:
protected:
private:
};
/// A Windows Sound API implementation of the SoundSubsystem.
class WASAPISubsystem : public SoundSubsystem

View File

@@ -8,6 +8,7 @@
#include <format>
#include <cstring>
#include <thread>
#include <vector>
#include <iostream>
#include <cstdio>
@@ -15,6 +16,9 @@
#include <cstring>
#include <cerrno>
#include <fcntl.h>
#include <filesystem>
#include <fstream>
#include <iterator>
// https://github.com/pulseaudio/pulseaudio/blob/master/src/pulse/simple.c
// https://habr.com/en/articles/663352/#linux-and-pulseaudio
@@ -435,7 +439,6 @@ int pa_system_drain(pa_system* p, int *rerror)
return -1;
}
int pa_system_flush(pa_system* p, int *rerror)
{
pa_operation *o = NULL;
@@ -522,12 +525,84 @@ static void list_server_info(pa_context* c, pa_server_info* i, void* userdata)
auto *p = static_cast<pa_system *>(userdata);
pa_threaded_mainloop_signal(p->mainloop, 0);
}
static void stream_success_cb(pa_stream* s, int success, void* userdata)
int mix_sample_s16_pcm(int16_t a, int16_t b)
{
auto *p = static_cast<pa_system *>(userdata);
pa_threaded_mainloop_signal(p->mainloop, 0);
return (a + b) / 2.f;
//int m;
//a += 32768;
//b += 32768;
//if ((a < 32768) || (b < 32768)) {
// Viktor's first equation when both sources are quiet.
// (i.e. less than middle of the dynamic range)
// m = a * b / 32768;
//} else {
// Viktor's second equation when one or both sources are loud.
// m = 2 * (a + b) - (a * b) / 32768 - 65535;
//}
// Output is unsigned (0..65536) so convert back to signed (-3
//if (m == 65536) m = 65535;
//m -= 32768;
//return m;
}
// this dick
struct pcm_s16_data
{
std::vector<char> buffer;
explicit pcm_s16_data(const std::filesystem::path& file_path)
{
std::ifstream file(file_path, std::ios::binary | std::ios::ate);
file.unsetf(std::ios::skipws);
file.seekg(0, std::ios::end);
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
buffer.reserve(size);
buffer.insert(buffer.begin(),
std::istream_iterator<char>(file),
std::istream_iterator<char>());
}
explicit pcm_s16_data(const std::vector<char>& pcm_buf)
{
buffer = pcm_buf;
}
pcm_s16_data operator + (const pcm_s16_data& rhs) const
{
std::vector<char> sum;
auto rhs_buf = rhs.buffer;
auto lhs_buf = this->buffer;
for (int i = 0; i < std::max(lhs_buf.size(), rhs_buf.size()); i++)
{
int a = 0;
if (i >= lhs_buf.size() && i < rhs_buf.size())
{
sum.push_back(rhs_buf[i]);
continue;
}
if (i >= rhs_buf.size() && i < lhs_buf.size())
{
sum.push_back(lhs_buf[i]);
continue;
}
sum.push_back(mix_sample_s16_pcm(lhs_buf[i], rhs_buf[i]));
}
return pcm_s16_data(sum);
}
};
int main(int argc, char* argv[]) {
if (argc == 1 || argv[1] == "-h" || argv[1] == "help")
{
@@ -549,7 +624,20 @@ int main(int argc, char* argv[]) {
int error;
/* Replace STDIN with the specified file if needed. */
if (argc > 1) {
if (argc < 3)
{
std::cerr << "Please provide two input PCM files!" << std::endl;
return -1;
}
pcm_s16_data song = pcm_s16_data(argv[1]);
pcm_s16_data sfx = pcm_s16_data(argv[2]);
pcm_s16_data combined = song + sfx;
/*if (argc > 1) {
int fd;
if ((fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, __FILE__": open() failed: %s\n", strerror(errno));
@@ -561,12 +649,13 @@ int main(int argc, char* argv[]) {
goto finish;
}
close(fd);
}
}*/
/* Create a new playback stream */
if (!(s = pa_system_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
return -1;
//goto finish;
}
pa_context_get_server_info(s->context, reinterpret_cast<pa_server_info_cb_t>(list_server_info), s);
@@ -575,7 +664,12 @@ int main(int argc, char* argv[]) {
pa_system_enumerate_devices(s);
for (;;) {
if (pa_system_write(s, combined.buffer.data(), combined.buffer.size(), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
goto finish;
}
/* for (;;) {
uint8_t buf[BUFSIZE];
ssize_t r;
@@ -589,32 +683,31 @@ int main(int argc, char* argv[]) {
}
fprintf(stderr, "%0.0f usec \r", (float)latency);
#endif
/* Read some data */
if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) {
if (r == 0) /* EOF */
if (r == 0)
break;
fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
goto finish;
}
/* and play it */
if (pa_system_write(s, buf, (size_t)r, &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
goto finish;
}
}
}*/
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
pa_stream_cork(s->stream, 1, stream_success_cb, s);
pa_stream_cork(s->stream, 1, success_cb, s);
std::this_thread::sleep_for(1s);
pa_stream_cork(s->stream, 0, stream_success_cb, s);
pa_stream_cork(s->stream, 0, success_cb, s);
/* Make sure that every single sample was played */
if (pa_system_drain(s, &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));