Skip to content

Commit 18204f7

Browse files
fix: fix bugs pitch wheel packing, channel pressure and clamp return, add unit tests
1 parent 2fa280c commit 18204f7

File tree

3 files changed

+142
-4
lines changed

3 files changed

+142
-4
lines changed

src/el/midi.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ static int f_pitch (lua_State* L)
107107
PackedMessage msg = { .packed = 0x00 };
108108
msg.data.byte1 = 0xE0 | (uint8_t) (lua_tointeger (L, 1) - 1);
109109
msg.data.byte2 = (uint8_t) (position & 127);
110-
msg.data.byte2 = (uint8_t) ((position >> 7) & 127);
111-
msg.data.byte2 = 0x00;
110+
msg.data.byte3 = (uint8_t) ((position >> 7) & 127);
112111
lua_pushinteger (L, msg.packed);
113112
return 1;
114113
}
@@ -134,7 +133,7 @@ static int f_aftertouch (lua_State* L)
134133
static int f_channelpressure (lua_State* L)
135134
{
136135
lua_pushinteger (L, 0x00);
137-
return f_msg3bytes (L, 0x00);
136+
return f_msg3bytes (L, 0xD0);
138137
}
139138

140139
/// Make an all notes off message.
@@ -247,7 +246,7 @@ static int f_clamp (lua_State* L)
247246
else if (value > 127)
248247
value = 127;
249248
lua_pushinteger (L, value);
250-
return 0;
249+
return 1;
251250
}
252251

