Permalink
Browse files

-CodeChange: Working MT32 sounds/music with MUNT

Tested on FreeBSD 10.3 with /dev/dsp (oss) sound

fixes #272
  • Loading branch information...
miniupnp committed Feb 12, 2017
1 parent 2706917 commit f540b195d3e8b71de6843a0b088316c80cb1c7f4
Showing with 135 additions and 9 deletions.
  1. +8 −2 README.txt
  2. +127 −7 src/audio/midi_munt.c
View
@@ -48,6 +48,8 @@ For Linux/FreeBSD, you need to install LibSDL yourself. It is available in every
system.
In order to use sounds and music on Linux, you need a working ALSA driver.
Music is sent to MIDI Out port of Atari machines.
+It is also possible to build with Munt MT32 emulator http://munt.sourceforge.net/
+to have MT32 music.
Installation & Running
@@ -62,15 +64,19 @@ Start 'opendune'.
Additional options may be specified using an opendune.ini file located
in the data/ directory, in the current directory or in %APPDATA%\OpenDUNE
(on Windows) or ~/Library/Application Support/OpenDUNE (on Mac OS X) or
-~/.config/opendune (on Linux/FreeBSD). All options must be in an [opendune] section.
+~/.config/opendune (on Linux/FreeBSD). All options must be in an [opendune]
+section.
+
Available options are :
- language : english / french / german
- datadir : directory where Dune data files are
- savedir : directory for Dune personal data files (savegames)
- scalefactor : 2 (default), 3, 4
- scalefilter : nearest (default), scale2x, hqx
-- mt32midi : 0(default)/1 send MT32 init, use .XMI files
- framerate : maximum frame rate (60 FPS default)
+- mt32midi : 0(default)/1 send MT32 init, use .XMI files
+- mt32rompath : directory containing CM32L_CONTROL.ROM/CM32L_PCM.ROM files
+ for Munt MT32 emulator.
Ingame
View
@@ -1,46 +1,152 @@
/** @file src/audio/midi_munt.c use the MT32 emulator MUNT */
#include <mt32emu/mt32emu.h>
+#include <stdlib.h>
+
+/* OSS API */
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/soundcard.h>
+
+#include <string.h>
+#include <errno.h>
+
+#define AUDIO_DEVICE "/dev/dsp"
#include "types.h"
#include "midi.h"
+#include "../timer.h"
+#include "../inifile.h"
+#include "../os/strings.h"
#include "../os/error.h"
+#define MUNT_RENDER_RATE 50
+
+static int s_oss_fd = -1;
+
+static void munt_tick(void);
+
+static void show_lcd_message(void * instance_data, const char * message)
+{
+ (void)instance_data;
+ Debug("MT32 LCD Message : %s\n", message);
+}
+static void print_debug(void *instance_data, const char *fmt, va_list list)
+{
+ char buffer[4096];
+ (void)instance_data;
+ vsnprintf(buffer, sizeof(buffer), fmt, list);
+ Debug("MT32 debug message : %s\n", buffer);
+}
+
static mt32emu_context s_context = NULL;
const char * s_romfiles[] = {
- "/Users/nanard/roms/CM32L_CONTROL.1989-12-05.v1.02.ROM",
- "/Users/nanard/roms/CM32L_PCM.ROM",
+ "CM32L_CONTROL.ROM",
+ "CM32L_PCM.ROM",
NULL
};
+static const mt32emu_report_handler_i_v0 handler_v0 = {
+ /** Returns the actual interface version ID */
+ NULL, /*mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i);*/
+ /** Callback for debug messages, in vprintf() format */
+ print_debug, /*void (*printDebug)(void *instance_data, const char *fmt, va_list list);*/
+ /** Callbacks for reporting errors */
+ NULL, /*void (*onErrorControlROM)(void *instance_data);*/
+ NULL, /*void (*onErrorPCMROM)(void *instance_data);*/
+ /** Callback for reporting about displaying a new custom message on LCD */
+ show_lcd_message, /*void (*showLCDMessage)(void *instance_data, const char *message);*/
+ /** Callback for reporting actual processing of a MIDI message */
+ NULL, /*void (*onMIDIMessagePlayed)(void *instance_data);*/
+ /**
+ * Callback for reporting an overflow of the input MIDI queue.
+ * Returns MT32EMU_BOOL_TRUE if a recovery action was taken
+ * and yet another attempt to enqueue the MIDI event is desired.
+ */
+ NULL, /*mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data);*/
+ /**
+ * Callback invoked when a System Realtime MIDI message is detected in functions
+ * mt32emu_parse_stream and mt32emu_play_short_message and the likes.
+ */
+ NULL, /*void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime);*/
+ /** Callbacks for reporting system events */
+ NULL, /*void (*onDeviceReset)(void *instance_data);*/
+ NULL, /*void (*onDeviceReconfig)(void *instance_data);*/
+ /** Callbacks for reporting changes of reverb settings */
+ NULL, /*void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode);*/
+ NULL, /*void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time);*/
+ NULL, /*void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level);*/
+ /** Callbacks for reporting various information */
+ NULL, /*void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num);*/
+ NULL /*void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name)*/
+};
+
+static const mt32emu_report_handler_i s_handler = { &handler_v0 };
+static unsigned int s_sample_rate;
+static int16 * s_buffer = NULL;
+
bool midi_init(void)
{
+ char rompath[1024];
+ char romfile[1024];
int i;
- mt32emu_report_handler_i handler = { NULL };
Debug("munt version : %s\n", mt32emu_get_library_version_string());
- s_context = mt32emu_create_context(handler, NULL);
+ s_context = mt32emu_create_context(s_handler, NULL);
if (s_context == NULL) return false;
+ IniFile_GetString("mt32rompath", "./roms", rompath, sizeof(rompath));
for (i = 0; s_romfiles[i] != NULL; i++) {
- mt32emu_return_code ret = mt32emu_add_rom_file(s_context, s_romfiles[i]);
+ mt32emu_return_code ret;
+ snprintf(romfile, sizeof(romfile), "%s/%s", rompath, s_romfiles[i]);
+ ret = mt32emu_add_rom_file(s_context, romfile);
if (ret < MT32EMU_RC_OK) {
- Error("Failed to load MT32 ROM file '%s' error %d\n", s_romfiles[i], (int)ret);
+ Error("Failed to load MT32 ROM file '%s' error %d\n", romfile, (int)ret);
return false;
}
}
if (mt32emu_open_synth(s_context) != MT32EMU_RC_OK) {
Error("Failed to open synth\n");
return false;
}
+
+ s_sample_rate = mt32emu_get_actual_stereo_output_samplerate(s_context);
+ Debug("munt output samplerate = %uHz\n", s_sample_rate);
+ s_oss_fd = open(AUDIO_DEVICE, O_WRONLY);
+ if(s_oss_fd < 0) {
+ Error("open(%s) : %s\n", AUDIO_DEVICE, strerror(errno));
+ return false;
+ } else {
+ i = AFMT_S16_NE; /* signed 16bit samples, NATIVE order */
+ if(ioctl(s_oss_fd, SNDCTL_DSP_SETFMT, &i) < 0) {
+ Error("Failed to set signed 16bit format\n");
+ return false;
+ }
+ i = 1; /* stereo */
+ if(ioctl(s_oss_fd, SNDCTL_DSP_STEREO, &i) < 0) {
+ Error("Failed to set stereo\n");
+ return false;
+ }
+ i = s_sample_rate;
+ if(ioctl(s_oss_fd, SNDCTL_DSP_SPEED, &i) < 0) {
+ Error("Failed to set sample rate\n");
+ return false;
+ }
+ Debug("Real sample rate = %d\n", i);
+ }
+ s_buffer = malloc(s_sample_rate * 4 / MUNT_RENDER_RATE);
+ Timer_Add(munt_tick, 1000000 / MUNT_RENDER_RATE, false);
return true;
}
void midi_uninit(void)
{
+ Timer_Remove(munt_tick);
mt32emu_close_synth(s_context);
mt32emu_free_context(s_context);
s_context = NULL;
+ free(s_buffer);
+ s_buffer = NULL;
}
/**
@@ -71,4 +177,18 @@ void midi_reset(void)
{
}
-
+static void munt_tick(void)
+{
+ ssize_t n;
+ if(s_context != NULL && s_buffer != NULL) {
+ mt32emu_render_bit16s(s_context, s_buffer, s_sample_rate / MUNT_RENDER_RATE);
+ if(s_oss_fd >= 0) {
+ n = write(s_oss_fd, s_buffer, (s_sample_rate * 4) / MUNT_RENDER_RATE);
+ if(n < 0) {
+ Warning("munt_tick() write() : %s\n", strerror(errno));
+ } else if(n != (s_sample_rate * 4) / MUNT_RENDER_RATE) {
+ Warning("write() returned %lu\n", (unsigned long)n);
+ }
+ }
+ }
+}

0 comments on commit f540b19

Please sign in to comment.