Skip to content

Commit

Permalink
feat(sound): add beeper
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartPolarBear committed Jan 16, 2022
1 parent 058abcf commit f387b66
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 3 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ add_subdirectory(base)

add_subdirectory(processor)
add_subdirectory(display)
add_subdirectory(sound)

target_link_libraries(cchip8 PRIVATE SDL2::SDL2 SDL2::SDL2main)
# use custom entry point
Expand Down
8 changes: 8 additions & 0 deletions processor/include/processor/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ class machine
START_ADDRESS = 0x200,
};

enum audio_frequencies
{
TIMER_BEEP = 440,
ERROR_BEEP = 350,
};

static constexpr size_t BEEP_DURATION = 20;

enum general_purpose_registers
{
V0,
Expand Down
11 changes: 8 additions & 3 deletions processor/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
#include <gsl/gsl>

#include "processor/processor.h"
#include "sound/beeper.h"

using namespace std;
using namespace std::chrono;

using namespace gsl;

using namespace cchip8::processor;
using namespace cchip8::sound;

machine::machine()
: reg_pc_(START_ADDRESS),
Expand Down Expand Up @@ -45,8 +47,11 @@ void machine::cycle()

if (sound_timer_ > 0)
{
// TODO: go off a beep
sound_timer_ -= 1;

beeper b{};
b.beep(TIMER_BEEP, BEEP_DURATION);
b.wait();
}
}

Expand Down Expand Up @@ -105,8 +110,8 @@ void machine::load(std::string_view filename)

void machine::op_default()
{
// TODO: logging and/or sounding
int fuck = 0;
beeper b{};
b.beep(ERROR_BEEP, BEEP_DURATION);
}

// 00e0: clear the screen
Expand Down
3 changes: 3 additions & 0 deletions sound/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.21)

target_sources(cchip8
PRIVATE beeper.cpp)

target_include_directories(cchip8 PRIVATE include)
100 changes: 100 additions & 0 deletions sound/beeper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// Created by cleve on 1/16/2022.
//

#include "sound/beeper.h"

#include <cmath>
#include <stdexcept>

using namespace std;

cchip8::sound::beeper::beeper()
{
SDL_AudioSpec spec;

spec.freq = FREQUENCY;
spec.format = AUDIO_S16SYS;
spec.channels = 1;
spec.samples = 2048;
spec.callback = callback;
spec.userdata = this;

SDL_AudioSpec obtained;

// you might want to look for errors here
if (SDL_OpenAudio(&spec, &obtained) != 0)
{
throw runtime_error{ SDL_GetError() };
}

// start play audio
SDL_PauseAudio(0);
}

cchip8::sound::beeper::~beeper()
{
SDL_CloseAudio();
}

void cchip8::sound::beeper::beep(double freq, int duration)
{
SDL_LockAudio();
beep_segs_.emplace(freq, duration * FREQUENCY / 1000);
SDL_UnlockAudio();
}

void cchip8::sound::beeper::wait()
{
int size = 0;
do
{
SDL_Delay(20);
SDL_LockAudio();
size = beep_segs_.size();
SDL_UnlockAudio();
} while (size > 0);
}

void cchip8::sound::beeper::sample(std::span<Sint16> stream)
{
int i = 0;
while (i < stream.size())
{

if (beep_segs_.empty())
{
while (i < stream.size())
{
stream[i] = 0;
i++;
}
return;
}
auto& bo = beep_segs_.front();

int samples_count = std::min(i + bo.second, (int)stream.size());
bo.second -= samples_count - i;

while (i < samples_count)
{
stream[i] = AMPLITUDE * std::sin(v_ * 2 * 3.1415926f / FREQUENCY);
i++;
v_ += bo.first;
}

if (bo.second == 0)
{
beep_segs_.pop();
}
}
}

void cchip8::sound::beeper::callback(void* b, Uint8* s, int len)
{
auto* stream = (Sint16*)s;
int length = len / 2;
auto* bp = (beeper*)b;

bp->sample({ stream, (size_t)length });
}
43 changes: 43 additions & 0 deletions sound/include/sound/beeper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Created by cleve on 1/16/2022.
//

#pragma once

#include <queue>
#include <utility>
#include <span>

#include <SDL.h>
#include <SDL_audio.h>

namespace cchip8::sound
{
class beeper
{
public:
static constexpr int AMPLITUDE = 28000;
static constexpr int FREQUENCY = 44100;

beeper();

~beeper();

beeper(beeper&&) = delete;

beeper(const beeper&) = delete;

beeper& operator=(const beeper&) = delete;

void beep(double freq,int duration);

void wait();

private:
void sample(std::span<Sint16> stream);
static void callback(void*,Uint8*,int);

double v_{};
std::queue<std::pair<double, int>> beep_segs_{};
};
}

0 comments on commit f387b66

Please sign in to comment.