mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 05:45:38 +00:00
Added support for custom MPEG music in a new Music.xml config file
This commit is contained in:
parent
dd90d0e2e0
commit
dbfe2b1a72
31
Config/Music.xml
Normal file
31
Config/Music.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
Supermodel
|
||||
A Sega Model 3 Arcade Emulator.
|
||||
Copyright 2003-2024 The Supermodel Team
|
||||
|
||||
Music.xml
|
||||
|
||||
This file defines custom MPEG music tracks to be used in DSB1 and DSB2 games.
|
||||
Make sure to use MP3 files sampled at 32 KHz. Normal sampling rates (e.g. 44.1
|
||||
or 48 KHz) will sound slow.
|
||||
|
||||
The example below is wrapped in a dummy <comment></comment> block to render it
|
||||
inactive. Remove these and add your own MP3 files.
|
||||
-->
|
||||
<games>
|
||||
<!-- Scud Race (Australian version) example -->
|
||||
<comment> <!-- Remove this tag -->
|
||||
<game name="scudau">
|
||||
<track mpeg_rom_start_offset="0x001d4b42" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Beginner Day -->
|
||||
<track mpeg_rom_start_offset="0x000e7e41" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Beginner Night (initial start) -->
|
||||
<track mpeg_rom_start_offset="0x00103981" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Beginner Night (loop point) -->
|
||||
<track mpeg_rom_start_offset="0x00000000" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Medium (initial start) -->
|
||||
<track mpeg_rom_start_offset="0x0001caff" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Medium (loop point) -->
|
||||
<track mpeg_rom_start_offset="0x0037a4c4" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Expert (initial start) -->
|
||||
<track mpeg_rom_start_offset="0x0037fc84" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Expert (loop point) -->
|
||||
<track mpeg_rom_start_offset="0x002afa83" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Extra (initial start) -->
|
||||
<track mpeg_rom_start_offset="0x002b4943" filepath="Rick Astley - Together Forever - 32 KHz.mp3" /> <!-- Extra (loop point) -->
|
||||
<track mpeg_rom_start_offset="0x00463745" filepath="Rick Astley - Never Gonna Give You Up - 32 KHz.mp3" /> <!-- Selector -->
|
||||
</game>
|
||||
</comment> <!-- Remove this tag! -->
|
||||
</games>
|
|
@ -221,7 +221,7 @@ void CDSB1::IOWrite8(UINT32 addr, UINT8 data)
|
|||
usingMPEGStart = mpegStart;
|
||||
usingMPEGEnd = mpegEnd;
|
||||
|
||||
MpegDec::SetMemory(&mpegROM[mpegStart], mpegEnd - mpegStart, false);
|
||||
MpegDec::SetMemory(mpegROM, mpegStart, mpegEnd - mpegStart, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ void CDSB1::IOWrite8(UINT32 addr, UINT8 data)
|
|||
usingMPEGStart = mpegStart;
|
||||
usingMPEGEnd = mpegEnd;
|
||||
|
||||
MpegDec::SetMemory(&mpegROM[mpegStart], mpegEnd - mpegStart, false); // assume not looped for now
|
||||
MpegDec::SetMemory(mpegROM, mpegStart, mpegEnd - mpegStart, false); // assume not looped for now
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -266,13 +266,13 @@ void CDSB1::IOWrite8(UINT32 addr, UINT8 data)
|
|||
{
|
||||
usingLoopStart = loopStart;
|
||||
usingLoopEnd = mpegEnd-loopStart;
|
||||
MpegDec::UpdateMemory(&mpegROM[usingLoopStart], usingLoopEnd, true);
|
||||
MpegDec::UpdateMemory(mpegROM, usingLoopStart, usingLoopEnd, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
usingLoopStart = loopStart;
|
||||
usingLoopEnd = loopEnd-loopStart;
|
||||
MpegDec::UpdateMemory(&mpegROM[usingLoopStart], usingLoopEnd, true);
|
||||
MpegDec::UpdateMemory(mpegROM, usingLoopStart, usingLoopEnd, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,7 +302,7 @@ void CDSB1::IOWrite8(UINT32 addr, UINT8 data)
|
|||
loopEnd = endLatch;
|
||||
usingLoopStart = loopStart;
|
||||
usingLoopEnd = loopEnd-loopStart;
|
||||
MpegDec::UpdateMemory(&mpegROM[usingLoopStart], usingLoopEnd, true);
|
||||
MpegDec::UpdateMemory(mpegROM, usingLoopStart, usingLoopEnd, true);
|
||||
//printf("loopEnd = %08X\n", loopEnd);
|
||||
}
|
||||
break;
|
||||
|
@ -529,10 +529,10 @@ void CDSB1::LoadState(CBlockFile *StateFile)
|
|||
// Restart MPEG audio at the appropriate position
|
||||
if (isPlaying)
|
||||
{
|
||||
MpegDec::SetMemory(&mpegROM[usingMPEGStart], usingMPEGEnd - usingMPEGStart, false);
|
||||
MpegDec::SetMemory(mpegROM, usingMPEGStart, usingMPEGEnd - usingMPEGStart, false);
|
||||
|
||||
if (usingLoopEnd != 0) { // only if looping was actually enabled
|
||||
MpegDec::UpdateMemory(&mpegROM[usingLoopStart], usingLoopEnd, true);
|
||||
MpegDec::UpdateMemory(mpegROM, usingLoopStart, usingLoopEnd, true);
|
||||
}
|
||||
|
||||
MpegDec::SetPosition(playOffset);
|
||||
|
@ -691,7 +691,7 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte)
|
|||
usingMPEGEnd = mpegEnd;
|
||||
playing = 1;
|
||||
|
||||
MpegDec::SetMemory(&mpegROM[mpegStart], mpegEnd - mpegStart, false);
|
||||
MpegDec::SetMemory(mpegROM, mpegStart, mpegEnd - mpegStart, false);
|
||||
|
||||
mpegState = ST_IDLE;
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte)
|
|||
{
|
||||
usingLoopStart = mpegStart;
|
||||
usingLoopEnd = mpegEnd - mpegStart;
|
||||
MpegDec::UpdateMemory(&mpegROM[usingLoopStart], usingLoopEnd, true);
|
||||
MpegDec::UpdateMemory(mpegROM, usingLoopStart, usingLoopEnd, true);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -773,7 +773,7 @@ void CDSB2::WriteMPEGFIFO(UINT8 byte)
|
|||
usingMPEGStart = mpegStart;
|
||||
usingMPEGEnd = mpegEnd;
|
||||
playing = 1;
|
||||
MpegDec::SetMemory(&mpegROM[mpegStart], mpegEnd - mpegStart, false);
|
||||
MpegDec::SetMemory(mpegROM, mpegStart, mpegEnd - mpegStart, false);
|
||||
}
|
||||
break;
|
||||
case ST_GOTA5:
|
||||
|
@ -1165,10 +1165,10 @@ void CDSB2::LoadState(CBlockFile *StateFile)
|
|||
// Restart MPEG audio at the appropriate position
|
||||
if (isPlaying)
|
||||
{
|
||||
MpegDec::SetMemory(&mpegROM[usingMPEGStart], usingMPEGEnd - usingMPEGStart, false);
|
||||
MpegDec::SetMemory(mpegROM, usingMPEGStart, usingMPEGEnd - usingMPEGStart, false);
|
||||
|
||||
if (usingLoopEnd != 0) { // only if looping was actually enabled
|
||||
MpegDec::UpdateMemory(&mpegROM[usingLoopStart], usingLoopEnd, true);
|
||||
MpegDec::UpdateMemory(mpegROM, usingLoopStart, usingLoopEnd, true);
|
||||
}
|
||||
|
||||
MpegDec::SetPosition(playOffset);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
** Supermodel
|
||||
** A Sega Model 3 Arcade Emulator.
|
||||
** Copyright 2003-2023 The Supermodel Team
|
||||
** Copyright 2003-2024 The Supermodel Team
|
||||
**
|
||||
** This file is part of Supermodel.
|
||||
**
|
||||
|
@ -95,6 +95,7 @@
|
|||
#include "OSD/Audio.h"
|
||||
#include "Graphics/New3D/VBO.h"
|
||||
#include "Graphics/SuperAA.h"
|
||||
#include "Sound/MPEG/MpegAudio.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "Util/BMPFile.h"
|
||||
|
@ -105,6 +106,12 @@
|
|||
Global Run-time Config
|
||||
******************************************************************************/
|
||||
|
||||
static const std::string s_analysisPath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Analysis);
|
||||
static const std::string s_configFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Supermodel.ini";
|
||||
static const std::string s_gameXMLFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Games.xml";
|
||||
static const std::string s_musicXMLFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Music.xml";
|
||||
static const std::string s_logFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Log) << "Supermodel.log";
|
||||
|
||||
static Util::Config::Node s_runtime_config("Global");
|
||||
|
||||
|
||||
|
@ -914,6 +921,9 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
|
|||
return 1;
|
||||
*rom_set = ROMSet(); // free up this memory we won't need anymore
|
||||
|
||||
// Customized music for games with MPEG boards
|
||||
MpegDec::LoadCustomTracks(s_musicXMLFilePath, game);
|
||||
|
||||
// Load NVRAM
|
||||
LoadNVRAM(Model3);
|
||||
|
||||
|
@ -982,7 +992,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
|
|||
goto QuitError;
|
||||
if (OKAY != Render3D->Init(xOffset*aaValue, yOffset*aaValue, xRes*aaValue, yRes*aaValue, totalXRes*aaValue, totalYRes*aaValue, superAA->GetTargetID()))
|
||||
goto QuitError;
|
||||
|
||||
|
||||
Model3->AttachRenderers(Render2D,Render3D, superAA);
|
||||
|
||||
// Reset emulator
|
||||
|
@ -1356,12 +1366,6 @@ QuitError:
|
|||
/******************************************************************************
|
||||
Entry Point and Command Line Procesing
|
||||
******************************************************************************/
|
||||
|
||||
static const std::string s_analysisPath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Analysis);
|
||||
static const std::string s_configFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Supermodel.ini";
|
||||
static const std::string s_gameXMLFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Games.xml";
|
||||
static const std::string s_logFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Log) << "Supermodel.log";
|
||||
|
||||
// Create and configure inputs
|
||||
static bool ConfigureInputs(CInputs *Inputs, Util::Config::Node *fileConfig, Util::Config::Node *runtimeConfig, const Game &game, bool configure)
|
||||
{
|
||||
|
@ -1543,7 +1547,7 @@ static Util::Config::Node DefaultConfig()
|
|||
static void Title(void)
|
||||
{
|
||||
puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")");
|
||||
puts("Copyright 2003-2023 by The Supermodel Team");
|
||||
puts("Copyright 2003-2024 by The Supermodel Team");
|
||||
}
|
||||
|
||||
static void Help(void)
|
||||
|
|
|
@ -1,6 +1,205 @@
|
|||
/**
|
||||
** Supermodel
|
||||
** A Sega Model 3 Arcade Emulator.
|
||||
** Copyright 2003-2024 The Supermodel Team
|
||||
**
|
||||
** This file is part of Supermodel.
|
||||
**
|
||||
** Supermodel is free software: you can redistribute it and/or modify it under
|
||||
** the terms of the GNU General Public License as published by the Free
|
||||
** Software Foundation, either version 3 of the License, or (at your option)
|
||||
** any later version.
|
||||
**
|
||||
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
||||
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
** more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License along
|
||||
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#define MINIMP3_IMPLEMENTATION
|
||||
#include "Pkgs/minimp3.h"
|
||||
#include "MpegAudio.h"
|
||||
#include "Util/ConfigBuilders.h"
|
||||
#include "OSD/Logger.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <tuple>
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
Custom MPEG Tracks
|
||||
***************************************************************************************************/
|
||||
|
||||
struct CustomTrack
|
||||
{
|
||||
std::shared_ptr<uint8_t[]> mpeg_data;
|
||||
size_t mpeg_data_size;
|
||||
uint32_t mpeg_rom_start_offset;
|
||||
size_t file_start_offset;
|
||||
|
||||
CustomTrack()
|
||||
: mpeg_data(nullptr),
|
||||
mpeg_data_size(0),
|
||||
mpeg_rom_start_offset(0),
|
||||
file_start_offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
CustomTrack(const std::shared_ptr<uint8_t[]> &mpeg_data, size_t mpeg_data_size, uint32_t mpeg_rom_start_offset, size_t file_start_offset)
|
||||
: mpeg_data(mpeg_data),
|
||||
mpeg_data_size(mpeg_data_size),
|
||||
mpeg_rom_start_offset(mpeg_rom_start_offset),
|
||||
file_start_offset(file_start_offset)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct FileContents
|
||||
{
|
||||
std::shared_ptr<uint8_t[]> bytes;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static std::map<uint32_t, CustomTrack> s_custom_tracks_by_mpeg_rom_address;
|
||||
|
||||
static FileContents LoadFile(const std::string &filepath)
|
||||
{
|
||||
FILE *fp = fopen(filepath.c_str(), "rb");
|
||||
if (!fp)
|
||||
{
|
||||
ErrorLog("Unable to load music track from disk: %s.", filepath.c_str());
|
||||
return { .bytes = nullptr, .size = 0 };
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long file_size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
std::shared_ptr<uint8_t[]> mpeg_data(new uint8_t[file_size], std::default_delete<uint8_t[]>());
|
||||
fread(mpeg_data.get(), sizeof(uint8_t), file_size, fp);
|
||||
fclose(fp);
|
||||
return { .bytes = mpeg_data, .size = size_t(file_size) };
|
||||
}
|
||||
|
||||
void MpegDec::LoadCustomTracks(const std::string &music_filepath, const Game &game)
|
||||
{
|
||||
s_custom_tracks_by_mpeg_rom_address.clear();
|
||||
|
||||
if (game.mpeg_board.empty())
|
||||
{
|
||||
// No MPEG board
|
||||
return;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(music_filepath))
|
||||
{
|
||||
// Custom music configuration file is optional
|
||||
return;
|
||||
}
|
||||
|
||||
Util::Config::Node xml("xml");
|
||||
if (Util::Config::FromXMLFile(&xml, music_filepath))
|
||||
{
|
||||
ErrorLog("Custom music configuration file could not be loaded. Original game tracks will be used.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample XML:
|
||||
*
|
||||
* <games>
|
||||
* <game name="scud">
|
||||
* <track mpeg_rom_start_offset="" file_start_offset="0" filepath="song1.mp3" />
|
||||
* <track mpeg_rom_start_offset="" file_start_offset="0x1000" filepath="song2.mp3" />
|
||||
* </game>
|
||||
* </games>
|
||||
*/
|
||||
|
||||
std::map<std::string, FileContents> file_contents_by_filepath;
|
||||
|
||||
for (auto it = xml.begin(); it != xml.end(); ++it)
|
||||
{
|
||||
auto &root_node = *it;
|
||||
if (root_node.Key() != "games")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &game_node: root_node)
|
||||
{
|
||||
if (game_node.Key() != "game")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (game_node["name"].Empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
std::string game_name = game_node["name"].ValueAs<std::string>();
|
||||
if (game_name != game.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &track_node: game_node)
|
||||
{
|
||||
if (track_node.Key() != "track")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t file_start_offset = 0;
|
||||
if (track_node["mpeg_rom_start_offset"].Empty())
|
||||
{
|
||||
ErrorLog("%s: Track in '%s' is missing 'mpeg_rom_start_offset' attribute and will be ignored.", music_filepath.c_str(), game.name.c_str());
|
||||
continue;
|
||||
}
|
||||
if (track_node["filepath"].Empty())
|
||||
{
|
||||
ErrorLog("%s: Track in '%s' is missing 'filepath' attribute and will be ignored.", music_filepath.c_str(), game.name.c_str());
|
||||
continue;
|
||||
}
|
||||
if (track_node["file_start_offset"].Exists())
|
||||
{
|
||||
file_start_offset = track_node["file_start_offset"].ValueAs<size_t>();
|
||||
}
|
||||
const std::string filepath = track_node["filepath"].ValueAs<std::string>();
|
||||
const uint32_t mpeg_rom_start_offset = track_node["mpeg_rom_start_offset"].ValueAs<uint32_t>();
|
||||
|
||||
if (s_custom_tracks_by_mpeg_rom_address.count(mpeg_rom_start_offset) != 0)
|
||||
{
|
||||
ErrorLog("%s: Multiple tracks defined for '%s' MPEG ROM offset 0x%08x. Only the first will be used.", music_filepath.c_str(), game.name.c_str(), mpeg_rom_start_offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file_contents_by_filepath.count(filepath) == 0)
|
||||
{
|
||||
FileContents contents = LoadFile(filepath);
|
||||
if (contents.bytes == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
file_contents_by_filepath[filepath] = contents;
|
||||
InfoLog("Loaded custom track: %s.", filepath.c_str());
|
||||
printf("Loaded custom track: %s.\n", filepath.c_str());
|
||||
}
|
||||
|
||||
FileContents contents = file_contents_by_filepath[filepath];
|
||||
s_custom_tracks_by_mpeg_rom_address[mpeg_rom_start_offset] = CustomTrack(contents.bytes, contents.size, mpeg_rom_start_offset, file_start_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
MPEG Music Playback
|
||||
***************************************************************************************************/
|
||||
|
||||
struct Decoder
|
||||
{
|
||||
|
@ -13,37 +212,95 @@ struct Decoder
|
|||
int numSamples;
|
||||
int pcmPos;
|
||||
short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
|
||||
|
||||
std::shared_ptr<uint8_t[]> custom_mpeg_data;
|
||||
};
|
||||
|
||||
static Decoder dec = { 0 };
|
||||
|
||||
void MpegDec::SetMemory(const uint8_t *data, int length, bool loop)
|
||||
void MpegDec::SetMemory(const uint8_t *data, int offset, int length, bool loop)
|
||||
{
|
||||
mp3dec_init(&dec.mp3d);
|
||||
|
||||
dec.buffer = data;
|
||||
dec.size = length;
|
||||
dec.pos = 0;
|
||||
dec.numSamples = 0;
|
||||
dec.pcmPos = 0;
|
||||
dec.loop = loop;
|
||||
dec.stopped = false;
|
||||
auto it = s_custom_tracks_by_mpeg_rom_address.find(offset);
|
||||
if (it == s_custom_tracks_by_mpeg_rom_address.end()) {
|
||||
// MPEG ROM
|
||||
dec.buffer = data + offset;
|
||||
dec.size = length;
|
||||
dec.custom_mpeg_data = nullptr;
|
||||
}
|
||||
else {
|
||||
// Custom track available
|
||||
const CustomTrack &track = it->second;
|
||||
|
||||
size_t offset_in_file = track.file_start_offset;
|
||||
if (offset_in_file >= track.mpeg_data_size)
|
||||
{
|
||||
// Out of bounds, go to start of file
|
||||
offset_in_file = 0;
|
||||
}
|
||||
|
||||
dec.buffer = track.mpeg_data.get() + offset_in_file;
|
||||
dec.size = track.mpeg_data_size - offset_in_file;
|
||||
dec.custom_mpeg_data = track.mpeg_data;
|
||||
}
|
||||
|
||||
dec.pos = 0;
|
||||
dec.numSamples = 0;
|
||||
dec.pcmPos = 0;
|
||||
dec.loop = loop;
|
||||
dec.stopped = false;
|
||||
|
||||
printf("SET MEMORY: %08x\n", offset);
|
||||
}
|
||||
|
||||
void MpegDec::UpdateMemory(const uint8_t* data, int length, bool loop)
|
||||
void MpegDec::UpdateMemory(const uint8_t* data, int offset, int length, bool loop)
|
||||
{
|
||||
int diff;
|
||||
if (data > dec.buffer) {
|
||||
diff = (int)(data - dec.buffer);
|
||||
}
|
||||
else {
|
||||
diff = -(int)(dec.buffer - data);
|
||||
}
|
||||
auto it = s_custom_tracks_by_mpeg_rom_address.find(offset);
|
||||
if (it == s_custom_tracks_by_mpeg_rom_address.end()) {
|
||||
// MPEG ROM
|
||||
int diff;
|
||||
if ((data + offset) > dec.buffer) {
|
||||
diff = (int)(data + offset - dec.buffer);
|
||||
}
|
||||
else {
|
||||
diff = -(int)(dec.buffer - data - offset);
|
||||
}
|
||||
dec.buffer = data + offset;
|
||||
dec.size = length;
|
||||
dec.pos = dec.pos - diff; // update position relative to our new start location
|
||||
}
|
||||
else {
|
||||
// Custom track available. This is tricky. This command updates the start/end pointers (usually
|
||||
// used by games to create a loop point). We need to ensure that the custom track definition is
|
||||
// consistent: the custom track associated with this ROM offset must be the same file as is
|
||||
// currently playing, otherwise we do nothing.
|
||||
CustomTrack &track = it->second;
|
||||
if (track.mpeg_data == dec.custom_mpeg_data)
|
||||
{
|
||||
size_t offset_in_file = track.file_start_offset;
|
||||
if (offset_in_file >= track.mpeg_data_size)
|
||||
{
|
||||
// Out of bounds, just use start of file
|
||||
offset_in_file = 0;
|
||||
}
|
||||
|
||||
int diff;
|
||||
if ((track.mpeg_data.get() + offset_in_file) > dec.buffer) {
|
||||
diff = (int)(track.mpeg_data.get() + offset_in_file - dec.buffer);
|
||||
}
|
||||
else {
|
||||
diff = -(int)(dec.buffer - track.mpeg_data.get() - offset_in_file);
|
||||
}
|
||||
dec.buffer = track.mpeg_data.get() + offset_in_file;
|
||||
dec.size = track.mpeg_data_size - offset_in_file; // ignoring length specified by caller because MPEG ROM end offsets won't in general match with track, so we always have to use EOF
|
||||
dec.pos = dec.pos - diff; // update position relative to our new start location
|
||||
}
|
||||
}
|
||||
|
||||
dec.buffer = data;
|
||||
dec.size = length;
|
||||
dec.pos = dec.pos - diff; // update position relative to our new start location
|
||||
dec.loop = loop;
|
||||
|
||||
printf("UPDATE MEMORY: %08x\n", offset);
|
||||
}
|
||||
|
||||
int MpegDec::GetPosition()
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#ifndef _MPEG_AUDIO_H_
|
||||
#define _MPEG_AUDIO_H_
|
||||
|
||||
#include "Game.h"
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace MpegDec
|
||||
{
|
||||
void SetMemory(const uint8_t *data, int length, bool loop);
|
||||
void UpdateMemory(const uint8_t *data, int length, bool loop);
|
||||
void LoadCustomTracks(const std::string &music_filepath, const Game &game);
|
||||
void SetMemory(const uint8_t *data, int offset, int length, bool loop);
|
||||
void UpdateMemory(const uint8_t *data, int offset, int length, bool loop);
|
||||
int GetPosition();
|
||||
void SetPosition(int pos);
|
||||
void DecodeAudio(int16_t* left, int16_t* right, int numStereoSamples);
|
||||
|
|
Loading…
Reference in a new issue