Tuesday, October 6, 2026
My journey with agentic coding
All of this is to say that I program as a hobby, and some may consider my methodology more involved when compared to most other hobbyist programmers.
A modern trend that I have noticed take off in the past year or so is using large language models to generate code. I have noticed that many of the resulting projects range from barely useful, to technically impressive software that I thought was practically impossible to develop in a short amount of time, and everything in between. Starting in early august of 2026, I decided to take a crack at this software development trend, as I wanted to see if my experience with developing low-level software would make a difference in the resulting projects. I spent a month developing a Win32 application with the assistance of AI, and I have mixed opinions on how my previous experience with software development impacted the final project. This document serves as a reflection on the development process, as well as developer documentation for the project itself.
To elaborate on the latter point, I have observed that most documentation that is generated by large language models is outright useless. It usually says a lot and nothing at all at the same time, and it tends to get things wrong, even when it is about the code that it had previously generated. In my opinion, the journey of the development process written by the person who prompted the software into existence is far more valuable than any document that describes the software alone.
A couple years ago, I decided to make a fork of the Timidity MIDI player. The original objective was to have a lightweight software synthesizer library that could easily be integrated into other applications, and as far as I know this has never been done with the Timidity engine. I started with the GSPlayer MIDI plugin, as the code was fairly minimal and thus would be easy to work with. GSPlayer is an open source media player primarily targeting Windows CE, and its MIDI plugin used a lightly modified version of Timidity 0.2i.
The first obstacle I faced was the structure of the code itself. Timidity was originally a command-line application written in the late 90s, and it used global variables everywhere. The GSPlayer adaptation already removed most of the code that formed the basis for the user interface of the original program, so that part was already taken care of in the early 2000s. I moved all global variables into a state structure, which is effectively an instance handle that applications use to communicate with the library. In other words, multiple instances of the synthesizer can safely exist in a single process.
The audio output mechanism of the original program was not really flexible either, as it implemented audio output callbacks which would communicate with audio hardware or write to audio files. The GSPlayer version of the code somewhat held onto this concept, as it implemented an audio output callback that would write to a Win32 wave header structure who's pointer was stored in a global variable that was set in the plugin code. The library that I developed doesn't implement this mechanism for outputting audio, as the caller provides a buffer that the library fills as fast as it can. In other words, the library doesn't care what happens to the generated PCM, as it can be streamed to an audio device, written to a file, or processed in any other imaginable way. several common PCM formats are supported by the library, including 8 through 32-bit integer, 32 and 64-bit floating point, and 8-bit uLaw.
Internally, Timidity mixes audio into a 32-bit fixed point accumulator, which uses a particular number of bits as a guard to prevent overflows. The 8 through 24-bit fixed point output functions simply shift the samples to the right and clamp them appropriately. The 32-bit fixed point output function first clamps the samples, then shifts them to the left so that the audio output level matches the other rendering functions.
The floating point rendering functions are especially interesting, as they do nothing more than scale the samples down appropriately. This is significant because floating point PCM can represent audio above 0 dBFS, so this allows the guard bits to be used as extra headroom, where each additional bit represents approximately 6 dB. It is worth noting that as the samples are internally 32-bit integers, the dynamic range of the floating point output functions has a hard sealing. This isn't much of a problem in practice, however the audio will inevitably clip if the amplification setting in the synthesizer is significantly increased, or a rather large number of notes are playing simultaneously. I find it fascinating that this decades old code produces data that takes advantage of a more modern PCM format when properly scaled, and I imagine this was a use case that the original developers most likely never considered.
The uLaw output support is more or less a holdover from the original Timidity code that I decided to keep in. This rendering function works by reducing to 13 bits in the same way as the 8 through 24-bit fixed point rendering functions, and then using a lookup table for determining the final 8-bit values.
Despite all the audio output changes, the original synthesis logic was kept in tact. This has a nice side-effect of the code running reasonably well on relatively slow processors, and the output PCM is almost byte for byte identical when compared with the original program. A notable change that I made to the MIDI handling logic was implementing mono and poly channel mode messages. There was a flag in the channel structure for monophonic operation, and the code only allowed a single note to play on the appropriate channel if the flag was set. However, there weren't any code paths to enable or disable this flag, so I essentially finished work on a feature that was only partially implemented.
I also changed a few of the default synthesizer settings. I increased the maximum allowed number of simultaneous voices from 48 to 1024, and I decreased the default amplification from 70% to 50%. The reason I decreased the default amplification is because I noticed that the output clipped more frequently with the original default setting.
When I started work on this Timidity library, my priority was live MIDI input, which would allow applications to directly program the synthesizer. The MIDI file player logic from the original code was later merged into the library, so it could now act as either a low-level synthesizer or a high-level file player. I continued improving the library over time, and I eventually got it into a state that I was happy with. I have integrated the library into several projects, including a VST instrument, a user-mode Windows MIDI driver, and a DirectShow source filter. I have always envisioned a standalone player application based around the library, however I could never find the motivation to sit down and make this a reality. As this project was more or less a GUI layer around a solid library that was entirely written by hand, and it wouldn't be my primary MIDI player anyway, I felt it was a good candidate for experimenting with LLM assisted code generation.
Before going into the actual development process, I would like to talk about the operating system compatibility of this program, as well as my development environment. This application relies on Win32 API functions that were introduced in Windows 2000, so naturally that is the minimum supported Windows version. I did test the ANSI version of the application on Windows Millennium edition, and that went as well as I expected. Windows Me was notorious for being a rather unstable operating system back in the day, so I wasn't too surprised when the system randomly crashed after I attempted to add a folder of MIDI files to the player.
On my main machine, I have a MinGW compiler set up so that myself (or the AI agent) can quickly generate builds for testing purposes. The production builds are generated by copying the code to a Windows XP virtual machine, and running a script located in the root directory of the repository. The virtual machine has Visual studio 2005 and the Windows Server 2003 Platform SDK installed, and the build script compiles the code for the X86, X64, and IA64 processor architectures. Before anyone asks, I don't have any Itanium hardware, and the main reason I bother building for IA64 at all is simply because the builds are trivial to produce. The other reason for the IA64 builds is because I have a weird sense of humor, and one of these days I hope to get my hands on an Itanium system and test some of my projects on it. I know that the performance of Itanium was abysmal, however I tend to enjoy experimenting with obscure hardware and software.
I had already written a command-line program that could convert MIDI files to WAV using the Timidity library, so I started by prompting the coding agent to create a batch converter with a standard Win32 GUI. As the MIDI to WAV converter that I had previously written was part of the Timidity Windows driver project, I set up the coding agent to work in a local copy of that repository so it would learn from what I had already created and reuse existing code when appropriate. When the first build arrived, I was honestly impressed. The agent had created a dialog-based Win32 application that could allow me to add up to 512 MIDI files, and convert them using the WAV file writer code that I had already written for the CLI converter.
Something that the agent did without me explicitly prompting it was that it wrote the code so that a dedicated thread was created for the actual conversion process. This batch converter was far from finished, so I prompted in some new functionality. This included a button for setting the default output directory, as well as generating statistics about the converted files. When I prompted the statistics feature into existence, I told the agent to reference the code for the CLI converter for reference. After that was done, I told the agent to make this program into a standalone player, while making the batch converter accessible through an option in the main user interface. For the code that managed the audio device, I told the agent to reference the MIDI driver code, as it implemented an audio player based on the waveOut API. It was at this point where I started brainstorming features and prompting them as I thought of them, and this is when things started to get a little frustrating.
Before continuing, I would like to discuss a notable characteristic of AI coding agents that I feel is important to keep in mind. While the generated code might work when given common test cases, it usually falls apart when given edge cases, unless the agent is explicitly prompted to write the code to take particular things into account. This is how I initially ended up with obscure bugs, such as the player not loading the next file in the cue if the currently playing file was removed from the playlist. Another notable bug that I ran into was that if a message box automatically appeared when a modal dialog was opened, the window would get into a disabled state, and I would have to restart the application. You could argue that I signed up for this behavior as I was working directly with the Win32 API, which most modern apps don't do anymore.
The features that I got implemented in the initial brainstorm session included seeking, a sleep timer, a jump to time dialog, playlist support, a recent files menu, system tray mode, and media key handling. Some of these features worked the way I wanted on the first implementation, and others took several prompts until I was happy with them. The initial implementation of the media key support only functioned when the app was in focus, and I eventually implemented global hotkeys for play/pause, stop, next track, and previous track. I also implemented global hotkeys for volume up/down, however I eventually put these behind a setting called intercept volume media keys (disabled by default), as these keys are usually expected to adjust the entire system volume. I don't actually blame that initial flaw on the AI agent, as that is an implementation detail that I may have overlooked even if I was coding this app by hand.
As a quick historical note, the earliest revision of the Windows header files that appear to include the media key declarations are from late 1999, which is around the time Windows 2000 was released. Several keyboards from the late 90s and early 2000s included dedicated media buttons, and many modern keyboards have methods of invoking the media functions as well.
After hours of prompting and testing, I had a single C source file that was 113 KB in size, and I went to sleep for several more hours. The next time I started working on the project, I prompted the agent to strip all comments from the file. Like documentation, I found that LLM generated code comments got in the way, and were extremely verbose. I also prompted the agent to split the code into multiple translation units, as I wanted to make the code easier to maintain by hand when needed. Additionally, I prompted the agent to move all global app state into a single data structure, as I am not fond of many global variables scattered throughout the code. After that was done, I did my first manual code review, which took some time. Whenever I made manual fixes, I prompted the agent to look them over, and most of the fixes came back clean.
Over the next few weeks, I prompted more functionality into the program, got bugs fixed as I found them, and added support for several more C/C++ compilers that I have on my computer. For the record, the supported compilers include various versions of the Microsoft C/C++ compiler, Borland C++ 5.5, Digital Mars C++, MinGW, Open Watcom, and the Tiny C Compiler (TCC). Adding the Digital Mars build support took a bit more effort than the other compilers, as I had to have the agent create a compatibility shim for functionality that wasn't declared in the supplied Win32 API headers and libraries.
The new functionality that was added includes live MIDI playback, a channel mixer, a virtual keyboard, and a feature that allows the user to inject raw MIDI events directly into the synthesizer. I had the agent put the code for these features into new source files to keep manual maintainability practical.
Another feature that I added early on allows the user to quickly convert the currently loaded MIDI file to WAV, and this is where the multi instance capability of the Timidity library really becomes useful. Like the batch converter,the quick conversion process runs on its own thread, so MIDI files can play while a conversion is running in the background. While a quick conversion is in progress, the status bar is updated with the percentage of the conversion, and information relevant to the state of the realtime playback is omitted.
The batch converter gained more functionality, including the abilities to output audio files in various PCM formats and save the conversion statistics to a CSV file. An option to preserve the folder structure of the input paths when generating the output paths was added as well. Options for customizing the main window of the application were also added, including toggles for showing or hiding the status bar, seek bar, and playlist view. An always on top toggle was added to the system menu, because I wanted the program to feel like a real application that could have been around in the late 90s.
A more sophisticated playlist manager was also implemented, as well as an option to shuffle the playlist. Besides the ability to reorder and remove items, the playlist manager includes search functionality and the ability to play the selected track. Like some of the other features, the playlist manager took several prompts until I was happy with the result.
A statistics dialog that shows information about the currently loaded file was added as well, and most of the info shown in this dialog is queried straight from the library. A statistic that Is shown which isn't provided by the library is the CPU load, which is a percentage that shows how well the system is holding up when rendering audio in realtime. For example, if it takes 50 MS to render 50 MS of audio, this results in 100% CPU usage. This is obviously a worst case scenario, and real world usage on a modern processor can reach under 1% with the default synthesizer configuration, which really shows how efficient this decades old synthesis engine is. To really drive the efficiency point home, the default configuration performs realtime synthesis reasonably well on processors from the Pentium II era.
The status bar also shows some statistics, however I limited this representation to information that a user would more likely want to know right away. The status bar only shows the transport state and playback position, song title and copyright when applicable, the active number of voices, the audio output volume, and the CPU load. By default, the title bar shows the name of the currently loaded file alongside the name of the application, however this behavior can be disabled in the player settings dialog if it isn't desired.
The program gained the ability to take command-line arguments. The names of files, folders, and wildcards can be provided, and the /add switch can be appended after the name of the executable to add the files without discarding a playlist if one already exists in the programs memory. This command-line handling is quite elegant, as the files are passed to an existing instance if the program is already running. The /c switch can be appended right after the name of the executable to launch straight into the batch converter without bringing up the main interface, and there are additional switches to control how the batch converter is set up when initialized in this way.
A design decision that I made early on was that only one instance of the application is allowed to run at any given time. If the user simply launches the program without any command-line arguments while another instance is already running, the window is brought to the foreground if system tray mode is disabled. If additional arguments are passed and the program is already running, the user is asked if they want to load files into the existing instance. This dialog has an additional checkbox to suppress this prompt, and the actual setting is saved in the registry when yes or no is answered. This setting can also be changed in the player settings dialog.
Near the end of the development process, I fixed a bug in the sleep timer that I didn't catch early on. When the user paused or stopped playback, the timer would continue running. The revised logic gets the current time when the user pauses playback and stops the timer. The result of this fix is that the remainder of the time runs when the user resumes playback from a paused state. When the user fully stops playback while the timer is running, the timer is stopped as well. I also made it so that the sleep timer has no effect when the program is acting as a live MIDI synthesizer, as a sleep timer simply doesn't make any sense for that particular use case.
Another small bug that I fixed was that a pop could be heard when a MIDI file finished playing, and this only happened when the audio driver was configured to output 8-bit PCM. For a bit of background, I designed the function in my Timidity library that generates audio from a loaded MIDI file to return 0 once all events have been processed and all notes have fully stopped. The audio output code in the application was sending a buffer of silence to the audio device when this condition was met, which isn't a problem in itself. The problem was that 8-bit PCM is usually unsigned, while 16-bit PCM is usually signed. silence is represented by 0 in signed PCM, while in unsigned PCM, silence is represented by the middle value of the data type. in the case of an unsigned 8-bit integer, this value is 128.
A much more significant audio bug that I found manifested when the synthesizer was reconfigured to use a different sample rate, bit depth, or number of channels while playback was active. Changing the sample rate resulted in the audio playing back at the wrong speed, and the change in bit depth or number of channels resulted in distorted playback on top of that. Even worse, if the synthesizer attempted to write stereo data into a buffer that was allocated for mono data, the application would crash. The problem was that the audio device wasn't reopened when the synthesizer was configured to output in a different format, and this took several prompts to get properly fixed. This is yet another instance of the AI agent not having a true understanding of the system as a whole, and why manual testing really pays off in the end.
Another feature that I got the agent to implement was the ability to restore the settings to their defaults, as well as the ability to export and import settings files. When settings are restored or imported, the application's ability to write to the registry is limited for the rest of the session, which almost guarantees that the default or imported settings take effect the next time the program starts. Under normal circumstances, the current playlist is saved to the registry when the user exits the application, unless this feature is disabled in the player settings dialog. However, when settings have been restored or imported, this obviously can't happen. This had the unintended side-effect of silently discarding the users playlist when the application exited under these conditions.
I had the agent make it so that any action that results in the playlist being modified marks it as not manually saved, and saving the playlist as an M3U file sets this flag to true. When settings are restored or imported and this flag is false, the user is asked if they want to save the playlist when they exit the application. This is another example of the agent not accounting for human behavior during the initial implementation of a feature, and I am extremely glad that I caught this before public release.
When I implemented clipboard pasting functionality, I had an interesting bug crop up relating to character sets. Rather than limiting this feature to file objects, I also made it so that the user could copy a line-separated list of file paths to the clipboard, and paste the text into the application. My primary build target was Unicode, and when I initially tested this feature with the ANSI build, I got what amounted to a garbled mess of characters. This was another instance of the agent failing to account for edge cases, and the fix was quite simple in the end, as the data type requested from the clipboard is different depending on the build target.
I ran into a similar issue with the binary-based settings file format, as settings files exported by a Unicode build could only be imported by a Unicode build, and the ANSI version had a similar issue. I made it so that the header of the settings file includes a flag that states whether the file was generated by a Unicode build or not, and text strings are converted during the import process as needed. This is yet another instance of the AI agent introducing obscure bugs into the code, and I almost guarantee they would have stuck around if I didn't explicitly think of testing for these sorts of things.
Another thing that the AI agent really struggled with was keyboard shortcuts. If a menu or dialog had multiple options that had a shared letter in the name, the agent tended to chews the same letter for more than one item in that particular resource. This resulted in the menu or dialog manager in the operating system moving between items rather than activating them, which is something that I try to avoid. As editing resource scripts is something that I feel I am really good at, these fixes were mostly done manually. However, I would occasionally prompt the agent to do a thorough check for shortcut key conflicts in the resource script, and it would sometimes find things that I had missed in my manual edits.
Something else that I did throughout the development process was prompting the agent to clean up after itself by removing duplicated code introduced by new functionality, and this was a rather tedious process. I also prompted the agent to make sure that functions only relevant to a single translation unit were declared as static, and to make sure that the order of the function declarations in the shared header file matched the order of the functions in the source files.
Another thing I did near the end of the development process was integrating reverb into the Timidity library, and the reverb engine I used was a standalone version of code that was derived from the EAX reverb implementation found in older versions of the OpenALSoft project. When reverb is disabled (which is the default setting) the audio generation still runs as fast as it did before the reverb engine was implemented. A notable characteristic of the way I implemented reverb into the Timidity library is that per channel reverb level is taken into account, so it isn't strictly a global effect.
This integration was mostly done by hand, and the only thing I used the agent for was sketching out the architecture for integrating the reverb engine into the existing synthesis pipeline, and generating the array that contains all 113 EAX reverb presets. To be clear, the agent didn't generate the actual preset data, as I simply told it to use the presets header file that I copied from the OpenALSoft project some time ago. I reviewed and manually edited the code that connected the reverb engine to the rest of the library, and this process didn't take much time as the code is fairly minimal and straightforward.
There is actually an interesting bit of irony when it comes to the reverb integration. Timidity uses Gravis Ultrasound patches for instrument samples, and the reverb I integrated emulates a standard that was developed by Creative Labs. The ironic part is that Creative and Gravis were close competitors back in the 90s, and I didn't even think of this connection when I integrated the EAX reverb engine into the Timidity library.
As you could probably imagine, I felt I was making real progress. However, in the back of my mind I felt I wasn't really gaining many new skills either, and I didn't want to get addicted to this method of software development. As these AI tools rely on the cloud in order to function, they can go away at any time, and the people who rely on these tools as a crutch will essentially have no way of maintaining their projects when these tools inevitably go away. I am aware that local models exist, however the system requirements are quite high, and the output may not be as useful when compared to the models that are produced by the major AI providers. All of this is to say that I decided to set a deadline as to when I was going to stop using the LLM, and by the end of August I had gotten all the features that I wanted implemented anyway.
When September 6th rolled around, I had fixed all major bugs that I found during the development process. After deleting the session files that the coding agent relied on, I canceled my subscription to the AI provider, and moved the code out of the copy of the Timidity driver repository that I was using for this project. Moving the code to its own repository was quite straightforward, as the only changes made during this process were updating include statements in some source files, as well as the build scripts for all the supported compilers.
Over the next several days, I did another manual code review, and fixed a couple small things that stood out. For example, I fixed the placement of some UI elements, silenced compiler warnings in callback functions where one or more arguments were unused, and moved some local variables into the scopes where they were actually needed rather than declaring them function-wide. As you could probably tell, these changes were purely cosmetic, as they had no impact on the behavior of the application. I also implemented a trivial feature that allows the user to clear the recent file list, and promoted the maximum number of files that the player and batch converter could support from 512 to 1024.
The Timidity library got some updates as well. Modulation wheel support was added, and this was trivial to implement as there was already a mechanism for generating vibrato in the original code. The vibrato generator was Initially only used for instrument patches that include vibrato information.
To complement the reverb integration, Support for the chorus effect controller was implemented. Like reverb, chorus is disabled by default. The underlying DSP algorithm that generates the chorus effect is based on public domain code that I found online, and the function that processes audio takes one input sample and generates one output sample. This means that two instances of the effect are allocated, and only one instance is used when generating mono audio data. the low frequency oscillator is out of phase on the instance that is used for the right channel, in order to make the effect more pronounced in stereo.
Finally, I added optional TPDF dithering for the fixed point rendering functions, and fixed the reset all controllers event to reset the volume and pitch of actively playing notes. The pseudorandom number generator that is used for the dithering functionality is a public domain implementation of the Mersenne Twister algorithm, and it is seeded with a hard-coded value when the synthesizer is reset. This means that if the exact same MIDI file is converted more than once with the exact same synthesizer configuration, the hashes of the output WAV files should be identical.
Over all, this was an interesting experiment, and I will admit that coding by hand is more rewarding in the end. Even though manually writing code takes longer, I find it more enjoyable to solve problems purely on my own.
If you decide to test this program and you find an obscure bug, you now know why it may have been introduced. At the time of this writing, I believe I have tracked down all major issues. However, if you find anything significant, feel free to let me know so I can attempt to fix things without the help of an AI agent. By releasing this program to the public, I claim full responsibility for any problems that may arise. To end on a more positive statement, I hope that someone else out there finds this program useful or at the very least interesting. However, I understand that the probability of this occurring is quite low, especially because this is an extremely niche application that I mainly prompted together as an experiment for my own amusement.
Wednesday, July 1, 2026
Midisoft Legacy MIDI Collection
Introduction
This is a collection of MIDI files that were included with various products that were produced by Midisoft Corporation. Midisoft was an early participant in the 1990s multimedia PC software industry. Although Midisoft continued to develop products into the late 1990s, this collection focuses on files dating from 1993 or earlier. This cutoff is based on the observation that later products generally do not contain revised versions of tracks found in earlier releases, suggesting a distinct phase in the company's history.
History
Midisoft Corporation was one of the earliest companies to develop MIDI sequencing and music education software for Microsoft Windows. Their products were frequently bundled with sound cards and multimedia PCs, making them a common introduction to computer music for many people.
Several files in this archive contain metadata referencing Music Technology Associates (MTA), a consulting company active during the early 1990s that specialized in multimedia-based music education. The exact nature of the relationship between Midisoft and MTA is unclear. However, surviving references suggest MTA produced many of the MIDI sequences that Midisoft included with its earlier products, and Midisoft eventually acquired MTA sometime around 1993.
Playing Back These Files
In the early 1990s, Microsoft's Multimedia PC (MPC) specification defined conventions for arranging MIDI sequences that could simultaneously support multiple classes of playback hardware. These conventions were implemented through Windows MIDI Mapper behavior rather than becoming part of the official MIDI specification. The intent was to allow a single MIDI file to contain arrangements for both high-end and low-end devices, and Windows 3.1's MIDI Mapper would automatically route channels to the appropriate synthesizer. This standard was short-lived. However, there are still many MIDI files for this setup in circulation over three decades after the MPC standard was introduced, and many files in this archive follow these conventions. By the mid-1990s, many publishers had begun reissuing their MIDI libraries in the standard General MIDI (GM) format, which avoided some notable flaws in the MPC standard.
It is worth noting that the MPC specification predates widespread General MIDI adoption, and was largely superseded once GM became the industry standard. The Roland Sound Canvas SC-55 became one of the most influential early General MIDI devices, and is often regarded by enthusiasts as the de facto reference for General MIDI playback.
Under Microsoft's MPC architecture, MIDI channels 1 through 10 were routed to an Extended-level synthesizer, while channels 13 through 16 were routed to a Base-level synthesizer. Channels 11 and 12 were typically unused. Extended-level devices were typically higher-end MIDI modules such as the Roland Sound Canvas SC-55, while Base-level devices were typically FM-based synthesizers such as AdLib-compatible sound cards. Extended-level MPC arrangements often map reasonably well to GM-compatible devices, but the two standards are not identical. Unlike conventional GM, Base-level MPC arrangements used MIDI channel 16 for percussion instead of channel 10. A side effect of this mapping was that if a Base-level performance is played back on more conventional GM setups, a melodic instrument such as a piano could end up playing parts intended for a drum kit. Although that might be amusing in some cases, it is not an accurate representation of the intended playback.
Multimedia PC (MPC) MIDI files often contain two arrangements in a single file. The intention of Windows 3.1's MIDI Mapper was to route channels 1 through 10 to an Extended-level device, and channels 13 through 16 to a Base-level device. While this approach could theoretically simplify compatibility, it also created problems when the files were played on more traditional setups. In some rare cases, including some of the files in this collection, arrangers would produce two versions of the same file, one for Extended-level and another for Base-level. In such cases, I recommend sticking with the Extended-level arrangements for most playback situations. The Base-level arrangements are mostly useful for historical interest.
Playing MPC files on a more modern or conventional system requires a bit of preprocessing or editing of the MIDI data. I would generally recommend keeping channels 11 through 16 muted for playing these files, as you will get the extended performance, which does not require any channel remapping. If, for whatever reason, you want to hear the Base-level performance, I recommend keeping the data for channels 1 through 10 muted, and remapping channel 16 to channel 10.
Hardware Playback Tips
If you are using a hardware sound module such as a Roland Sound Canvas, I recommend sending a System Exclusive (SysEx) reset message before starting playback. The reason for this is that many files do not reset channel parameters before the end of the track, so sending a SysEx reset message helps avoid glitches such as wrong instruments being used or notes playing out of tune. On Roland-compatible devices, I recommend sending a GS reset before playback, as some tracks in this collection use GS instrument banks.
Archive Sources
The files in this collection were sourced from various BBS archives and shovelware CD collections that I located on DiskMaster. The following notes list the sources for each subset, the original compression format (where applicable), and the MIDI standards for which the files were arranged.
The primary archive categories correspond to identifiable Midisoft products and releases. The UncertainProvenance category contains related files whose exact origins cannot be determined with confidence but which are historically relevant to the evolution documented by this collection.
MultimediaMusicLibrary
- CD Title: MIDI Music Collection.
- Disk Image Filename: MUSIC.iso.
- Subdirectory: MUSICLIB.104.
- Compression: Microsoft SZDD.
- Arrangement: GM and MPC arrangements of each track.
- Additional Notes: Text files that contain song descriptions and credits are also included. The original file extension for these files was MBS. However, these were renamed to TXT for convenience.
MusicMentor
- CD Title: MIDI Music Collection.
- Disk Image Filename: MUSIC.iso.
- Subdirectory: MENTOR/MIDFILES.
- Compression: LZH (self-extracting archive: MIDFILES.EXE).
- Arrangement: GM and MPC arrangements of each track.
WorldOfMusicSampler
- Collection Title: IBM-WGAM-WBIZ: xtra 0340 - 0349.
- Path to Archive: xtra0340-0349/xtra0347.tar/xtra0347/BSA_MDM.ZIP.
- Compression: Microsoft SZDD.
- Arrangement: GM and Base-level MPC arrangements of each track.
WorldOfMusicSamplerLE
- CD Title: Sound Explorer Plus.
- Disk Image Filename: SOUNDEXP.BIN.
- Subdirectory: WOMSMPLR.
- Arrangement: MPC.
MusicMagic
1.11
- Collection Title: MeiMei's BBS Prog 30 - 38.
- Path to Archive: prog30-38.zip/PROG_32/MUSICMGC.ZIP.
- Compression: Microsoft SZDD.
- Arrangement: MPC.
- Additional Notes: There appears to be a one-year discontinuity in the file timestamps. It is possible that someone in the distribution chain did not set the system clock on their computer correctly, which was not uncommon at the time. Alternatively, it could simply be a coincidence.
1.12
- CD Title: MIDI Masterpiece.
- Disk Image Filename: MidiMasterpieceMidisoftMusicMagic.iso.
- Subdirectory: DISK1.
- Compression: Microsoft SZDD.
- Arrangement: MPC.
- Additional Notes: This particular subset of files also appears in newer versions of RecordingSession and Studio.
Songbook
- Collection Title: MeiMei's BBS Prog 30 - 38.
- Path to Archive: prog30-38.zip/PROG_35/MUSMNTA*.ZIP.
- Compression: Microsoft SZDD.
- Arrangement: MPC.
SongbookLE
- CD Title: Sound Explorer Plus.
- Disk Image Filename: SOUNDEXP.BIN.
- Subdirectory: SONGBOOK.
- Arrangement: MPC.
TandySensation
- CD Title: Tandy Sensation 2.
- Disk Image Filename: Tandy Sensation II System.iso.
- Subdirectory: MUSMAGIC.
- Compression: Microsoft SZDD for all files except SOCKHOP.MID.
- Arrangement: GM.
RecordingSession
1.00
- CD Title: Media PAK: Basic Software Bundle MBP 01.
- Disk Image Filename: Media PAK Basic Software Bundle MBP-01.iso.
- Subdirectory: MIDI.
- Compression: Microsoft SZDD.
- Arrangement: GM.
1.07
- Collection Title: Piper's Pit BBS/FTP: ibm 0080 - 0089.
- Path to Archive: ibm0080-0089/ibm0087.tar/ibm0087/RS107NTA.ZIP.
- Arrangement: MPC.
1.07_Demo
- CD Title: Stars of Shareware: Font & Sound.
- Disk Image Filename: SOS-FONT_SOUND.ISO.
- Path to Archive: ARCHIV/MIDISOFT.ZIP.
- Arrangement: MPC.
- Additional Notes: The underscores at the start of the filenames were present in the originals.
1.07_Pro
- CD Title: Professional Soft Collection 6.
- Disk Image Filename: Professional Soft Collection - Multimedia CD6.0.iso.
- Subdirectory: MIDISHOP/DISK6/MUS/SSN.
- Arrangement: Mix of GM and MPC files.
1.10
- CD Title: MIDI Music Collection.
- Disk Image Filename: MUSIC.iso.
- Subdirectory: RSESSION.110.
- Compression: Microsoft SZDD.
- Arrangement: MPC.
1.11
- CD Title: MIDI Music Collection.
- Disk Image Filename: MUSIC.iso.
- Subdirectory: MENTOR/SESSION.
- Arrangement: GM.
Studio
3.01
- Collection Title: MeiMei's BBS Prog 30 - 38.
- Path to Archive: prog30-38.zip/PROG_36/MIDISFT*.ZIP.
- Arrangement: GM.
3.09
- CD Title: Professional Soft Collection 6.
- Disk Image Filename: Professional Soft Collection - Multimedia CD6.0.iso.
- Subdirectory: STUDIO.
- Compression: Microsoft SZDD.
- Arrangement: GM.
- Additional Notes: This particular subset of files also appears in various other bundles of RecordingSession and Studio.
3.10
- CD Title: MIDI Music Collection.
- Disk Image Filename: MUSIC.iso.
- Subdirectory: STUDIO.310.
- Compression: Microsoft SZDD.
- Arrangement: MPC.
3.10_DealerDemo
- Collection Title: Piper's Pit BBS/FTP: ibm 0150 - 0159.
- Path to Archive: ibm0150-0159/ibm0153.tar/ibm0153/BC_MSTUD.ZIP.
- Compression: Microsoft SZDD.
- Arrangement: GM and Base-level MPC arrangements of each track.
UncertainProvenance
The true origins of most files in this category cannot be determined with confidence, so the listed origins should be considered rough hypotheses rather than definitive attributions.
December92
A_BRIDGE.MID
- Collection Title: Piper's Pit BBS/FTP: ibm 0110 - 0119.
- Path to Archive: ibm0110-0119/ibm0114.tar/ibm0114/GENMID.ZIP.
- Arrangement: GM.
- Reason for Inclusion: This version of the file is a bit smaller than the other versions in this collection. The ZIP archive in which this was found also contains MIDI files taken from official Midisoft releases, so it is possible that this version of the file was included in a release of RecordingSession or Studio from late 1992.
- Additional Notes: the piano track appears to have a couple stray note off events. As these events are scheduled for a time that is much later than when the actual music ends, the runtime of the file is nearly 5 minutes longer than it should be.
ROCKNOUT.MID
- CD Title: PCMania 15.
- Disk Image Filename: PCMania CD 15 mas disquetes.nrg.
- Subdirectory: AUDIO.
- Arrangement: GM.
- Reason for Inclusion: It is possible that this version of ROCKNOUT.MID is from a release of RecordingSession or Studio from late 1992. Interestingly, the track names in this version of the file are stored as MIDI track names and not as generic text events.
STRIVING.MID
- CD Title: 3,800 MIDI Magic.
- Disk Image Filename: 3800 MIDI Magic.iso.
- Subdirectory: MAGIC/GENERAL.
- Arrangement: GM.
- Reason for Inclusion: This version of the file is slightly smaller than the other versions in this collection.
- Additional Notes: This edit appears to be based on the October 1991 version discussed later in this document.
GUS
- CD Title: Action pur!.
- Disk Image Filename: ACTPUR_201.ISO.
- Path to Archive: ZIP/12502.ZIP/GUSMID.ZIP.
- Arrangement: GM.
- Reason for Inclusion: These are arrangements commonly attributed to Gravis Ultrasound sound cards, although their true origin remains a mystery.
- Additional Notes:
- The edit of STRIVING.MID in this subset is somewhat unusual. It abruptly cuts off the piano before the key change that segues into the final section of the song, and the last set of piano notes are never turned off. This may result in hanging notes on some synthesizers.
- The version of A_BRIDGE.MID in this subset has a slightly different drum arrangement compared to other versions in this collection.
- WOWMAN.MID appears to be an alternate arrangement of the track also known as JAZZVIBE.MID. This arrangement has a slightly slower tempo, and the instrumentation is more involved. According to the file timestamp, it appears to have been modified on the same day as the version of STRIVING.MID that is in this subset.
HSC_CLABS
- CD Title: Vision of Sound, Graphic & Animation 2.
- Disk Archive Filename: vision.zip.
- Subdirectory: vision/HSC/CLABS.
- Arrangement: Unknown standard.
- Reason for Inclusion: MOVING.MID appears to be an arrangement of Striving For Glory with an unknown origin. It has a slightly faster tempo than STRIVING.MID, repeats several times for some reason, and the total runtime is approximately 11 minutes.
HSC_SUNMOON
- CD Title: Vision of Sound, Graphic & Animation 2.
- Disk Archive Filename: vision.zip.
- Subdirectory: vision/HSC/SUNMOON.
- Arrangement: Unknown standard.
- Reason for Inclusion: These are obscure versions of Striving For Glory that I encountered during my archival research. Other digital historians might find them useful or at the very least interesting.
- Additional Notes: The copy of STRIVING.MID in this subset appears to be based on the February 1992 edit, as it has the same stuck piano notes problem at the end. It also has odd instrument choices, so I hesitate to classify this arrangement as GM. STR_JON.MID appears to be a larger version of MOVING.MID, and it could possibly be an older version of this arrangement if the timestamp is accurate.
July92
- CD Title: The SelectWare System: Windows & OS/2 Conference 1992.
- Disk Image Filename: WIN92F.ISO.
- Subdirectory: OPEN.
- Arrangement: GM.
- Reason for Inclusion: This is another edit of STRIVING.MID from July of 1992.
- Additional Notes: This edit appears to be based on the October 1991 version discussed later in this document, as it does not omit the piano from the final section of the song.
Late93_GM
- CD Title: Multimedia Sound Factory: The Ultimate Sound CD for Your PC.
- Disk Archive Filename: USN 70 Multimedia Sound Factory The Ultimate Sound CD for your PC.zip.
- Subdirectory: MUSIC/MID/*.
- Arrangement: GM.
- Reason for Inclusion: These are standard GM arrangements of sequences found in other subsets. These might be from the same production run as the RecordingSession 1.11 files, as the timestamps and metadata structure are similar.
- Additional Notes: This subset includes the only copy of PARIS.MID in the entire collection. The other version of this arrangement is named CAFE.MID, and can be found in MusicMagic/Songbook.
RecordingSession_1.07_Demo_FullLengthVersions
- CD Title: Corel ArtShow 3.
- Disk Image Filename: Corel_ArtShow3_1992.bin.
- Subdirectory: ARTSHOW3/MIDI.
- Arrangement: MPC.
- Reason for Inclusion: These are essentially full-length versions of the tracks that are included with the RecordingSession 1.07 Demo, and the timestamps of both sets of files fall on the same day.
- Additional Notes: The timestamps on this subset of files may not actually be entirely accurate, as all of the files that are on the disk they were sourced from share the same timestamp.
RecordingSession_1.07_NewerVersions
- CD Title: MIDI & Wave Workshop.
- Disk Image Filename: Midi and Wave Workshop (Powersource, Inc.).ISO.
- Subdirectory: MID.
- Arrangement: MPC.
- Reason for Inclusion: These appear to be larger versions of many of the files that are included with RecordingSession 1.07. They could possibly have been taken from a version of RecordingSession that was released after 1.07 and before 1.10.
- Additional Notes: Unlike the older versions of these files, the track names are stored as generic text events and not as MIDI track names.
TurtleBeach (includes oldest known version of STRIVING.MID)
- Collection Title: MeiMei's BBS Prog 104 - 108.
- Path to Archive: prog104_108.zip/prog104_108/PROG_107/TTOOL1_4.ZIP.
- Arrangement: GM.
- Reason for Inclusion: Striving For Glory is a well-known track among retro MIDI enthusiasts. This file is the oldest arrangement I could find, as it is from October 1991. The version that is commonly known is from February 1992, and can be found in the GUS subset.
- Additional Notes: I found this early version of STRIVING.MID included with an obscure Turtle Beach sound card driver. In order to extract the file with its timestamp preserved, I had to run the installer in a Windows XP virtual machine. Although the installer included other files, they are duplicates of files in other subsets, including their timestamps. Specifically, the installer also includes most of the files from the Studio 3.09 subset, as well as the GM arrangements from the WorldOfMusicSampler subset.
WorldOfMusicSampler_GUSVolumeMapped
- CD Title: Sound, Music & MIDI Collection 2.
- Disk Image Filename: SMMVOL2.bin.
- Path to Archive: MUSIC/MID/G1/GM_MIDI.ZIP.
- Arrangement: GM.
- Reason for Inclusion: These files are the exact same size as the GM arrangements in the WorldOfMusicSampler subset, although the volumes and velocities are different. This suggests that the MIDI files were modified at a low level, possibly by an automated process.
- Additional Notes: This subset of files most likely originated from the Gravis Ultrasound BBS, as the archive that contained these files (GM_MIDI.ZIP) is referenced in directory listings for that particular BBS. Unfortunately, no mirrors of this BBS that include this particular file appear to have been archived, possibly because the file was removed at a later date and the file listing was never updated to reflect the change.
WorldOfMusicSampler_OlderFiles
- Collection Title: MeiMei's BBS Prog 11 - 20.
- Path to Archive: prog11-20.zip/PROG_11/WRLDMUS*.ZIP.
- Arrangement: GM and Base-level MPC arrangements of each track.
- Reason for Inclusion: These files are slightly larger than the newer versions that are more commonly found. They don't appear to be musically different, though.
- Additional Notes: Unlike the newer versions of these files, the track names are stored as generic text events and not as MIDI track names.
Archiving Methodology
File Naming Conventions
The files in this archive retain their original filenames. Filenames starting with GM are General MIDI arrangements, filenames starting with DI (short for Device Independent) are MPC arrangements, and filenames starting with FM are Base-level MPC arrangements.
Duplicates and Alternate Arrangements
A common trend throughout this archive is that different arrangements of the same tracks appear in multiple places. These arrangements differ from each other in several ways, including file size, length, instrumentation, volume and pan settings, and so on. To make things even more confusing, there are different versions of the same tracks with completely different filenames. In some cases, it appears Midisoft reused the exact same files in multiple product releases, so there are many byte-for-byte identical files in different subsets.
While analyzing the files to check for exact duplicates, I discovered a couple of discrepancies in the MultimediaMusicLibrary and WorldOfMusicSampler files. It appears that FMSALSA.MID is an exact copy of FMHALF.MID in the WorldOfMusicSampler subset, and this discrepancy also appears in the older versions of the files. Similarly, DIRESET.MID appears to be a copy of GMRESET.MID in MultimediaMusicLibrary, and the proper version of DIRESET.MID can be found in MusicMentor. These were most likely mistakes that went unnoticed while the files were being prepared for release. Another notable discrepancy is that the copy of GMQUEEN.MID in UncertainProvenance/WorldOfMusicSampler_OlderFiles is an exact duplicate of the same file in WorldOfMusicSampler.
Timestamps
Original file timestamps have been preserved. In several cases, file timestamps provide the only surviving evidence for establishing the relative chronology of different software distributions and arrangement revisions. However, timestamps should not be considered definitive proof of creation dates, as many files were redistributed through BBS systems and shareware collections where system clocks were frequently set incorrectly.
Compression
7-Zip was used for archive extraction, and thankfully I did not encounter any corrupted archives. Files compressed with the Microsoft SZDD format were renamed in bulk after extraction, as the extracted files either did not have the last character of the file extension, or had no file extension.
For context, many developers in the early to mid-1990s would compress individual files to save space on installation media. This was especially important for installers stored on floppy disks, as file compression would result in fewer disks being needed to install larger programs. Microsoft developed the SZDD compression format for software distribution in the early Windows era. Files compressed in this format typically had the last character of the file extension replaced with an underscore. This was not always the case, as some of the compressed files encountered throughout this project had the underscore replaced with the last character of the file extension.
Copyright Disclaimer
These files are being distributed for historical, research, and archival purposes only. Their inclusion in this archive does not imply that they are in the public domain, nor does it alter any existing copyright ownership. Although composition and/or sequencing credits are not well documented, all compositions and sequences are the property of their respective owners.