diff --git a/README.md b/README.md index a65f21d..2aab230 100644 --- a/README.md +++ b/README.md @@ -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. -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 diff --git a/autosample.raddbg b/autosample.raddbg index e6a5398..4d33de9 100644 --- a/autosample.raddbg +++ b/autosample.raddbg @@ -1,7 +1,7 @@ // raddbg 0.9.24 project file -recent_file: path: "src/theme.cpp" recent_file: path: "src/main.cpp" +recent_file: path: "src/theme.cpp" recent_file: path: "nob.obj" recent_file: path: "vendor/imgui/imgui.h" recent_file: path: "src/platform/platform.h" @@ -14,7 +14,7 @@ target: debug_info: { path: "C:/Users/mta/projects/autosample/build/autosample.pdb" - timestamp: 66207523114644 + timestamp: 66207529127862 } target: { @@ -22,8 +22,3 @@ target: working_directory: "build/" enabled: 1 } -breakpoint: -{ - source_location: "src/theme.cpp:4:1" - hit_count: 1 -} diff --git a/nob.c b/nob.c index 4dd905a..6e316dd 100644 --- a/nob.c +++ b/nob.c @@ -31,6 +31,7 @@ static const char *link_libs[] = { "shell32.lib", "ole32.lib", "dwmapi.lib", + "winmm.lib", }; static const char *obj_name(const char *src_path) { diff --git a/src/main.cpp b/src/main.cpp index 62f2514..2c79c34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ // [h] #include "platform/platform.h" #include "renderer/renderer.h" +#include "midi/midi.h" #include "imgui.h" #include "imgui_internal.h" #include @@ -10,6 +11,7 @@ // [cpp] #include "platform/platform_win32.cpp" #include "renderer/renderer_dx12.cpp" +#include "midi/midi_win32.cpp" #include "menus.cpp" #include "theme.cpp" @@ -26,8 +28,9 @@ static void build_default_layout(ImGuiID dockspace_id) { ImGui::DockBuilderDockWindow("Browser", left); ImGui::DockBuilderDockWindow("Main", center); - ImGui::DockBuilderDockWindow("Properties", right); - ImGui::DockBuilderDockWindow("Log", bottom); + ImGui::DockBuilderDockWindow("Properties", right); + ImGui::DockBuilderDockWindow("MIDI Devices", right); + ImGui::DockBuilderDockWindow("Log", bottom); ImGui::DockBuilderFinish(dockspace_id); } @@ -57,15 +60,18 @@ int main(int argc, char **argv) { return 1; } + MidiEngine *midi = midi_create(); + setup_theme(); setup_menus(window); int32_t last_w = w, last_h = h; - bool show_demo = true; - bool show_browser = true; - bool show_props = true; - bool show_log = true; - bool first_frame = true; + bool show_demo = true; + bool show_browser = true; + bool show_props = true; + bool show_log = true; + bool show_midi_devices = true; + bool first_frame = true; while (platform_poll_events(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_PROPERTIES:show_props = !show_props; 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; } platform_get_size(window, &w, &h); @@ -117,6 +124,21 @@ int main(int argc, char **argv) { 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 if (show_log) { ImGui::Begin("Log", &show_log); @@ -132,6 +154,7 @@ int main(int argc, char **argv) { renderer_end_frame(renderer); } + midi_destroy(midi); renderer_destroy(renderer); platform_destroy_window(window); return 0; diff --git a/src/menus.cpp b/src/menus.cpp index 0185bf4..b59f272 100644 --- a/src/menus.cpp +++ b/src/menus.cpp @@ -13,6 +13,7 @@ enum MenuCmd { MENU_VIEW_PROPERTIES, MENU_VIEW_LOG, MENU_VIEW_DEMO, + MENU_VIEW_MIDI_DEVICES, }; static void setup_menus(PlatformWindow *window) { @@ -35,7 +36,8 @@ static void setup_menus(PlatformWindow *window) { { "Properties", MENU_VIEW_PROPERTIES }, { "Log", MENU_VIEW_LOG }, { nullptr, 0 }, - { "Demo", MENU_VIEW_DEMO }, + { "Demo", MENU_VIEW_DEMO }, + { "MIDI Devices", MENU_VIEW_MIDI_DEVICES }, }; PlatformMenu menus[] = { diff --git a/src/midi/midi.h b/src/midi/midi.h new file mode 100644 index 0000000..68af76b --- /dev/null +++ b/src/midi/midi.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +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); diff --git a/src/midi/midi_win32.cpp b/src/midi/midi_win32.cpp new file mode 100644 index 0000000..7c8db22 --- /dev/null +++ b/src/midi/midi_win32.cpp @@ -0,0 +1,58 @@ +#include "midi/midi.h" +#include +#include +#include + +#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]; +}