Skip to content

Commit 6d8643f

Browse files
author
dashodanger
committed
Initial Emu de MIDI commit
1 parent dd8464f commit 6d8643f

37 files changed

+5868
-4
lines changed

docs/licenses/License Attribution.txt

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ AlmostEquals Google Test Framework Component - Copyright (c) 2005 Google, Inc.
1616

1717
Blasphemer (various assets) - Copyright (c) 2021 Contributors to the Blasphemer project
1818

19+
Emu de MIDI library - Copyright (C) 2004 Mitsutaka Okazaki
20+
1921
FMMIDI library - Copyright (c) 2003-2006 yuno
2022

2123
Freedoom (various assets) - Copyright (c) 2001-2019 Contributors to the Freedoom project

libraries/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ else()
99
add_subdirectory(gl4es)
1010
endif()
1111
add_subdirectory(hmm)
12+
add_subdirectory(libemidi)
1213
add_subdirectory(libRAD)
1314
add_subdirectory(libvwad)
1415
add_subdirectory(lua)

libraries/libemidi/CMakeLists.txt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
##########################################
2+
# Emu de MIDI
3+
##########################################
4+
5+
add_library(libemidi
6+
source/CEnvelope.cpp
7+
source/device/emu2413.c
8+
source/device/emu2212.c
9+
source/device/emu2149.c
10+
source/CMIDIModule.cpp
11+
source/CSccDevice.cpp
12+
source/CPSGDrum.cpp
13+
source/CMIDIMessage.cpp
14+
source/COpllDevice.cpp
15+
source/CSMFPlay.cpp
16+
)
17+
18+
target_include_directories(libemidi PUBLIC ./source)

