Skip to content

Instantly share code, notes, and snippets.

@HertzDevil
Last active October 25, 2016 09:27
Show Gist options
  • Save HertzDevil/6f1705e23635067ef855f2c1da45fd05 to your computer and use it in GitHub Desktop.
Save HertzDevil/6f1705e23635067ef855f2c1da45fd05 to your computer and use it in GitHub Desktop.
how to add muting support to any MML compiler
local MGCInts = require "mgcints"
local engine = MGCInts.Default.Engine(4, "test driver")
local macros = engine:getCommandTable()
local builder = MGCInts.MML.CmdBuilder()
-- this one-liner gives everything we need
engine:importFeature(require "mgcints.mml.feature.mute")
-- extra: show information about the feature (will be available from the frontend)
print(require "mgcints.mml.feature.mute":description())
for k, v in pairs {c = 0, d = 2, e = 4, f = 5, g = 7, a = 9, b = 11} do
local cmd = builder:setHandler(function (ch)
if not ch:isMuted() then -- this method is provided by the feature
ch:addChunk((" Note: %d (%s)\n"):format(60 + v, k:upper()))
end
end):make()
macros:addCommand(k, cmd)
macros:addCommand(k:upper(), cmd)
end
builder:setTable(macros)
builder:setHandler(function (ch, v)
ch:addChunk((" Volume: %d\n"):format(v))
end):param "Uint8":optional "100":make "v"
engine:getChannelClass():beforeCallback(function (self)
self:addChunk("Channel " .. self:getID() .. ": \n")
end)
engine:getChannelClass():afterCallback(function (self)
self:addChunk "End of data\n\n"
end)
engine:setInserter(function (rom, song, track)
rom:write("MGCInts test\nTrack: " .. track .. "\n\n")
song:doAll(function (ch)
rom:write(ch:getStream():build())
end)
end)
-- m1 mutes, m0 unmutes
-- volume commands apply even when muted (in some examples like amk, volume slide
-- command convert to single volume commands while the channel is muted)
local mmlstr = [[
!2 m1 v80
!1 v50 cd !23 eF m0
!1234 gAb m1
!4 v100 cde
]]
MGCInts.Music.Compiler.processFile(engine, mmlstr, io.stdout, 1)
-- our muting feature class
local cls = {}
-- to be safe and avoid name conflicts we make this property inside-out
local ch_muted = setmetatable({}, {__mode = "k"})
local builder = require "mgcints.mml.command.builder" ()
-- single table for convenience
local CMDS = {
mute = { -- this is the feature's command identifier
builder:setHandler(function (ch, x)
ch_muted[ch] = x
end):param "Bool":make(), "m"
},
}
-- feature name
function cls.getName (_)
return "Channel muting"
end
-- accessor for the command class (i.e. function returned by the builder)
function cls.getCommandType (_, name)
local t = CMDS[name]
return t and t[1]
end
-- accessor for the command name (i.e. "m")
function cls.getCommandName (_, name)
local t = CMDS[name]
return t and t[2]
end
-- iterates through the identifiers (in this case only "mute")
function cls.identifiers (_)
return coroutine.wrap(function ()
for k in pairs(CMDS) do coroutine.yield(k) end
end)
end
-- directly inject this method into the engine's channel class
function cls.channelMethods (_)
return {isMuted = function (ch)
return ch_muted[ch]
end}
end
-- unmute every channel before compiling
function cls.getCallback (cself, kind, when)
if kind == "channel" and when == "before" then
return function (ch)
ch_muted[ch] = false
end
end
return function () end
end
return require "mgcints.util.class" (cls, require "mgcints.mml.feature")
Feature name: Channel muting
Supported commands:
- mute: m
Song methods:
Channel methods:
- isMuted
MGCInts test
Track: 1
Channel 1:
Volume: 50
Note: 60 (C)
Note: 62 (D)
Note: 67 (G)
Note: 69 (A)
Note: 71 (B)
End of data
Channel 2:
Volume: 80
Note: 67 (G)
Note: 69 (A)
Note: 71 (B)
End of data
Channel 3:
Note: 64 (E)
Note: 65 (F)
Note: 67 (G)
Note: 69 (A)
Note: 71 (B)
End of data
Channel 4:
Note: 67 (G)
Note: 69 (A)
Note: 71 (B)
Volume: 100
End of data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment