forked from openrs2/openrs2
It's basically a simplified MIDI file (lacks support for SMPTE and most meta/system messages) encoded in a smarter way. This implementation can decode anything in the 550 cache, convert it to MIDI format and then re-encode it bit-for-bit identically to the original. Signed-off-by: Graham <gpe@openrs2.org>bzip2
parent
739d5faea7
commit
c79ce805df
@ -0,0 +1,538 @@ |
|||||||
|
package org.openrs2.cache.midi |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf |
||||||
|
import io.netty.buffer.ByteBufAllocator |
||||||
|
import org.openrs2.buffer.readVarInt |
||||||
|
import org.openrs2.buffer.writeVarInt |
||||||
|
import javax.sound.midi.MetaMessage |
||||||
|
import javax.sound.midi.MidiEvent |
||||||
|
import javax.sound.midi.Sequence |
||||||
|
import javax.sound.midi.ShortMessage |
||||||
|
|
||||||
|
public object Song { |
||||||
|
private const val NOTE_ON = 0 |
||||||
|
private const val NOTE_OFF = 1 |
||||||
|
private const val CONTROL_CHANGE = 2 |
||||||
|
private const val PITCH_WHEEL_CHANGE = 3 |
||||||
|
private const val CHANNEL_PRESSURE_CHANGE = 4 |
||||||
|
private const val KEY_PRESSURE_CHANGE = 5 |
||||||
|
private const val PROGRAM_CHANGE = 6 |
||||||
|
private const val END_OF_TRACK = 7 |
||||||
|
private const val SET_TEMPO = 23 |
||||||
|
|
||||||
|
private const val BANK_SELECT_MSB = 0 |
||||||
|
private const val BANK_SELECT_LSB = 32 |
||||||
|
private const val MODULATION_WHEEL_MSB = 1 |
||||||
|
private const val MODULATION_WHEEL_LSB = 33 |
||||||
|
private const val CHANNEL_VOLUME_MSB = 7 |
||||||
|
private const val CHANNEL_VOLUME_LSB = 39 |
||||||
|
private const val PAN_MSB = 10 |
||||||
|
private const val PAN_LSB = 42 |
||||||
|
private const val NON_REGISTERED_MSB = 99 |
||||||
|
private const val NON_REGISTERED_LSB = 98 |
||||||
|
private const val REGISTERED_MSB = 101 |
||||||
|
private const val REGISTERED_LSB = 100 |
||||||
|
private const val DAMPER = 64 |
||||||
|
private const val PORTAMENTO = 65 |
||||||
|
private const val ALL_SOUND_OFF = 120 |
||||||
|
private const val RESET_CONTROLLERS = 121 |
||||||
|
private const val ALL_NOTES_OFF = 123 |
||||||
|
|
||||||
|
private const val META_END_OF_TRACK = 47 |
||||||
|
private const val META_SET_TEMPO = 81 |
||||||
|
|
||||||
|
private const val CONTROLLERS = 128 |
||||||
|
|
||||||
|
public fun read(buf: ByteBuf): Sequence { |
||||||
|
buf.markReaderIndex() |
||||||
|
|
||||||
|
val tracks = buf.getUnsignedByte(buf.writerIndex() - 3).toInt() |
||||||
|
val division = buf.getUnsignedShort(buf.writerIndex() - 2) |
||||||
|
|
||||||
|
if (division and 0x8000 != 0) { |
||||||
|
throw IllegalArgumentException("SMPTE unsupported") |
||||||
|
} |
||||||
|
|
||||||
|
val sequence = Sequence(Sequence.PPQ, division and 0x7FFF) |
||||||
|
|
||||||
|
var events = 0 |
||||||
|
var tempoChanges = 0 |
||||||
|
var noteOnEvents = 0 |
||||||
|
var noteOffEvents = 0 |
||||||
|
var controllerEvents = 0 |
||||||
|
var pitchWheelEvents = 0 |
||||||
|
var channelPressureEvents = 0 |
||||||
|
var keyPressureEvents = 0 |
||||||
|
var bankSelectEvents = 0 |
||||||
|
|
||||||
|
for (i in 0 until tracks) { |
||||||
|
while (true) { |
||||||
|
events++ |
||||||
|
|
||||||
|
val statusAndChannel = buf.readUnsignedByte().toInt() |
||||||
|
if (statusAndChannel == END_OF_TRACK) { |
||||||
|
break |
||||||
|
} else if (statusAndChannel == SET_TEMPO) { |
||||||
|
tempoChanges++ |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
when (val status = statusAndChannel and 0xF) { |
||||||
|
NOTE_ON -> noteOnEvents++ |
||||||
|
NOTE_OFF -> noteOffEvents++ |
||||||
|
CONTROL_CHANGE -> controllerEvents++ |
||||||
|
PITCH_WHEEL_CHANGE -> pitchWheelEvents++ |
||||||
|
CHANNEL_PRESSURE_CHANGE -> channelPressureEvents++ |
||||||
|
KEY_PRESSURE_CHANGE -> keyPressureEvents++ |
||||||
|
PROGRAM_CHANGE -> bankSelectEvents++ |
||||||
|
else -> throw IllegalArgumentException("Unsupported status: $status") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val deltaTimeBuf = buf.slice() |
||||||
|
for (i in 0 until events) { |
||||||
|
buf.readVarInt() |
||||||
|
} |
||||||
|
|
||||||
|
var modulationWheelMsbEvents = 0 |
||||||
|
var modulationWheelLsbEvents = 0 |
||||||
|
var channelVolumeMsbEvents = 0 |
||||||
|
var channelVolumeLsbEvents = 0 |
||||||
|
var panMsbEvents = 0 |
||||||
|
var panLsbEvents = 0 |
||||||
|
var nonRegisteredMsbEvents = 0 |
||||||
|
var nonRegisteredLsbEvents = 0 |
||||||
|
var registeredMsbEvents = 0 |
||||||
|
var registeredLsbEvents = 0 |
||||||
|
var otherKnownControllerEvents = 0 |
||||||
|
var unknownControllerEvents = 0 |
||||||
|
|
||||||
|
val controllerBuf = buf.slice() |
||||||
|
|
||||||
|
var controller = 0 |
||||||
|
for (i in 0 until controllerEvents) { |
||||||
|
controller = (controller + buf.readUnsignedByte()) and 0x7F |
||||||
|
|
||||||
|
when (controller) { |
||||||
|
BANK_SELECT_MSB, BANK_SELECT_LSB -> bankSelectEvents++ |
||||||
|
MODULATION_WHEEL_MSB -> modulationWheelMsbEvents++ |
||||||
|
MODULATION_WHEEL_LSB -> modulationWheelLsbEvents++ |
||||||
|
CHANNEL_VOLUME_MSB -> channelVolumeMsbEvents++ |
||||||
|
CHANNEL_VOLUME_LSB -> channelVolumeLsbEvents++ |
||||||
|
PAN_MSB -> panMsbEvents++ |
||||||
|
PAN_LSB -> panLsbEvents++ |
||||||
|
NON_REGISTERED_MSB -> nonRegisteredMsbEvents++ |
||||||
|
NON_REGISTERED_LSB -> nonRegisteredLsbEvents++ |
||||||
|
REGISTERED_MSB -> registeredMsbEvents++ |
||||||
|
REGISTERED_LSB -> registeredLsbEvents++ |
||||||
|
DAMPER, PORTAMENTO, ALL_SOUND_OFF, RESET_CONTROLLERS, ALL_NOTES_OFF -> otherKnownControllerEvents++ |
||||||
|
else -> unknownControllerEvents++ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val otherKnownControllerBuf = buf.readSlice(otherKnownControllerEvents) |
||||||
|
val keyPressureBuf = buf.readSlice(keyPressureEvents) |
||||||
|
val channelPressureBuf = buf.readSlice(channelPressureEvents) |
||||||
|
val pitchWheelMsbBuf = buf.readSlice(pitchWheelEvents) |
||||||
|
val modulationWheelMsbBuf = buf.readSlice(modulationWheelMsbEvents) |
||||||
|
val channelVolumeMsbBuf = buf.readSlice(channelVolumeMsbEvents) |
||||||
|
val panMsbBuf = buf.readSlice(panMsbEvents) |
||||||
|
val keyBuf = buf.readSlice(noteOnEvents + noteOffEvents + keyPressureEvents) |
||||||
|
val onVelocityBuf = buf.readSlice(noteOnEvents) |
||||||
|
val unknownControllerBuf = buf.readSlice(unknownControllerEvents) |
||||||
|
val offVelocityBuf = buf.readSlice(noteOffEvents) |
||||||
|
val modulationWheelLsbBuf = buf.readSlice(modulationWheelLsbEvents) |
||||||
|
val channelVolumeLsbBuf = buf.readSlice(channelVolumeLsbEvents) |
||||||
|
val panLsbBuf = buf.readSlice(panLsbEvents) |
||||||
|
val bankSelectBuf = buf.readSlice(bankSelectEvents) |
||||||
|
val pitchWheelLsbBuf = buf.readSlice(pitchWheelEvents) |
||||||
|
val nonRegisteredMsbBuf = buf.readSlice(nonRegisteredMsbEvents) |
||||||
|
val nonRegisteredLsbBuf = buf.readSlice(nonRegisteredLsbEvents) |
||||||
|
val registeredMsbBuf = buf.readSlice(registeredMsbEvents) |
||||||
|
val registeredLsbBuf = buf.readSlice(registeredLsbEvents) |
||||||
|
val tempoBuf = buf.readSlice(tempoChanges * 3) |
||||||
|
|
||||||
|
// check only the three trailer bytes are remaining |
||||||
|
assert(buf.readableBytes() == 3) |
||||||
|
|
||||||
|
buf.resetReaderIndex() |
||||||
|
|
||||||
|
var channel = 0 |
||||||
|
var key = 0 |
||||||
|
var onVelocity = 0 |
||||||
|
var offVelocity = 0 |
||||||
|
controller = 0 |
||||||
|
val values = IntArray(CONTROLLERS) |
||||||
|
var pitchWheel = 0 |
||||||
|
var channelPressure = 0 |
||||||
|
var keyPressure = 0 |
||||||
|
|
||||||
|
for (i in 0 until tracks) { |
||||||
|
val track = sequence.createTrack() |
||||||
|
|
||||||
|
var time = 0L |
||||||
|
|
||||||
|
while (true) { |
||||||
|
time += deltaTimeBuf.readVarInt() |
||||||
|
|
||||||
|
val statusAndChannel = buf.readUnsignedByte().toInt() |
||||||
|
if (statusAndChannel == END_OF_TRACK) { |
||||||
|
track.add(MidiEvent(MetaMessage(META_END_OF_TRACK, null, 0), time)) |
||||||
|
break |
||||||
|
} else if (statusAndChannel == SET_TEMPO) { |
||||||
|
val tempo = ByteArray(3) |
||||||
|
tempoBuf.readBytes(tempo) |
||||||
|
track.add(MidiEvent(MetaMessage(META_SET_TEMPO, tempo, tempo.size), time)) |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
val status = statusAndChannel and 0xF |
||||||
|
channel = channel xor (statusAndChannel shr 4) |
||||||
|
|
||||||
|
val message = when (status) { |
||||||
|
NOTE_ON -> { |
||||||
|
key = (key + keyBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
onVelocity = (onVelocity + onVelocityBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
ShortMessage(ShortMessage.NOTE_ON, channel, key, onVelocity) |
||||||
|
} |
||||||
|
NOTE_OFF -> { |
||||||
|
key = (key + keyBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
offVelocity = (offVelocity + offVelocityBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
ShortMessage(ShortMessage.NOTE_OFF, channel, key, offVelocity) |
||||||
|
} |
||||||
|
CONTROL_CHANGE -> { |
||||||
|
controller = (controller + controllerBuf.readUnsignedByte()) and 0x7F |
||||||
|
|
||||||
|
val valueDelta = when (controller) { |
||||||
|
BANK_SELECT_MSB, BANK_SELECT_LSB -> bankSelectBuf.readUnsignedByte().toInt() |
||||||
|
MODULATION_WHEEL_MSB -> modulationWheelMsbBuf.readUnsignedByte().toInt() |
||||||
|
MODULATION_WHEEL_LSB -> modulationWheelLsbBuf.readUnsignedByte().toInt() |
||||||
|
CHANNEL_VOLUME_MSB -> channelVolumeMsbBuf.readUnsignedByte().toInt() |
||||||
|
CHANNEL_VOLUME_LSB -> channelVolumeLsbBuf.readUnsignedByte().toInt() |
||||||
|
PAN_MSB -> panMsbBuf.readUnsignedByte().toInt() |
||||||
|
PAN_LSB -> panLsbBuf.readUnsignedByte().toInt() |
||||||
|
NON_REGISTERED_MSB -> nonRegisteredMsbBuf.readUnsignedByte().toInt() |
||||||
|
NON_REGISTERED_LSB -> nonRegisteredLsbBuf.readUnsignedByte().toInt() |
||||||
|
REGISTERED_MSB -> registeredMsbBuf.readUnsignedByte().toInt() |
||||||
|
REGISTERED_LSB -> registeredLsbBuf.readUnsignedByte().toInt() |
||||||
|
DAMPER, PORTAMENTO, ALL_SOUND_OFF, RESET_CONTROLLERS, ALL_NOTES_OFF -> |
||||||
|
otherKnownControllerBuf.readUnsignedByte().toInt() |
||||||
|
else -> unknownControllerBuf.readUnsignedByte().toInt() |
||||||
|
} |
||||||
|
|
||||||
|
val value = values[controller] + valueDelta |
||||||
|
values[controller] = value |
||||||
|
ShortMessage(ShortMessage.CONTROL_CHANGE, channel, controller, value and 0x7F) |
||||||
|
} |
||||||
|
PITCH_WHEEL_CHANGE -> { |
||||||
|
pitchWheel += pitchWheelLsbBuf.readUnsignedByte().toInt() |
||||||
|
pitchWheel += (pitchWheelMsbBuf.readUnsignedByte().toInt() shl 7) |
||||||
|
pitchWheel = pitchWheel and 0x3FFF |
||||||
|
ShortMessage(ShortMessage.PITCH_BEND, channel, pitchWheel and 0x7F, pitchWheel shr 7) |
||||||
|
} |
||||||
|
CHANNEL_PRESSURE_CHANGE -> { |
||||||
|
channelPressure = (channelPressure + channelPressureBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
ShortMessage(ShortMessage.CHANNEL_PRESSURE, channel, channelPressure, 0) |
||||||
|
} |
||||||
|
KEY_PRESSURE_CHANGE -> { |
||||||
|
key = (key + keyBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
keyPressure = (keyPressure + keyPressureBuf.readUnsignedByte().toInt()) and 0x7F |
||||||
|
ShortMessage(ShortMessage.POLY_PRESSURE, channel, key, keyPressure) |
||||||
|
} |
||||||
|
PROGRAM_CHANGE -> { |
||||||
|
val bankSelect = bankSelectBuf.readUnsignedByte().toInt() |
||||||
|
ShortMessage(ShortMessage.PROGRAM_CHANGE, channel, bankSelect, 0) |
||||||
|
} |
||||||
|
else -> throw IllegalStateException() |
||||||
|
} |
||||||
|
|
||||||
|
track.add(MidiEvent(message, time)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// we've consumed the entire buf (checked by an assertion above) |
||||||
|
buf.readerIndex(buf.writerIndex()) |
||||||
|
|
||||||
|
return sequence |
||||||
|
} |
||||||
|
|
||||||
|
public fun write(sequence: Sequence, buf: ByteBuf) { |
||||||
|
if (sequence.divisionType != Sequence.PPQ) { |
||||||
|
throw IllegalArgumentException("SMPTE unsupported") |
||||||
|
} |
||||||
|
|
||||||
|
val buffers = Buffers.alloc(buf.alloc()) |
||||||
|
try { |
||||||
|
val deltaTimeBuf = buffers.deltaTimeBuf |
||||||
|
val controllerBuf = buffers.controllerBuf |
||||||
|
val otherKnownControllerBuf = buffers.otherKnownControllerBuf |
||||||
|
val keyPressureBuf = buffers.keyPressureBuf |
||||||
|
val channelPressureBuf = buffers.channelPressureBuf |
||||||
|
val pitchWheelMsbBuf = buffers.pitchWheelMsbBuf |
||||||
|
val modulationWheelMsbBuf = buffers.modulationWheelMsbBuf |
||||||
|
val channelVolumeMsbBuf = buffers.channelVolumeMsbBuf |
||||||
|
val panMsbBuf = buffers.panMsbBuf |
||||||
|
val keyBuf = buffers.keyBuf |
||||||
|
val onVelocityBuf = buffers.onVelocityBuf |
||||||
|
val unknownControllerBuf = buffers.unknownControllerBuf |
||||||
|
val offVelocityBuf = buffers.offVelocityBuf |
||||||
|
val modulationWheelLsbBuf = buffers.modulationWheelLsbBuf |
||||||
|
val channelVolumeLsbBuf = buffers.channelVolumeLsbBuf |
||||||
|
val panLsbBuf = buffers.panLsbBuf |
||||||
|
val bankSelectBuf = buffers.bankSelectBuf |
||||||
|
val pitchWheelLsbBuf = buffers.pitchWheelLsbBuf |
||||||
|
val nonRegisteredMsbBuf = buffers.nonRegisteredMsbBuf |
||||||
|
val nonRegisteredLsbBuf = buffers.nonRegisteredLsbBuf |
||||||
|
val registeredMsbBuf = buffers.nonRegisteredMsbBuf |
||||||
|
val registeredLsbBuf = buffers.nonRegisteredLsbBuf |
||||||
|
val tempoBuf = buffers.tempoBuf |
||||||
|
|
||||||
|
var prevChannel = 0 |
||||||
|
var prevKey = 0 |
||||||
|
var prevOnVelocity = 0 |
||||||
|
var prevOffVelocity = 0 |
||||||
|
var prevController = 0 |
||||||
|
var prevPitchWheel = 0 |
||||||
|
var prevChannelPressure = 0 |
||||||
|
var prevKeyPressure = 0 |
||||||
|
val prevValues = IntArray(CONTROLLERS) |
||||||
|
|
||||||
|
for (track in sequence.tracks) { |
||||||
|
var prevTime = 0L |
||||||
|
|
||||||
|
for (i in 0 until track.size()) { |
||||||
|
val event = track[i] |
||||||
|
|
||||||
|
val time = event.tick |
||||||
|
deltaTimeBuf.writeVarInt((time - prevTime).toInt()) |
||||||
|
prevTime = time |
||||||
|
|
||||||
|
when (val message = event.message) { |
||||||
|
is MetaMessage -> { |
||||||
|
when (val type = message.type) { |
||||||
|
META_END_OF_TRACK -> buf.writeByte(END_OF_TRACK) |
||||||
|
META_SET_TEMPO -> { |
||||||
|
buf.writeByte(SET_TEMPO) |
||||||
|
require(message.data.size == 3) |
||||||
|
tempoBuf.writeBytes(message.data) |
||||||
|
} |
||||||
|
else -> throw IllegalArgumentException("Unsupported meta type: $type") |
||||||
|
} |
||||||
|
} |
||||||
|
is ShortMessage -> { |
||||||
|
val command = message.status and 0xF0 |
||||||
|
val channel = message.status and 0xF |
||||||
|
|
||||||
|
val status = when (command) { |
||||||
|
ShortMessage.NOTE_ON -> NOTE_ON |
||||||
|
ShortMessage.NOTE_OFF -> NOTE_OFF |
||||||
|
ShortMessage.CONTROL_CHANGE -> CONTROL_CHANGE |
||||||
|
ShortMessage.PITCH_BEND -> PITCH_WHEEL_CHANGE |
||||||
|
ShortMessage.CHANNEL_PRESSURE -> CHANNEL_PRESSURE_CHANGE |
||||||
|
ShortMessage.POLY_PRESSURE -> KEY_PRESSURE_CHANGE |
||||||
|
ShortMessage.PROGRAM_CHANGE -> PROGRAM_CHANGE |
||||||
|
else -> throw IllegalArgumentException("Unsupported command: $command") |
||||||
|
} |
||||||
|
|
||||||
|
buf.writeByte(((channel xor prevChannel) shl 4) or status) |
||||||
|
prevChannel = channel |
||||||
|
|
||||||
|
if ( |
||||||
|
command == ShortMessage.NOTE_ON || |
||||||
|
command == ShortMessage.NOTE_OFF || |
||||||
|
command == ShortMessage.POLY_PRESSURE |
||||||
|
) { |
||||||
|
val key = message.data1 |
||||||
|
keyBuf.writeByte((key - prevKey) and 0x7F) |
||||||
|
prevKey = key |
||||||
|
} |
||||||
|
|
||||||
|
when (command) { |
||||||
|
ShortMessage.NOTE_ON -> { |
||||||
|
val onVelocity = message.data2 |
||||||
|
onVelocityBuf.writeByte((onVelocity - prevOnVelocity) and 0x7F) |
||||||
|
prevOnVelocity = onVelocity |
||||||
|
} |
||||||
|
ShortMessage.NOTE_OFF -> { |
||||||
|
val offVelocity = message.data2 |
||||||
|
offVelocityBuf.writeByte((offVelocity - prevOffVelocity) and 0x7F) |
||||||
|
prevOffVelocity = offVelocity |
||||||
|
} |
||||||
|
ShortMessage.CONTROL_CHANGE -> { |
||||||
|
val controller = message.data1 |
||||||
|
controllerBuf.writeByte((controller - prevController) and 0x7F) |
||||||
|
prevController = controller |
||||||
|
|
||||||
|
val value = message.data2 |
||||||
|
val valueDelta = (value - prevValues[controller]) and 0x7F |
||||||
|
|
||||||
|
when (controller) { |
||||||
|
BANK_SELECT_MSB, BANK_SELECT_LSB -> bankSelectBuf.writeByte(valueDelta) |
||||||
|
MODULATION_WHEEL_MSB -> modulationWheelMsbBuf.writeByte(valueDelta) |
||||||
|
MODULATION_WHEEL_LSB -> modulationWheelLsbBuf.writeByte(valueDelta) |
||||||
|
CHANNEL_VOLUME_MSB -> channelVolumeMsbBuf.writeByte(valueDelta) |
||||||
|
CHANNEL_VOLUME_LSB -> channelVolumeLsbBuf.writeByte(valueDelta) |
||||||
|
PAN_MSB -> panMsbBuf.writeByte(valueDelta) |
||||||
|
PAN_LSB -> panLsbBuf.writeByte(valueDelta) |
||||||
|
NON_REGISTERED_MSB -> nonRegisteredMsbBuf.writeByte(valueDelta) |
||||||
|
NON_REGISTERED_LSB -> nonRegisteredLsbBuf.writeByte(valueDelta) |
||||||
|
REGISTERED_MSB -> registeredMsbBuf.writeByte(valueDelta) |
||||||
|
REGISTERED_LSB -> registeredLsbBuf.writeByte(valueDelta) |
||||||
|
DAMPER, PORTAMENTO, ALL_SOUND_OFF, RESET_CONTROLLERS, ALL_NOTES_OFF -> |
||||||
|
otherKnownControllerBuf.writeByte(valueDelta) |
||||||
|
else -> unknownControllerBuf.writeByte(valueDelta) |
||||||
|
} |
||||||
|
|
||||||
|
prevValues[controller] = value |
||||||
|
} |
||||||
|
ShortMessage.PITCH_BEND -> { |
||||||
|
val pitchWheel = message.data1 or (message.data2 shl 7) |
||||||
|
val pitchWheelDelta = (pitchWheel - prevPitchWheel) and 0x3FFF |
||||||
|
pitchWheelLsbBuf.writeByte(pitchWheelDelta and 0x7F) |
||||||
|
pitchWheelMsbBuf.writeByte(pitchWheelDelta shr 7) |
||||||
|
prevPitchWheel = pitchWheel |
||||||
|
} |
||||||
|
ShortMessage.CHANNEL_PRESSURE -> { |
||||||
|
val channelPressure = message.data1 |
||||||
|
channelPressureBuf.writeByte((channelPressure - prevChannelPressure) and 0x7F) |
||||||
|
prevChannelPressure = channelPressure |
||||||
|
} |
||||||
|
ShortMessage.POLY_PRESSURE -> { |
||||||
|
val keyPressure = message.data2 |
||||||
|
keyPressureBuf.writeByte((keyPressure - prevKeyPressure) and 0x7F) |
||||||
|
prevKeyPressure = keyPressure |
||||||
|
} |
||||||
|
ShortMessage.PROGRAM_CHANGE -> { |
||||||
|
bankSelectBuf.writeByte(message.data1) |
||||||
|
} |
||||||
|
else -> throw IllegalStateException() |
||||||
|
} |
||||||
|
} |
||||||
|
else -> throw IllegalArgumentException("Unsupported message type: ${message.javaClass.name}") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
buf.writeBytes(deltaTimeBuf) |
||||||
|
buf.writeBytes(controllerBuf) |
||||||
|
buf.writeBytes(otherKnownControllerBuf) |
||||||
|
buf.writeBytes(keyPressureBuf) |
||||||
|
buf.writeBytes(channelPressureBuf) |
||||||
|
buf.writeBytes(pitchWheelMsbBuf) |
||||||
|
buf.writeBytes(modulationWheelMsbBuf) |
||||||
|
buf.writeBytes(channelVolumeMsbBuf) |
||||||
|
buf.writeBytes(panMsbBuf) |
||||||
|
buf.writeBytes(keyBuf) |
||||||
|
buf.writeBytes(onVelocityBuf) |
||||||
|
buf.writeBytes(unknownControllerBuf) |
||||||
|
buf.writeBytes(offVelocityBuf) |
||||||
|
buf.writeBytes(modulationWheelLsbBuf) |
||||||
|
buf.writeBytes(channelVolumeLsbBuf) |
||||||
|
buf.writeBytes(panLsbBuf) |
||||||
|
buf.writeBytes(bankSelectBuf) |
||||||
|
buf.writeBytes(pitchWheelLsbBuf) |
||||||
|
buf.writeBytes(nonRegisteredMsbBuf) |
||||||
|
buf.writeBytes(nonRegisteredLsbBuf) |
||||||
|
buf.writeBytes(registeredMsbBuf) |
||||||
|
buf.writeBytes(registeredLsbBuf) |
||||||
|
buf.writeBytes(tempoBuf) |
||||||
|
} finally { |
||||||
|
buffers.release() |
||||||
|
} |
||||||
|
|
||||||
|
buf.writeByte(sequence.tracks.size) |
||||||
|
buf.writeShort(sequence.resolution and 0x7FFF) |
||||||
|
} |
||||||
|
|
||||||
|
private class Buffers private constructor( |
||||||
|
val deltaTimeBuf: ByteBuf, |
||||||
|
val controllerBuf: ByteBuf, |
||||||
|
val otherKnownControllerBuf: ByteBuf, |
||||||
|
val keyPressureBuf: ByteBuf, |
||||||
|
val channelPressureBuf: ByteBuf, |
||||||
|
val pitchWheelMsbBuf: ByteBuf, |
||||||
|
val modulationWheelMsbBuf: ByteBuf, |
||||||
|
val channelVolumeMsbBuf: ByteBuf, |
||||||
|
val panMsbBuf: ByteBuf, |
||||||
|
val keyBuf: ByteBuf, |
||||||
|
val onVelocityBuf: ByteBuf, |
||||||
|
val unknownControllerBuf: ByteBuf, |
||||||
|
val offVelocityBuf: ByteBuf, |
||||||
|
val modulationWheelLsbBuf: ByteBuf, |
||||||
|
val channelVolumeLsbBuf: ByteBuf, |
||||||
|
val panLsbBuf: ByteBuf, |
||||||
|
val bankSelectBuf: ByteBuf, |
||||||
|
val pitchWheelLsbBuf: ByteBuf, |
||||||
|
val nonRegisteredMsbBuf: ByteBuf, |
||||||
|
val nonRegisteredLsbBuf: ByteBuf, |
||||||
|
val registeredMsbBuf: ByteBuf, |
||||||
|
val registeredLsbBuf: ByteBuf, |
||||||
|
val tempoBuf: ByteBuf |
||||||
|
) { |
||||||
|
fun release() { |
||||||
|
deltaTimeBuf.release() |
||||||
|
controllerBuf.release() |
||||||
|
otherKnownControllerBuf.release() |
||||||
|
keyPressureBuf.release() |
||||||
|
channelPressureBuf.release() |
||||||
|
pitchWheelMsbBuf.release() |
||||||
|
modulationWheelMsbBuf.release() |
||||||
|
channelVolumeMsbBuf.release() |
||||||
|
panMsbBuf.release() |
||||||
|
keyBuf.release() |
||||||
|
onVelocityBuf.release() |
||||||
|
unknownControllerBuf.release() |
||||||
|
offVelocityBuf.release() |
||||||
|
modulationWheelLsbBuf.release() |
||||||
|
channelVolumeLsbBuf.release() |
||||||
|
panLsbBuf.release() |
||||||
|
bankSelectBuf.release() |
||||||
|
pitchWheelLsbBuf.release() |
||||||
|
nonRegisteredMsbBuf.release() |
||||||
|
nonRegisteredLsbBuf.release() |
||||||
|
registeredMsbBuf.release() |
||||||
|
registeredLsbBuf.release() |
||||||
|
tempoBuf.release() |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
fun alloc(alloc: ByteBufAllocator): Buffers { |
||||||
|
val bufs = mutableListOf<ByteBuf>() |
||||||
|
try { |
||||||
|
for (i in 0..22) { |
||||||
|
bufs += alloc.buffer() |
||||||
|
} |
||||||
|
|
||||||
|
return Buffers( |
||||||
|
bufs[0].retain(), |
||||||
|
bufs[1].retain(), |
||||||
|
bufs[2].retain(), |
||||||
|
bufs[3].retain(), |
||||||
|
bufs[4].retain(), |
||||||
|
bufs[5].retain(), |
||||||
|
bufs[6].retain(), |
||||||
|
bufs[7].retain(), |
||||||
|
bufs[8].retain(), |
||||||
|
bufs[9].retain(), |
||||||
|
bufs[10].retain(), |
||||||
|
bufs[11].retain(), |
||||||
|
bufs[12].retain(), |
||||||
|
bufs[13].retain(), |
||||||
|
bufs[14].retain(), |
||||||
|
bufs[15].retain(), |
||||||
|
bufs[16].retain(), |
||||||
|
bufs[17].retain(), |
||||||
|
bufs[18].retain(), |
||||||
|
bufs[19].retain(), |
||||||
|
bufs[20].retain(), |
||||||
|
bufs[21].retain(), |
||||||
|
bufs[22].retain() |
||||||
|
) |
||||||
|
} finally { |
||||||
|
bufs.forEach(ByteBuf::release) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue