-- @include constants.txt -- @include track.txt -- @include /koptilnya/libs/utils.txt require("track.txt") require("/koptilnya/libs/utils.txt") local CONSTANTS = require("constants.txt") function byteToHex(byte) return tostring(byte) end MidiPlayer = class("MidiPlayer") function MidiPlayer:initialize() self._startTime = 0 self._buffer = nil self._midiChunksByteLength = nil self._division = 0 self._format = nil self._setIntervalId = false self._tracks = {} self._instruments = {} self._defaultTempo = 120 self._tempo = null self._startTick = 0 self._tick = 0 self._lastTick = null self._inLoop = false self._totalTicks = 0 self._events = {} self._totalEvents = 0 self._eventListeners = {} end function MidiPlayer:loadURL(link) if not http.canRequest() then return end http.get(link, function(data, len) self._buffer = data self:_fileLoaded() end) end function MidiPlayer:_fileLoaded() if not self:isValid() then throw("Invalid MIDI file; should start with MThd") end self:setTempo(self._defaultTempo) self:_parseDivision() self:_parseFormat() self:_parseTracks() end function MidiPlayer:isValid() return string.char(unpack(byteTable(self._buffer, 1, 4))) == "MThd" end function MidiPlayer:setTempo(tempo) self._tempo = tempo end function MidiPlayer:_parseDivision() self._division = tonumber(bytesToHex(byteTable(self._buffer, 13, 2))) end function MidiPlayer:_parseFormat() self._format = tonumber(bytesToHex(byteTable(self._buffer, 9, 2))) end function MidiPlayer:_parseTracks() self._tracks = {} local offset = 1 while offset < #self._buffer do local length = tonumber(bytesToHex(byteTable(self._buffer, offset + 4, 4))) if string.char(unpack(byteTable(self._buffer, offset, 4))) == "MTrk" then table.insert(self._tracks, MidiTrack:new(#self._tracks + 1, string.sub(self._buffer, offset + 8, offset + 8 + length))) end offset = offset + length + 8 end end function MidiPlayer:resetTracks() for _, v in pairs(self._tracks) do v:reset() end end function MidiPlayer:enableTrack(id) self._tracks[id]:enable() end function MidiPlayer:disableTrack(id) self._tracks[id]:disable() end