1 /* 2 * Copyright (c) 2010, 2015, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 @summary Test RealTime-tunings using SoftReciver.send method 26 @modules java.desktop/com.sun.media.sound 27 */ 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 }