/* * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiEvent; import javax.sound.midi.MidiSystem; import javax.sound.midi.Receiver; import javax.sound.midi.Sequence; import javax.sound.midi.Sequencer; import javax.sound.midi.ShortMessage; import javax.sound.midi.Track; /** * @test * @bug 4932841 * @key intermittent * @summary Sequencer's recording feature does not work */ public class Recording { public static boolean failed = false; public static boolean passed = false; private static Sequencer seq = null; public static void main(String[] args) throws Exception { try { seq = MidiSystem.getSequencer(); // create an arbitrary sequence which lasts 10 seconds Sequence sequence = createSequence(10, 120, 240); seq.setSequence(sequence); out("Set Sequence to Sequencer. Tempo="+seq.getTempoInBPM()); Track track = sequence.createTrack(); int oldSize = track.size(); seq.recordEnable(track, -1); seq.open(); // if getReceiver throws Exception, failed! failed = true; Receiver rec = seq.getReceiver(); // start recording and add various events seq.startRecording(); // is exception from here on, not failed failed = false; if (!seq.isRecording()) { failed = true; throw new Exception("Sequencer did not start recording!"); } if (!seq.isRunning()) { failed = true; throw new Exception("Sequencer started recording, but is not running!"); } // first: add an event to the middle of the sequence ShortMessage msg = new ShortMessage(); msg.setMessage(0xC0, 80, 00); rec.send(msg, 5l * 1000l * 1000l); Thread.sleep(1000); // then add a real-time event msg = new ShortMessage(); msg.setMessage(0xC0, 81, 00); long secondEventTick = seq.getTickPosition(); rec.send(msg, -1); seq.stopRecording(); if (seq.isRecording()) { failed = true; throw new Exception("Stopped recording, but Sequencer is still recording!"); } if (!seq.isRunning()) { failed = true; throw new Exception("Stopped recording, but Sequencer but is not running anymore!"); } seq.stop(); if (seq.isRunning()) { failed = true; throw new Exception("Stopped Sequencer, but it is still running!"); } // now examine the contents of the recorded track: // 1) number of events: should be 2 more int newSize = track.size(); int addedEventCount = newSize - oldSize; out("Added "+addedEventCount+" events to recording track."); if (addedEventCount != 2) { failed = true; throw new Exception("Did not add 2 events!"); } // 2) the first event should be at roughly "secondEventTick" MidiEvent ev = track.get(0); msg = (ShortMessage) ev.getMessage(); out("The first recorded event is at tick position: "+ev.getTick()); if (Math.abs(ev.getTick() - secondEventTick) > 1000) { out(" -> but expected something like: "+secondEventTick+"! FAILED."); failed = true; } ev = track.get(1); msg = (ShortMessage) ev.getMessage(); out("The 2nd recorded event is at tick position: "+ev.getTick()); out(" -> sequence's tick length is "+seq.getTickLength()); if (Math.abs(ev.getTick() - (sequence.getTickLength() / 2)) > 1000) { out(" -> but expected something like: "+(seq.getTickLength()/2)+"! FAILED."); failed = true; } passed = true; } catch (Exception e) { out(e.toString()); if (!failed) out("Test not failed."); } if (seq != null) { seq.close(); } if (failed) { throw new Exception("Test FAILED!"); } else if (passed) { out("Test Passed."); } } /** * Create a new Sequence for testing. */ private static Sequence createSequence(int lengthInSeconds, int tempoInBPM, int resolution) { Sequence sequence = null; long lengthInMicroseconds = lengthInSeconds * 1000000; boolean createTempoEvent = true; if (tempoInBPM == 0) { tempoInBPM = 120; createTempoEvent = false; System.out.print("Creating sequence: "+lengthInSeconds+"sec, " +"resolution="+resolution+" ticks/beat..."); } else { System.out.print("Creating sequence: "+lengthInSeconds+"sec, " +tempoInBPM+" beats/min, " +"resolution="+resolution+" ticks/beat..."); } //long lengthInTicks = (lengthInMicroseconds * resolution) / tempoInBPM; long lengthInTicks = (lengthInMicroseconds * tempoInBPM * resolution) / 60000000l; //out("expected length in ticks: " + lengthInTicks); try { sequence = new Sequence(Sequence.PPQ, resolution); Track track = sequence.createTrack(); if (createTempoEvent) { int tempoInMPQ = (int) (60000000l / tempoInBPM); MetaMessage tm = new MetaMessage(); byte[] msg = new byte[3]; msg[0] = (byte) (tempoInMPQ >> 16); msg[1] = (byte) ((tempoInMPQ >> 8) & 0xFF); msg[2] = (byte) (tempoInMPQ & 0xFF); tm.setMessage(0x51 /* Meta Tempo */, msg, msg.length); track.add(new MidiEvent(tm, 0)); //out("regtest: tempoInMPQ="+tempoInMPQ); //out("Added tempo event: new size="+track.size()); } ShortMessage mm = new ShortMessage(); mm.setMessage(0xF6, 0, 0); MidiEvent me = new MidiEvent(mm, lengthInTicks); track.add(me); //out("Added realtime event: new size="+track.size()); } catch (InvalidMidiDataException e) { out(e); } out("OK"); return sequence; } private static void out(Throwable t) { t.printStackTrace(System.out); } private static void out(String message) { System.out.println(message); } }