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
24import javax.sound.midi.Instrument;
25import javax.sound.midi.InvalidMidiDataException;
26import javax.sound.midi.MetaEventListener;
27import javax.sound.midi.MetaMessage;
28import javax.sound.midi.MidiEvent;
29import javax.sound.midi.MidiSystem;
30import javax.sound.midi.Sequence;
31import javax.sound.midi.Sequencer;
32import javax.sound.midi.ShortMessage;
33import javax.sound.midi.Track;
34
35/**
36 * @test
37 * @bug 4347135
38 * @summary MIDI MetaMessage callback inconsistent
39 * @run main/othervm MetaCallback
40 */
41public class MetaCallback implements MetaEventListener {
42
43    static ShortMessage MidiMsg3(int a, int b, int c) {
44        try {
45            ShortMessage msg = new ShortMessage();
46            msg.setMessage((byte)a,(byte)b,(byte)c);
47            return msg;
48        } catch(InvalidMidiDataException ex) {
49            throw new RuntimeException();
50        }
51    }
52
53    //Synthesizer synth;
54    Instrument[] instruments;
55    Sequencer sequencer;
56    Sequence sequence;
57    Track track;
58
59    public static int TOTAL_COUNT = 100;
60
61    int metaCount = 0;
62    boolean finished = false;
63
64    MetaCallback() throws Exception {
65
66        sequencer=MidiSystem.getSequencer();
67        sequence=new Sequence(Sequence.PPQ,240);
68        track=sequence.createTrack();
69        sequencer.addMetaEventListener(this);
70
71        byte[] data = new byte[1];
72
73        track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+0,45,100),0));
74        track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+0,45,0),0 + 240));
75        int c;
76        for(c=0; c < TOTAL_COUNT; c++) {
77            data[0]=(byte)(c+1);
78            MetaMessage meta = new MetaMessage();
79            meta.setMessage(1, data, 1); // type, data, length
80            track.add(new MidiEvent(meta,c*20));
81        }
82        track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+9,45,100),c*20));
83        track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+9,45,0),c*20 + 10));
84
85        sequencer.setSlaveSyncMode(Sequencer.SyncMode.INTERNAL_CLOCK);
86        sequencer.setMasterSyncMode(Sequencer.SyncMode.INTERNAL_CLOCK);
87        sequencer.open();
88        sequencer.setSequence(sequence);
89        sequencer.setTempoInBPM(100);
90        System.out.println("Starting playback...");
91        this.start();
92        while (!finished && sequencer.getTickPosition() < sequencer.getTickLength()) {
93            System.out.println("Tick "+sequencer.getTickPosition()+"...");
94            Thread.sleep(1000);
95        }
96        System.out.println("Stopping playback...");
97        this.stop();
98        if (metaCount != TOTAL_COUNT) {
99            throw new Exception("Expected "+TOTAL_COUNT+" callbacks, but got "+metaCount+"!");
100        }
101    }
102    void start() {sequencer.start();}
103    void stop() {sequencer.stop();}
104
105    public void meta(MetaMessage msg) {
106        System.out.println(""+metaCount+": got "+msg);
107        if (msg.getType() == 0x2F) {
108            finished = true;
109        } else if (msg.getData().length > 0 && msg.getType() == 1) {
110            metaCount++;
111        }
112    }
113
114    public static void main(String[] argv) throws Exception {
115        if (hasSequencer()) {
116            new MetaCallback();
117            System.out.println("Test passed");
118        }
119    }
120
121    static boolean hasSequencer() {
122        try {
123            Sequencer seq = MidiSystem.getSequencer();
124            if (seq != null) {
125                seq.open();
126                seq.close();
127                return true;
128            }
129        } catch (Exception e) {}
130        System.out.println("No sequencer available! Cannot execute test.");
131        return false;
132    }
133}
134