3 Commits

9 changed files with 347 additions and 178 deletions
+9 -1
View File
@@ -23,7 +23,8 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{61c6f079-9b1c-4d66-b9c7-4646f87181a6}</ProjectGuid>
<RootNamespace>bouncecpp</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
<ProjectName>hyrax</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -109,6 +110,8 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gdiplus.lib;
winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -125,13 +128,18 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gdiplus.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="physics.cpp" />
<ClCompile Include="sound_handler.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="physics.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sound_handler.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resource.rc" />
+12
View File
@@ -18,11 +18,23 @@
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="physics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sound_handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="physics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sound_handler.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resource.rc">
Binary file not shown.
+45 -177
View File
@@ -8,6 +8,7 @@ Quick description of the app:
- A hyrax picture which bounces around your desktop, like bonzi buddy but not destructive, more of a fun thing which you can open
when you get bored.
- Run the exe youll find out.
- you can click and it will awawa
This is not malware or a virus, its purely for fun and entertainment purpouses.
@@ -24,27 +25,18 @@ rattatwinko - 04/05/26
#include <cstdlib>
#include <ctime>
#include <cstdint>
#include <memory>
#include "resource.h"
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "winmm.lib")
#include "sound_handler.h"
#include "physics.h"
using namespace Gdiplus;
// consts
static constexpr double GRAVITY = 1200.0;
static constexpr double RESTITUTION = 0.6;
static constexpr double AIR_DRAG = 0.999;
static constexpr double GROUND_FRICTION = 0.8;
static constexpr double REST_THRESHOLD = 5.0;
static constexpr UINT TIMER_MS = 10;
static constexpr int IMAGE_RESOURCE = 111;
static constexpr int RESIZE_BORDER = 12; // make wider so easier grab
static constexpr int DRAG_THRESHOLD = 5; // pixels before its a drag not a click
static constexpr int WAV_COUNT = 9;
static constexpr int MAX_PEAKS = 64; // max screams per sound
static constexpr double PEAK_HOLD = 0.10; // seconds which we hold the awawa face
static constexpr double PEAK_THRESH = 0.65; // fraction of max amplitude to count as a peak
// globals
static ULONG_PTR g_gdiplusToken = 0;
@@ -54,10 +46,8 @@ static int g_winW = 640;
static int g_winH = 480;
static LARGE_INTEGER g_freq = {};
// physics states
static double g_x = 200.0, g_y = 50.0;
static double g_vx = 0.0, g_vy = 0.0;
static double g_lastTime = 0.0;
// physics object (initial position 200,50 with zero velocity)
static physics g_physics(200.0, 50.0, 0.0, 0.0);
// resize / drag status
static bool g_resizing = false;
@@ -68,14 +58,10 @@ static int g_dragOffsetY = 0;
static POINT g_lastMouse = {};
static POINT g_clickOrigin = {};
static double g_lastMouseTime = 0.0;
static double g_lastTime = 0.0;
// scream face stuff
static bool g_screaming = false;
static double g_screamUntil = 0.0; // timestamp to stop screaming
static double g_soundStart = 0.0; // when playback began
static double g_peakTimes[MAX_PEAKS] = {};
static int g_peakCount = 0;
static int g_peakIdx = 0; // next peak we havent fired yet
static std::unique_ptr<sound_handler> g_sound;
// helper definitions
static double Now() {
@@ -124,131 +110,6 @@ static Image* LoadImageFromResource(HINSTANCE hInst, int resId, LPCWSTR resType)
return img;
}
// walk RAW fucking PCM data and check for peaks
static void FindWavPeaks(const BYTE* buf, DWORD size) {
g_peakCount = 0;
g_peakIdx = 0;
if (size < 44) return;
if (memcmp(buf, "RIFF", 4) != 0 || memcmp(buf + 8, "WAVE", 4) != 0) return;
WORD channels = 0;
DWORD sampleRate = 0;
WORD bitsPerSample = 0;
const BYTE* pcm = nullptr;
DWORD pcmSize = 0;
// walk the chunks
DWORD pos = 12;
while (pos + 8 <= size) {
DWORD chunkSize = *reinterpret_cast<const DWORD*>(buf + pos + 4);
if (memcmp(buf + pos, "fmt ", 4) == 0 && chunkSize >= 16) {
channels = *reinterpret_cast<const WORD*> (buf + pos + 10);
sampleRate = *reinterpret_cast<const DWORD*>(buf + pos + 12);
bitsPerSample = *reinterpret_cast<const WORD*> (buf + pos + 22);
}
else if (memcmp(buf + pos, "data", 4) == 0) {
pcm = buf + pos + 8;
pcmSize = chunkSize;
break;
}
pos += 8 + chunkSize;
if (chunkSize & 1) pos++; // align word cause microsoft likes to fuck my ass
}
// only 16bit PCM cause everything else is just stoopid
if (!pcm || !sampleRate || bitsPerSample != 16) return;
DWORD totalSamples = pcmSize / (channels * sizeof(int16_t));
// global maximum
int maxAmp = 1;
for (DWORD i = 0; i < pcmSize / sizeof(int16_t); i++) {
int s = abs((int)*reinterpret_cast<const int16_t*>(pcm + i * sizeof(int16_t)));
if (s > maxAmp) maxAmp = s;
}
int threshold = static_cast<int>(maxAmp * PEAK_THRESH);
DWORD windowSamples = sampleRate / 50; // 20ms windows
DWORD debounce = sampleRate / 8; // 125ms min gap so we dont spam
DWORD lastPeak = 0xFFFFFFFF;
// stupid fucking logic. scan for loud moments
for (DWORD s = 0; s + windowSamples <= totalSamples; s += windowSamples / 2) {
int winMax = 0;
for (DWORD j = 0; j < windowSamples * channels; j++) {
DWORD byteOff = (s * channels + j) * sizeof(int16_t);
if (byteOff + sizeof(int16_t) > pcmSize) break;
int amp = abs((int)*reinterpret_cast<const int16_t*>(pcm + byteOff));
if (amp > winMax) winMax = amp;
}
bool gapOk = (lastPeak == 0xFFFFFFFF) || (s - lastPeak >= debounce);
if (winMax >= threshold && gapOk && g_peakCount < MAX_PEAKS) {
g_peakTimes[g_peakCount++] = static_cast<double>(s) / sampleRate;
lastPeak = s;
}
}
}
// play a random hyrax sound and prep the scream timeline
static void PlayRandomSound(HINSTANCE hInst) {
int id = IDR_WAVE1 + (rand() % WAV_COUNT);
// grab raw wave data and look for peaks ; possible cause of .rc WAVE type
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(id), L"WAVE");
HGLOBAL hData = hRes ? LoadResource(hInst, hRes) : nullptr;
BYTE* pData = hData ? static_cast<BYTE*>(LockResource(hData)) : nullptr;
DWORD sz = hRes ? SizeofResource(hInst, hRes) : 0;
if (pData && sz)
FindWavPeaks(pData, sz);
g_soundStart = Now();
PlaySoundW(MAKEINTRESOURCEW(id), hInst, SND_RESOURCE | SND_ASYNC | SND_NODEFAULT);
}
// physics "engine"
static void StepPhysics(double dt) {
const int screenW = GetSystemMetrics(SM_CXSCREEN);
const int screenH = GetSystemMetrics(SM_CYSCREEN);
g_vy += GRAVITY * dt;
g_vx *= AIR_DRAG;
g_vy *= AIR_DRAG;
g_x += g_vx * dt;
g_y += g_vy * dt;
// left / right monitor borders
if (g_x < 0.0) {
g_x = 0.0;
g_vx = -g_vx * RESTITUTION;
}
else if (g_x > screenW - g_winW) {
g_x = static_cast<double>(screenW - g_winW);
g_vx = -g_vx * RESTITUTION;
}
// top
if (g_y < 0.0) {
g_y = 0.0;
g_vy = -g_vy * RESTITUTION;
}
// bottom
if (g_y > screenH - g_winH) {
g_y = static_cast<double>(screenH - g_winH);
g_vy = -g_vy * RESTITUTION;
g_vx *= GROUND_FRICTION;
if (fabs(g_vy) < REST_THRESHOLD)
g_vy = 0.0;
}
}
// win api window proc
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
@@ -267,12 +128,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
g_imageScream = LoadImageFromResource(hInst, IDB_BITMAP1, L"JPG");
if (g_image) {
g_winW = static_cast<int>(g_image->GetWidth());
g_winH = static_cast<int>(g_image->GetHeight());
g_winW = 480;
g_winH = 480;
SetWindowPos(hwnd, nullptr, 0, 0, g_winW, g_winH,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
// sound handler
g_sound = std::make_unique<sound_handler>(
hInst,
std::initializer_list<int>{
IDR_WAVE1, IDR_WAVE2, IDR_WAVE3,
IDR_WAVE4, IDR_WAVE5, IDR_WAVE6,
IDR_WAVE7, IDR_WAVE8, IDR_WAVE9
}
);
g_lastTime = Now();
g_lastMouseTime = g_lastTime;
@@ -286,7 +157,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
g_didDrag = false;
g_dragOffsetX = GET_X_LPARAM(lParam);
g_dragOffsetY = GET_Y_LPARAM(lParam);
g_vx = g_vy = 0.0;
g_physics.resetVelocity(); // stop all motion
GetCursorPos(&g_lastMouse);
g_clickOrigin = g_lastMouse;
@@ -311,17 +182,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
const double dt = now - g_lastMouseTime;
if (dt > 0.0) {
g_vx = (p.x - g_lastMouse.x) / dt;
g_vy = (p.y - g_lastMouse.y) / dt;
double vx = (p.x - g_lastMouse.x) / dt;
double vy = (p.y - g_lastMouse.y) / dt;
g_physics.setVelocity(vx, vy);
}
g_lastMouse = p;
g_lastMouseTime = now;
g_x = p.x - g_dragOffsetX;
g_y = p.y - g_dragOffsetY;
g_physics.setPos(p.x - g_dragOffsetX, p.y - g_dragOffsetY);
SetWindowPos(hwnd, nullptr, static_cast<int>(g_x), static_cast<int>(g_y),
SetWindowPos(hwnd, nullptr, static_cast<int>(g_physics.x()), static_cast<int>(g_physics.y()),
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
}
@@ -329,8 +200,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
// drag end or click
case WM_LBUTTONUP: {
if (!g_didDrag) {
HINSTANCE hInst = reinterpret_cast<HINSTANCE>(GetWindowLongPtrW(hwnd, GWLP_HINSTANCE));
PlayRandomSound(hInst);
// play random sound
if (g_sound)
g_sound->PlayRandom();
}
g_dragging = false;
ReleaseCapture();
@@ -344,13 +216,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
case WM_EXITSIZEMOVE: {
g_resizing = false;
g_vx = g_vy = 0.0;
g_physics.resetVelocity();
// sync gx/y with resized cords
RECT r;
GetWindowRect(hwnd, &r);
g_x = static_cast<double>(r.left);
g_y = static_cast<double>(r.top);
g_physics.setPos(static_cast<double>(r.left), static_cast<double>(r.top));
g_lastTime = Now(); // after everything is clean then redraw
break;
@@ -400,27 +271,23 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
g_lastTime = now;
if (!g_dragging && !g_resizing) {
StepPhysics(dt);
SetWindowPos(hwnd, nullptr, static_cast<int>(g_x), static_cast<int>(g_y),
int screenW = GetSystemMetrics(SM_CXSCREEN);
int screenH = GetSystemMetrics(SM_CYSCREEN);
g_physics.update(dt, screenW, screenH, g_winW, g_winH);
SetWindowPos(hwnd, nullptr, static_cast<int>(g_physics.x()), static_cast<int>(g_physics.y()),
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
// extend scream hold
if (g_peakCount > 0) {
double elapsed = now - g_soundStart;
while (g_peakIdx < g_peakCount && elapsed >= g_peakTimes[g_peakIdx]) {
g_screamUntil = now + PEAK_HOLD;
g_peakIdx++;
// use sound handler instead of doing this in main
if (g_sound) {
g_sound->Update(now);
bool shouldScream = (g_imageScream && g_sound->IsAwAwA(now));
if (shouldScream != g_screaming) {
g_screaming = shouldScream;
InvalidateRect(hwnd, nullptr, FALSE);
}
}
// flip face state
bool shouldScream = (g_imageScream && now < g_screamUntil);
if (shouldScream != g_screaming) {
g_screaming = shouldScream;
InvalidateRect(hwnd, nullptr, FALSE);
}
break;
}
@@ -460,10 +327,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
DestroyWindow(hwnd);
break;
// consuela
case WM_DESTROY:
KillTimer(hwnd, 1);
g_sound.reset(); // clean up sound handler
delete g_image;
delete g_imageScream;
g_image = g_imageScream = nullptr;
@@ -491,7 +359,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow) {
WS_EX_TOPMOST,
L"Hyrax", L"",
WS_POPUP,
static_cast<int>(g_x), static_cast<int>(g_y),
static_cast<int>(g_physics.x()), static_cast<int>(g_physics.y()),
g_winW, g_winH,
nullptr, nullptr, hInstance, nullptr
);
+74
View File
@@ -0,0 +1,74 @@
/*
Preamble:
These exact physics calculations are documented in a TeX Document soon to be in the source tree of
the project. (as of 06/05/26 not in the tree; as of 07/05/26 there is a TeX doc. file name: hyrax_exe-TeX_07_05_2026.pdf)
The physics calculations are done using a Semi-Implicit Euler integrator. (big words)
| Parameter | Value | Description | Mapped code identifier |
|--------------------|--------|------------------------------------------------|------------------------------|
| `GRAVITY` | 1200.0 | Downward acceleration (pxs^-2) | `GRAVITY` (constant) |
| `RESTITUTION` | 0.6 | Energy retention after bounce | `RESTITUTION` (constant) |
| `AIR_DRAG` | 0.999 | Velocity multiplier per frame | `AIR_DRAG` (constant) |
| `GROUND_FRICTION` | 0.8 | Horizontal speed reduction on ground | `GROUND_FRICTION` (constant) |
| `REST_THRESHOLD` | 5.0 | Minimum `\|v_y\|` to consider at rest | `REST_THRESHOLD` (constant) |
06/05/26 - rattatwinko ; when cleaning the source code
*/
#include "physics.h"
#include <cmath>
physics::physics() : physics(0.0, 0.0) {}
physics::physics(double x, double y, double vx, double vy)
: m_x(x), m_y(y), m_vx(vx), m_vy(vy) {
}
void physics::update(double dt, int screenWidth, int screenHeight, int objWidth, int objHeight) {
m_vy += GRAVITY * dt;
m_vx *= AIR_DRAG;
m_vy *= AIR_DRAG;
m_x += m_vx * dt;
m_y += m_vy * dt;
const double rightBound = static_cast<double>(screenWidth - objWidth);
const double bottomBound = static_cast<double>(screenHeight - objHeight);
if (m_x < 0.0) {
m_x = 0.0;
m_vx = -m_vx * RESTITUTION;
}
else if (m_x > rightBound) {
m_x = rightBound;
m_vx = -m_vx * RESTITUTION;
}
if (m_y < 0.0) {
m_y = 0.0;
m_vy = -m_vy * RESTITUTION;
}
else if (m_y > bottomBound) {
m_y = bottomBound;
m_vy = -m_vy * RESTITUTION;
m_vx *= GROUND_FRICTION;
if (std::fabs(m_vy) < REST_THRESHOLD)
m_vy = 0.0;
}
}
void physics::setPos(double x, double y) {
m_x = x;
m_y = y;
}
void physics::setVelocity(double vx, double vy) {
m_vx = vx;
m_vy = vy;
}
void physics::resetVelocity() {
m_vx = m_vy = 0.0;
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#define scd static constexpr double
class physics
{
public:
scd GRAVITY = 2500.0;
scd RESTITUTION = 0.9;
scd AIR_DRAG = 0.999;
scd GROUND_FRICTION = 0.8;
scd REST_THRESHOLD = 5.0;
physics();
physics(double x, double y, double vx = 0.0, double vy = 0.0);
void update(double dt, int screenW, int screenH, int objW, int objH);
// getters / setters
double x() const { return m_x; }
double y() const { return m_y; }
double vx() const { return m_vx; }
double vy() const { return m_vy; }
void setPos(double x, double y);
void setVelocity(double vx, double vy);
void resetVelocity();
private:
double m_x, m_y;
double m_vx, m_vy;
};
+135
View File
@@ -0,0 +1,135 @@
#include "sound_handler.h"
#include <cstdlib>
#include <cstring>
sound_handler::sound_handler(HINSTANCE hInst, std::initializer_list<int> waveIds)
: m_hInst(hInst), m_wavIds(waveIds)
{
for (int id : m_wavIds)
m_peaks.push_back(AnalyzeWavResource(id));
}
void sound_handler::PlayRandom()
{
if (m_wavIds.empty()) return;
int idx = rand() % static_cast<int>(m_wavIds.size());
m_currentWave = idx;
m_soundStart = Now();
m_nextPeak = 0;
int id = m_wavIds[idx];
PlaySoundW(MAKEINTRESOURCEW(id), m_hInst,
SND_RESOURCE | SND_ASYNC | SND_NODEFAULT);
}
void sound_handler::Update(double now)
{
if (m_currentWave < 0 || m_currentWave >= static_cast<int>(m_peaks.size()))
return;
const auto& peaks = m_peaks[m_currentWave].times;
double elapsed = now - m_soundStart;
while (m_nextPeak < static_cast<int>(peaks.size()) && elapsed >= peaks[m_nextPeak]) {
m_screamUntil = now + p_hold;
++m_nextPeak;
}
}
bool sound_handler::IsAwAwA(double now) const
{
return now < m_screamUntil;
}
sound_handler::PeakData sound_handler::AnalyzeWavResource(int resId)
{
PeakData data;
HRSRC hRes = FindResource(m_hInst, MAKEINTRESOURCE(resId), L"WAVE");
if (!hRes) return data;
HGLOBAL hData = LoadResource(m_hInst, hRes);
if (!hData) return data;
DWORD size = SizeofResource(m_hInst, hRes);
const BYTE* buf = static_cast<const BYTE*>(LockResource(hData));
if (!buf) return data;
if (size < 44) return data;
if (memcmp(buf, "RIFF", 4) != 0 || memcmp(buf + 8, "WAVE", 4) != 0)
return data;
WORD channels = 0;
DWORD sampleRate = 0;
WORD bitsPerSample = 0;
const BYTE* pcm = nullptr;
DWORD pcmSize = 0;
DWORD pos = 12;
while (pos + 8 <= size) {
DWORD chunkSize = *reinterpret_cast<const DWORD*>(buf + pos + 4);
if (memcmp(buf + pos, "fmt ", 4) == 0 && chunkSize >= 16) {
channels = *reinterpret_cast<const WORD*>(buf + pos + 10);
sampleRate = *reinterpret_cast<const DWORD*>(buf + pos + 12);
bitsPerSample = *reinterpret_cast<const WORD*>(buf + pos + 22);
}
else if (memcmp(buf + pos, "data", 4) == 0) {
pcm = buf + pos + 8;
pcmSize = chunkSize;
break;
}
pos += 8 + chunkSize;
if (chunkSize & 1) pos++;
}
if (!pcm || bitsPerSample != 16) return data;
DWORD totalSamples = pcmSize / (channels * sizeof(int16_t));
int maxAmp = 1;
for (DWORD i = 0; i < pcmSize / sizeof(int16_t); i++) {
int s = abs(static_cast<int>(
*reinterpret_cast<const int16_t*>(pcm + i * sizeof(int16_t))));
if (s > maxAmp) maxAmp = s;
}
int threshold = static_cast<int>(maxAmp * p_thresh);
DWORD windowSamples = sampleRate / 50; // 20 ms windows
DWORD debounce = sampleRate / 8; // 125 ms minimum gap
DWORD lastPeak = 0xFFFFFFFF;
for (DWORD s = 0; s + windowSamples <= totalSamples; s += windowSamples / 2) {
int winMax = 0;
for (DWORD j = 0; j < windowSamples * channels; j++) {
DWORD byteOff = (s * channels + j) * sizeof(int16_t);
if (byteOff + sizeof(int16_t) > pcmSize) break;
int amp = abs(static_cast<int>(
*reinterpret_cast<const int16_t*>(pcm + byteOff)));
if (amp > winMax) winMax = amp;
}
bool gapOk = (lastPeak == 0xFFFFFFFF) || (s - lastPeak >= debounce);
if (winMax >= threshold && gapOk && data.times.size() < p_max) {
data.times.push_back(static_cast<double>(s) / sampleRate);
lastPeak = s;
if (data.times.size() >= p_max) break;
}
}
return data;
}
double sound_handler::Now()
{
static LARGE_INTEGER freq = [] {
LARGE_INTEGER f;
QueryPerformanceFrequency(&f);
return f;
}();
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
return static_cast<double>(t.QuadPart) / static_cast<double>(freq.QuadPart);
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include <Windows.h>
#include <mmsystem.h>
#include <vector>
#include <cstdint>
#include <initializer_list>
using namespace std;
class sound_handler
{
public:
struct PeakData {
vector<double> times;
};
private:
HINSTANCE m_hInst;
vector<int> m_wavIds;
vector<PeakData> m_peaks;
int m_currentWave = -1;
double m_soundStart = 0.0; // time of playsound
int m_nextPeak = 0;
double m_screamUntil = 0.0;
static constexpr double p_hold = 0.10;
static constexpr double p_thresh = 0.65;
static constexpr int p_max = 64;
public:
sound_handler(HINSTANCE hInst, initializer_list<int> waveIds);
void PlayRandom();
void Update(double now);
bool IsAwAwA(double now) const;
private:
PeakData AnalyzeWavResource(int resId);
static double Now();
};
View File