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>
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