blob: c5bfb5f697f8edcd49376e66b754ae370e6d6de6 [file] [log] [blame]
Mike Lockwoodf0a41d12015-03-24 08:27:11 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.bluetoothmidiservice;
18
19import android.media.midi.MidiReceiver;
20import android.util.Log;
21
22import java.io.IOException;
23
24/**
25 * This is an abstract base class that decodes a packet buffer and passes it to a
26 * {@link android.media.midi.MidiReceiver}
27 */
28public class BluetoothPacketDecoder extends PacketDecoder {
29
30 private static final String TAG = "BluetoothPacketDecoder";
31
32 private final byte[] mBuffer;
33
34 private final int TIMESTAMP_MASK_HIGH = 0x1F80;
35 private final int TIMESTAMP_MASK_LOW = 0x7F;
36 private final int HEADER_TIMESTAMP_MASK = 0x3F;
37
38 public BluetoothPacketDecoder(int maxPacketSize) {
39 mBuffer = new byte[maxPacketSize];
40 }
41
42 @Override
43 public void decodePacket(byte[] buffer, MidiReceiver receiver) {
44 int length = buffer.length;
45
46 // NOTE his code allows running status across packets,
47 // although the specification does not allow that.
48
49 if (length < 1) {
50 Log.e(TAG, "empty packet");
51 return;
52 }
53 byte header = buffer[0];
54 if ((header & 0xC0) != 0x80) {
55 Log.e(TAG, "packet does not start with header");
56 return;
57 }
58
59 // shift bits 0 - 5 to bits 7 - 12
60 int timestamp = (header & HEADER_TIMESTAMP_MASK) << 7;
61 boolean lastWasTimestamp = false;
62 int dataCount = 0;
63 int previousLowTimestamp = 0;
64
65 // iterate through the rest of the packet, separating MIDI data from timestamps
66 for (int i = 1; i < buffer.length; i++) {
67 byte b = buffer[i];
68
69 if ((b & 0x80) != 0 && !lastWasTimestamp) {
70 lastWasTimestamp = true;
71 int lowTimestamp = b & TIMESTAMP_MASK_LOW;
72 int newTimestamp = (timestamp & TIMESTAMP_MASK_HIGH) | lowTimestamp;
73 if (lowTimestamp < previousLowTimestamp) {
74 newTimestamp = (newTimestamp + 0x0080) & TIMESTAMP_MASK_HIGH;
75 }
76 previousLowTimestamp = lowTimestamp;
77
78 if (newTimestamp != timestamp) {
79 if (dataCount > 0) {
80 // send previous message separately since it has a different timestamp
81 try {
82 // FIXME use sendWithTimestamp
83 receiver.send(mBuffer, 0, dataCount);
84 } catch (IOException e) {
85 // ???
86 }
87 dataCount = 0;
88 }
89 }
90 timestamp = newTimestamp;
91 } else {
92 lastWasTimestamp = false;
93 mBuffer[dataCount++] = b;
94 }
95 }
96
97 if (dataCount > 0) {
98 try {
99 // FIXME use sendWithTimestamp
100 receiver.send(mBuffer, 0, dataCount);
101 } catch (IOException e) {
102 // ???
103 }
104 }
105 }
106}