libraries/libemidi/license.txt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Copyright (C) Mitsutaka Okazaki 2004
2+
3+
This software is provided 'as-is', without any express or implied warranty.
4+
In no event will the authors be held liable for any damages arising from
5+
the use of this software.
6+
7+
Permission is granted to anyone to use this software for any purpose,
8+
including commercial applications, and to alter it and redistribute it
9+
freely, subject to the following restrictions:
10+
11+
1. The origin of this software must not be misrepresented; you must not
12+
claim that you wrote the original software. If you use this software
13+
in a product, an acknowledgment in the product documentation would be
14+
appreciated but is not required.
15+
2. Altered source versions must be plainly marked as such, and must not
16+
be misrepresented as being the original software.
17+
3. This notice may not be removed or altered from any source distribution.
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include "CEnvelope.hpp"
2+
3+
#if defined(_MSC_VER)
4+
#if defined(_DEBUG)
5+
#define new new (_CLIENT_BLOCK, __FILE__, __LINE__)
6+
#endif
7+
#endif
8+
9+
using namespace dsa;
10+
11+
#define GETA_BITS 20
12+
#define MAX_CNT (1 << (GETA_BITS + 8))
13+
14+
uint32_t CEnvelope::_CalcSpeed(uint32_t ms)
15+
{
16+
if (ms == 0)
17+
return MAX_CNT;
18+
else
19+
return (MAX_CNT / (ms * m_clock / 1000)) * m_rate;
20+
}
21+
22+
CEnvelope::CEnvelope(uint32_t ch) : m_ch(ch)
23+
{
24+
m_ci = new ChannelInfo[ch];
25+
}
26+
27+
CEnvelope::~CEnvelope()
28+
{
29+
delete[] m_ci;
30+
}
31+
32+
void CEnvelope::Reset(uint32_t clock, uint32_t rate)
33+
{
34+
m_rate = rate;
35+
m_clock = clock;
36+
m_cnt = 0;
37+
m_inc = (MAX_CNT / m_clock) * m_rate;
38+
for (uint32_t ch = 0; ch < m_ch; ch++)
39+
{
40+
m_ci[ch].value = 0;
41+
m_ci[ch].speed = 0;
42+
m_ci[ch].state = FINISH;
43+
}
44+
}
45+
46+
bool CEnvelope::Update()
47+
{
48+
49+
m_cnt += m_inc;
50+
if (m_cnt < MAX_CNT)
51+
return false;
52+
m_cnt &= 0xFFFFFFF;
53+
54+
for (uint32_t ch = 0; ch < m_ch; ch++)
55+
{
56+
57+
switch (m_ci[ch].state)
58+
{
59+
case ATTACK:
60+
if (m_ci[ch].speed + m_ci[ch].value < MAX_CNT)
61+
m_ci[ch].value += m_ci[ch].speed;
62+
else
63+
{
64+
m_ci[ch].value = MAX_CNT;
65+
m_ci[ch].speed = _CalcSpeed(m_ci[ch].param.dr);
66+
m_ci[ch].state = DECAY;
67+
}
68+
break;
69+
case DECAY:
70+
if ((m_ci[ch].value > m_ci[ch].speed) && (m_ci[ch].value > (uint32_t)m_ci[ch].param.sl << GETA_BITS))
71+
{
72+
m_ci[ch].value -= m_ci[ch].speed;
73+
}
74+
else
75+
{
76+
m_ci[ch].speed = _CalcSpeed(m_ci[ch].param.sr);
77+
m_ci[ch].value = (uint32_t)m_ci[ch].param.sl << GETA_BITS;
78+
m_ci[ch].state = SUSTINE;
79+
}
80+
break;
81+
case SUSTINE:
82+
if ((m_ci[ch].speed > m_ci[ch].value))
83+
{
84+
m_ci[ch].value = 0;
85+
m_ci[ch].state = FINISH;
86+
}
87+
else
88+
{
89+
m_ci[ch].value -= m_ci[ch].speed;
90+
}
91+
break;
92+
case RELEASE:
93+
if ((m_ci[ch].speed > m_ci[ch].value))
94+
{
95+
m_ci[ch].value = 0;
96+
m_ci[ch].state = FINISH;
97+
}
98+
else
99+
{
100+
m_ci[ch].value -= m_ci[ch].speed;
101+
}
102+
break;
103+
default:
104+
break;
105+
}
106+
}
107+
108+
return true;
109+
}
110+
111+
void CEnvelope::KeyOn(uint32_t ch)
112+
{
113+
m_ci[ch].value = 0;
114+
m_ci[ch].speed = _CalcSpeed(m_ci[ch].param.ar);
115+
m_ci[ch].state = ATTACK;
116+
}
117+
118+
void CEnvelope::KeyOff(uint32_t ch)
119+
{
120+
m_ci[ch].state = RELEASE;
121+
m_ci[ch].speed = _CalcSpeed(m_ci[ch].param.rr);
122+
}
123+
124+
void CEnvelope::SetParam(uint32_t ch, const Param &param)
125+
{
126+
m_ci[ch].param = param;
127+
}
128+
129+
uint32_t CEnvelope::GetValue(uint32_t ch) const
130+
{
131+
return m_ci[ch].value >> GETA_BITS;
132+
}
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef __CENVELOPE_HPP__
2+
#define __CENVELOPE_HPP__
3+
4+
#include <stdint.h>
5+
6+
namespace dsa
7+
{
8+
9+
class CEnvelope
10+
{
11+
public:
12+
enum EnvState
13+
{
14+
SETTLE,
15+
ATTACK,
16+
DECAY,
17+
SUSTINE,
18+
RELEASE,
19+
FINISH
20+
};
21+
struct Param
22+
{
23+
uint32_t ar, dr, sl, sr, rr;
24+
};
25+
struct ChannelInfo
26+
{
27+
EnvState state;
28+
uint32_t speed;
29+
uint32_t value;
30+
Param param;
31+
};
32+
33+
private:
34+
uint32_t m_ch;
35+
ChannelInfo *m_ci;
36+
uint32_t m_clock;
37+
uint32_t m_rate;
38+
uint32_t m_cnt;
39+
uint32_t m_inc;
40+
uint32_t _CalcSpeed(uint32_t ms);
41+
42+
public:
43+
CEnvelope(uint32_t ch);
44+
~CEnvelope();
45+
void Reset(uint32_t clock = 44100, uint32_t rate = 60);
46+
void KeyOn(uint32_t ch);
47+
void KeyOff(uint32_t ch);
48+
bool Update();
49+
void SetParam(uint32_t ch, const Param &param);
50+
uint32_t GetValue(uint32_t ch) const;
51+
};
52+
53+
} // namespace dsa
54+
#endif
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "CMIDIMessage.hpp"
2+
3+
using namespace dsa;
4+
5+
CMIDIMsg::CMIDIMsg(MsgType type, int ch, uint8_t data1, uint8_t data2 )
6+
: m_type(type), m_ch(ch), m_data1(data1), m_data2(data2)
7+
{
8+
}
9+
10+
CMIDIMsg &CMIDIMsg::operator=(const CMIDIMsg &arg)
11+
{
12+
m_type = arg.m_type;
13+
m_ch = arg.m_ch;
14+
m_data1 = arg.m_data1;
15+
m_data2 = arg.m_data2;
16+
return (*this);
17+
}
18+
19+
CMIDIMsg::CMIDIMsg(const CMIDIMsg &arg)
20+
{
21+
m_type = arg.m_type;
22+
m_ch = arg.m_ch;
23+
m_data1 = arg.m_data1;
24+
m_data2 = arg.m_data2;
25+
}
26+
27+
CMIDIMsg::~CMIDIMsg()
28+
{
29+
}
30+
31+
const char *CMIDIMsg::c_str() const
32+
{
33+
const char *text[] = {// CANNEL
34+
"NOTE_OFF", "NOTE_ON", "POLYPHONIC_KEY_PRESSURE", "CONTROL_CHANGE", "PROGRAM_CHANGE",
35+
"CHANNEL_PRESSURE", "PITCH_BEND_CHANGE",
36+
// MODE
37+
"ALL_SOUND_OFF", "RESET_ALL_CONTROLLERS", "LOCAL_CONTROL", "ALL_NOTES_OFF", "OMNI_OFF",
38+
"OMNI_ON", "POLYPHONIC_OPERATION", "MONOPHONIC_OPERATION",
39+
// SYSTEM
40+
"SYSTEM_EXCLUSIVE", "MTC_QUARTER_FRAME", "SONG_POSITION_POINTER", "SONG_SELECT",
41+
"TUNE_REQUEST",
42+
// REALTIME
43+
"REALTIME_CLOCK", "REALTIME_TICK", "REALTIME_START", "REALTIME_CONTINUE", "REALTIME_STOP",
44+
"REALTIME_ACTIVE_SENSE", "REALTIME_SYSTEM_RESET", "UNKNOWN_MESSAGE"};
45+
return text[m_type];
46+
}
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#ifndef __MIDI_MESSAGE_HPP__
2+
#define __MIDI_MESSAGE_HPP__
3+
#include <stdint.h>
4+
#include <string.h>
5+
6+
#include <deque>
7+
#include <string>
8+
9+
namespace dsa
10+
{
11+
12+
// MIDI Msgs (Channel or exclusive Msg)
13+
class CMIDIMsg
14+
{
15+
public:
16+
enum MsgType
17+
{
18+
// CHANNEL Msg
19+
NOTE_OFF = 0, // 8n #note #velo
20+
NOTE_ON, // 9n #note #velo
21+
POLYPHONIC_KEY_PRESSURE, // An #note #data
22+
CONTROL_CHANGE, // Bn #ctrl #data
23+
PROGRAM_CHANGE, // Cn #data
24+
CHANNEL_PRESSURE, // Dn #data
25+
PITCH_BEND_CHANGE, // En #data #data
26+
// MODE Msg
27+
ALL_SOUND_OFF, // Bn 78 00
28+
RESET_ALL_CONTROLLERS, // Bn 79 00
29+
LOCAL_CONTROL, // Bn 7A #data
30+
ALL_NOTES_OFF, // Bn 7B 00
31+
OMNI_OFF, // Bn 7C 00
32+
OMNI_ON, // Bn 7D 00
33+
POLYPHONIC_OPERATION, // Bn 7E 00
34+
MONOPHONIC_OPERATION, // Bn 7F 00
35+
// SYSTEM Msg
36+
SYSTEM_EXCLUSIVE, // F0 ... F7
37+
MTC_QUARTER_FRAME, // F1 #data
38+
SONG_POSITION_POINTER, // F2 #data #data
39+
SONG_SELECT, // F3 #data
40+
TUNE_REQUEST, // F6
41+
// REALTIME Msg
42+
REALTIME_CLOCK, // F8
43+
REALTIME_TICK, // F9
44+
REALTIME_START, // FA
45+
REALTIME_CONTINUE, // FB
46+
REALTIME_STOP, // FC
47+
REALTIME_ACTIVE_SENSE, // FE
48+
REALTIME_SYSTEM_RESET, // FF
49+
UNKNOWN_MESSAGE
50+
};
51+
52+
MsgType m_type; // The Msg identifier
53+
uint32_t m_ch; // The channel
54+
uint8_t m_data1;
55+
uint8_t m_data2;
56+
CMIDIMsg(MsgType type = UNKNOWN_MESSAGE, int ch = 0, uint8_t data1 = 0, uint8_t data2 = 0);
57+
CMIDIMsg(const CMIDIMsg &);
58+
~CMIDIMsg();
59+
CMIDIMsg &operator=(const CMIDIMsg &arg);
60+
const char *c_str() const;
61+
};
62+
63+
} // namespace dsa
64+
65+
#endif

0 commit comments

Comments
 (0)