Created
November 26, 2020 19:03
-
-
Save rymdolle/84e852fbeb9571351ab0e8f01fea4479 to your computer and use it in GitHub Desktop.
dtxplorer MIDI remap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
-module(midi). | |
-export([parse_string/1]). | |
-export([save_file/2]). | |
-export([events/1]). | |
-export([varint/1]). | |
-export([varinte/1]). | |
main([File, Out]) -> | |
{ok, Data} = file:read_file(File), | |
Chunks = parse_string(Data), | |
save_file(Out, [events(Chunk) || Chunk <- Chunks]); | |
main(_) -> | |
Script = filename:basename(escript:script_name()), | |
io:format("Usage:\n"), | |
io:format(" ~s INPUT_FILE OUTPUT_FILE\n\n", [Script]). | |
parse_string(String) -> | |
[[Chunk, Data] || <<Chunk:4/bytes, Size:32, Data:Size/bytes>> <= String]. | |
save_file(File, Chunks) -> | |
file:write_file(File, [[Chunk, <<(iolist_size(Data)):32>>, Data] || [Chunk, Data] <- Chunks]). | |
events([Type = <<"MTrk">>, Chunk]) -> | |
io:format("<track start>\n", []), | |
[Type, event(Chunk)]; | |
events([Type = <<"MThd">>, Chunk]) -> | |
<<Format:16, Tracks:16, Division:16>> = Chunk, | |
io:format("<head> f:~b t:~b d:~b\n", [Format, Tracks, Division]), | |
[Type, Chunk]. | |
event(Data) -> | |
{Delta, Rest} = varint(Data), | |
event(Delta, Rest). | |
%% meta end event | |
event(Delta, Event = <<16#ff, 16#2f, 0>>) -> | |
io:format("<track end>\n", []), | |
[varinte(Delta), Event]; | |
%% meta-event | |
event(Delta, <<16#ff, Type, Buffer/bytes>>) -> | |
{Data, Rest} = data(Buffer), | |
io:format("<meta> ~b: 0x~2.16.0b ~p\n", [Delta, Type, Data]), | |
[[varinte(Delta), 16#ff, Type, varinte(byte_size(Data)), Data] | event(Rest)]; | |
%% sysex-event | |
event(Delta, <<16#f0, Buffer/bytes>>) -> | |
{Data, Rest} = data(Buffer), | |
io:format("<sysx> ~b: ~p\n", [Delta, Data]), | |
[[varinte(Delta), 16#f0, varinte(byte_size(Data)), Data] | event(Rest)]; | |
%% sysex-event | |
event(Delta, <<16#f7, Buffer/bytes>>) -> | |
{Data, Rest} = data(Buffer), | |
io:format("<sysx> ~b: ~p\n", [Delta, Data]), | |
[[varinte(Delta), 16#f7, varinte(byte_size(Data)), Data] | event(Rest)]; | |
%% Note off | |
event(Delta, <<16#8:4, Channel:4, Key, Velocity, Buffer/bytes>>) -> | |
NewKey = dtx_remap(Key), | |
if Key /= NewKey -> | |
io:format("<noff> ~5.10.0b: 0x~2.16.0b => 0x~2.16.0b [C:~2.10.0b]\n", | |
[Delta, Key, NewKey, Channel+1]); | |
true -> ok | |
end, | |
[[varinte(Delta), <<16#8:4, Channel:4>>, NewKey, Velocity] | event(Buffer)]; | |
%% Note on | |
event(Delta, <<16#9:4, Channel:4, Key, Velocity, Buffer/bytes>>) -> | |
NewKey = dtx_remap(Key), | |
if Key /= NewKey -> | |
io:format("<noff> ~5.10.0b: 0x~2.16.0b => 0x~2.16.0b [C:~2.10.0b]\n", | |
[Delta, Key, NewKey, Channel+1]); | |
true -> ok | |
end, | |
[[varinte(Delta), <<16#9:4, Channel:4>>, NewKey, Velocity] | event(Buffer)]; | |
%% Polyphonic key pressure | |
event(Delta, <<16#a:4, Channel:4, Key, Pressure, Buffer/bytes>>) -> | |
%%io:format("<poly> ~b: 0x~2.16.0b\n", [Delta, Key]), | |
[[varinte(Delta), <<16#a:4, Channel:4>>, Key, Pressure] | event(Buffer)]; | |
%% Controller change | |
event(Delta, <<16#b:4, Channel:4, Number, Value, Buffer/bytes>>) -> | |
%%io:format("<ctrl> ~b: 0x~2.16.0b\n", [Delta, Number]), | |
[[varinte(Delta), <<16#b:4, Channel:4>>, Number, Value] | event(Buffer)]; | |
%% Program change | |
event(Delta, <<16#c:4, Channel:4, ProgramNumber, Buffer/bytes>>) -> | |
io:format("<prog> ~b: 0x~2.16.0b\n", [Delta, ProgramNumber]), | |
[[varinte(Delta), <<16#c:4, Channel:4>>, ProgramNumber] | event(Buffer)]; | |
%% Channel key pressure | |
event(Delta, <<16#d:4, Channel:4, Pressure, Buffer/bytes>>) -> | |
io:format("<pres> ~b: 0x~2.16.0b\n", [Delta, Pressure]), | |
[[varinte(Delta), <<16#d:4, Channel:4>>, Pressure] | event(Buffer)]; | |
%% Pitch bend | |
event(Delta, <<16#e:4, Channel:4, LSB, MSB, Buffer/bytes>>) -> | |
%%io:format("<pitc> ~b: 0x~2.16.0b\n", [Delta]), | |
[[varinte(Delta), <<16#e:4, Channel:4>>, LSB, MSB] | event(Buffer)]. | |
dtx_remap(31) -> 38; % G0 Snare | |
dtx_remap(37) -> 37; % C#1 Cross Stick | |
dtx_remap(34) -> 34; % A#0 Rim Shot | |
dtx_remap(48) -> 50; % C2 Hi Tom | |
dtx_remap(47) -> 47; % B1 Mid Tom | |
dtx_remap(43) -> 45; % G1 Lo Tom | |
dtx_remap(51) -> 51; % D#2 Ride bow | |
dtx_remap(52) -> 53; % E2 Ride edge | |
dtx_remap(49) -> 49; % C#2 Crash | |
dtx_remap(57) -> 57; % A2 Crash edge | |
dtx_remap(46) -> 46; % A#1 Hi-hat open | |
dtx_remap(42) -> 42; % F#1 Hi-hat closed | |
dtx_remap(44) -> 44; % G#1 Hi-hat pedal CLOSE | |
dtx_remap(46) -> 44; % A#1 Hi-hat pedal SPLASH | |
dtx_remap(33) -> 36; % A0 Bass Drum | |
dtx_remap(55) -> 52; % G2 China Lo | |
dtx_remap(Key) -> | |
Key. | |
data(Data) -> | |
{Size, Rest} = varint(Data), | |
<<Ret:Size/bytes, Rest2/bytes>> = Rest, | |
{Ret, Rest2}. | |
varint(Data) -> | |
varint(Data, 0). | |
varint(<<0:1, I:7, Rest/bytes>>, Acc) -> | |
{Acc bsl 7 + I, Rest}; | |
varint(<<1:1, I:7, Rest/bytes>>, Acc) -> | |
varint(Rest, Acc bsl 7 + I). | |
varinte(N) -> | |
varinte(N bsr 7, N band 16#7f). | |
varinte(0, Acc) when Acc band 16#80 > 0 -> | |
<<(Acc band 16#ff), (varinte(0, Acc bsr 8))/bytes>>; | |
varinte(0, Acc) -> | |
<<(Acc band bnot 16#80)>>; | |
varinte(N, Acc) when Acc =< 16#ffffff -> | |
varinte(N bsr 7, Acc bsl 8 + (N band 16#7f bor 16#80)). | |
-ifdef(TEST). | |
-include_lib("eunit/include/eunit.hrl"). | |
varint_data() -> | |
[ | |
{<<16#00>>, 16#00}, % 0 | |
{<<16#7F>>, 16#7F}, % 127 | |
{<<16#81_00:16>>, 16#80}, % 128 | |
{<<16#87_68:16>>, 16#03_E8}, % 1000 | |
{<<16#BD_84_40:24>>, 16#0F_42_40}, % 1000000 | |
{<<16#FF_FF_FF_7F:32>>, 16#0F_FF_FF_FF} % 268435455 | |
]. | |
varint_test_() -> | |
Values = varint_data(), | |
[?_assertMatch({Result, <<>>}, varint(Data)) || {Data, Result} <- Values]. | |
varinte_test_() -> | |
Values = varint_data(), | |
[?_assertMatch(Result, varinte(Data)) || {Result, Data} <- Values]. | |
-endif. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment