aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2023-10-22 09:00:16 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2023-10-22 09:00:16 +0530
commiteb6adb4b212cd55f8e6a553ecdcffa2f8a7cc63a (patch)
treea744ce43eeb5c2ff758ccc9d02750489b04bafc2
parent689fa26e124cebb42518ed7ca14185d80fff20b9 (diff)
Implement sound
-rw-r--r--src/chip8.cpp29
-rw-r--r--src/chip8.hpp5
-rw-r--r--src/main.cpp3
-rw-r--r--src/platform.cpp74
-rw-r--r--src/platform.hpp8
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