|
1 /* |
|
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 /* @test |
|
27 @summary Test RealTime-tunings using SoftReciver.send method */ |
|
28 |
|
29 import java.io.IOException; |
|
30 |
|
31 import javax.sound.midi.*; |
|
32 import javax.sound.sampled.*; |
|
33 |
|
34 import com.sun.media.sound.*; |
|
35 |
|
36 public class RealTimeTuning { |
|
37 |
|
38 private static class PitchSpy { |
|
39 public float pitch = 0; |
|
40 |
|
41 public Soundbank getSoundBank() { |
|
42 ModelOscillator osc = new ModelOscillator() { |
|
43 public float getAttenuation() { |
|
44 return 0; |
|
45 } |
|
46 |
|
47 public int getChannels() { |
|
48 return 0; |
|
49 } |
|
50 |
|
51 public ModelOscillatorStream open(float samplerate) { |
|
52 return new ModelOscillatorStream() { |
|
53 public void close() throws IOException { |
|
54 pitch = 0; |
|
55 } |
|
56 |
|
57 public void noteOff(int velocity) { |
|
58 pitch = 0; |
|
59 } |
|
60 |
|
61 public void noteOn(MidiChannel channel, |
|
62 VoiceStatus voice, int noteNumber, int velocity) { |
|
63 pitch = noteNumber * 100; |
|
64 } |
|
65 |
|
66 public int read(float[][] buffer, int offset, int len) |
|
67 throws IOException { |
|
68 return len; |
|
69 } |
|
70 |
|
71 public void setPitch(float ipitch) { |
|
72 pitch = ipitch; |
|
73 } |
|
74 }; |
|
75 } |
|
76 }; |
|
77 ModelPerformer performer = new ModelPerformer(); |
|
78 performer.getOscillators().add(osc); |
|
79 SimpleInstrument testinstrument = new SimpleInstrument(); |
|
80 testinstrument.setPatch(new Patch(0, 0)); |
|
81 testinstrument.add(performer); |
|
82 SimpleSoundbank testsoundbank = new SimpleSoundbank(); |
|
83 testsoundbank.addInstrument(testinstrument); |
|
84 return testsoundbank; |
|
85 } |
|
86 } |
|
87 |
|
88 public static void sendTuningChange(Receiver recv, int channel, |
|
89 int tuningpreset, int tuningbank) throws InvalidMidiDataException { |
|
90 // Data Entry |
|
91 ShortMessage sm1 = new ShortMessage(); |
|
92 sm1.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x64, 04); |
|
93 ShortMessage sm2 = new ShortMessage(); |
|
94 sm2.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x65, 00); |
|
95 |
|
96 // Tuning Bank |
|
97 ShortMessage sm3 = new ShortMessage(); |
|
98 sm3.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x06, tuningbank); |
|
99 // Data Increment |
|
100 ShortMessage sm4 = new ShortMessage(); |
|
101 sm4.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x60, 0x7F); |
|
102 // Data Decrement |
|
103 ShortMessage sm5 = new ShortMessage(); |
|
104 sm5.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x61, 0x7F); |
|
105 |
|
106 // Data Entry |
|
107 ShortMessage sm6 = new ShortMessage(); |
|
108 sm6.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x64, 03); |
|
109 ShortMessage sm7 = new ShortMessage(); |
|
110 sm7.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x65, 00); |
|
111 |
|
112 // Tuning program |
|
113 ShortMessage sm8 = new ShortMessage(); |
|
114 sm8 |
|
115 .setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x06, |
|
116 tuningpreset); |
|
117 // Data Increment |
|
118 ShortMessage sm9 = new ShortMessage(); |
|
119 sm9.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x60, 0x7F); |
|
120 // Data Decrement |
|
121 ShortMessage sm10 = new ShortMessage(); |
|
122 sm10.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x61, 0x7F); |
|
123 |
|
124 recv.send(sm1, -1); |
|
125 recv.send(sm2, -1); |
|
126 recv.send(sm3, -1); |
|
127 recv.send(sm4, -1); |
|
128 recv.send(sm5, -1); |
|
129 recv.send(sm6, -1); |
|
130 recv.send(sm7, -1); |
|
131 recv.send(sm8, -1); |
|
132 recv.send(sm9, -1); |
|
133 recv.send(sm10, -1); |
|
134 |
|
135 } |
|
136 |
|
137 private static void assertTrue(boolean value) throws Exception { |
|
138 if (!value) |
|
139 throw new RuntimeException("assertTrue fails!"); |
|
140 } |
|
141 |
|
142 public static void testTunings(int[] msg, int tuningProgram, |
|
143 int tuningBank, int targetNote, float targetPitch, boolean realtime) |
|
144 throws Exception { |
|
145 AudioSynthesizer synth = new SoftSynthesizer(); |
|
146 AudioInputStream stream = synth.openStream(null, null); |
|
147 Receiver recv = synth.getReceiver(); |
|
148 MidiChannel channel = synth.getChannels()[0]; |
|
149 byte[] buff = new byte[2048]; |
|
150 |
|
151 // Create test instrument which we can use to monitor pitch changes |
|
152 PitchSpy pitchspy = new PitchSpy(); |
|
153 |
|
154 synth.unloadAllInstruments(synth.getDefaultSoundbank()); |
|
155 synth.loadAllInstruments(pitchspy.getSoundBank()); |
|
156 |
|
157 SysexMessage sysex = null; |
|
158 |
|
159 // Send tuning changes |
|
160 if (msg != null) { |
|
161 byte[] bmsg = new byte[msg.length]; |
|
162 for (int i = 0; i < bmsg.length; i++) |
|
163 bmsg[i] = (byte) msg[i]; |
|
164 sysex = new SysexMessage(); |
|
165 sysex.setMessage(bmsg, bmsg.length); |
|
166 if (targetPitch == 0) { |
|
167 targetPitch = (float) new SoftTuning(bmsg) |
|
168 .getTuning(targetNote); |
|
169 // Check if targetPitch != targetNote * 100 |
|
170 assertTrue(Math.abs(targetPitch - targetNote * 100.0) > 0.001); |
|
171 } |
|
172 } |
|
173 |
|
174 if (tuningProgram != -1) |
|
175 sendTuningChange(recv, 0, tuningProgram, tuningBank); |
|
176 |
|
177 // First test without tunings |
|
178 channel.noteOn(targetNote, 64); |
|
179 stream.read(buff, 0, buff.length); |
|
180 assertTrue(Math.abs(pitchspy.pitch - (targetNote * 100.0)) < 0.001); |
|
181 |
|
182 // Test if realtime/non-realtime works |
|
183 if (sysex != null) |
|
184 recv.send(sysex, -1); |
|
185 stream.read(buff, 0, buff.length); |
|
186 if (realtime) |
|
187 assertTrue(Math.abs(pitchspy.pitch - targetPitch) < 0.001); |
|
188 else |
|
189 assertTrue(Math.abs(pitchspy.pitch - (targetNote * 100.0)) < 0.001); |
|
190 |
|
191 // Test if tunings works |
|
192 channel.noteOn(targetNote, 0); |
|
193 stream.read(buff, 0, buff.length); |
|
194 assertTrue(Math.abs(pitchspy.pitch - 0.0) < 0.001); |
|
195 |
|
196 channel.noteOn(targetNote, 64); |
|
197 stream.read(buff, 0, buff.length); |
|
198 assertTrue(Math.abs(pitchspy.pitch - targetPitch) < 0.001); |
|
199 |
|
200 channel.noteOn(targetNote, 0); |
|
201 stream.read(buff, 0, buff.length); |
|
202 assertTrue(Math.abs(pitchspy.pitch - 0.0) < 0.001); |
|
203 |
|
204 stream.close(); |
|
205 } |
|
206 |
|
207 public static void main(String[] args) throws Exception { |
|
208 // Test with no-tunings |
|
209 testTunings(null, -1, -1, 60, 6000, false); |
|
210 |
|
211 int[] msg; |
|
212 // 0x02 SINGLE NOTE TUNING CHANGE (REAL-TIME) |
|
213 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x02, 0x10, 0x02, 36, 36, 64, |
|
214 0, 60, 70, 0, 0, 0xf7 }; |
|
215 testTunings(msg, 0x10, 0, 60, 7000, true); |
|
216 |
|
217 // 0x07 SINGLE NOTE TUNING CHANGE (NON REAL-TIME) (BANK) |
|
218 msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x07, 0x05, 0x07, 0x02, 36, |
|
219 36, 64, 0, 60, 80, 0, 0, 0xf7 }; |
|
220 testTunings(msg, 0x07, 0x05, 60, 8000, false); |
|
221 |
|
222 // 0x07 SINGLE NOTE TUNING CHANGE (REAL-TIME) (BANK) |
|
223 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x07, 0x05, 0x07, 0x02, 36, |
|
224 36, 64, 0, 60, 80, 0, 0, 0xf7 }; |
|
225 testTunings(msg, 0x07, 0x05, 60, 8000, true); |
|
226 |
|
227 // 0x08 scale/octave tuning 1-byte form (Non Real-Time) |
|
228 msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x08, 0x03, 0x7f, 0x7f, 5, |
|
229 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 0xf7 }; |
|
230 testTunings(msg, -1, -1, 60, 0, false); |
|
231 |
|
232 // 0x08 scale/octave tuning 1-byte form (REAL-TIME) |
|
233 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x08, 0x03, 0x7f, 0x7f, 5, |
|
234 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 0xf7 }; |
|
235 testTunings(msg, -1, -1, 60, 0, true); |
|
236 |
|
237 // 0x09 scale/octave tuning 2-byte form (Non Real-Time) |
|
238 msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x09, 0x03, 0x7f, 0x7f, 5, |
|
239 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 5, 10, 15, 20, 25, |
|
240 30, 35, 40, 45, 50, 51, 52, 0xf7 }; |
|
241 testTunings(msg, -1, -1, 60, 0, false); |
|
242 |
|
243 // 0x09 scale/octave tuning 2-byte form (REAL-TIME) |
|
244 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x09, 0x03, 0x7f, 0x7f, 5, |
|
245 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 5, 10, 15, 20, 25, |
|
246 30, 35, 40, 45, 50, 51, 52, 0xf7 }; |
|
247 testTunings(msg, -1, -1, 60, 0, true); |
|
248 |
|
249 } |
|
250 } |