1 /* 2 * Copyright (c) 2003, 2016, 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 import javax.sound.midi.InvalidMidiDataException; 25 import javax.sound.midi.MetaMessage; 26 import javax.sound.midi.MidiEvent; 27 import javax.sound.midi.MidiSystem; 28 import javax.sound.midi.Receiver; 29 import javax.sound.midi.Sequence; 30 import javax.sound.midi.Sequencer; 31 import javax.sound.midi.ShortMessage; 32 import javax.sound.midi.Track; 33 34 /** 35 * @test 36 * @bug 4932841 37 * @key intermittent 38 * @summary Sequencer's recording feature does not work 39 */ 40 public class Recording { 41 42 public static boolean failed = false; 43 public static boolean passed = false; 44 private static Sequencer seq = null; 45 46 public static void main(String[] args) throws Exception { 47 try { 48 seq = MidiSystem.getSequencer(); 49 50 // create an arbitrary sequence which lasts 10 seconds 51 Sequence sequence = createSequence(10, 120, 240); 52 53 seq.setSequence(sequence); 54 out("Set Sequence to Sequencer. Tempo="+seq.getTempoInBPM()); 55 56 Track track = sequence.createTrack(); 57 int oldSize = track.size(); 58 seq.recordEnable(track, -1); 59 60 seq.open(); 61 62 // if getReceiver throws Exception, failed! 63 failed = true; 64 Receiver rec = seq.getReceiver(); 65 66 // start recording and add various events 67 seq.startRecording(); 68 69 // is exception from here on, not failed 70 failed = false; 71 72 if (!seq.isRecording()) { 73 failed = true; 74 throw new Exception("Sequencer did not start recording!"); 75 } 76 if (!seq.isRunning()) { 77 failed = true; 78 throw new Exception("Sequencer started recording, but is not running!"); 79 } 80 81 // first: add an event to the middle of the sequence 82 ShortMessage msg = new ShortMessage(); 83 msg.setMessage(0xC0, 80, 00); 84 rec.send(msg, 5l * 1000l * 1000l); 85 86 Thread.sleep(1000); 87 88 // then add a real-time event 89 msg = new ShortMessage(); 90 msg.setMessage(0xC0, 81, 00); 91 long secondEventTick = seq.getTickPosition(); 92 rec.send(msg, -1); 93 94 seq.stopRecording(); 95 if (seq.isRecording()) { 96 failed = true; 97 throw new Exception("Stopped recording, but Sequencer is still recording!"); 98 } 99 if (!seq.isRunning()) { 100 failed = true; 101 throw new Exception("Stopped recording, but Sequencer but is not running anymore!"); 102 } 103 104 seq.stop(); 105 if (seq.isRunning()) { 106 failed = true; 107 throw new Exception("Stopped Sequencer, but it is still running!"); 108 } 109 110 // now examine the contents of the recorded track: 111 // 1) number of events: should be 2 more 112 int newSize = track.size(); 113 int addedEventCount = newSize - oldSize; 114 115 out("Added "+addedEventCount+" events to recording track."); 116 if (addedEventCount != 2) { 117 failed = true; 118 throw new Exception("Did not add 2 events!"); 119 } 120 121 // 2) the first event should be at roughly "secondEventTick" 122 MidiEvent ev = track.get(0); 123 msg = (ShortMessage) ev.getMessage(); 124 out("The first recorded event is at tick position: "+ev.getTick()); 125 if (Math.abs(ev.getTick() - secondEventTick) > 1000) { 126 out(" -> but expected something like: "+secondEventTick+"! FAILED."); 127 failed = true; 128 } 129 130 ev = track.get(1); 131 msg = (ShortMessage) ev.getMessage(); 132 out("The 2nd recorded event is at tick position: "+ev.getTick()); 133 out(" -> sequence's tick length is "+seq.getTickLength()); 134 if (Math.abs(ev.getTick() - (sequence.getTickLength() / 2)) > 1000) { 135 out(" -> but expected something like: "+(seq.getTickLength()/2)+"! FAILED."); 136 failed = true; 137 } 138 139 passed = true; 140 } catch (Exception e) { 141 out(e.toString()); 142 if (!failed) out("Test not failed."); 143 } 144 if (seq != null) { 145 seq.close(); 146 } 147 148 if (failed) { 149 throw new Exception("Test FAILED!"); 150 } 151 else if (passed) { 152 out("Test Passed."); 153 } 154 } 155 156 /** 157 * Create a new Sequence for testing. 158 */ 159 private static Sequence createSequence(int lengthInSeconds, int tempoInBPM, 160 int resolution) { 161 Sequence sequence = null; 162 long lengthInMicroseconds = lengthInSeconds * 1000000; 163 boolean createTempoEvent = true; 164 if (tempoInBPM == 0) { 165 tempoInBPM = 120; 166 createTempoEvent = false; 167 System.out.print("Creating sequence: "+lengthInSeconds+"sec, " 168 +"resolution="+resolution+" ticks/beat..."); 169 } else { 170 System.out.print("Creating sequence: "+lengthInSeconds+"sec, " 171 +tempoInBPM+" beats/min, " 172 +"resolution="+resolution+" ticks/beat..."); 173 } 174 //long lengthInTicks = (lengthInMicroseconds * resolution) / tempoInBPM; 175 long lengthInTicks = (lengthInMicroseconds * tempoInBPM * resolution) / 60000000l; 176 //out("expected length in ticks: " + lengthInTicks); 177 try { 178 sequence = new Sequence(Sequence.PPQ, resolution); 179 Track track = sequence.createTrack(); 180 if (createTempoEvent) { 181 int tempoInMPQ = (int) (60000000l / tempoInBPM); 182 MetaMessage tm = new MetaMessage(); 183 byte[] msg = new byte[3]; 184 msg[0] = (byte) (tempoInMPQ >> 16); 185 msg[1] = (byte) ((tempoInMPQ >> 8) & 0xFF); 186 msg[2] = (byte) (tempoInMPQ & 0xFF); 187 188 tm.setMessage(0x51 /* Meta Tempo */, msg, msg.length); 189 track.add(new MidiEvent(tm, 0)); 190 //out("regtest: tempoInMPQ="+tempoInMPQ); 191 //out("Added tempo event: new size="+track.size()); 192 } 193 ShortMessage mm = new ShortMessage(); 194 mm.setMessage(0xF6, 0, 0); 195 MidiEvent me = new MidiEvent(mm, lengthInTicks); 196 track.add(me); 197 //out("Added realtime event: new size="+track.size()); 198 } catch (InvalidMidiDataException e) { 199 out(e); 200 } 201 out("OK"); 202 203 return sequence; 204 } 205 206 private static void out(Throwable t) { 207 t.printStackTrace(System.out); 208 } 209 210 private static void out(String message) { 211 System.out.println(message); 212 } 213 }