253252
static const luaL_Reg midi_f[] = {

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ add_test(NAME "LinearFadeTest" COMMAND test_element --run_test=LinearFadeTest)
3131
add_test(NAME "MidiChannelMapTest" COMMAND test_element --run_test=MidiChannelMapTest)
3232
add_test(NAME "MidiClockTest" COMMAND test_element --run_test=MidiClockTest)
3333
add_test(NAME "MidiProgramMapTests" COMMAND test_element --run_test=MidiProgramMapTests)
34+
add_test(NAME "MidiScriptTests" COMMAND test_element --run_test=MidiScriptTests)
3435
add_test(NAME "NodeFactoryTests" COMMAND test_element --run_test=NodeFactoryTests)
3536
add_test(NAME "NodeObjectTests" COMMAND test_element --run_test=NodeObjectTests)
3637
add_test(NAME "NodeTests" COMMAND test_element --run_test=NodeTests)

test/scripting/midiscripttest.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#include <boost/test/unit_test.hpp>
2+
#include <boost/test/data/test_case.hpp>
3+
#include "luatest.hpp"
4+
5+
BOOST_AUTO_TEST_SUITE (MidiScriptTests)
6+
7+
namespace bdata = boost::unit_test::data;
8+
using JuceCounterpart = std::function<juce::MidiMessage()>;
9+
10+
struct LuaMidiTestCase {
11+
std::string luaMethodCall;
12+
JuceCounterpart juceCounterpart;
13+
bool shouldCheckTheSecondByte = true;
14+
bool shouldCheckThirdByte = true;
15+
16+
friend std::ostream& operator<< (std::ostream& os, const LuaMidiTestCase& testCase)
17+
{
18+
os << "{ luaMethodCall: \"" << testCase.luaMethodCall << "\", ... } ";
19+
return os;
20+
}
21+
};
22+
23+
BOOST_DATA_TEST_CASE (
24+
luaSimpleBindigs,
25+
bdata::make (std::initializer_list<LuaMidiTestCase> {
26+
{ .luaMethodCall = "return midi.controller(1, 7, 120)",
27+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::controllerEvent (1, 7, 120); } },
28+
29+
{ .luaMethodCall = "return midi.noteon(1, 60, 100)",
30+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::noteOn (1, 60, (uint8_t) 100); } },
31+
32+
{ .luaMethodCall = "return midi.noteoff(1, 60)",
33+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::noteOff (1, 60); } },
34+
35+
{ .luaMethodCall = "return midi.program(1, 5)",
36+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::programChange (1, 5); },
37+
.shouldCheckThirdByte = false },
38+
39+
{ .luaMethodCall = "return midi.pitch(1, 8192)",
40+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::pitchWheel (1, 8192); } },
41+
42+
{ .luaMethodCall = "return midi.aftertouch(1, 60, 64)",
43+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::aftertouchChange (1, 60, 64); } },
44+
45+
{ .luaMethodCall = "return midi.channelpressure(1, 45)",
46+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::channelPressureChange (1, 45); },
47+
.shouldCheckThirdByte = false },
48+
49+
{ .luaMethodCall = "return midi.allnotesoff(1)",
50+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::allNotesOff (1); } },
51+
52+
{ .luaMethodCall = "return midi.allsoundsoff(1)",
53+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::allSoundOff (1); } },
54+
55+
{ .luaMethodCall = "return midi.allcontrollersoff(1)",
56+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::allControllersOff (1); } },
57+
58+
{ .luaMethodCall = "return midi.clock()",
59+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::midiClock(); },
60+
.shouldCheckTheSecondByte = false,
61+
.shouldCheckThirdByte = false },
62+
63+
{ .luaMethodCall = "return midi.start()",
64+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::midiStart(); },
65+
.shouldCheckTheSecondByte = false,
66+
.shouldCheckThirdByte = false },
67+
68+
{ .luaMethodCall = "return midi.stop()",
69+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::midiStop(); },
70+
.shouldCheckTheSecondByte = false,
71+
.shouldCheckThirdByte = false },
72+
73+
{ .luaMethodCall = "return midi.continue()",
74+
.juceCounterpart = []() -> juce::MidiMessage { return juce::MidiMessage::midiContinue(); },
75+
.shouldCheckTheSecondByte = false,
76+
.shouldCheckThirdByte = false },
77+
}),
78+
testData)
79+
{
80+
LuaFixture fix;
81+
sol::state_view lua (fix.luaState());
82+
lua.script ("midi = require('el.midi')");
83+
84+
int64_t packed = lua.script (testData.luaMethodCall);
85+
86+
auto expected = testData.juceCounterpart();
87+
BOOST_CHECK_EQUAL (uint8_t (packed), expected.getRawData()[0]);
88+
if (testData.shouldCheckTheSecondByte) {
89+
BOOST_CHECK_EQUAL (uint8_t (packed >> 8), expected.getRawData()[1]);
90+
} else {
91+
BOOST_CHECK_EQUAL (uint8_t (packed >> 8), 0);
92+
}
93+
if (testData.shouldCheckThirdByte) {
94+
BOOST_CHECK_EQUAL (uint8_t (packed >> 16), expected.getRawData()[2]);
95+
} else {
96+
BOOST_CHECK_EQUAL (uint8_t (packed >> 16), 0);
97+
}
98+
}
99+
100+
BOOST_AUTO_TEST_CASE (test_tohertz)
101+
{
102+
LuaFixture fix;
103+
sol::state_view lua (fix.luaState());
104+
lua.script ("midi = require('el.midi')");
105+
106+
for (int note = 0; note <= 127; ++note) {
107+
std::string script = "return midi.tohertz(" + std::to_string (note) + ")";
108+
double luaFreq = lua.script (script);
109+
110+
double juceFreq = juce::MidiMessage::getMidiNoteInHertz (note);
111+
112+
BOOST_CHECK_CLOSE (luaFreq, juceFreq, 0.001);
113+
}
114+
}
115+
116+
BOOST_AUTO_TEST_CASE (test_clamp)
117+
{
118+
LuaFixture fix;
119+
sol::state_view lua (fix.luaState());
120+
121+
lua.script ("midi = require('el.midi')");
122+
123+
int64_t resultNormal = lua.script ("return midi.clamp(64)");
124+
BOOST_CHECK_EQUAL (resultNormal, 64.0);
125+
126+
int64_t resultMin = lua.script ("return midi.clamp(0)");
127+
BOOST_CHECK_EQUAL (resultMin, 0);
128+
129+
int64_t resultMax = lua.script ("return midi.clamp(127)");
130+
BOOST_CHECK_EQUAL (resultMax, 127);
131+
132+
int64_t resultUnder = lua.script ("return midi.clamp(-50)");
133+
BOOST_CHECK_EQUAL (resultUnder, 0);
134+
135+
int64_t resultOver = lua.script ("return midi.clamp(200)");
136+
BOOST_CHECK_EQUAL (resultOver, 127);
137+
}
138+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)