diff --git a/backends/midi/riscos.cpp b/backends/midi/riscos.cpp
new file mode 100644
index 000000000000..fa786961271f
--- /dev/null
+++ b/backends/midi/riscos.cpp
@@ -0,0 +1,174 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/scummsys.h"
+
+#ifdef RISCOS
+
+#include "common/error.h"
+#include "common/textconsole.h"
+#include "audio/musicplugin.h"
+#include "audio/mpu401.h"
+
+#include
+#include
+
+#ifndef MIDI_TxByte
+#define MIDI_TxByte 0x404C9
+#endif
+#ifndef MIDI_TxCommand
+#define MIDI_TxCommand 0x404CA
+#endif
+
+
+class MidiDriver_RISCOS final : public MidiDriver_MPU401 {
+public:
+ MidiDriver_RISCOS(int port = 0) : _isOpen(false), _port(port) {}
+ ~MidiDriver_RISCOS() {}
+
+ int open() override;
+ bool isOpen() const override { return _isOpen; }
+ void close() override;
+ void send(uint32 b) override;
+ void sysEx(const byte *msg, uint16 length) override;
+
+private:
+ _kernel_oserror *txByte(int r0);
+ _kernel_oserror *txCommand(int r0, int r1);
+
+ bool _isOpen;
+ int _port;
+};
+
+int MidiDriver_RISCOS::open() {
+ if (isOpen())
+ return MERR_ALREADY_OPEN;
+
+ _isOpen = true;
+ return 0;
+}
+
+void MidiDriver_RISCOS::close() {
+ MidiDriver_MPU401::close();
+ _isOpen = false;
+}
+
+void MidiDriver_RISCOS::send(uint32 b) {
+ assert(isOpen());
+
+ midiDriverCommonSend(b);
+
+ // Extract the MIDI data
+ byte status_byte = (b & 0x000000FF);
+ // byte first_byte = (b & 0x0000FF00) >> 8;
+ // byte second_byte = (b & 0x00FF0000) >> 16;
+
+ // Compute the correct length of the MIDI command. This is important,
+ // else things may screw up badly...
+ byte length;
+ switch (status_byte & 0xF0) {
+ case 0x80: // Note Off
+ case 0x90: // Note On
+ case 0xA0: // Polyphonic Aftertouch
+ case 0xB0: // Controller Change
+ case 0xE0: // Pitch Bending
+ length = 3;
+ break;
+ case 0xC0: // Programm Change
+ case 0xD0: // Monophonic Aftertouch
+ length = 2;
+ break;
+ default:
+ warning("RISC OS driver encountered unsupported status byte: 0x%02x", status_byte);
+ length = 3;
+ break;
+ }
+
+ // Finally send it out to the synthesizer.
+ txCommand(b | (length << 24) | (_port << 28), 0);
+}
+
+void MidiDriver_RISCOS::sysEx(const byte *msg, uint16 length) {
+ assert(isOpen());
+
+ int port = (_port << 28);
+
+ txByte(0xF0 | port);
+ for (; length; --length, ++msg) {
+ txByte(*msg | port);
+ }
+ txByte(0xF7 | port);
+}
+
+_kernel_oserror *MidiDriver_RISCOS::txByte(int r0) {
+ _kernel_swi_regs regs;
+ regs.r[0] = r0;
+ return _kernel_swi(MIDI_TxByte, ®s, ®s);
+}
+
+_kernel_oserror *MidiDriver_RISCOS::txCommand(int r0, int r1) {
+ _kernel_swi_regs regs;
+ regs.r[0] = r0;
+ regs.r[1] = r1;
+ return _kernel_swi(MIDI_TxCommand, ®s, ®s);
+}
+
+
+// Plugin interface
+
+class RISCOSMusicPlugin : public MusicPluginObject {
+public:
+ const char *getName() const {
+ return "RISC OS MIDI";
+ }
+
+ const char *getId() const {
+ return "riscos";
+ }
+
+ MusicDevices getDevices() const;
+ Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
+};
+
+MusicDevices RISCOSMusicPlugin::getDevices() const {
+ MusicDevices devices;
+ // TODO: Return a different music type depending on the configuration
+ // TODO: List the available devices
+ devices.push_back(MusicDevice(this, "", MT_GM));
+ return devices;
+}
+
+Common::Error RISCOSMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle device) const {
+ *mididriver = new MidiDriver_RISCOS();
+
+ return Common::kNoError;
+}
+
+//#if PLUGIN_ENABLED_DYNAMIC(RISCOS)
+ //REGISTER_PLUGIN_DYNAMIC(RISCOS, PLUGIN_TYPE_MUSIC, RISCOSMusicPlugin);
+//#else
+ REGISTER_PLUGIN_STATIC(RISCOS, PLUGIN_TYPE_MUSIC, RISCOSMusicPlugin);
+//#endif
+
+#endif // RISCOS
diff --git a/backends/module.mk b/backends/module.mk
index 3501fcca805a..2f27ad9e1640 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -275,6 +275,7 @@ MODULE_OBJS += \
events/riscossdl/riscossdl-events.o \
fs/riscos/riscos-fs.o \
fs/riscos/riscos-fs-factory.o \
+ midi/riscos.o \
plugins/riscos/riscos-provider.o
ifndef SDL_BACKEND
# This is needed for null backend but already included in SDL backend
diff --git a/base/plugins.cpp b/base/plugins.cpp
index fc5043e35415..e6022be019d1 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -130,6 +130,9 @@ class StaticPluginProvider : public PluginProvider {
#if defined(__amigaos4__) || defined(__MORPHOS__)
LINK_PLUGIN(CAMD)
#endif
+ #if defined(RISCOS)
+ LINK_PLUGIN(RISCOS)
+ #endif
#if defined(MACOSX)
LINK_PLUGIN(COREAUDIO)
LINK_PLUGIN(COREMIDI)