Begin midi engine

This commit is contained in:
2026-02-25 12:16:31 -05:00
parent 789e2b678b
commit 6656b6d0b2
7 changed files with 118 additions and 18 deletions

View File

@@ -40,9 +40,12 @@ The platform and renderer layers are C-style APIs with opaque handles. `platform
This project is written in C-style C++. We use `.cpp` files and a small subset of C++ features (default struct values, function overloading, namespaces where useful) but avoid the rest. No classes, no inheritance, limit templates, no exceptions, no RAII, avoid STL containers or algorithms. Data is plain structs. Functions operate on those structs, or pointers to them. This project is written in C-style C++. We use `.cpp` files and a small subset of C++ features (default struct values, function overloading, namespaces where useful) but avoid the rest. No classes, no inheritance, limit templates, no exceptions, no RAII, avoid STL containers or algorithms. Data is plain structs. Functions operate on those structs, or pointers to them.
Opening braces go on the same line as the function signature (K&R style), not on the next line. Memory should be managed with arena allocators where possible rather than individual `malloc`/`free` or `new`/`delete` calls. Arenas make allocation fast, avoid fragmentation, and simplify cleanup.
Memory is managed with arena allocators where possible rather than individual `malloc`/`free` or `new`/`delete` calls. Arenas make allocation fast, avoid fragmentation, and simplify cleanup. ### Syntax Style
- Opening braces go on the same line as the function signature (K&R style), not on the next line.
- use CAPS_SNAKE_CASE for constants, lower_snake_case for functions and variables, and CapsCamelCase for types.
## Dependencies ## Dependencies

View File

@@ -1,7 +1,7 @@
// raddbg 0.9.24 project file // raddbg 0.9.24 project file
recent_file: path: "src/theme.cpp"
recent_file: path: "src/main.cpp" recent_file: path: "src/main.cpp"
recent_file: path: "src/theme.cpp"
recent_file: path: "nob.obj" recent_file: path: "nob.obj"
recent_file: path: "vendor/imgui/imgui.h" recent_file: path: "vendor/imgui/imgui.h"
recent_file: path: "src/platform/platform.h" recent_file: path: "src/platform/platform.h"
@@ -14,7 +14,7 @@ target:
debug_info: debug_info:
{ {
path: "C:/Users/mta/projects/autosample/build/autosample.pdb" path: "C:/Users/mta/projects/autosample/build/autosample.pdb"
timestamp: 66207523114644 timestamp: 66207529127862
} }
target: target:
{ {
@@ -22,8 +22,3 @@ target:
working_directory: "build/" working_directory: "build/"
enabled: 1 enabled: 1
} }
breakpoint:
{
source_location: "src/theme.cpp:4:1"
hit_count: 1
}

1
nob.c
View File

@@ -31,6 +31,7 @@ static const char *link_libs[] = {
"shell32.lib", "shell32.lib",
"ole32.lib", "ole32.lib",
"dwmapi.lib", "dwmapi.lib",
"winmm.lib",
}; };
static const char *obj_name(const char *src_path) { static const char *obj_name(const char *src_path) {

View File

@@ -3,6 +3,7 @@
// [h] // [h]
#include "platform/platform.h" #include "platform/platform.h"
#include "renderer/renderer.h" #include "renderer/renderer.h"
#include "midi/midi.h"
#include "imgui.h" #include "imgui.h"
#include "imgui_internal.h" #include "imgui_internal.h"
#include <iostream> #include <iostream>
@@ -10,6 +11,7 @@
// [cpp] // [cpp]
#include "platform/platform_win32.cpp" #include "platform/platform_win32.cpp"
#include "renderer/renderer_dx12.cpp" #include "renderer/renderer_dx12.cpp"
#include "midi/midi_win32.cpp"
#include "menus.cpp" #include "menus.cpp"
#include "theme.cpp" #include "theme.cpp"
@@ -26,8 +28,9 @@ static void build_default_layout(ImGuiID dockspace_id) {
ImGui::DockBuilderDockWindow("Browser", left); ImGui::DockBuilderDockWindow("Browser", left);
ImGui::DockBuilderDockWindow("Main", center); ImGui::DockBuilderDockWindow("Main", center);
ImGui::DockBuilderDockWindow("Properties", right); ImGui::DockBuilderDockWindow("Properties", right);
ImGui::DockBuilderDockWindow("Log", bottom); ImGui::DockBuilderDockWindow("MIDI Devices", right);
ImGui::DockBuilderDockWindow("Log", bottom);
ImGui::DockBuilderFinish(dockspace_id); ImGui::DockBuilderFinish(dockspace_id);
} }
@@ -57,15 +60,18 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
MidiEngine *midi = midi_create();
setup_theme(); setup_theme();
setup_menus(window); setup_menus(window);
int32_t last_w = w, last_h = h; int32_t last_w = w, last_h = h;
bool show_demo = true; bool show_demo = true;
bool show_browser = true; bool show_browser = true;
bool show_props = true; bool show_props = true;
bool show_log = true; bool show_log = true;
bool first_frame = true; bool show_midi_devices = true;
bool first_frame = true;
while (platform_poll_events(window)) { while (platform_poll_events(window)) {
int32_t menu_cmd = platform_poll_menu_command(window); int32_t menu_cmd = platform_poll_menu_command(window);
@@ -74,7 +80,8 @@ int main(int argc, char **argv) {
case MENU_VIEW_BROWSER: show_browser = !show_browser; break; case MENU_VIEW_BROWSER: show_browser = !show_browser; break;
case MENU_VIEW_PROPERTIES:show_props = !show_props; break; case MENU_VIEW_PROPERTIES:show_props = !show_props; break;
case MENU_VIEW_LOG: show_log = !show_log; break; case MENU_VIEW_LOG: show_log = !show_log; break;
case MENU_VIEW_DEMO: show_demo = !show_demo; break; case MENU_VIEW_DEMO: show_demo = !show_demo; break;
case MENU_VIEW_MIDI_DEVICES: show_midi_devices = !show_midi_devices; break;
default: break; default: break;
} }
platform_get_size(window, &w, &h); platform_get_size(window, &w, &h);
@@ -117,6 +124,21 @@ int main(int argc, char **argv) {
ImGui::End(); ImGui::End();
} }
// MIDI Devices panel
if (show_midi_devices) {
ImGui::Begin("MIDI Devices", &show_midi_devices);
if (ImGui::Button("Refresh"))
midi_refresh_devices(midi);
ImGui::Separator();
for (int32_t i = 0; i < midi_get_device_count(midi); i++) {
MidiDeviceInfo *dev = midi_get_device(midi, i);
ImGui::Text("[%s] %s", dev->is_input ? "IN" : "OUT", dev->name);
}
if (midi_get_device_count(midi) == 0)
ImGui::TextDisabled("No MIDI devices found");
ImGui::End();
}
// Bottom panel // Bottom panel
if (show_log) { if (show_log) {
ImGui::Begin("Log", &show_log); ImGui::Begin("Log", &show_log);
@@ -132,6 +154,7 @@ int main(int argc, char **argv) {
renderer_end_frame(renderer); renderer_end_frame(renderer);
} }
midi_destroy(midi);
renderer_destroy(renderer); renderer_destroy(renderer);
platform_destroy_window(window); platform_destroy_window(window);
return 0; return 0;

View File

@@ -13,6 +13,7 @@ enum MenuCmd {
MENU_VIEW_PROPERTIES, MENU_VIEW_PROPERTIES,
MENU_VIEW_LOG, MENU_VIEW_LOG,
MENU_VIEW_DEMO, MENU_VIEW_DEMO,
MENU_VIEW_MIDI_DEVICES,
}; };
static void setup_menus(PlatformWindow *window) { static void setup_menus(PlatformWindow *window) {
@@ -35,7 +36,8 @@ static void setup_menus(PlatformWindow *window) {
{ "Properties", MENU_VIEW_PROPERTIES }, { "Properties", MENU_VIEW_PROPERTIES },
{ "Log", MENU_VIEW_LOG }, { "Log", MENU_VIEW_LOG },
{ nullptr, 0 }, { nullptr, 0 },
{ "Demo", MENU_VIEW_DEMO }, { "Demo", MENU_VIEW_DEMO },
{ "MIDI Devices", MENU_VIEW_MIDI_DEVICES },
}; };
PlatformMenu menus[] = { PlatformMenu menus[] = {

18
src/midi/midi.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
struct MidiEngine;
struct MidiDeviceInfo {
char name[64];
int32_t id;
bool is_input;
};
MidiEngine *midi_create();
void midi_destroy(MidiEngine *engine);
void midi_refresh_devices(MidiEngine *engine);
int32_t midi_get_device_count(MidiEngine *engine);
MidiDeviceInfo *midi_get_device(MidiEngine *engine, int32_t index);

58
src/midi/midi_win32.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "midi/midi.h"
#include <windows.h>
#include <mmeapi.h>
#include <string.h>
#define MIDI_MAX_DEVICES 64
struct MidiEngine {
MidiDeviceInfo devices[MIDI_MAX_DEVICES];
int32_t device_count;
};
MidiEngine *midi_create() {
MidiEngine *engine = new MidiEngine();
engine->device_count = 0;
midi_refresh_devices(engine);
return engine;
}
void midi_destroy(MidiEngine *engine) {
delete engine;
}
void midi_refresh_devices(MidiEngine *engine) {
engine->device_count = 0;
UINT num_in = midiInGetNumDevs();
for (UINT i = 0; i < num_in && engine->device_count < MIDI_MAX_DEVICES; i++) {
MIDIINCAPSA caps = {};
if (midiInGetDevCapsA(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
MidiDeviceInfo *dev = &engine->devices[engine->device_count++];
strncpy_s(dev->name, sizeof(dev->name), caps.szPname, _TRUNCATE);
dev->id = (int32_t)i;
dev->is_input = true;
}
}
UINT num_out = midiOutGetNumDevs();
for (UINT i = 0; i < num_out && engine->device_count < MIDI_MAX_DEVICES; i++) {
MIDIOUTCAPSA caps = {};
if (midiOutGetDevCapsA(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
MidiDeviceInfo *dev = &engine->devices[engine->device_count++];
strncpy_s(dev->name, sizeof(dev->name), caps.szPname, _TRUNCATE);
dev->id = (int32_t)i;
dev->is_input = false;
}
}
}
int32_t midi_get_device_count(MidiEngine *engine) {
return engine->device_count;
}
MidiDeviceInfo *midi_get_device(MidiEngine *engine, int32_t index) {
if (index < 0 || index >= engine->device_count)
return nullptr;
return &engine->devices[index];
}