MIDI delta times are composed of one to four bytes, depending on their values. If there is still bytes to write, the MSB (most significant bit) of the current byte is 1, else 0. This functions is automatically tested. https://en.wikipedia.org/wiki/Variable-length_quantity
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer(kind=int32), | intent(in) | :: | i |
pure function variable_length_quantity(i) result(VLQ) integer(int32), intent(in) :: i integer(int8), allocatable, dimension(:) :: VLQ integer(int32) :: j, again ! A First In Last Out 4 bytes stack (or Last In First Out): integer(int32) :: filo ! We use a variable j because i has intent(in): j = i filo = 0 ! The 7 least significant bits are placed in filo (0x7F = 0b01111111): filo = iand(j, z'7F') ! They are now eliminated from j by shifting bits of j 7 places ! to the right (zeros are introduced on the left): j = ishft(j, -7) ! The same process is a applied until j is empty: do if (j == 0) exit ! The bits already in filo are shifted 1 byte to the left ! (filo is Little Endian): filo = ishft(filo, +8) ! A byte of j with the most signicant bit set to 1 (0x80 = 0b10000000) ! can now be added on the right of filo: filo = filo + ior(iand(j, z'7F'), z'80') ! Preparing next iteration: j = ishft(j, -7) end do ! Starting with a void array: allocate(VLQ(0)) ! The bytes accumulated in filo are now written in the VLQ array ! in the reverse order (MIDI files are Big Endian): do ! Appending the LSB of filo in the VLQ array: VLQ = [ VLQ, int(filo, int8) ] ! Is the bit 8 a 1? (meaning there is still other bytes to read): again = iand(filo, z'80') if (again /= 0) then ! The written LSB can now be eliminated before next iteration: filo = ishft(filo, -8) else ! Nothing left to write: exit end if end do end function variable_length_quantity