Skip to content

Commit

Permalink
PCMSound utility functions | makeMono | makeStereo | append (#272)
Browse files Browse the repository at this point in the history
* update README

* PCMSound makeMono, makeStereo, append

* code rev

* add test

* code rev

* code rev

* update version
  • Loading branch information
Raffaello authored Nov 9, 2023
1 parent 5d3e039 commit e64d17e
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 13 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
endif()


project ("sdl2-hyper-sonic-drivers" VERSION 0.13.4 DESCRIPTION "SDL2 based Hyper-Sonic Drivers for emulating old soundcards")
project ("sdl2-hyper-sonic-drivers" VERSION 0.14.0 DESCRIPTION "SDL2 based Hyper-Sonic Drivers for emulating old soundcards")
include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ At the moment the only implemented emulators are OPL chips.
### Adlib/Sound Blaster PRO 2.0 chips

- [x] Mame OPL2
- [x] Mame OPL3
- [ ] Mame OPL3
- [x] DosBox OPL2
- [x] DosBox Dual OPL2
- [x] DosBox OPL3
Expand Down
10 changes: 2 additions & 8 deletions sdl2-hyper-sonic-drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ target_sources(${LIB_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/utils/constants.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/utils/endianness.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/utils/opl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/utils/sound.cpp
# --- #
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/utils/ILogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/utils/sdl2/Logger.cpp
Expand Down Expand Up @@ -211,14 +212,7 @@ unset(LIB_VER)

# Add source to this project's executable.
add_executable(sdl2-hyper-sonic-drivers "sdl2-hyper-sonic-drivers.cpp")
#target_sources(sdl2-sonic-drivers PUBLIC
# --- #
#${CMAKE_CURRENT_SOURCE_DIR}/src/files/IFFFile.cpp
#${CMAKE_CURRENT_SOURCE_DIR}/src/files/XMIFile.cpp
#${CMAKE_CURRENT_SOURCE_DIR}/src/files/MIDFile.cpp
#)

target_link_libraries(sdl2-hyper-sonic-drivers PRIVATE ${LIB_SDL2main} hyper-sonic-drivers-static)
target_link_libraries(sdl2-hyper-sonic-drivers PRIVATE ${LIB_SDL2main} hyper-sonic-drivers-static)

if(MSVC)
# @see https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=vs-2019
Expand Down
29 changes: 29 additions & 0 deletions sdl2-hyper-sonic-drivers/sdl2-hyper-sonic-drivers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// TODO: delete this file and its target, this is kinda scratch pad

#include <iostream>
#include <memory>

#include <SDL2/SDL.h>

Expand Down Expand Up @@ -32,6 +33,11 @@
#include <mt32emu/c_interface/cpp_interface.h>
#include <HyperSonicDrivers/hardware/mt32/MT32.hpp>

#include <HyperSonicDrivers/utils/sound.hpp>
#include <HyperSonicDrivers/drivers/PCMDriver.hpp>
#include <HyperSonicDrivers/audio/PCMSound.hpp>


using namespace std;
using namespace HyperSonicDrivers;

Expand Down Expand Up @@ -383,6 +389,27 @@ void testMT32()
// utils::delayMillis(1000);
}


void pcm_sound_append()
{
auto mixer = audio::make_mixer<audio::sdl2::Mixer>(8, 44100, 1024);
files::WAVFile w1("test/fixtures/test_renderer_adlib_mame2.wav");

mixer->init();
auto s1 = w1.getSound();
auto s1b = w1.getSound();
//auto s2a = utils::makeMono(s1);
//auto s2b = utils::makeStereo(s1);
auto s2 = utils::append(s1, s1);
drivers::PCMDriver drv(mixer);

drv.play(s2);
while (drv.isPlaying())
{
utils::delayMillis(100);
}
}

int main(int argc, char* argv[])
{
//newMixerTest();
Expand All @@ -391,6 +418,8 @@ int main(int argc, char* argv[])
//rendererMIDI();
//midi_adlib();
//testMT32();

pcm_sound_append();
return 0;
//sdlMixer();
//SDL_Delay(100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace HyperSonicDrivers::audio
PCMSound(PCMSound&) = delete;
PCMSound(PCMSound&&) = delete;
PCMSound& operator=(PCMSound&) = delete;

PCMSound(
const mixer::eChannelGroup group,
const bool isStereo,
Expand All @@ -26,10 +27,12 @@ namespace HyperSonicDrivers::audio
const std::shared_ptr<int16_t[]> &data
);

bool append(const PCMSound* sound2) noexcept;

const mixer::eChannelGroup group;
const bool stereo;
const uint32_t freq;
uint32_t dataSize;
std::shared_ptr<int16_t[]> data;
const uint32_t dataSize;
const std::shared_ptr<int16_t[]> data;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ namespace HyperSonicDrivers::drivers
void stop(const std::shared_ptr<audio::PCMSound>& sound, const bool releaseEndedStreams = true);
void stop() noexcept;


const uint8_t max_streams;
private:
std::shared_ptr<audio::IMixer> m_mixer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ namespace HyperSonicDrivers::utils
/// wrapper, helper function
/// </summary>
std::string chars_vector_to_string(const std::vector<uint8_t>& e);

/// <summary>
/// Skip first char
/// </summary>
Expand Down
64 changes: 64 additions & 0 deletions sdl2-hyper-sonic-drivers/src/HyperSonicDrivers/utils/sound.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <cstdint>
#include <HyperSonicDrivers/utils/sound.hpp>
#include <HyperSonicDrivers/audio/converters/LinearRateConverter.hpp>

namespace HyperSonicDrivers::utils
{
std::shared_ptr<audio::PCMSound> makeMono(const std::shared_ptr<audio::PCMSound>& sound)
{
if (!sound->stereo)
return sound;

const uint32_t monoDataSize = sound->dataSize / 2;

auto monoData = std::make_shared<int16_t[]>(monoDataSize);
for (uint32_t i = 0, j = 0; i < sound->dataSize; i += 2, j++)
{
monoData[j] = (sound->data[i] + sound->data[i + 1]) / 2;
}

return std::make_shared<audio::PCMSound>(sound->group, false, sound->freq, monoDataSize, monoData);
}

std::shared_ptr<audio::PCMSound> makeStereo(const std::shared_ptr<audio::PCMSound>& sound)
{
if (sound->stereo)
return sound;

const uint32_t stereoDataSize = sound->dataSize * 2;
auto stereoData = std::make_shared<int16_t[]>(stereoDataSize);
for (uint32_t i = 0, j = 0; i < sound->dataSize; i++, j += 2)
{
stereoData[j] = stereoData[j + 1] = sound->data[i];
}

return std::make_shared<audio::PCMSound>(sound->group, true, sound->freq, stereoDataSize, stereoData);
}

std::shared_ptr<audio::PCMSound> append(
const std::shared_ptr<audio::PCMSound>& sound1,
const std::shared_ptr<audio::PCMSound>& sound2)
{
std::shared_ptr<audio::PCMSound> s2;

if (sound1->stereo)
s2 = makeStereo(sound2);
else
s2 = makeMono(sound2);

if (sound1->freq != sound2->freq)
{
// TODO:
// use covert frequency/ sample rate libraries for this ?
utils::throwLogC<std::runtime_error>("different frequency, not implemented yet");
}

const uint32_t dataSize = sound1->dataSize + s2->dataSize;
auto data = std::make_shared<int16_t[]>(dataSize);

memcpy(data.get(), sound1->data.get(), sound1->dataSize * sizeof(int16_t));
memcpy(&data[sound1->dataSize], s2->data.get(), s2->dataSize * sizeof(int16_t));

return std::make_shared<audio::PCMSound>(sound1->group, sound1->stereo, sound1->freq, dataSize, data);
}
}
27 changes: 27 additions & 0 deletions sdl2-hyper-sonic-drivers/src/HyperSonicDrivers/utils/sound.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <memory>
#include <HyperSonicDrivers/audio/PCMSound.hpp>

namespace HyperSonicDrivers::utils
{
/**
* @returns a new mono PCMSound if the parameter is stereo
* otherwise returns the parameter itself.
**/
std::shared_ptr<audio::PCMSound> makeMono(const std::shared_ptr<audio::PCMSound>& sound);

/**
* @returns a new stereo PCMSound if the parameter is mono
* otherwise returns the parameter itself.
**/
std::shared_ptr<audio::PCMSound> makeStereo(const std::shared_ptr<audio::PCMSound>& sound);

/**
* @returns sound1 + sound2.
* it converts sound2 to the same freq and mono/stereo of sound1
**/
std::shared_ptr<audio::PCMSound> append(
const std::shared_ptr<audio::PCMSound>& sound1,
const std::shared_ptr<audio::PCMSound>& sound2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ macro_test(
LINKS_PRIVATE hyper-sonic-drivers-static
)

macro_test(
EXE TestSound
FILES "utils/TestSound.cpp"
LINKS_PRIVATE hyper-sonic-drivers-static
)

macro_test(
EXE TestPCSpeaker
FILES "hardware/TestPCSpeaker.cpp"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <cstdint>
#include <memory>
#include <HyperSonicDrivers/utils/sound.hpp>
#include <HyperSonicDrivers/audio/PCMSound.hpp>

namespace HyperSonicDrivers::utils
{
using audio::mixer::eChannelGroup;
using audio::PCMSound;

TEST(utils, makeMono0)
{
const uint32_t size = 100;
auto data = std::make_shared<int16_t[]>(size);

auto s1 = std::make_shared<PCMSound>(eChannelGroup::Plain, true, 44100, size, data);
auto s2 = makeMono(s1);

EXPECT_TRUE(s1->stereo);
EXPECT_FALSE(s2->stereo);
EXPECT_EQ(s1->group, s2->group);
EXPECT_EQ(s1->freq, s2->freq);
EXPECT_EQ(s1->dataSize, size);
EXPECT_EQ(s2->dataSize, size / 2);
}

TEST(utils, makeMono1)
{
const uint32_t size = 100;
auto data = std::make_shared<int16_t[]>(size);

auto s1 = std::make_shared<PCMSound>(eChannelGroup::Plain, false, 44100, size, data);
auto s2 = makeMono(s1);

ASSERT_EQ(s1, s2);
}

TEST(utils, makeStereo0)
{
const uint32_t size = 100;
auto data = std::make_shared<int16_t[]>(size);

auto s1 = std::make_shared<PCMSound>(eChannelGroup::Plain, false, 44100, size, data);
auto s2 = makeStereo(s1);

EXPECT_FALSE(s1->stereo);
EXPECT_TRUE(s2->stereo);
EXPECT_EQ(s1->group, s2->group);
EXPECT_EQ(s1->freq, s2->freq);
EXPECT_EQ(s1->dataSize, size);
EXPECT_EQ(s2->dataSize, size * 2);
}

TEST(utils, makeStereo1)
{
const uint32_t size = 100;
auto data = std::make_shared<int16_t[]>(size);

auto s1 = std::make_shared<PCMSound>(eChannelGroup::Plain, true, 44100, size, data);
auto s2 = makeStereo(s1);

ASSERT_EQ(s1, s2);
}
}

int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit e64d17e

Please sign in to comment.