1 /* 2 * Copyright (c) 2010, 2013, 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 27 import java.io.IOException; 28 29 import javax.sound.midi.*; 30 import javax.sound.sampled.*; 31 32 import com.sun.media.sound.*; 33 34 public class RealTimeTuning { 35 36 private static class PitchSpy { 37 public float pitch = 0; 38 39 public Soundbank getSoundBank() { 40 ModelOscillator osc = new ModelOscillator() { 41 public float getAttenuation() { 42 return 0; 43 } 44 45 public int getChannels() { 46 return 0; 47 } 48 49 public ModelOscillatorStream open(float samplerate) { 50 return new ModelOscillatorStream() { 51 public void close() throws IOException { 52 pitch = 0; 53 } 54 55 public void noteOff(int velocity) { 56 pitch = 0; 57 } 58 59 public void noteOn(MidiChannel channel, 60 VoiceStatus voice, int noteNumber, int velocity) { 61 pitch = noteNumber * 100; 62 } 63 64 public int read(float[][] buffer, int offset, int len) 65 throws IOException { 66 return len; 67 } 68 69 public void setPitch(float ipitch) { 70 pitch = ipitch; 71 } 72 }; 73 } 74 }; 75 ModelPerformer performer = new ModelPerformer(); 76 performer.getOscillators().add(osc); 77 SimpleInstrument testinstrument = new SimpleInstrument(); 78 testinstrument.setPatch(new Patch(0, 0)); 79 testinstrument.add(performer); 80 SimpleSoundbank testsoundbank = new SimpleSoundbank(); 81 testsoundbank.addInstrument(testinstrument); 82 return testsoundbank; 83 } 84 } 85 86 public static void sendTuningChange(Receiver recv, int channel, 87 int tuningpreset, int tuningbank) throws InvalidMidiDataException { 88 // Data Entry 89 ShortMessage sm1 = new ShortMessage(); 90 sm1.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x64, 04); 91 ShortMessage sm2 = new ShortMessage(); 92 sm2.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x65, 00); 93 94 // Tuning Bank 95 ShortMessage sm3 = new ShortMessage(); 96 sm3.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x06, tuningbank); 97 // Data Increment 98 ShortMessage sm4 = new ShortMessage(); 99 sm4.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x60, 0x7F); 100 // Data Decrement 101 ShortMessage sm5 = new ShortMessage(); 102 sm5.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x61, 0x7F); 103 104 // Data Entry 105 ShortMessage sm6 = new ShortMessage(); 106 sm6.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x64, 03); 107 ShortMessage sm7 = new ShortMessage(); 108 sm7.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x65, 00); 109 110 // Tuning program 111 ShortMessage sm8 = new ShortMessage(); 112 sm8 113 .setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x06, 114 tuningpreset); 115 // Data Increment 116 ShortMessage sm9 = new ShortMessage(); 117 sm9.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x60, 0x7F); 118 // Data Decrement 119 ShortMessage sm10 = new ShortMessage(); 120 sm10.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x61, 0x7F); 121 122 recv.send(sm1, -1); 123 recv.send(sm2, -1); 124 recv.send(sm3, -1); 125 recv.send(sm4, -1); 126 recv.send(sm5, -1); 127 recv.send(sm6, -1); 128 recv.send(sm7, -1); 129 recv.send(sm8, -1); 130 recv.send(sm9, -1); 131 recv.send(sm10, -1); 132 133 } 134 135 private static void assertTrue(boolean value) throws Exception { 136 if (!value) 137 throw new RuntimeException("assertTrue fails!"); 138 } 139 140 public static void testTunings(int[] msg, int tuningProgram, 141 int tuningBank, int targetNote, float targetPitch, boolean realtime) 142 throws Exception { 143 AudioSynthesizer synth = new SoftSynthesizer(); 144 AudioInputStream stream = synth.openStream(null, null); 145 Receiver recv = synth.getReceiver(); 146 MidiChannel channel = synth.getChannels()[0]; 147 byte[] buff = new byte[2048]; 148 149 // Create test instrument which we can use to monitor pitch changes 150 PitchSpy pitchspy = new PitchSpy(); 151 152 synth.unloadAllInstruments(synth.getDefaultSoundbank()); 153 synth.loadAllInstruments(pitchspy.getSoundBank()); 154 155 SysexMessage sysex = null; 156 157 // Send tuning changes 158 if (msg != null) { 159 byte[] bmsg = new byte[msg.length]; 160 for (int i = 0; i < bmsg.length; i++) 161 bmsg[i] = (byte) msg[i]; 162 sysex = new SysexMessage(); 163 sysex.setMessage(bmsg, bmsg.length); 164 if (targetPitch == 0) { 165 targetPitch = (float) new SoftTuning(bmsg) 166 .getTuning(targetNote); 167 // Check if targetPitch != targetNote * 100 168 assertTrue(Math.abs(targetPitch - targetNote * 100.0) > 0.001); 169 } 170 } 171 172 if (tuningProgram != -1) 173 sendTuningChange(recv, 0, tuningProgram, tuningBank); 174 175 // First test without tunings 176 channel.noteOn(targetNote, 64); 177 stream.read(buff, 0, buff.length); 178 assertTrue(Math.abs(pitchspy.pitch - (targetNote * 100.0)) < 0.001); 179 180 // Test if realtime/non-realtime works 181 if (sysex != null) 182 recv.send(sysex, -1); 183 stream.read(buff, 0, buff.length); 184 if (realtime) 185 assertTrue(Math.abs(pitchspy.pitch - targetPitch) < 0.001); 186 else 187 assertTrue(Math.abs(pitchspy.pitch - (targetNote * 100.0)) < 0.001); 188 189 // Test if tunings works 190 channel.noteOn(targetNote, 0); 191 stream.read(buff, 0, buff.length); 192 assertTrue(Math.abs(pitchspy.pitch - 0.0) < 0.001); 193 194 channel.noteOn(targetNote, 64); 195 stream.read(buff, 0, buff.length); 196 assertTrue(Math.abs(pitchspy.pitch - targetPitch) < 0.001); 197 198 channel.noteOn(targetNote, 0); 199 stream.read(buff, 0, buff.length); 200 assertTrue(Math.abs(pitchspy.pitch - 0.0) < 0.001); 201 202 stream.close(); 203 } 204 205 public static void main(String[] args) throws Exception { 206 // Test with no-tunings 207 testTunings(null, -1, -1, 60, 6000, false); 208 209 int[] msg; 210 // 0x02 SINGLE NOTE TUNING CHANGE (REAL-TIME) 211 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x02, 0x10, 0x02, 36, 36, 64, 212 0, 60, 70, 0, 0, 0xf7 }; 213 testTunings(msg, 0x10, 0, 60, 7000, true); 214 215 // 0x07 SINGLE NOTE TUNING CHANGE (NON REAL-TIME) (BANK) 216 msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x07, 0x05, 0x07, 0x02, 36, 217 36, 64, 0, 60, 80, 0, 0, 0xf7 }; 218 testTunings(msg, 0x07, 0x05, 60, 8000, false); 219 220 // 0x07 SINGLE NOTE TUNING CHANGE (REAL-TIME) (BANK) 221 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x07, 0x05, 0x07, 0x02, 36, 222 36, 64, 0, 60, 80, 0, 0, 0xf7 }; 223 testTunings(msg, 0x07, 0x05, 60, 8000, true); 224 225 // 0x08 scale/octave tuning 1-byte form (Non Real-Time) 226 msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x08, 0x03, 0x7f, 0x7f, 5, 227 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 0xf7 }; 228 testTunings(msg, -1, -1, 60, 0, false); 229 230 // 0x08 scale/octave tuning 1-byte form (REAL-TIME) 231 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x08, 0x03, 0x7f, 0x7f, 5, 232 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 0xf7 }; 233 testTunings(msg, -1, -1, 60, 0, true); 234 235 // 0x09 scale/octave tuning 2-byte form (Non Real-Time) 236 msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x09, 0x03, 0x7f, 0x7f, 5, 237 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 5, 10, 15, 20, 25, 238 30, 35, 40, 45, 50, 51, 52, 0xf7 }; 239 testTunings(msg, -1, -1, 60, 0, false); 240 241 // 0x09 scale/octave tuning 2-byte form (REAL-TIME) 242 msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x09, 0x03, 0x7f, 0x7f, 5, 243 10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 5, 10, 15, 20, 25, 244 30, 35, 40, 45, 50, 51, 52, 0xf7 }; 245 testTunings(msg, -1, -1, 60, 0, true); 246 247 } 248 }