1/*
2 * Copyright (C) 2014 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.internal.midi;
18
19import android.media.midi.MidiReceiver;
20
21import java.io.IOException;
22
23/**
24 * Add MIDI Events to an EventScheduler
25 */
26public class MidiEventScheduler extends EventScheduler {
27    private static final String TAG = "MidiEventScheduler";
28    // Maintain a pool of scheduled events to reduce memory allocation.
29    // This pool increases performance by about 14%.
30    private final static int POOL_EVENT_SIZE = 16;
31    private MidiReceiver mReceiver = new SchedulingReceiver();
32
33    private class SchedulingReceiver extends MidiReceiver {
34        /**
35         * Store these bytes in the EventScheduler to be delivered at the specified
36         * time.
37         */
38        @Override
39        public void onSend(byte[] msg, int offset, int count, long timestamp)
40                throws IOException {
41            MidiEvent event = createScheduledEvent(msg, offset, count, timestamp);
42            if (event != null) {
43                add(event);
44            }
45        }
46
47        @Override
48        public void onFlush() {
49            MidiEventScheduler.this.flush();
50        }
51    }
52
53    public static class MidiEvent extends SchedulableEvent {
54        public int count = 0;
55        public byte[] data;
56
57        private MidiEvent(int count) {
58            super(0);
59            data = new byte[count];
60        }
61
62        private MidiEvent(byte[] msg, int offset, int count, long timestamp) {
63            super(timestamp);
64            data = new byte[count];
65            System.arraycopy(msg, offset, data, 0, count);
66            this.count = count;
67        }
68
69        @Override
70        public String toString() {
71            String text = "Event: ";
72            for (int i = 0; i < count; i++) {
73                text += data[i] + ", ";
74            }
75            return text;
76        }
77    }
78
79    /**
80     * Create an event that contains the message.
81     */
82    private MidiEvent createScheduledEvent(byte[] msg, int offset, int count,
83            long timestamp) {
84        MidiEvent event;
85        if (count > POOL_EVENT_SIZE) {
86            event = new MidiEvent(msg, offset, count, timestamp);
87        } else {
88            event = (MidiEvent) removeEventfromPool();
89            if (event == null) {
90                event = new MidiEvent(POOL_EVENT_SIZE);
91            }
92            System.arraycopy(msg, offset, event.data, 0, count);
93            event.count = count;
94            event.setTimestamp(timestamp);
95        }
96        return event;
97    }
98
99    /**
100     * Return events to a pool so they can be reused.
101     *
102     * @param event
103     */
104    @Override
105    public void addEventToPool(SchedulableEvent event) {
106        // Make sure the event is suitable for the pool.
107        if (event instanceof MidiEvent) {
108            MidiEvent midiEvent = (MidiEvent) event;
109            if (midiEvent.data.length == POOL_EVENT_SIZE) {
110                super.addEventToPool(event);
111            }
112        }
113    }
114
115    /**
116     * This MidiReceiver will write date to the scheduling buffer.
117     * @return the MidiReceiver
118     */
119    public MidiReceiver getReceiver() {
120        return mReceiver;
121    }
122
123}
124