1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package javax.sound.midi;
19
20import org.apache.harmony.sound.internal.nls.Messages;
21
22public class ShortMessage extends MidiMessage {
23
24    public static final int ACTIVE_SENSING = 254;
25
26    public static final int CHANNEL_PRESSURE = 208;
27
28    public static final int CONTINUE = 251;
29
30    public static final int CONTROL_CHANGE = 176;
31
32    public static final int END_OF_EXCLUSIVE = 247;
33
34    public static final int MIDI_TIME_CODE = 241;
35
36    public static final int NOTE_OFF = 128;
37
38    public static final int NOTE_ON = 144;
39
40    public static final int PITCH_BEND = 224;
41
42    public static final int POLY_PRESSURE = 160;
43
44    public static final int PROGRAM_CHANGE = 192;
45
46    public static final int SONG_POSITION_POINTER = 242;
47
48    public static final int SONG_SELECT = 243;
49
50    public static final int START = 250;
51
52    public static final int STOP = 252;
53
54    public static final int SYSTEM_RESET = 255;
55
56    public static final int TIMING_CLOCK = 248;
57
58    public static final int TUNE_REQUEST = 246;
59
60    public ShortMessage() {
61        super(new byte[] {-112, 64, 127});
62    }
63
64    protected ShortMessage(byte[] data) {
65        super(data);
66    }
67
68    @Override
69    public Object clone() {
70        return new ShortMessage(this.getMessage());
71    }
72
73    public int getChannel() {
74        /*
75         * channel change from 0 up to 15
76         */
77        if ((data == null) || (data.length == 0)) {
78            return 0;
79        }
80        return data[0] & 0x0F;
81    }
82
83    public int getCommand() {
84       /*
85        * command should be divisible by 16 without rest
86        */
87        if ((data == null) || (data.length == 0)) {
88            return 0;
89        }
90        return (data[0] & 0xFF) - getChannel();
91    }
92
93    public int getData1() {
94        if ((data == null) || (data.length == 0)) {
95            return 0;
96        } else if (data.length < 2) {
97            return 0;
98        } else {
99            return data[1] & 0xFF;
100        }
101    }
102
103    public int getData2() {
104        if ((data == null) || (data.length == 0)) {
105            return 0;
106        } else if (data.length < 3) {
107            return 0;
108        } else {
109            return data[2] & 0xFF;
110        }
111    }
112
113    protected final int getDataLength(int status)
114            throws InvalidMidiDataException {
115        // FIXME
116        /*
117         * I have some question about this method. I didn't understand how
118         * should to work this method, but some results I get by experimental
119         * method. From 0 up to 127, from 256 up to 383 and so on this method
120         * throw out exception, i.e. after 256 begin cycle with some small
121         * differences in the first lap, from 0 up to 255. From the second lap
122         * and so on this method, getDataLenght(int), throw out exception with
123         * value of status from 496 up to 511, from 752 up to 767 and so on,
124         * i.e. on the last 16 number of 256-lap. And now differences in the
125         * first lap. This method don't throw out exception with value of status
126         * from 240 up to 255. It has next behavior:
127         * - value of status equals 240 -- throw out exception;
128         * - 241 -- return 1;
129         * - 242 -- return 2;
130         * - 243 -- return 1;
131         * - from 244 up to 245 -- throw out exception;
132         * - from 246 up to 255 -- return 0;
133         */
134        if (status < 0) {
135            // sound.04=Invalid status byte: {0}
136            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
137        }
138        if (((status % 256) >= 0) && ((status % 256) <= 127)) {
139            // sound.04=Invalid status byte: {0}
140            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
141        }
142        if (((status / 256) == 0)
143                && ((status == 240) || (status == 244) || (status == 245))) {
144            // sound.04=Invalid status byte: {0}
145            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
146        }
147        if (((status / 256) != 0) && ((status % 256) >= 244)
148                && ((status % 256) <= 255)) {
149            // sound.04=Invalid status byte: {0}
150            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
151        }
152
153        if ((status / 256) == 0) {
154            if ((status == 241) || (status == 243)) {
155                return 1;
156            } else if (status == 242) {
157                return 2;
158            } else if ((status >= 246) && (status <= 255)) {
159                return 0;
160            }
161        }
162        if (((status % 256) >= 128) && ((status % 256) <= 191)) {
163            return 2;
164        } else if (((status % 256) >= 192) && ((status % 256) <= 223)) {
165            return 1;
166        } else {
167            return 2;
168        }
169    }
170
171    public void setMessage(int status) throws InvalidMidiDataException {
172        /*
173         * value of variable status is more or equals 246 and less or equals 255
174         */
175        if ((status < 246) || (status > 255)) {
176            // sound.04=Invalid status byte: {0}
177            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
178        }
179        super.setMessage(new byte[] {(byte) status}, 1);
180    }
181
182    public void setMessage(int status, int data1, int data2)
183            throws InvalidMidiDataException {
184        // FIXME
185        /*
186         * In the Sun's implementation variables data1 and data2 don't use; I
187         * don't find situation when this variables influence on result of
188         * functions getData1() and getData2(). But function getDataLength(int)
189         * return 0 when I modify status byte from 246 up to 255, and so I think
190         * it's true.
191         */
192        if ((status < 246) || (status > 255)) {
193            // sound.04=Invalid status byte: {0}
194            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
195        }
196        super.setMessage(new byte[] {(byte) status}, 1);
197    }
198
199    public void setMessage(int command, int channel, int data1, int data2)
200            throws InvalidMidiDataException {
201        // FIXME
202        /*
203         * value of variable command is more or equals 128 and less or equals
204         * 239
205         */
206        if ((command < 128) || (command > 239)) {
207            /*
208             * when this exception throw out, the value of variable command
209             * should be the hexadecimal number
210             */
211            // sound.05=command out of range: {0}
212            throw new InvalidMidiDataException(Messages.getString("sound.05", command)); //$NON-NLS-1$
213        }
214        /*
215         * value of variable channel is more or equals 0 and less or equals 15
216         */
217        if ((channel < 0) || (channel > 15)) {
218            // sound.06=channel out of range: {0}
219            throw new InvalidMidiDataException(Messages.getString("sound.06", channel)); //$NON-NLS-1$
220        }
221        /*
222         * value of data1 and data2 is more or equals 0 and less or equals 127,
223         * but when command more or equals 192 and less or equals 223 the second
224         * data, data2, is unused, because getDataLength(int) return 1 in this
225         * case, and in other cases it return 2
226         */
227        if ((getDataLength(command) >= 1) && ((data1 < 0) || (data1 > 127))) {
228            // sound.07=data1 out of range: {0}
229            throw new InvalidMidiDataException(Messages.getString("sound.07", data1)); //$NON-NLS-1$
230        }
231        if ((getDataLength(command) == 2) && ((data2 < 0) || (data2 > 127))) {
232            // sound.08=data2 out of range: {0}
233            throw new InvalidMidiDataException(Messages.getString("sound.08", data2)); //$NON-NLS-1$
234        }
235
236        int tcom = command - (command % 16);
237        if (getDataLength(command) == 1) {
238            super.setMessage(new byte[] {(byte) (tcom + channel), (byte) data1}, 2);
239        } else {
240            super.setMessage(new byte[] {(byte) (tcom + channel), (byte) data1,
241                    (byte) data2}, 3);
242        }
243    }
244
245}
246