summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-09-18 12:18:00 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-09-18 12:18:00 -0400
commita8e6384c89a204518a210e3e38d6af089fe57f84 (patch)
tree3217451bdb07eb03e895aea5dd40a71384e27297
parentf5328ba8b42dacd3e47223481dc4f1ea58d9bbd3 (diff)
pke-at: first-pass metronome
-rw-r--r--Makefile1
-rw-r--r--src/level-main.cpp29
-rw-r--r--src/main.cpp10
-rw-r--r--src/pke-at-common.cpp55
-rw-r--r--src/pke-at-common.hpp12
-rw-r--r--src/pke-at-settings.cpp2
-rw-r--r--src/pke-at-settings.hpp20
-rw-r--r--src/pke-at.cpp4
8 files changed, 122 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index c0e9f52..f63b4a4 100644
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@ obj/%.o : src/%.cpp | prepare
bin/pke-at: ## Builds the pke-at executable
bin/pke-at: obj/main.o
bin/pke-at: obj/pke-at-settings.o
+bin/pke-at: obj/pke-at-common.o
bin/pke-at: obj/pke-at.o
bin/pke-at: obj/level-main.o
$(CXX) -v -std=c++23 $(BUILD_MODE_FLAGS) $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -o $@
diff --git a/src/level-main.cpp b/src/level-main.cpp
index d0cfcba..26618e4 100644
--- a/src/level-main.cpp
+++ b/src/level-main.cpp
@@ -1,6 +1,10 @@
#include "level-main.hpp"
+#include "pke-at-common.hpp"
+#include "pke-at-settings.hpp"
+#include "pke/audio-types.hpp"
+#include "pke/audio.hpp"
#include "pke/level.hpp"
struct pke_level_main_master {
@@ -22,10 +26,35 @@ void pke_at_level_main_init() {
hello_world->min_size = glm::vec2(0.9);
hello_world->max_size = glm::vec2(0.9);
pke_level_register_root_ui_box(main_mstr.level, hello_world);
+ pke_at_bpm_reset(120);
+ g_at.mtrnm.beep = pke_at_audio_get_or_generate_sawtooth(440.f, 0.30);
+ g_at.mtrnm.beep_accent = pke_at_audio_get_or_generate_sawtooth(440.f * (3/2.f), 0.30);
+ pke_audio_set_volume(pke_audio_source_sfx, 0.25);
}
void pke_at_level_main_tick(double delta) {
(void)delta;
+ g_at.bpm.delta_since_last_beat += delta;
+ if (g_at.bpm.lerp_delta <= g_at.bpm.lerp_delta_duration) {
+ g_at.bpm.lerp_delta += delta;
+ g_at.bpm.current = std::lerp(g_at.bpm.last, g_at.bpm.target, g_at.bpm.lerp_delta / g_at.bpm.lerp_delta_duration);
+ } else {
+ g_at.bpm.current = g_at.bpm.target;
+ }
+ g_at.bpm.delta_per_beat = 60.f / g_at.bpm.current;
+ g_at.bpm.delta_since_last_beat += delta;
+ if (g_at.bpm.delta_since_last_beat >= g_at.bpm.delta_per_beat) {
+ if (g_at.mtrnm.beat == 0) {
+ pke_audio_play(g_at.mtrnm.beep_accent, pke_audio_source_sfx, pke_audio_flag_none);
+ fprintf(stdout, "beat accent %f\n", delta);
+ } else {
+ pke_audio_play(g_at.mtrnm.beep, pke_audio_source_sfx, pke_audio_flag_none);
+ fprintf(stdout, "beat %f\n", delta);
+ }
+ g_at.bpm.delta_since_last_beat = std::fmod(g_at.bpm.delta_since_last_beat, g_at.bpm.delta_per_beat);
+ g_at.mtrnm.beat += 1;
+ g_at.mtrnm.beat %= g_at.mtrnm.beats_per_bar;
+ }
}
void pke_at_level_main_teardown() {
diff --git a/src/main.cpp b/src/main.cpp
index d1e16cd..7da12ee 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,15 +24,15 @@ int main(int argc, char *argv[]) {
signal(SIGTERM, signal_handler);
fprintf(stdout, "PKE_AT ENTERING\n");
{
- pke_at_settings.mem.bkt = pk_mem_bucket_create("pke-at main", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
- pke_at_settings.mem.bkt_transient = pk_mem_bucket_create("pke-at transient", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_TRANSIENT);
- pk_mem_bucket_set_client_mem_bucket(pke_at_settings.mem.bkt);
+ g_at.mem.bkt = pk_mem_bucket_create("pke-at main", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
+ g_at.mem.bkt_transient = pk_mem_bucket_create("pke-at transient", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_TRANSIENT);
+ pk_mem_bucket_set_client_mem_bucket(g_at.mem.bkt);
pk_arr_append_t(&LoadedPkePlugins, pke_at_plugin);
}
PkeArgs_Parse(argc, argv);
Game_Main({}, argv[0]);
- pk_mem_bucket_destroy(pke_at_settings.mem.bkt_transient);
- pk_mem_bucket_destroy(pke_at_settings.mem.bkt);
+ pk_mem_bucket_destroy(g_at.mem.bkt_transient);
+ pk_mem_bucket_destroy(g_at.mem.bkt);
fprintf(stdout, "PKE_AT EXITING\n");
return 0;
}
diff --git a/src/pke-at-common.cpp b/src/pke-at-common.cpp
new file mode 100644
index 0000000..a2a290f
--- /dev/null
+++ b/src/pke-at-common.cpp
@@ -0,0 +1,55 @@
+
+#include "pke-at-common.hpp"
+
+#include "pke-at-settings.hpp"
+
+#include "pke/audio-types.hpp"
+
+void pke_at_bpm_reset(uint8_t bpm) {
+ g_at.bpm.last = bpm;
+ g_at.bpm.target = bpm;
+ g_at.bpm.current = bpm;
+ g_at.bpm.lerp_delta = 0.f;
+ g_at.bpm.lerp_delta_duration = 0.f;
+ g_at.bpm.delta_per_beat = 60.f / (double)bpm;
+ g_at.bpm.delta_since_last_beat = 0.f;
+ g_at.mtrnm.beat = 0;
+ g_at.mtrnm.beats_per_bar = 4;
+}
+
+AssetHandle pke_at_audio_get_or_generate_sawtooth(double pitch_freq, double duration) {
+ uint32_t u;
+ uint32_t len;
+ float *bytes;
+ float phase;
+ float phase_increment;
+ pke_asset_details details{};
+ AssetHandle handle;
+ AssetKey key;
+
+ snprintf(key, AssetKeyLength, "saw%.5u;%.2f", (uint32_t)pitch_freq, duration);
+ fprintf(stdout, "sawtooth: %s%c\n", key, '\0');
+
+ handle = AM_GetHandle(key);
+ if (handle != AssetHandle_MAX) {
+ return handle;
+ }
+
+ len = std::ceil(PKE_AUDIO_BITRATE * duration);
+ bytes = pk_new_arr<float>(len, g_at.mem.bkt_transient);
+ if (bytes == nullptr) {
+ throw "[pke_at_audio_get_or_generate_sawtooth] failed to alloc";
+ }
+ phase = 0.0f;
+ phase_increment = pitch_freq / float(PKE_AUDIO_BITRATE);
+ for (u = 0; u < len; ++u) {
+ bytes[u] = 2.f * (phase - floor(phase + 0.5f));
+ phase += phase_increment;
+ if (phase >= 1.f) phase -= 1.f;
+ }
+
+ // TODO
+ // details.audio.
+ handle = AM_Register(key, PKE_ASSET_TYPE_AUDIO, bytes, len, 64, &details);
+ return handle;
+}
diff --git a/src/pke-at-common.hpp b/src/pke-at-common.hpp
new file mode 100644
index 0000000..a7b9a69
--- /dev/null
+++ b/src/pke-at-common.hpp
@@ -0,0 +1,12 @@
+#ifndef PKE_AT_PKE_AT_COMMON_HPP
+#define PKE_AT_PKE_AT_COMMON_HPP
+
+#include "pke/asset-manager.hpp"
+
+#include <cstdint>
+
+void pke_at_bpm_reset(uint8_t bpm);
+
+AssetHandle pke_at_audio_get_or_generate_sawtooth(double pitch_freq, double duration);
+
+#endif /* PKE_AT_PKE_AT_COMMON_HPP */
diff --git a/src/pke-at-settings.cpp b/src/pke-at-settings.cpp
index 3f5c6c0..0f25589 100644
--- a/src/pke-at-settings.cpp
+++ b/src/pke-at-settings.cpp
@@ -1,4 +1,4 @@
#include "pke-at-settings.hpp"
-struct pke_at_global_settings pke_at_settings{};
+struct pke_at_global_settings g_at{};
diff --git a/src/pke-at-settings.hpp b/src/pke-at-settings.hpp
index 1eca096..7d89e51 100644
--- a/src/pke-at-settings.hpp
+++ b/src/pke-at-settings.hpp
@@ -1,6 +1,7 @@
#ifndef PKE_AT_PKE_AT_SETTINGS_HPP
#define PKE_AT_PKE_AT_SETTINGS_HPP
+#include "pke/asset-manager.hpp"
#include "pke/pk.h"
struct pke_at_global_settings {
@@ -8,8 +9,25 @@ struct pke_at_global_settings {
pk_membucket *bkt;
pk_membucket *bkt_transient;
} mem;
+ struct pke_at_global_settings_bpm {
+ float last;
+ float target;
+ float current;
+ double lerp_delta;
+ double lerp_delta_duration;
+ double delta_per_beat;
+ double delta_since_last_beat;
+ } bpm;
+ struct pke_at_global_settings_metronome {
+ uint8_t beat;
+ uint8_t beats_per_bar;
+ AssetHandle beep;
+ AssetHandle beep_accent;
+ } mtrnm;
+ struct pke_at_global_settings_rt {
+ } rt;
};
-extern struct pke_at_global_settings pke_at_settings;
+extern struct pke_at_global_settings g_at;
#endif /* PKE_AT_PKE_AT_SETTINGS_HPP */
diff --git a/src/pke-at.cpp b/src/pke-at.cpp
index f256a10..f4c7462 100644
--- a/src/pke-at.cpp
+++ b/src/pke-at.cpp
@@ -2,7 +2,6 @@
#include <pke/pke.hpp>
#include "pke-at.hpp"
-#include "pke/level.hpp"
#include "level-main.hpp"
struct pke_at_master {
@@ -19,7 +18,4 @@ void pke_at_init() {
}
void pke_at_teardown() {
- if (pkeSettings.rt.activeLevel != nullptr) {
- pke_level_teardown(pkeSettings.rt.activeLevel);
- }
}