https://github.com/GothicKit/dmusic Skip to content Navigation Menu Toggle navigation Sign in * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + GitHub Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code Explore + All features + Documentation + GitHub Skills + Blog * Solutions For + Enterprise + Teams + Startups + Education By Solution + CI/CD & Automation + DevOps + DevSecOps Resources + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Enterprise + Enterprise platform AI-powered developer platform Available add-ons + Advanced Security Enterprise-grade security features + GitHub Copilot Enterprise-grade AI features + Premium Support Enterprise-grade 24/7 support * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} GothicKit / dmusic Public * Notifications You must be signed in to change notification settings * Fork 0 * Star 28 * An incomplete re-implementation of DirectMusic, Microsoft's adaptive soundtrack API for games delivered as part of Direct3D and DirectX dm.gothickit.dev/ License View license 28 stars 0 forks Branches Tags Activity Star Notifications You must be signed in to change notification settings * Code * Issues 0 * Pull requests 0 * Actions * Projects 1 * Security * Insights Additional navigation options * Code * Issues * Pull requests * Actions * Projects * Security * Insights GothicKit/dmusic This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. main BranchesTags Go to file Code Folders and files Name Name Last commit Last commit message date Latest commit History 131 Commits .github/workflows .github/ workflows docs docs examples examples include include src src support support vendor vendor .clang-format .clang-format .clang-tidy .clang-tidy .gitignore .gitignore CMakeLists.txt CMakeLists.txt LICENSE.md LICENSE.md README.md README.md View all files Repository files navigation * README * License DirectMusic -- A re-implementation. This project aims to re-implement Microsoft's long-deprecated DirectMusic API available in early Direct3D and DirectX versions. It is currently under heavy development at this time and might be unstable for some use-cases. Soundtracks tested and verified to work (somewhat) correctly: * Gothic * Gothic II (+ Night of the Raven) Gothic II's "Khorinis Day Standard" theme rendered using this library: KH_DayStd.mp4 Download the MP3 here. If you tested other games, please let me know. If you own any games with .dls, .sty and .sgt files in the data folders, and you want to contribute, please contact me as well or open an issue. Important A C# wrapper package is also available at GothicKit/dmusic-cs. Building To build this project, you will need a C11-capable C compiler (like gcc or clang) and CMake 3.10 or newer. Linux, macOS and Windows are supported, but I can only assist with compilation error in a limited fashion on platforms other than Linux. On Linux, you can build the project like this (macOS and Windows might work differently): cmake -B build -DDM_ENABLE_ASAN=OFF -DDM_BUILD_EXAMPLES=ON cmake --build build (set -DDM_BUILD_EXAMPLES=OFF, if the example fails to compile) You will find the library and executable files in the build and build /examples directories. Note that the example only works on systems providing the and headers. Example Here's how you play back a segment. This example works on POSIX only since it uses for the file resolver. On Windows, you simply need to replace dm_resolve_file with a Windows-compatible implementation. #include #include #include #include #include #include static void* dm_resolve_file(void* ctx, char const* name, size_t* len); int main(int argc, char** argv) { Dm_setLoggerDefault(DmLogLevel_INFO); // 1. Create a new DmLoader. The loader is responsible for loading and caching DirectMusic files using a // user-defined callback function called a "resolver". You really only ever need one for your application. DmLoader* loader = NULL; DmResult rv = DmLoader_create(&loader, DmLoader_DEFAULT | DmLoader_DOWNLOAD); if (rv != DmResult_SUCCESS) { puts("Creating the loader failed\n"); return rv; } // 2. Register a resolver with the loader. A resolver is simply a function which gets a context pointer, // a filename and returns a memory buffer and its length as an output parameter. The context pointer // is user-defined, here it's just a path string. You can return NULL from a resolver to indicate that // the file was not found. rv = DmLoader_addResolver(loader, dm_resolve_file, "/path/to/your/music/folder"); if (rv != DmResult_SUCCESS) { puts("Adding the resolver failed\n"); return rv; } // 3. Use the loader to obtain a segment. The loader will call your resolvers in order to read in the // file, and it will then perform some internal magic to load the segment. Since we set the // DmLoader_DOWNLOAD option when constructing the loader, we don't need to call DmSegment_download // afterward. Otherwise, you do have to call it. DmSegment* segment = NULL; rv = DmLoader_getSegment(loader, "YourSegment.sgt", &segment); if (rv != DmResult_SUCCESS) { puts("Getting the segment failed\n"); return rv; } // 4. Create a new performance. The performance represents your main playback device. It handles all // the DirectMusic magic needed to produce music from your segments. You typically only need one // performance for your application. The second parameter here is the sample rate, defaulted to // 44100 Hz. DmPerformance* performance = NULL; rv = DmPerformance_create(&performance, 44100); if (rv != DmResult_SUCCESS) { puts("Creating the performance failed\n"); return rv; } // 5. Instruct the performance to play a segment. This will set up the performance's internals so that // the following call to DmPerformance_renderPcm will start producing music. The performance renders // music on-demand, so as long as you don't call DmPerformance_renderPcm, you can consider playback to // be paused. To stop playing music, you can pass NULL as the segment parameter. // // The third parameter here is the timing. It tells the performance at which boundary to start playing // the new segment as to not interrupt the flow of music. The options are "instant", which ignores all // that and immediately plays the segment, "grid" which plays the segment at the next possible beat // subdivision, "beat" which plays the segment at the next beat and "measure" which plays it at the next // measure boundary. // // The performance also supports transitions. To play those, use DmPerformance_playTransition and see // its inline documentation for more information. rv = DmPerformance_playSegment(performance, segment, DmTiming_MEASURE); if (rv != DmResult_SUCCESS) { puts("Playing the segment failed\n"); return rv; } size_t len = 1000000; float* pcm = malloc(sizeof *pcm * len); // 6. Finally, render some PCM! This will instruct the performance to start processing the underlying // DirectMusic messages and render the resulting PCM to the output buffer. In this case it will // render 1000000 stereo samples which is 500000 samples per channel. // // This will advance the internal clock for as many ticks as required to render the requested number // of samples. No more, no less. rv = DmPerformance_renderPcm(performance, pcm, len, DmRender_FLOAT | DmRender_STEREO); if (rv != DmResult_SUCCESS) { puts("Playing the PCM failed\n"); return rv; } // 6.1. Write out the PCM data to some place where we can access it later. This could also just be some // audio output device or another library. FILE* fp = fopen("output.pcm", "w"); if (fp == NULL) { puts("Opening the output file failed\n"); return -1; } (void) fwrite(pcm, sizeof *pcm, len, fp); (void) fclose(fp); // 7. Don't forget to clean up after yourself. free(pcm); DmSegment_release(segment); DmPerformance_release(performance); DmLoader_release(loader); return 0; } static void* dm_resolve_file(void* ctx, char const* name, size_t* len) { char const* root = ctx; // 1. Concat `root` and `name` to produce the final path. If a slash is missing // at the end of `root`, add it. size_t root_len = strlen(root); size_t name_len = strlen(name); int miss_sep = root[root_len - 1] != '/'; char* path = malloc(root_len + name_len + 1 + miss_sep); memcpy(path, root, root_len); memcpy(path + root_len + miss_sep, name, name_len); if (miss_sep) { path[root_len] = '/'; } path[root_len + name_len + miss_sep] = '\0'; // 2. Check if the file we want to open actually exists. If it doesn't, return NULL. struct stat st; if (stat(path, &st) != 0) { free(path); return NULL; } // 3. Read in data from the file. FILE* fp = fopen(path, "re"); if (fp == NULL) { free(path); return NULL; } void* bytes = malloc((size_t) st.st_size); *len = fread(bytes, 1, (size_t) st.st_size, fp); (void) fclose(fp); free(path); return bytes; } More examples can be found in the examples/ folder. Contact If you have any questions, or you just want to say hi, you can reach me via e-mail (me@lmichaelis.de) or on Discord either via DM but preferably in the Gothic VR and GMC Discords (@lmichaelis). About An incomplete re-implementation of DirectMusic, Microsoft's adaptive soundtrack API for games delivered as part of Direct3D and DirectX dm.gothickit.dev/ Topics directx reimplementation direct3d gothic gothic2 directx8 directmusic Resources Readme License View license Activity Custom properties Stars 28 stars Watchers 1 watching Forks 0 forks Report repository Releases No releases published Packages 0 No packages published Languages * C 97.8% * CMake 2.2% Footer (c) 2024 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact * Manage cookies * Do not share my personal information You can't perform that action at this time.