Skip to content
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

Develop #35

Merged
merged 9 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CHIP8TOPIA_VERSION "2.1.1")
set(CHIP8TOPIA_VERSION "2.1.2")

project("Chip8topia" VERSION ${CHIP8TOPIA_VERSION})
add_subdirectory(${PROJECT_NAME})
Expand Down
2 changes: 1 addition & 1 deletion Chip8topia/Chip8Emulator/Chip8CoreBase/Chip8CoreBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ enum class Chip8Frequency : uint32
Freq24000000Hz = 24000000 // 24MHz for Alien-Inv8sion
};

// TODO: make clock private and call it in a non public virtual function ClockCore which will call the cock method in a try catch block for safety.
// TODO: make clock method private and call it in a non public virtual function ClockCore which will call the clock method in a try catch block for safety.
// This way we will remove the dependency to the InputHandler in the Cpu and throw error.

// class CpuBase;
Expand Down
59 changes: 12 additions & 47 deletions Chip8topia/Chip8Emulator/Chip8Emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ Chip8Emulator::Chip8Emulator() : m_breakpoints{},
#else
m_core(std::make_unique<XoChipCore>(DEFAULT_FREQUENCY)),
#endif
// m_accumulator(0.0F),
m_isRomLoaded(false),
// m_isTurboMode(false),
m_isBreak(false),
m_step(false),
m_canBreak(true),
m_errorTriggered(false),
m_soundMuted(false)
m_errorTriggered(false)
{
Chip8topiaInputHandler& inputHandler = Chip8topiaInputHandler::getInstance();
inputHandler.m_GameInput.subscribe(this, &Chip8Emulator::OnInput);
Expand All @@ -43,9 +40,6 @@ Chip8Emulator::Chip8Emulator() : m_breakpoints{},
inputHandler.m_EmulationError.subscribe(this, &Chip8Emulator::triggerEmulationError);
#endif

// m_pcHistory.reserve(PC_HISTORY_SIZE);
// m_pcHistory.push_back(CpuBase::START_ADDRESS);

resetColorPalette();
}

Expand Down Expand Up @@ -75,9 +69,8 @@ void Chip8Emulator::restart()
{
m_core->reset();
m_videoEmulation.reset();
m_soundEmulation.stop();
m_soundEmulation.reset();
m_errorTriggered = false;
// m_accumulator = 0.0F;
}

void Chip8Emulator::loadRom(const std::vector<uint8_t>& romData)
Expand All @@ -100,21 +93,14 @@ void Chip8Emulator::update(const float deltaTime)
{
m_step = false;
m_core->clock();
// updatePcHistory();
}
}
else
{
// m_accumulator += deltaTime;

// if (m_isTurboMode || m_accumulator >= 1.0F / Chip8Core::SCREEN_AND_TIMERS_FREQUENCY)
// {
// m_accumulator = 0.0F;
bool screenUpdated = false;
while (!screenUpdated && !m_isBreak && !m_errorTriggered)
{
screenUpdated = m_core->clock();
// updatePcHistory();

if (m_breakpoints[m_core->getCpu()->getPc()])
{
Expand All @@ -123,14 +109,13 @@ void Chip8Emulator::update(const float deltaTime)
"Breakpoint hit", fmt::format("Breakpoint hit at 0x{:04X}", m_core->getCpu()->getPc()).c_str() });
}
}
// }
}
}

