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 
17 package com.android.internal.midi;
18 
19 import android.media.midi.MidiReceiver;
20 
21 import java.io.IOException;
22 
23 /**
24  * Add MIDI Events to an EventScheduler
25  */
26 public 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
onSend(byte[] msg, int offset, int count, long timestamp)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
onFlush()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 
MidiEvent(int count)57         private MidiEvent(int count) {
58             super(0);
59             data = new byte[count];
60         }
61 
MidiEvent(byte[] msg, int offset, int count, long timestamp)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
toString()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      */
createScheduledEvent(byte[] msg, int offset, int count, long timestamp)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
addEventToPool(SchedulableEvent event)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      */
getReceiver()119     public MidiReceiver getReceiver() {
120         return mReceiver;
121     }
122 
123 }
124