From 6ef14046c76e2c24484b5f5a4228cb170acdf17d Mon Sep 17 00:00:00 2001 From: indigoparadox Date: Thu, 2 Jun 2022 21:37:50 -0400 Subject: [PATCH] Roughly implemented DOS beeping. --- README.md | 11 +++++++++++ src/midibeep.c | 27 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/README.md b/README.md index 1588963..85c5fe8 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,17 @@ Currently a work in progress and very volatile. - Check framework, for running tests: `sudo apt install check` - ALSA development libraries for beep playback: `sudo apt install libasound2-dev` +## DOS MIDI Player + +(WARNING: Experimental, extremely funny-sounding. Needs work! If you try it right now on a real machine, you will probably have to reboot that machine!) + +midibeep is a simple one-track MIDI player that can be cross-compiled for DOS from a modern UNIX-like system. Given a type 1 MIDI file and a track number, it will attempt to beep out that track on the PC speaker. It requires the OpenWatcom compiler to compile. + +- Ensure that `wcc` and `wcl` are in your PATH. +- Ensure that the `WATCOM` environment variable is set to your watcom installation directory (e.g. `/opt/watcom`). +- Ensure that the `INCLUDE` environment variable is set to the `h` subdirectory of your watcom installation directory (e.g. `/opt/watcom/h`). +- Execute `make midibeep.exe` in the project root. + ## References - https://web.archive.org/web/20140216225718/http://www.sonicspot.com/guide/midifiles.html diff --git a/src/midibeep.c b/src/midibeep.c index 3d2f338..374d389 100644 --- a/src/midibeep.c +++ b/src/midibeep.c @@ -7,6 +7,8 @@ #ifdef USE_ALSA #include +#elif defined( USE_DOS ) +#include #endif /* USE_ALSA */ #ifdef USE_MMAP @@ -58,6 +60,31 @@ void beep( int freq_hz, int duration_ms ) { } } #elif defined( USE_DOS ) + uint32_t freq_division = 0; + uint8_t prev_keyb_status = 0; + + /* TODO: Needs cleanup with constants for port numbers, bitmasks, etc. */ + + freq_division = 1193180 / freq_hz; + + /* Set the programmable interrupt timer to the given frequency. */ + outp( 0x43, 0xb6 ); + outp( 0x42, (uint8_t)freq_division ); + outp( 0x42, (uint8_t)(freq_division >> 8) ); + + /* Set keyboard controller status to enable PC speaker. */ + prev_keyb_status = inp( 0x61 ); + if( prev_keyb_status != (prev_keyb_status | 0x03) ) { + outp( 0x61, (prev_keyb_status | 0x03) ); + } + + delay( duration_ms ); + + /* Turn off the PC speaker. */ + prev_keyb_status = inp( 0x61 ); + outp( 0x61, (prev_keyb_status & 0xfc) ); + + /* TODO: Reset the PIT to its previous frequency. */ #endif /* USE_ALSA || USE_DOS */ }