-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathgb2midi.lua
More file actions
133 lines (112 loc) · 3.48 KB
/
gb2midi.lua
File metadata and controls
133 lines (112 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
-- Note: do not use vba-rr v24, it doesn't work on GB games. use v23 instead.
require("emu2midi")
function GBSoundWriter()
local self = VGMSoundWriter()
-- functions in base class
self.base = ToFunctionTable(self);
-- channel type list
self.CHANNEL_TYPE = {
SQUARE = "square";
WAVEMEMORY = "wavememory";
NOISE = "noise";
};
-- pseudo patch number for noise
self.NOISE_PATCH_NUMBER = {
LONG = 0;
SHORT = 1;
};
self.FRAMERATE = 16777216 / 280896;
-- reset current logging state
self.clear = function(self)
self.base.clear(self)
-- tempo (fixed value)
local bpm = self.FRAMERATE
table.insert(self.scoreGlobal, { 'set_tempo', 0, math.floor(60000000 / bpm) })
end;
-- get MIDI TPQN (integer)
self.getTPQN = function(self)
return 60
end;
-- event conversion: convert patch event for MIDI
-- @param source 'patch_change' event
self.eventPatchToMidi = function(self, event)
return { { 'patch_change', event[2], event[3], event[4] } }
end;
-- get FlMML patch command
-- @param string patch type (wavememory, dpcm, etc.)
-- @param number patch number
-- @return string patch mml text
self.getFlMMLPatchCmd = function(self, patchType, patchNumber)
if patchType == self.CHANNEL_TYPE.SQUARE then
if patchNumber >= 0 and patchNumber <= 3 then
local dutyTable = { 1, 2, 4, 6 }
return string.format("@5@W%d", dutyTable[1 + patchNumber])
else
error(string.format("Unknown patch number '%d' for '%s'", patchNumber, patchType))
end
elseif patchType == self.CHANNEL_TYPE.WAVEMEMORY then
return string.format("@13-%d", patchNumber)
elseif patchType == self.CHANNEL_TYPE.NOISE then
if patchNumber == self.NOISE_PATCH_NUMBER.LONG then
return "@11"
elseif patchNumber == self.NOISE_PATCH_NUMBER.SHORT then
return "@12"
else
error(string.format("Unknown patch number '%d' for '%s'", patchNumber, patchType))
end
else
error(string.format("Unknown patch type '%s'", patchType))
end
end;
-- get FlMML waveform definition MML
-- @return string waveform define mml
self.getFlMMLWaveformDef = function(self)
local mml = ""
for waveChannelType, waveList in pairs(self.waveformList) do
for waveIndex, waveValue in ipairs(waveList) do
if waveChannelType == self.CHANNEL_TYPE.WAVEMEMORY then
mml = mml .. string.format("#WAV13 %d,%s\n", waveIndex - 1, waveValue)
else
error(string.format("Unknown patch type '%s'", waveChannelType))
end
end
end
return mml
end;
self:clear()
return self
end
local writer = GBSoundWriter()
emu.registerafter(function()
local ch = {}
local channels = {}
local snd = sound.get()
ch = snd.square1
ch.type = writer.CHANNEL_TYPE.SQUARE
ch.patch = ch.duty
table.insert(channels, ch)
ch = snd.square2
ch.type = writer.CHANNEL_TYPE.SQUARE
ch.patch = ch.duty
table.insert(channels, ch)
ch = snd.wavememory
ch.type = writer.CHANNEL_TYPE.WAVEMEMORY
ch.patch = writer.bytestohex(ch.waveform)
table.insert(channels, ch)
ch = snd.noise
ch.type = writer.CHANNEL_TYPE.NOISE
ch.midikey = writer.gbNoiseFreqRegToNote(ch.regs.frequency)
ch.patch = (ch.short and writer.NOISE_PATCH_NUMBER.SHORT or writer.NOISE_PATCH_NUMBER.LONG)
table.insert(channels, ch)
writer:write(channels)
end)
_registerexit_firstrun = true
emu.registerexit(function()
if _registerexit_firstrun then
-- vba: without this, we will get an infinite loop on error
_registerexit_firstrun = false
writer:writeTextFile("testVGM.txt")
writer:writeMidiFile("testVGM.mid")
writer:writeFlMMLFile("testVGM.mml")
end
end)