Skip to content

review ADLFile #285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Aug 23, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
- uses: actions/checkout@v4
- name: create build dir
run: mkdir build
- uses: actions/cache@v2
- uses: actions/cache@v4
id: dep-cache
with:
path: C:/vcpkg/packages
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ jobs:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: create build dir
run: mkdir build
- uses: actions/cache@v2
- uses: actions/cache@v4
id: dep-cache
with:
path: C:/vcpkg/packages
key: ${{ runner.os }}-x64-windows-dep-cache-${{ hashFiles('**/*') }}
restore-keys: ${{ runner.os }}-x64-windows-dep-cache
- uses: actions/cache@v2
- uses: actions/cache@v4
id: sonar-cache
with:
path: |
Expand Down
12 changes: 12 additions & 0 deletions sdl2-hyper-sonic-drivers/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ macro_example(
NONE
)

macro_example(
EXE ADLPlay
FILE "adl-play.cpp"
DEPS hyper-sonic-drivers-static
LINKS ${LIB_SDL2main} hyper-sonic-drivers-static spdlog::spdlog SDL2::SDL2
FIXTURES
"../test/fixtures/DUNE0.ADL"
#"../test/fixtures/EOBSOUND.ADL"
#"../test/fixtures/LOREINTR.ADL"
NONE
)

macro_example(
EXE PCMExample
FILE "pcm-example.cpp"
Expand Down
224 changes: 224 additions & 0 deletions sdl2-hyper-sonic-drivers/examples/adl-play.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#include <HyperSonicDrivers/audio/sdl2/Mixer.hpp>
#include <HyperSonicDrivers/hardware/opl/OPL.hpp>
#include <HyperSonicDrivers/hardware/opl/OPLFactory.hpp>
#include <HyperSonicDrivers/utils/algorithms.hpp>
#include <HyperSonicDrivers/files/westwood/ADLFile.hpp>
#include <HyperSonicDrivers/drivers/westwood/ADLDriver.hpp>
#include <HyperSonicDrivers/utils/ILogger.hpp>
#include <HyperSonicDrivers/devices/Adlib.hpp>
#include <HyperSonicDrivers/devices/SbPro.hpp>
#include <HyperSonicDrivers/devices/SbPro2.hpp>

#include <spdlog/spdlog.h>
#include <fmt/color.h>


#include <SDL2/SDL.h>

#include <memory>
#include <cstdint>
#include <map>
#include <string>

using namespace HyperSonicDrivers;

using hardware::opl::OPLFactory;
using hardware::opl::OplEmulator;
using hardware::opl::OplType;
using utils::delayMillis;
using files::westwood::ADLFile;
using drivers::westwood::ADLDriver;


/**
* @brief Play an ADL file using a chosen OPL emulator/type until the user exits.
*
* Plays the given ADL file through an OPL device constructed from the specified
* emulator and OPL type. The function creates an ADLDriver bound to the
* Music channel group and enters an SDL event-driven loop that starts playback
* (initial track index is 5) and responds to key presses to control playback.
*
* Behavior:
* - Selects an OPL device based on `type`:
* - OPL2 -> Adlib + Opl
* - DUAL_OPL2-> SbPro + Opl
* - OPL3 -> SbPro2 + Opl
* - If the provided mixer is not ready, logs an error and returns immediately.
* - Starts playing the current track when not already playing.
* - Key controls (during playback):
* - ESC: stop all channels and return (exit function)
* - RIGHT: stop channels and advance to the next track (wraps to 0)
* - LEFT: stop channels and go to the previous track (wraps to last)
*
* This function blocks until ESC is pressed.
*
* @param emu OPL emulator selection used when constructing the device.
* @param type OPL hardware type used to choose the concrete device implementation.
* @param filename Path to the ADL file to load and play.
*/
void adl_play(const OplEmulator emu, const OplType type, std::shared_ptr<audio::IMixer> mixer, const std::string& filename)
{
using devices::make_device;
using utils::ILogger;

auto adlFile = std::make_shared<ADLFile>(filename);
std::shared_ptr<devices::Opl> device;
switch (type)
{
using enum OplType;

case OPL2:
device = make_device<devices::Adlib, devices::Opl>(mixer, emu);
break;
case DUAL_OPL2:
device = make_device<devices::SbPro, devices::Opl>(mixer, emu);
break;
case OPL3:
device = make_device<devices::SbPro2, devices::Opl>(mixer, emu);
break;

}

uint8_t track = 0;

ADLDriver adlDrv(device, audio::mixer::eChannelGroup::Music);
adlDrv.setADLFile(adlFile);

if(!mixer->isReady()) {
spdlog::error("mixer not ready yet..");
return;
}

do
{
if (!adlDrv.isPlaying())
{
adlDrv.play(track);
ILogger::instance->info(fmt::format("Playing track: {}/{}", static_cast<int>(track), adlFile->getNumTracks()), ILogger::eCategory::Application);
}
//delayMillis(1000);
SDL_Event e;
while (SDL_WaitEventTimeout(&e, 100))
{
if (e.type == SDL_QUIT)
{
adlDrv.stopAllChannels();
return;
}
else if (e.type == SDL_KEYDOWN)
{
switch (e.key.keysym.sym)
{
case SDLK_ESCAPE:
{
adlDrv.stopAllChannels();
return;
}
case SDLK_RIGHT:
{
adlDrv.stopAllChannels();
track++;
if (track >= adlFile->getNumTracks())
track = 0;

break;
}
case SDLK_LEFT:
{
adlDrv.stopAllChannels();
if (track > 0)
track--;
else
track = adlFile->getNumTracks() - 1;

break;
}
}
}
}

} while (true);
}

/**
* @brief Program entry point for the ADL playback demo using SDL2 and OPL emulation.
*
* Initializes SDL video, creates a minimal SDL window, and starts an SDL-based audio mixer.
* Iterates over configured OPL emulator and OPL type combinations, prints a colored header
* for each pair, and invokes adl_play to run the ADL playback demo for "DUNE0.ADL".
* Cleans up SDL resources before exiting.
*
* Return codes:
* - 0 : Normal exit after running demos and cleanup.
* - 1 : Mixer initialization failed.
* - -1 : SDL video initialization failed.
* - -2 : SDL window creation failed.
*/
int main(int argc, char* argv[])
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0)
return -1;

auto pWin = SDL_CreateWindow("for Keyboard Input...", 0, 0, 320, 200, 0);
if (!pWin)
{
SDL_Quit();
return -2;
}


auto mixer = audio::make_mixer<audio::sdl2::Mixer>(8, 44100, 1024);
if (!mixer->init())
{
spdlog::error("can't init mixer");
SDL_DestroyWindow(pWin);
SDL_Quit();
return 1;
}


const std::map<OplEmulator, std::string> emus = {
{ OplEmulator::DOS_BOX, "DOS_BOX" },
//{ OplEmulator::MAME, "MAME" },
//{ OplEmulator::NUKED, "NUKED" },
//{ OplEmulator::WOODY, "WOODY" },
};

const std::map<OplType, std::string> types = {
{OplType::OPL2, "OPL2"},
//{OplType::DUAL_OPL2, "DUAL_OPL2"},
//{OplType::OPL3, "OPL3"},
};

const std::string m = "##### {} {} #####";

spdlog::set_level(spdlog::level::info);
HyperSonicDrivers::utils::ILogger::instance->setLevelAll(HyperSonicDrivers::utils::ILogger::eLevel::Info);
for (const auto& emu : emus)
{
for (const auto& type : types)
{
using enum fmt::color;

for (const auto& c : { white_smoke, yellow, aqua,
lime_green, blue_violet, indian_red }) {
spdlog::info(fmt::format(fg(c), m, emu.second, type.second));
}

try
{
adl_play(emu.first, type.first, mixer, "DUNE0.ADL");
//adl_test(emu.first, type.first, mixer, "EOBSOUND.ADL", 1);
//adl_test(emu.first, type.first, mixer, "LOREINTR.ADL", 3);
}
catch (const std::exception& e)
{
spdlog::default_logger()->error(e.what());
}
}
}

SDL_DestroyWindow(pWin);
SDL_Quit();
return 0;
}
Loading
Loading