void Chip8Emulator::emitSound()
{
// TODO: Improve this condition...
if (!m_soundMuted && !m_isBreak && m_isRomLoaded && !m_errorTriggered)
if (!m_isBreak && m_isRomLoaded && !m_errorTriggered)
{
m_soundEmulation.update(m_core);
}
Expand All @@ -146,7 +131,7 @@ void Chip8Emulator::stop()
{
if (m_isRomLoaded)
{
m_soundEmulation.stop();
m_soundEmulation.reset();
m_isRomLoaded = false;
m_romName = "ROM";
ImGui::InsertNotification({ ImGuiToastType::Info, TOAST_DURATION_INFO, "Emulation stopped", "The emulation has been stopped. Please load a ROM to continue." });
Expand All @@ -167,25 +152,20 @@ void Chip8Emulator::setSoundVolume(float volume)
#if defined(BUILD_PARAM_SAFE)
void Chip8Emulator::triggerEmulationError(const std::string& message)
{
m_soundEmulation.stop();
m_soundEmulation.reset();
m_errorTriggered = true;
LOG_ERROR(message);
}
#endif

// void Chip8Emulator::setIsTurboMode(const bool isTurboMode)
//{
// m_isTurboMode = isTurboMode;
// }

void Chip8Emulator::setRomName(const std::string& romName)
{
m_romName = romName;
}

void Chip8Emulator::switchCoreFrequency(const Chip8CoreType coreType, const Chip8Frequency frequency)
{
m_soundEmulation.stop();
m_soundEmulation.reset();

switch (coreType)
{
Expand Down Expand Up @@ -222,41 +202,31 @@ void Chip8Emulator::clearBreakpoints()

void Chip8Emulator::stepEmulation()
{
m_soundEmulation.stop();
m_soundEmulation.reset();
m_isBreak = true;
m_step = true;
}
void Chip8Emulator::runEmulation()
{
m_isBreak = false;
}

void Chip8Emulator::breakEmulation()
{
m_soundEmulation.stop();
m_soundEmulation.reset();
m_isBreak = true;
}

void Chip8Emulator::toggleBreakEmulation()
{
m_isBreak = !m_isBreak;

if (m_isBreak)
{
m_soundEmulation.stop();
m_soundEmulation.reset();
}
}

// void Chip8Emulator::updatePcHistory()
//{
// if (m_pcHistory.back() != m_core->getCpu()->getPc())
// {
// if (m_pcHistory.size() >= PC_HISTORY_SIZE)
// {
// m_pcHistory.erase(m_pcHistory.begin());
// }
//
// m_pcHistory.push_back(m_core->getCpu()->getPc());
// }
// }

void Chip8Emulator::OnInput(const uint8 key, const bool isPressed)
{
m_core->updateKey(key, isPressed);
Expand Down Expand Up @@ -321,8 +291,3 @@ auto Chip8Emulator::getFrequency() const -> Chip8Frequency
{
return m_core->getFrequency();
}

// auto Chip8Emulator::getPcHistory() const -> const std::vector<uint16>&
//{
// return m_pcHistory;
// }
6 changes: 0 additions & 6 deletions Chip8topia/Chip8Emulator/Chip8Emulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ class Chip8Emulator
[[nodiscard]] auto getBreakpointsList() -> std::set<uint16>&;
[[nodiscard]] auto getCoreType() const -> Chip8CoreType;
[[nodiscard]] auto getFrequency() const -> Chip8Frequency;
// [[nodiscard]] auto getPcHistory() const -> const std::vector<uint16>&;

private:
std::string m_romName = "ROM";
Expand All @@ -78,17 +77,12 @@ class Chip8Emulator
Chip8VideoEmulation m_videoEmulation;
Chip8SoundEmulation m_soundEmulation;

// float m_accumulator;
bool m_isRomLoaded;
// bool m_isTurboMode;
bool m_isBreak;
bool m_step;
bool m_canBreak;
bool m_errorTriggered;
bool m_soundMuted;

std::set<uint16> m_breakpointsList;
std::array<bool, CpuBase::MEMORY_SIZE> m_breakpoints;

// std::vector<uint16> m_pcHistory;
};
95 changes: 70 additions & 25 deletions Chip8topia/Chip8Emulator/Chip8Emulator/Chip8SoundEmulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@
Sint16 format(double sample, double amplitude)
{
// 32567 is the maximum value of a 16 bit signed integer (2^15-1)
return (Sint16)(sample * 32567 * amplitude);
return static_cast<Sint16>(sample * 32567 * amplitude);
}

// Generate a sine wave
double tone(double hz, unsigned long time)
{
return sin(time * hz * M_PI * 2 / Chip8SoundEmulation::FREQUENCY_RESOLUTION);
}

// Generate a sawtooth wave
double saw(double hz, unsigned long time)
{
return fmod(time * hz / Chip8SoundEmulation::FREQUENCY_RESOLUTION, 1) * 2 - 1;
}

// Generate a square wave
double square(double hz, unsigned long time)
{
double sine = tone(hz, time);
Expand All @@ -41,74 +44,111 @@ Chip8SoundEmulation::Chip8SoundEmulation() : m_buffer{},
m_bufferPosition(0),
m_volume(0.5),
m_isPlaying(false),
m_squareSoundFrequency(440)
m_squareSoundFrequency(440),
m_waveType(WaveType::Square)
{
m_dev = SDL_OpenAudioDevice(nullptr, 0, &m_spec, nullptr, 0);
initSoundBuffer();
initSoundBuffer(square);
}

Chip8SoundEmulation::~Chip8SoundEmulation()
{
SDL_CloseAudioDevice(m_dev);
}

void Chip8SoundEmulation::initSoundBuffer()
void Chip8SoundEmulation::reset()
{
stop();
}

void Chip8SoundEmulation::initSoundBuffer(std::function<double(double, unsigned long)> waveFunction)
{
stop();

for (int i = 0; i < BUFFER_LEN; i++)
{
m_buffer[i] = format(square(m_squareSoundFrequency, i), m_volume);
m_buffer[i] = format(waveFunction(m_squareSoundFrequency, i), m_volume);
}
}

void Chip8SoundEmulation::setWaveType(WaveType waveType)
{
// TODO: Correct this code which may lead to crash in webassembly
stop();

m_waveType = waveType;

switch (m_waveType)
{
case WaveType::Sine:
initSoundBuffer(tone);
break;
case WaveType::Saw:
initSoundBuffer(saw);
break;
case WaveType::Square:
initSoundBuffer(square);
break;
}
}

void Chip8SoundEmulation::update(const std::unique_ptr<Chip8CoreBase>& chip8Core)
{
#if !defined(__EMSCRIPTEN__)
const auto st = chip8Core->getCpu()->getST();

if (st > 0)
{
if (!m_isPlaying)
{
SDL_PauseAudioDevice(m_dev, 0);
m_isPlaying = true;
}
play();
}
else
{
if (m_isPlaying)
{
SDL_PauseAudioDevice(m_dev, 1);
m_isPlaying = false;
}
stop();
}
#endif
}

void Chip8SoundEmulation::stop()
{
SDL_PauseAudioDevice(m_dev, 1);
m_isPlaying = false;
if (m_isPlaying)
{
SDL_PauseAudioDevice(m_dev, 1);
m_isPlaying = false;
}
}

void Chip8SoundEmulation::play()
{
if (!m_isPlaying)
{
SDL_PauseAudioDevice(m_dev, 0);
m_isPlaying = true;
}
}

void Chip8SoundEmulation::soundPlayerCallback(void* userdata, unsigned char* stream, int len)
void Chip8SoundEmulation::soundPlayerCallback(void* userdata, unsigned char* stream, int streamLength)
{
auto* chip8SoundEmulation = static_cast<Chip8SoundEmulation*>(userdata);

chip8SoundEmulation->soundPlayer(stream, len);
chip8SoundEmulation->soundPlayer(stream, streamLength);
}

void Chip8SoundEmulation::soundPlayer(unsigned char* stream, int len)
void Chip8SoundEmulation::soundPlayer(unsigned char* stream, int streamLength)
{
SDL_memset(stream, m_spec.silence, len);
static constexpr size_t SAMPLE_SIZE = sizeof(Sint16);
const int sampleLength = streamLength / SAMPLE_SIZE;

len /= 2;
SDL_memset(stream, m_spec.silence, streamLength);

if (m_bufferPosition + len >= BUFFER_LEN)
if (m_bufferPosition + sampleLength >= BUFFER_LEN)
{
m_bufferPosition = 0;
}

SDL_memcpy(stream, &m_buffer[m_bufferPosition], len * 2);
// TODO: Correct the strange crash here in webassembly
SDL_memcpy(stream, &m_buffer[m_bufferPosition], streamLength);

m_bufferPosition += len;
m_bufferPosition += sampleLength;
}

auto Chip8SoundEmulation::getIsPlaying() const -> bool
Expand All @@ -125,3 +165,8 @@ auto Chip8SoundEmulation::getVolumePtr() -> float*
{
return &m_volume;
}

auto Chip8SoundEmulation::getWaveType() const -> WaveType
{
return m_waveType;
}
Loading
Loading