Skip to content

Commit

Permalink
MidiDriver interface refactor (#256)
Browse files Browse the repository at this point in the history
* init

* code rev

* midi interfaces WIP

* midi drivers refactor

* fix build

* [wip]

* [WIP]

* OplDriver refactor

* clean-ups

* clean-ups

* clean-ups

* clean-ups

* code rev

* code refactor

* code rev

* coder ev

* clean up scumm midi drv

* clean up scumm midi drv

* clean up scumm midi drv

* clean up scumm midi drv

* code rev

* scummvm MidiDriver pitchbend

* midi gm driver scummvm refactor

* midi gm driver scummvm refactor

* midi gm driver scummvm refactor

* midi gm driver scummvm refactor

* midi gm driver scummvm refactor

* remove scummvm MidiDriver_BASE

* midi driver scumm gm clean-ups

* midi driver scumm gm clean-ups

* midi driver scumm gm clean-ups

* midi driver scumm gm clean-ups

* midi driver scumm gm clean-ups

* fix midi scumm gm adlib

* code rev

* code rev

* code rev

* code rev

* code rev

* code rev

* sonarcloud code rev

* code rev

* code rev

* code rev

* code rev
  • Loading branch information
Raffaello authored Oct 10, 2023
1 parent 9a17c14 commit ad5b0f1
Show file tree
Hide file tree
Showing 35 changed files with 1,245 additions and 1,353 deletions.
Binary file added doc/midi/MIDI Control Change Messages.pdf
Binary file not shown.
6 changes: 4 additions & 2 deletions sdl2-hyper-sonic-drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,14 @@ target_sources(${LIB_NAME} PRIVATE
# --- #
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/PCMDriver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/MIDDriver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/IMidiDriver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/IMidiChannel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/IMidiChannelVoice.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/westwood/ADLDriver.cpp

${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/MidiDriver_BASE.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/MidiDriver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/AdLibInstrument.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/AdLibPart.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/AdLibChannel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/AdLibPercussionChannel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HyperSonicDrivers/drivers/midi/scummvm/MidiDriver_ADLIB.cpp

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace HyperSonicDrivers::audio::midi
{
// TODO: store it as uint32_t
class MIDIEvent
{
public:
Expand All @@ -25,6 +26,7 @@ namespace HyperSonicDrivers::audio::midi
b += (data[1] << 16);
return b;
}

// removed abs_time as it is not a MIDIEvent.
//uint32_t abs_time = 0; /// absolute ticks time derived from delta_time used for conversion.
};
Expand Down
70 changes: 60 additions & 10 deletions sdl2-hyper-sonic-drivers/src/HyperSonicDrivers/audio/midi/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace HyperSonicDrivers::audio::midi
{
constexpr uint8_t MIDI_MAX_CHANNELS = 16;
constexpr uint8_t MIDI_PERCUSSION_CHANNEL = 9; // standard MIDI percussion channel
constexpr uint16_t MIDI_PITCH_BEND_DEFAULT = 0x2000; // pitch bend default value (zero)

typedef std::vector<uint8_t> midi_vector_t;

Expand All @@ -16,10 +17,8 @@ namespace HyperSonicDrivers::audio::midi
SINGLE_TRACK = 0,
SIMULTANEOUS_TRACK = 1,
MULTI_TRACK = 2
//TODO: add XMI_FORMAT?
};

// move to MIDIEvent class ?
typedef union MIDI_EVENT_type_u
{
uint8_t val;
Expand Down Expand Up @@ -79,18 +78,16 @@ namespace HyperSonicDrivers::audio::midi
SYS_EX7 = static_cast<uint8_t>((std::byte(MIDI_EVENT_TYPES_HIGH::META_SYSEX) << 4) | std::byte(MIDI_META_EVENT_TYPES_LOW::SYS_EX7)),
};

/*
// TODO: too many repetitions to be an enum
enum class MIDI_EVENT_CONTROLLER_TYPES : uint8_t
{
BANK_SELECT = 0,
BANK_SELECT_MSB = 0,
MODULATION_WHEEL = 1,
BREATH_CONTROL = 2,
FOOT_CONTROLLER = 4,
PORTAMENTO_TIME = 5,
DATA_ENTRY = 6,
CHANNEL_VOLUME = 7, // (MAIN VOLUME)
BALANCE = 8, // (PAN)
DATA_ENTRY_MSB = 6,
CHANNEL_VOLUME = 7,
BALANCE = 8,
PAN = 10,
EXPRESSION_CONTROLLER = 11,
EFFECT_CONTROL_1 = 12,
Expand All @@ -99,15 +96,68 @@ namespace HyperSonicDrivers::audio::midi
GENERAL_PURPOSE_CONTROLLER_2 = 17,
GENERAL_PURPOSE_CONTROLLER_3 = 18,
GENERAL_PURPOSE_CONTROLLER_4 = 19,
BANK_SELECT_2 = 32,
BANK_SELECT_LSB = 32,
MODULATION_WHEEL_2 = 33,
BREATH_CONTROL_2 = 34,
DATA_ENTRY_LSB = 38,
SUSTAIN = 64,
REVERB = 91,
TREMOLO = 92,
CHORUS = 93,
DETUNE = 94,
PHASER = 95,
RPN_LSB = 100,
RPN_MSB = 101,
ALL_SOUND_OFF = 120,
RESET_ALL_CONTROLLERS = 121,
ALL_NOTES_OFF = 123,

// eXtended MIDI
CHANNEL_LOCK = 110,
CHANNEL_LOCK_PROTECT = 111,
VOICE_PROTECT = 112,
TIMBRE_PROTECT = 113,
PATCH_BANK_SELECT = 114,
INDIRECT_CONTROLLER_PREFIX = 115,
FOR_LOOP_CONTROLLER = 116,
NEXT_BREAK_LOOP_CONTROLLER = 117,
CLEAR_BEAT_BAR_COUNT = 118,
CALLBACK_TRIGGER = 119,
SEQUENCE_BRANCH_INDEX = 120,
};
*/

enum class MIDI_RPN_TYPES : uint16_t
{
PITCH_BEND_SENSITIVITY = 0x0000,
FINE_TUNING = 0x0001,
COARSE_TUNING = 0x0002,
TUNING_PROGRAM_SELECT = 0x0003,
TUNING_BANK_SELECT = 0x0004,
RPN_NULL = 0x7F7F
};

enum class MIDI_RPN_TYPES_LSB : uint8_t
{
PITCH_BEND_SENSITIVITY = 0x00,
FINE_TUNING = 0x01,
COARSE_TUNING = 0x02,
TUNING_PROGRAM_SELECT = 0x03,
TUNING_BANK_SELECT = 0x04,
RPN_NULL = 0x7F
};

enum class MIDI_RPN_TYPES_MSB : uint8_t
{
PITCH_BEND_SENSITIVITY = 0x00,
FINE_TUNING = 0x00,
COARSE_TUNING = 0x00,
TUNING_PROGRAM_SELECT = 0x00,
TUNING_BANK_SELECT = 0x00,
RPN_NULL = 0x7F
};

constexpr MIDI_EVENT_TYPES_HIGH TO_HIGH(const uint8_t x) { return static_cast<MIDI_EVENT_TYPES_HIGH>(x); }
constexpr MIDI_META_EVENT_TYPES_LOW TO_META_LOW(const uint8_t x) { return static_cast<MIDI_META_EVENT_TYPES_LOW>(x); }
constexpr MIDI_META_EVENT TO_META(const uint8_t x) { return static_cast<MIDI_META_EVENT>(x); }
constexpr MIDI_EVENT_CONTROLLER_TYPES TO_CTRL(const uint8_t x) { return static_cast<MIDI_EVENT_CONTROLLER_TYPES>(x); }
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ namespace HyperSonicDrivers::drivers
}

m_midiDriver.reset();

//auto opl = std::dynamic_pointer_cast<devices::Opl>(m_device)->getOpl();
auto opl_drv = std::make_unique<drivers::midi::opl::OplDriver>(std::dynamic_pointer_cast<devices::Opl>(m_device));
opl_drv->setOP2Bank(op2Bank);
m_midiDriver = std::move(opl_drv);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <HyperSonicDrivers/drivers/midi/IMidiChannel.hpp>
#include <HyperSonicDrivers/audio/midi/types.hpp>

namespace HyperSonicDrivers::drivers::midi
{
IMidiChannel::IMidiChannel(const uint8_t channel) :
channel(channel),
isPercussion(channel == audio::midi::MIDI_PERCUSSION_CHANNEL)
{}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <cstdint>
#include <HyperSonicDrivers/drivers/midi/IMidiChannelVoice.hpp>

namespace HyperSonicDrivers::drivers::midi
{
/**
* Interface for MIDI operation to a specific MIDI Channel
**/
class IMidiChannel
{
public:
explicit IMidiChannel(const uint8_t channel);
virtual ~IMidiChannel() = default;

const uint8_t channel; // MIDI channel number
uint8_t volume = 0; // channel volume
uint8_t pan = 64; // pan, 64=center
uint16_t pitch = 0; // pitch wheel, 0=normal
uint8_t sustain = 0; // sustain pedal value
uint8_t modulation = 0; // modulation pot value
uint8_t program = 0; // instrument number
const bool isPercussion;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <HyperSonicDrivers/drivers/midi/IMidiChannelVoice.hpp>
#include <HyperSonicDrivers/drivers/midi/IMidiChannel.hpp>
#include <cmath>

namespace HyperSonicDrivers::drivers::midi
{
uint8_t IMidiChannelVoice::getChannelNum() const noexcept
{
return m_channel->channel;
}

void IMidiChannelVoice::setVolumes(const uint8_t volume) noexcept
{
m_volume = volume;
m_real_volume = calcVolume_();
}

uint8_t IMidiChannelVoice::calcVolume_() const noexcept
{
return std::min<uint8_t>(static_cast<uint8_t>(m_volume * m_channel->volume / 127), 127);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include <cstdint>

namespace HyperSonicDrivers::drivers::midi
{
class IMidiChannel;

/**
* Interface for Midi Channel Voice message to have a polyphonic MidiChannel.
* this is mono-phonic channel, multiple combination of this gives a polyphonic MidiChannel
**/
class IMidiChannelVoice
{
public:
IMidiChannelVoice() = default;
virtual ~IMidiChannelVoice() = default;

inline IMidiChannel* getChannel() const noexcept { return m_channel; }
uint8_t getChannelNum() const noexcept;
inline uint8_t getNote() const noexcept { return m_note; }
//inline uint8_t getVolume() const noexcept { return m_volume; };
void setVolumes(const uint8_t volume) noexcept;
inline bool isFree() const noexcept { return m_free; }
inline bool isSustain() const noexcept { return m_sustain; };
inline bool isVibrato() const noexcept { return m_vibrato; }

protected:
IMidiChannel* m_channel = nullptr; // MIDI channel
uint8_t m_note = 0; /* note number */
uint8_t m_volume = 0; /* note volume */
uint8_t m_real_volume = 0; /* adjusted note volume */
int16_t m_pitch_factor = 0; /* pitch-wheel value */
bool m_free = true;
bool m_sustain = false; // this are Opl exclusive or are midi?
bool m_vibrato = false; // ""

private:
/// <summary>
/// The volume is between 0-127 as a per MIDI specification.
/// OPLWriter expect a MIDI volume value and converts to OPL value.
/// OPL chips has a volume attenuation (inverted values)
/// range from 0-64 inverted (0 is max, 64 is muted).
/// </summary>
uint8_t calcVolume_() const noexcept;
};

}
Loading

0 comments on commit ad5b0f1

Please sign in to comment.