diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2023-10-22 09:00:16 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2023-10-22 09:00:16 +0530 |
commit | eb6adb4b212cd55f8e6a553ecdcffa2f8a7cc63a (patch) | |
tree | a744ce43eeb5c2ff758ccc9d02750489b04bafc2 | |
parent | 689fa26e124cebb42518ed7ca14185d80fff20b9 (diff) |
Implement sound
-rw-r--r-- | src/chip8.cpp | 29 | ||||
-rw-r--r-- | src/chip8.hpp | 5 | ||||
-rw-r--r-- | src/main.cpp | 3 | ||||
-rw-r--r-- | src/platform.cpp | 74 | ||||
-rw-r--r-- | src/platform.hpp | 8 |
5 files changed, 92 insertions, 27 deletions
diff --git a/src/chip8.cpp b/src/chip8.cpp index 485d061..1d46c49 100644 --- a/src/chip8.cpp +++ b/src/chip8.cpp @@ -1,9 +1,11 @@ #include "chip8.hpp" +#include "platform.hpp" #include <fstream> #include <iostream> #include <cstdint> -#include <chrono> +#include <thread> +#include <mutex> const uint32_t FONTSET_START_ADDRESS = 0x050; const uint32_t ROM_START_ADDRESS = 0x200; @@ -124,15 +126,24 @@ void Chip8::Cycle() { // Decode and Execute ((*this).*(table[(opcode & 0xF000u) >> 12u]))(); - - // Decrement delay timer - if (delayTimer > 0) { - delayTimer--; - } +} - if (soundTimer > 0) { - --soundTimer; - } +void Chip8::TimerUpdateThread(Platform* platform) { + while (true) { + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + + std::lock_guard<std::mutex> lock(timerMutex); + if (delayTimer > 0) { + delayTimer--; + } + + if (soundTimer > 0) { + soundTimer--; + platform->StartBeep(); + } else { + platform->StopBeep(); + } + } } void Chip8::LoadROM(const char* filename) { diff --git a/src/chip8.hpp b/src/chip8.hpp index 5072c2e..01db296 100644 --- a/src/chip8.hpp +++ b/src/chip8.hpp @@ -4,6 +4,9 @@ #include <cstdint> #include <random> #include <bitset> +#include <mutex> + +#include "platform.hpp" const uint32_t VIDEO_HEIGHT = 32; const uint32_t VIDEO_WIDTH = 64; @@ -33,10 +36,12 @@ class Chip8 { private: std::default_random_engine randGen; std::uniform_int_distribution<uint8_t> randByte; + std::mutex timerMutex; public: void LoadROM(const char* filename); void Cycle(); + void TimerUpdateThread(Platform* platform); private: void SetupTable(); diff --git a/src/main.cpp b/src/main.cpp index 583b4ad..7e7d90a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include <iostream> #include <unistd.h> +#include <thread> #include "chip8.hpp" #include "platform.hpp" @@ -24,7 +25,7 @@ int main(int argc, char** argv) { Chip8 chip8; chip8.LoadROM(filename); - int count = 0; + std::thread timerThread(&Chip8::TimerUpdateThread, &chip8, &platform); bool quit = false; while (!quit) { diff --git a/src/platform.cpp b/src/platform.cpp index 4738c66..f2d5984 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -3,38 +3,57 @@ #include "platform.hpp" +#define SAMPLE_RATE 44100 +#define PI 3.14159265358979323846 +#define FREQUENCY 440.0 +#define TIMEPERIOD 200 + Platform::Platform(const char* title, int windowWidth, int windowHeight, int textureWidth, int textureHeight) { - SDL_Init(SDL_INIT_VIDEO); + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) { + std::cerr << "SDL initialization error: " << SDL_GetError() << std::endl; + } window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowWidth, windowHeight, SDL_WINDOW_SHOWN); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + + audioSpec.freq = SAMPLE_RATE; + audioSpec.format = AUDIO_S16SYS; + audioSpec.channels = 1; + audioSpec.samples = 4096; + audioSpec.userdata = this; + beepRequested = false; + audioSpec.callback = AudioCallback; + + audioDevice = SDL_OpenAudioDevice(nullptr, 0, &audioSpec, nullptr, 0); + if (audioDevice == 0) { + std::cerr << "Audio device opening error: " << SDL_GetError() << std::endl; + } + SDL_PauseAudioDevice(audioDevice, 0); } Platform::~Platform() { + SDL_CloseAudioDevice(audioDevice); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } void Platform::Update(const std::bitset<2048>& bitset, int videoScale) { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderClear(renderer); - - for (int y = 0; y < 32; ++y) { - for (int x = 0; x < 64; ++x) { - SDL_Rect pixelRect = {x * videoScale, y * videoScale, videoScale, videoScale}; + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); - if (bitset[y * 64 + x]) { - SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - } else { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - } - - SDL_RenderFillRect(renderer, &pixelRect); - } + for (int y = 0; y < 32; ++y) { + for (int x = 0; x < 64; ++x) { + SDL_Rect pixelRect = {x * videoScale, y * videoScale, videoScale, videoScale}; + if (bitset[y * 64 + x]) { + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + } else { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + } + SDL_RenderFillRect(renderer, &pixelRect); } - - SDL_RenderPresent(renderer); + } + SDL_RenderPresent(renderer); } bool Platform::ProcessInput(std::bitset<16>* keys) { @@ -93,3 +112,24 @@ bool Platform::ProcessInput(std::bitset<16>* keys) { return quit; } + +void Platform::AudioCallback(void* userdata, uint8_t* stream, int len) { + Platform* platform = static_cast<Platform*>(userdata); + if (platform->beepRequested) { + static double time = 0.0; + double freq = 440.0; + + int16_t* sample = reinterpret_cast<int16_t*>(stream); + for (int i = 0; i < len / 2; i++) { + int16_t value = static_cast<int16_t>(32767.0 * sin(2.0 * PI * freq * time)); + sample[i] = value; + time += 1.0 / SAMPLE_RATE; + } + } else { + memset(stream, 0, len); + } +} + +void Platform::StartBeep() { beepRequested = true; } + +void Platform::StopBeep(){ beepRequested = false; } diff --git a/src/platform.hpp b/src/platform.hpp index 872f84d..a037b6e 100644 --- a/src/platform.hpp +++ b/src/platform.hpp @@ -16,10 +16,18 @@ class Platform { public: void Update(const std::bitset<2048>& bitset, int videoScale); bool ProcessInput(std::bitset<16>* keys); + void StartBeep(); + void StopBeep(); + + private: + static void AudioCallback(void* userdata, uint8_t* stream, int len); + bool beepRequested = false; private: SDL_Window* window {}; SDL_Renderer* renderer {}; + SDL_AudioDeviceID audioDevice; + SDL_AudioSpec audioSpec {}; }; #endif |