jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java
author ohair
Wed, 06 Apr 2011 22:06:11 -0700
changeset 9035 1255eb81cc2f
parent 8528 f496950c5d98
child 16876 17f574546dc8
permissions -rw-r--r--
7033660: Update copyright year to 2011 on any files changed in 2011 Reviewed-by: dholmes
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
9035
1255eb81cc2f 7033660: Update copyright year to 2011 on any files changed in 2011
ohair
parents: 8528
diff changeset
     2
 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1846
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1846
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1846
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1846
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 1846
diff changeset
    23
 * questions.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package com.sun.media.sound;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.io.ByteArrayOutputStream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.io.ByteArrayInputStream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import java.io.DataOutputStream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.io.IOException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.io.InputStream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
import java.util.ArrayList;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
import java.util.List;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import javax.sound.midi.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
 * A Real Time Sequencer
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * @author Florian Bomers
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
/* TODO:
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * - rename PlayThread to PlayEngine (because isn't a thread)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
class RealTimeSequencer extends AbstractMidiDevice implements Sequencer, AutoConnectSequencer {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
    // STATIC VARIABLES
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
    /** debugging flags */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
    private final static boolean DEBUG_PUMP = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
    private final static boolean DEBUG_PUMP_ALL = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
     * Event Dispatcher thread. Should be using a shared event
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
     * dispatcher instance with a factory in EventDispatcher
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
    private static final EventDispatcher eventDispatcher;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
     * All RealTimeSequencers share this info object.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    static final RealTimeSequencerInfo info = new RealTimeSequencerInfo();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
    private static Sequencer.SyncMode[] masterSyncModes = { Sequencer.SyncMode.INTERNAL_CLOCK };
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
    private static Sequencer.SyncMode[] slaveSyncModes  = { Sequencer.SyncMode.NO_SYNC };
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
    private static Sequencer.SyncMode masterSyncMode    = Sequencer.SyncMode.INTERNAL_CLOCK;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
    private static Sequencer.SyncMode slaveSyncMode     = Sequencer.SyncMode.NO_SYNC;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
     * Sequence on which this sequencer is operating.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    private Sequence sequence = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
    // caches
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
     * Same for setTempoInMPQ...
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
     * -1 means not set.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
    private double cacheTempoMPQ = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
     * cache value for tempo factor until sequence is set
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
     * -1 means not set.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
    private float cacheTempoFactor = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
    /** if a particular track is muted */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
    private boolean[] trackMuted = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
    /** if a particular track is solo */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
    private boolean[] trackSolo = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
    /** tempo cache for getMicrosecondPosition */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
    private MidiUtils.TempoCache tempoCache = new MidiUtils.TempoCache();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
     * True if the sequence is running.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
    private boolean running = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
    /** the thread for pushing out the MIDI messages */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
    private PlayThread playThread;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
     * True if we are recording
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
    private boolean recording = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
     * List of tracks to which we're recording
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
    private List recordingTracks = new ArrayList();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
    private long loopStart = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
    private long loopEnd = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
    private int loopCount = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
     * Meta event listeners
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
    private ArrayList metaEventListeners = new ArrayList();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
     * Control change listeners
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
    private ArrayList controllerEventListeners = new ArrayList();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
    /** automatic connection support */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
    private boolean autoConnect = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
    /** if we need to autoconnect at next open */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
    private boolean doAutoConnectAtNextOpen = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
    /** the receiver that this device is auto-connected to */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
    Receiver autoConnectedReceiver = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
    static {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
        // create and start the global event thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
        eventDispatcher = new EventDispatcher();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
        eventDispatcher.start();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
    /* ****************************** CONSTRUCTOR ****************************** */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
    protected RealTimeSequencer() throws MidiUnavailableException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
        super(info);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
        if (Printer.trace) Printer.trace(">> RealTimeSequencer CONSTRUCTOR");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
        if (Printer.trace) Printer.trace("<< RealTimeSequencer CONSTRUCTOR completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
    /* ****************************** SEQUENCER METHODS ******************** */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
    public synchronized void setSequence(Sequence sequence)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
        throws InvalidMidiDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setSequence(" + sequence +")");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
        if (sequence != this.sequence) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
            if (this.sequence != null && sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
                setCaches();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
                stop();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
                // initialize some non-cached values
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
                trackMuted = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
                trackSolo = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
                loopStart = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
                loopEnd = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
                loopCount = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
                if (getDataPump() != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
                    getDataPump().setTickPos(0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
                    getDataPump().resetLoopCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
            if (playThread != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
                playThread.setSequence(sequence);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
            // store this sequence (do not copy - we want to give the possibility
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
            // of modifying the sequence at runtime)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
            this.sequence = sequence;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
            if (sequence != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
                tempoCache.refresh(sequence);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
                // rewind to the beginning
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
                setTickPosition(0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
                // propagate caches
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
                propagateCaches();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
        else if (sequence != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
            tempoCache.refresh(sequence);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
            if (playThread != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
                playThread.setSequence(sequence);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: setSequence(" + sequence +") completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
    public synchronized void setSequence(InputStream stream) throws IOException, InvalidMidiDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setSequence(" + stream +")");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
        if (stream == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
            setSequence((Sequence) null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
        Sequence seq = MidiSystem.getSequence(stream); // can throw IOException, InvalidMidiDataException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
        setSequence(seq);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: setSequence(" + stream +") completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
    public Sequence getSequence() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
        return sequence;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
    public synchronized void start() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: start()");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
        // sequencer not open: throw an exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
        if (!isOpen()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
            throw new IllegalStateException("sequencer not open");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
        // sequence not available: throw an exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
        if (sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
            throw new IllegalStateException("sequence not set");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
        // already running: return quietly
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
        if (running == true) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
        // start playback
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
        implStart();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: start() completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
    public synchronized void stop() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: stop()");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
        if (!isOpen()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
            throw new IllegalStateException("sequencer not open");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
        stopRecording();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
        // not running; just return
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
        if (running == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
            if (Printer.trace) Printer.trace("<< RealTimeSequencer: stop() not running!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
        // stop playback
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
        implStop();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: stop() completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
    public boolean isRunning() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
        return running;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
    public void startRecording() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
        if (!isOpen()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
            throw new IllegalStateException("Sequencer not open");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
        start();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
        recording = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
    public void stopRecording() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
        if (!isOpen()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
            throw new IllegalStateException("Sequencer not open");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
        recording = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
    public boolean isRecording() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
        return recording;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
    public void recordEnable(Track track, int channel) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
        if (!findTrack(track)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
            throw new IllegalArgumentException("Track does not exist in the current sequence");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
        synchronized(recordingTracks) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
            RecordingTrack rc = RecordingTrack.get(recordingTracks, track);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
            if (rc != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
                rc.channel = channel;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
                recordingTracks.add(new RecordingTrack(track, channel));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
    public void recordDisable(Track track) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
        synchronized(recordingTracks) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
            RecordingTrack rc = RecordingTrack.get(recordingTracks, track);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
            if (rc != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
                recordingTracks.remove(rc);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
    private boolean findTrack(Track track) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
        boolean found = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
        if (sequence != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
            Track[] tracks = sequence.getTracks();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
            for (int i = 0; i < tracks.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
                if (track == tracks[i]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
                    found = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
        return found;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
    public float getTempoInBPM() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoInBPM() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
        return (float) MidiUtils.convertTempo(getTempoInMPQ());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
    public void setTempoInBPM(float bpm) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setTempoInBPM() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
        if (bpm <= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
            // should throw IllegalArgumentException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
            bpm = 1.0f;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
        setTempoInMPQ((float) MidiUtils.convertTempo((double) bpm));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
    public float getTempoInMPQ() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoInMPQ() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
        if (needCaching()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
            // if the sequencer is closed, return cached value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
            if (cacheTempoMPQ != -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
                return (float) cacheTempoMPQ;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
            // if sequence is set, return current tempo
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
            if (sequence != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
                return tempoCache.getTempoMPQAt(getTickPosition());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
            // last resort: return a standard tempo: 120bpm
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
            return (float) MidiUtils.DEFAULT_TEMPO_MPQ;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
        return (float)getDataPump().getTempoMPQ();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
    public void setTempoInMPQ(float mpq) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
        if (mpq <= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
            // should throw IllegalArgumentException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
            mpq = 1.0f;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setTempoInMPQ() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
        if (needCaching()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
            // cache the value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
            cacheTempoMPQ = mpq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
            // set the native tempo in MPQ
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
            getDataPump().setTempoMPQ(mpq);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
            // reset the tempoInBPM and tempoInMPQ values so we won't use them again
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
            cacheTempoMPQ = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
    public void setTempoFactor(float factor) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
        if (factor <= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
            // should throw IllegalArgumentException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setTempoFactor() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
        if (needCaching()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
            cacheTempoFactor = factor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
            getDataPump().setTempoFactor(factor);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
            // don't need cache anymore
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
            cacheTempoFactor = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
    public float getTempoFactor() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoFactor() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
        if (needCaching()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
            if (cacheTempoFactor != -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
                return cacheTempoFactor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
            return 1.0f;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
        return getDataPump().getTempoFactor();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
    public long getTickLength() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTickLength() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
        if (sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
            return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
        return sequence.getTickLength();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
    public synchronized long getTickPosition() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTickPosition() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
        if (getDataPump() == null || sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
            return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
        return getDataPump().getTickPos();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   471
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
    public synchronized void setTickPosition(long tick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
        if (tick < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
            // should throw IllegalArgumentException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setTickPosition("+tick+") ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
        if (getDataPump() == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
            if (tick != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   483
                // throw new InvalidStateException("cannot set position in closed state");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
        else if (sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
            if (tick != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
                // throw new InvalidStateException("cannot set position if sequence is not set");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
            getDataPump().setTickPos(tick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
    public long getMicrosecondLength() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getMicrosecondLength() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
        if (sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
            return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
        return sequence.getMicrosecondLength();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   504
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
90ce3da70b43 Initial load
duke
parents:
diff changeset
   507
    public long getMicrosecondPosition() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   508
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: getMicrosecondPosition() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   509
90ce3da70b43 Initial load
duke
parents:
diff changeset
   510
        if (getDataPump() == null || sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   511
            return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   512
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   513
        synchronized (tempoCache) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   514
            return MidiUtils.tick2microsecond(sequence, getDataPump().getTickPos(), tempoCache);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   515
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   516
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   517
90ce3da70b43 Initial load
duke
parents:
diff changeset
   518
90ce3da70b43 Initial load
duke
parents:
diff changeset
   519
    public void setMicrosecondPosition(long microseconds) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   520
        if (microseconds < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   521
            // should throw IllegalArgumentException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   522
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   523
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   524
90ce3da70b43 Initial load
duke
parents:
diff changeset
   525
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: setMicrosecondPosition("+microseconds+") ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   526
90ce3da70b43 Initial load
duke
parents:
diff changeset
   527
        if (getDataPump() == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   528
            if (microseconds != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
                // throw new InvalidStateException("cannot set position in closed state");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   532
        else if (sequence == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   533
            if (microseconds != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   534
                // throw new InvalidStateException("cannot set position if sequence is not set");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   535
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   536
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   537
            synchronized(tempoCache) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   538
                setTickPosition(MidiUtils.microsecond2tick(sequence, microseconds, tempoCache));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   539
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   540
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   541
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   542
90ce3da70b43 Initial load
duke
parents:
diff changeset
   543
90ce3da70b43 Initial load
duke
parents:
diff changeset
   544
    public void setMasterSyncMode(Sequencer.SyncMode sync) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   545
        // not supported
90ce3da70b43 Initial load
duke
parents:
diff changeset
   546
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
90ce3da70b43 Initial load
duke
parents:
diff changeset
   548
90ce3da70b43 Initial load
duke
parents:
diff changeset
   549
    public Sequencer.SyncMode getMasterSyncMode() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
        return masterSyncMode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
    public Sequencer.SyncMode[] getMasterSyncModes() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   555
        Sequencer.SyncMode[] returnedModes = new Sequencer.SyncMode[masterSyncModes.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
        System.arraycopy(masterSyncModes, 0, returnedModes, 0, masterSyncModes.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   557
        return returnedModes;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   558
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   559
90ce3da70b43 Initial load
duke
parents:
diff changeset
   560
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
    public void setSlaveSyncMode(Sequencer.SyncMode sync) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   562
        // not supported
90ce3da70b43 Initial load
duke
parents:
diff changeset
   563
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   564
90ce3da70b43 Initial load
duke
parents:
diff changeset
   565
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
    public Sequencer.SyncMode getSlaveSyncMode() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
        return slaveSyncMode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   569
90ce3da70b43 Initial load
duke
parents:
diff changeset
   570
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
    public Sequencer.SyncMode[] getSlaveSyncModes() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   572
        Sequencer.SyncMode[] returnedModes = new Sequencer.SyncMode[slaveSyncModes.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   573
        System.arraycopy(slaveSyncModes, 0, returnedModes, 0, slaveSyncModes.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
        return returnedModes;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   576
90ce3da70b43 Initial load
duke
parents:
diff changeset
   577
    protected int getTrackCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   578
        Sequence seq = getSequence();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
        if (seq != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
            // $$fb wish there was a nicer way to get the number of tracks...
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
            return sequence.getTracks().length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   582
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   583
        return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   585
90ce3da70b43 Initial load
duke
parents:
diff changeset
   586
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
    public synchronized void setTrackMute(int track, boolean mute) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   589
        int trackCount = getTrackCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   590
        if (track < 0 || track >= getTrackCount()) return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   591
        trackMuted = ensureBoolArraySize(trackMuted, trackCount);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   592
        trackMuted[track] = mute;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   593
        if (getDataPump() != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   594
            getDataPump().muteSoloChanged();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   595
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   596
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   597
90ce3da70b43 Initial load
duke
parents:
diff changeset
   598
90ce3da70b43 Initial load
duke
parents:
diff changeset
   599
    public synchronized boolean getTrackMute(int track) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   600
        if (track < 0 || track >= getTrackCount()) return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   601
        if (trackMuted == null || trackMuted.length <= track) return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
        return trackMuted[track];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   604
90ce3da70b43 Initial load
duke
parents:
diff changeset
   605
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
    public synchronized void setTrackSolo(int track, boolean solo) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
        int trackCount = getTrackCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
        if (track < 0 || track >= getTrackCount()) return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
        trackSolo = ensureBoolArraySize(trackSolo, trackCount);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
        trackSolo[track] = solo;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   611
        if (getDataPump() != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   612
            getDataPump().muteSoloChanged();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
90ce3da70b43 Initial load
duke
parents:
diff changeset
   616
90ce3da70b43 Initial load
duke
parents:
diff changeset
   617
    public synchronized boolean getTrackSolo(int track) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
        if (track < 0 || track >= getTrackCount()) return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
        if (trackSolo == null || trackSolo.length <= track) return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   620
        return trackSolo[track];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   621
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   622
90ce3da70b43 Initial load
duke
parents:
diff changeset
   623
90ce3da70b43 Initial load
duke
parents:
diff changeset
   624
    public boolean addMetaEventListener(MetaEventListener listener) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   625
        synchronized(metaEventListeners) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   626
            if (! metaEventListeners.contains(listener)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   627
90ce3da70b43 Initial load
duke
parents:
diff changeset
   628
                metaEventListeners.add(listener);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   629
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   630
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   631
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   632
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   633
90ce3da70b43 Initial load
duke
parents:
diff changeset
   634
90ce3da70b43 Initial load
duke
parents:
diff changeset
   635
    public void removeMetaEventListener(MetaEventListener listener) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   636
        synchronized(metaEventListeners) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   637
            int index = metaEventListeners.indexOf(listener);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   638
            if (index >= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   639
                metaEventListeners.remove(index);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   640
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   641
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   642
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   643
90ce3da70b43 Initial load
duke
parents:
diff changeset
   644
90ce3da70b43 Initial load
duke
parents:
diff changeset
   645
    public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   646
        synchronized(controllerEventListeners) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   647
90ce3da70b43 Initial load
duke
parents:
diff changeset
   648
            // first find the listener.  if we have one, add the controllers
90ce3da70b43 Initial load
duke
parents:
diff changeset
   649
            // if not, create a new element for it.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   650
            ControllerListElement cve = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   651
            boolean flag = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   652
            for(int i=0; i < controllerEventListeners.size(); i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   653
90ce3da70b43 Initial load
duke
parents:
diff changeset
   654
                cve = (ControllerListElement) controllerEventListeners.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   655
90ce3da70b43 Initial load
duke
parents:
diff changeset
   656
                if (cve.listener.equals(listener)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   657
                    cve.addControllers(controllers);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   658
                    flag = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   659
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   660
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   661
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   662
            if (!flag) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   663
                cve = new ControllerListElement(listener, controllers);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   664
                controllerEventListeners.add(cve);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   665
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   666
90ce3da70b43 Initial load
duke
parents:
diff changeset
   667
            // and return all the controllers this listener is interested in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   668
            return cve.getControllers();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   669
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   670
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   671
90ce3da70b43 Initial load
duke
parents:
diff changeset
   672
90ce3da70b43 Initial load
duke
parents:
diff changeset
   673
    public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   674
        synchronized(controllerEventListeners) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   675
            ControllerListElement cve = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   676
            boolean flag = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   677
            for (int i=0; i < controllerEventListeners.size(); i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   678
                cve = (ControllerListElement) controllerEventListeners.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   679
                if (cve.listener.equals(listener)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   680
                    cve.removeControllers(controllers);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   681
                    flag = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   682
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   683
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   684
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   685
            if (!flag) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   686
                return new int[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   687
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   688
            if (controllers == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   689
                int index = controllerEventListeners.indexOf(cve);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   690
                if (index >= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   691
                    controllerEventListeners.remove(index);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   692
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   693
                return new int[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   694
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   695
            return cve.getControllers();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   696
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   697
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   698
90ce3da70b43 Initial load
duke
parents:
diff changeset
   699
90ce3da70b43 Initial load
duke
parents:
diff changeset
   700
    ////////////////// LOOPING (added in 1.5) ///////////////////////
90ce3da70b43 Initial load
duke
parents:
diff changeset
   701
90ce3da70b43 Initial load
duke
parents:
diff changeset
   702
    public void setLoopStartPoint(long tick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   703
        if ((tick > getTickLength())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   704
            || ((loopEnd != -1) && (tick > loopEnd))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   705
            || (tick < 0)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   706
            throw new IllegalArgumentException("invalid loop start point: "+tick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   707
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   708
        loopStart = tick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   709
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   710
90ce3da70b43 Initial load
duke
parents:
diff changeset
   711
    public long getLoopStartPoint() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   712
        return loopStart;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   713
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   714
90ce3da70b43 Initial load
duke
parents:
diff changeset
   715
    public void setLoopEndPoint(long tick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   716
        if ((tick > getTickLength())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   717
            || ((loopStart > tick) && (tick != -1))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   718
            || (tick < -1)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   719
            throw new IllegalArgumentException("invalid loop end point: "+tick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   720
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   721
        loopEnd = tick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   722
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   723
90ce3da70b43 Initial load
duke
parents:
diff changeset
   724
    public long getLoopEndPoint() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   725
        return loopEnd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   726
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   727
90ce3da70b43 Initial load
duke
parents:
diff changeset
   728
    public void setLoopCount(int count) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   729
        if (count != LOOP_CONTINUOUSLY
90ce3da70b43 Initial load
duke
parents:
diff changeset
   730
            && count < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   731
            throw new IllegalArgumentException("illegal value for loop count: "+count);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   732
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   733
        loopCount = count;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   734
        if (getDataPump() != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   735
            getDataPump().resetLoopCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   736
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   737
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   738
90ce3da70b43 Initial load
duke
parents:
diff changeset
   739
    public int getLoopCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   740
        return loopCount;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   741
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   742
90ce3da70b43 Initial load
duke
parents:
diff changeset
   743
90ce3da70b43 Initial load
duke
parents:
diff changeset
   744
    /* *********************************** play control ************************* */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   745
90ce3da70b43 Initial load
duke
parents:
diff changeset
   746
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   747
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   748
    protected void implOpen() throws MidiUnavailableException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   749
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: implOpen()");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   750
90ce3da70b43 Initial load
duke
parents:
diff changeset
   751
        //openInternalSynth();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   752
90ce3da70b43 Initial load
duke
parents:
diff changeset
   753
        // create PlayThread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   754
        playThread = new PlayThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   755
90ce3da70b43 Initial load
duke
parents:
diff changeset
   756
        //id = nOpen();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   757
        //if (id == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   758
        //    throw new MidiUnavailableException("unable to open sequencer");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   759
        //}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   760
        if (sequence != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   761
            playThread.setSequence(sequence);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   762
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   763
90ce3da70b43 Initial load
duke
parents:
diff changeset
   764
        // propagate caches
90ce3da70b43 Initial load
duke
parents:
diff changeset
   765
        propagateCaches();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   766
90ce3da70b43 Initial load
duke
parents:
diff changeset
   767
        if (doAutoConnectAtNextOpen) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   768
            doAutoConnect();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   769
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   770
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: implOpen() succeeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   771
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   772
90ce3da70b43 Initial load
duke
parents:
diff changeset
   773
    private void doAutoConnect() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   774
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: doAutoConnect()");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   775
        Receiver rec = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   776
        // first try to connect to the default synthesizer
90ce3da70b43 Initial load
duke
parents:
diff changeset
   777
        // IMPORTANT: this code needs to be synch'ed with
8528
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   778
        //            MidiSystem.getSequencer(boolean), because the same
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   779
        //            algorithm needs to be used!
90ce3da70b43 Initial load
duke
parents:
diff changeset
   780
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   781
            Synthesizer synth = MidiSystem.getSynthesizer();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   782
            if (synth instanceof ReferenceCountingDevice) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   783
                rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   784
            } else {
8528
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   785
                synth.open();
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   786
                try {
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   787
                    rec = synth.getReceiver();
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   788
                } finally {
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   789
                    // make sure that the synth is properly closed
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   790
                    if (rec == null) {
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   791
                        synth.close();
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   792
                    }
f496950c5d98 6660470: RealTimeSequencer incorrectly opens (implicitly) synthesizer
amenkov
parents: 6832
diff changeset
   793
                }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   794
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   795
        } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   796
            // something went wrong with synth
90ce3da70b43 Initial load
duke
parents:
diff changeset
   797
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   798
        if (rec == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   799
            // then try to connect to the default Receiver
90ce3da70b43 Initial load
duke
parents:
diff changeset
   800
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   801
                rec = MidiSystem.getReceiver();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   802
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   803
                // something went wrong. Nothing to do then!
90ce3da70b43 Initial load
duke
parents:
diff changeset
   804
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   805
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   806
        if (rec != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   807
            autoConnectedReceiver = rec;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   808
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   809
                getTransmitter().setReceiver(rec);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   810
            } catch (Exception e) {}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   811
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   812
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: doAutoConnect() succeeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   813
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   814
90ce3da70b43 Initial load
duke
parents:
diff changeset
   815
    private synchronized void propagateCaches() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   816
        // only set caches if open and sequence is set
90ce3da70b43 Initial load
duke
parents:
diff changeset
   817
        if (sequence != null && isOpen()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   818
            if (cacheTempoFactor != -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   819
                setTempoFactor(cacheTempoFactor);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   820
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   821
            if (cacheTempoMPQ == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   822
                setTempoInMPQ((new MidiUtils.TempoCache(sequence)).getTempoMPQAt(getTickPosition()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   823
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   824
                setTempoInMPQ((float) cacheTempoMPQ);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   825
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   826
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   827
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   828
90ce3da70b43 Initial load
duke
parents:
diff changeset
   829
    /** populate the caches with the current values */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   830
    private synchronized void setCaches() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   831
        cacheTempoFactor = getTempoFactor();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   832
        cacheTempoMPQ = getTempoInMPQ();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   833
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   834
90ce3da70b43 Initial load
duke
parents:
diff changeset
   835
90ce3da70b43 Initial load
duke
parents:
diff changeset
   836
90ce3da70b43 Initial load
duke
parents:
diff changeset
   837
    protected synchronized void implClose() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   838
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: implClose() ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   839
90ce3da70b43 Initial load
duke
parents:
diff changeset
   840
        if (playThread == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   841
            if (Printer.err) Printer.err("RealTimeSequencer.implClose() called, but playThread not instanciated!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   842
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   843
            // Interrupt playback loop.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   844
            playThread.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   845
            playThread = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   846
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   847
90ce3da70b43 Initial load
duke
parents:
diff changeset
   848
        super.implClose();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   849
90ce3da70b43 Initial load
duke
parents:
diff changeset
   850
        sequence = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   851
        running = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   852
        cacheTempoMPQ = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   853
        cacheTempoFactor = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   854
        trackMuted = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   855
        trackSolo = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   856
        loopStart = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   857
        loopEnd = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   858
        loopCount = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   859
90ce3da70b43 Initial load
duke
parents:
diff changeset
   860
        /** if this sequencer is set to autoconnect, need to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   861
         * re-establish the connection at next open!
90ce3da70b43 Initial load
duke
parents:
diff changeset
   862
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   863
        doAutoConnectAtNextOpen = autoConnect;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   864
90ce3da70b43 Initial load
duke
parents:
diff changeset
   865
        if (autoConnectedReceiver != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   866
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   867
                autoConnectedReceiver.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   868
            } catch (Exception e) {}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   869
            autoConnectedReceiver = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   870
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   871
90ce3da70b43 Initial load
duke
parents:
diff changeset
   872
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: implClose() completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   873
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   874
90ce3da70b43 Initial load
duke
parents:
diff changeset
   875
    protected void implStart() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   876
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: implStart()");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   877
90ce3da70b43 Initial load
duke
parents:
diff changeset
   878
        if (playThread == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   879
            if (Printer.err) Printer.err("RealTimeSequencer.implStart() called, but playThread not instanciated!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   880
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   881
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   882
90ce3da70b43 Initial load
duke
parents:
diff changeset
   883
        tempoCache.refresh(sequence);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   884
        if (!running) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   885
            running  = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   886
            playThread.start();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   887
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   888
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: implStart() completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   889
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   890
90ce3da70b43 Initial load
duke
parents:
diff changeset
   891
90ce3da70b43 Initial load
duke
parents:
diff changeset
   892
    protected void implStop() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   893
        if (Printer.trace) Printer.trace(">> RealTimeSequencer: implStop()");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   894
90ce3da70b43 Initial load
duke
parents:
diff changeset
   895
        if (playThread == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   896
            if (Printer.err) Printer.err("RealTimeSequencer.implStop() called, but playThread not instanciated!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   897
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   898
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   899
90ce3da70b43 Initial load
duke
parents:
diff changeset
   900
        recording = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   901
        if (running) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   902
            running = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   903
            playThread.stop();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   904
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   905
        if (Printer.trace) Printer.trace("<< RealTimeSequencer: implStop() completed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   906
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   907
90ce3da70b43 Initial load
duke
parents:
diff changeset
   908
90ce3da70b43 Initial load
duke
parents:
diff changeset
   909
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   910
     * Send midi player events.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   911
     * must not be synchronized on "this"
90ce3da70b43 Initial load
duke
parents:
diff changeset
   912
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   913
    protected void sendMetaEvents(MidiMessage message) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   914
        if (metaEventListeners.size() == 0) return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   915
90ce3da70b43 Initial load
duke
parents:
diff changeset
   916
        //if (Printer.debug) Printer.debug("sending a meta event");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   917
        eventDispatcher.sendAudioEvents(message, metaEventListeners);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   918
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   919
90ce3da70b43 Initial load
duke
parents:
diff changeset
   920
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   921
     * Send midi player events.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   922
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   923
    protected void sendControllerEvents(MidiMessage message) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   924
        int size = controllerEventListeners.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   925
        if (size == 0) return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   926
90ce3da70b43 Initial load
duke
parents:
diff changeset
   927
        //if (Printer.debug) Printer.debug("sending a controller event");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   928
90ce3da70b43 Initial load
duke
parents:
diff changeset
   929
        if (! (message instanceof ShortMessage)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   930
            if (Printer.debug) Printer.debug("sendControllerEvents: message is NOT instanceof ShortMessage!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   931
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   932
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   933
        ShortMessage msg = (ShortMessage) message;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   934
        int controller = msg.getData1();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   935
        List sendToListeners = new ArrayList();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   936
        for (int i = 0; i < size; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   937
            ControllerListElement cve = (ControllerListElement) controllerEventListeners.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   938
            for(int j = 0; j < cve.controllers.length; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   939
                if (cve.controllers[j] == controller) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   940
                    sendToListeners.add(cve.listener);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   941
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   942
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   943
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   944
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   945
        eventDispatcher.sendAudioEvents(message, sendToListeners);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   946
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   947
90ce3da70b43 Initial load
duke
parents:
diff changeset
   948
90ce3da70b43 Initial load
duke
parents:
diff changeset
   949
90ce3da70b43 Initial load
duke
parents:
diff changeset
   950
    private boolean needCaching() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   951
        return !isOpen() || (sequence == null) || (playThread == null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   952
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   953
90ce3da70b43 Initial load
duke
parents:
diff changeset
   954
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   955
     * return the data pump instance, owned by play thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   956
     * if playthread is null, return null.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   957
     * This method is guaranteed to return non-null if
90ce3da70b43 Initial load
duke
parents:
diff changeset
   958
     * needCaching returns false
90ce3da70b43 Initial load
duke
parents:
diff changeset
   959
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   960
    private DataPump getDataPump() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   961
        if (playThread != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   962
            return playThread.getDataPump();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   963
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   964
        return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   965
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   966
90ce3da70b43 Initial load
duke
parents:
diff changeset
   967
    private MidiUtils.TempoCache getTempoCache() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   968
        return tempoCache;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   969
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   970
90ce3da70b43 Initial load
duke
parents:
diff changeset
   971
    private static boolean[] ensureBoolArraySize(boolean[] array, int desiredSize) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   972
        if (array == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   973
            return new boolean[desiredSize];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   974
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   975
        if (array.length < desiredSize) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   976
            boolean[] newArray = new boolean[desiredSize];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   977
            System.arraycopy(array, 0, newArray, 0, array.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   978
            return newArray;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   979
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   980
        return array;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   981
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   982
90ce3da70b43 Initial load
duke
parents:
diff changeset
   983
90ce3da70b43 Initial load
duke
parents:
diff changeset
   984
    // OVERRIDES OF ABSTRACT MIDI DEVICE METHODS
90ce3da70b43 Initial load
duke
parents:
diff changeset
   985
90ce3da70b43 Initial load
duke
parents:
diff changeset
   986
    protected boolean hasReceivers() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   987
        return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   988
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   989
90ce3da70b43 Initial load
duke
parents:
diff changeset
   990
    // for recording
90ce3da70b43 Initial load
duke
parents:
diff changeset
   991
    protected Receiver createReceiver() throws MidiUnavailableException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   992
        return new SequencerReceiver();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   993
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   994
90ce3da70b43 Initial load
duke
parents:
diff changeset
   995
90ce3da70b43 Initial load
duke
parents:
diff changeset
   996
    protected boolean hasTransmitters() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   997
        return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   998
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   999
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1000
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1001
    protected Transmitter createTransmitter() throws MidiUnavailableException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1002
        return new SequencerTransmitter();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1003
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1004
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1005
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1006
    // interface AutoConnectSequencer
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1007
    public void setAutoConnect(Receiver autoConnectedReceiver) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1008
        this.autoConnect = (autoConnectedReceiver != null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1009
        this.autoConnectedReceiver = autoConnectedReceiver;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1010
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1011
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1012
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1013
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1014
    // INNER CLASSES
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1015
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1016
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1017
     * An own class to distinguish the class name from
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1018
     * the transmitter of other devices
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1019
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1020
    private class SequencerTransmitter extends BasicTransmitter {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1021
        private SequencerTransmitter() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1022
            super();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1023
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1024
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1025
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1026
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1027
    class SequencerReceiver extends AbstractReceiver {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1028
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1029
        protected void implSend(MidiMessage message, long timeStamp) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1030
            if (recording) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1031
                long tickPos = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1032
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1033
                // convert timeStamp to ticks
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1034
                if (timeStamp < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1035
                    tickPos = getTickPosition();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1036
                } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1037
                    synchronized(tempoCache) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1038
                        tickPos = MidiUtils.microsecond2tick(sequence, timeStamp, tempoCache);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1039
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1040
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1041
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1042
                // and record to the first matching Track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1043
                Track track = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1044
                // do not record real-time events
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1045
                // see 5048381: NullPointerException when saving a MIDI sequence
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1046
                if (message.getLength() > 1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1047
                    if (message instanceof ShortMessage) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1048
                        ShortMessage sm = (ShortMessage) message;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1049
                        // all real-time messages have 0xF in the high nibble of the status byte
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1050
                        if ((sm.getStatus() & 0xF0) != 0xF0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1051
                            track = RecordingTrack.get(recordingTracks, sm.getChannel());
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1052
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1053
                    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1054
                        // $$jb: where to record meta, sysex events?
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1055
                        // $$fb: the first recording track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1056
                        track = RecordingTrack.get(recordingTracks, -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1057
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1058
                    if (track != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1059
                        // create a copy of this message
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1060
                        if (message instanceof ShortMessage) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1061
                            message = new FastShortMessage((ShortMessage) message);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1062
                        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1063
                            message = (MidiMessage) message.clone();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1064
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1065
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1066
                        // create new MidiEvent
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1067
                        MidiEvent me = new MidiEvent(message, tickPos);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1068
                        track.add(me);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1069
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1070
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1071
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1072
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1073
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1074
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1075
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1076
    private static class RealTimeSequencerInfo extends MidiDevice.Info {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1077
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1078
        private static final String name = "Real Time Sequencer";
6832
cb693e02b3ed 6984047: sound sources needs vendor rebranding changes (jdk7 only)
amenkov
parents: 5506
diff changeset
  1079
        private static final String vendor = "Oracle Corporation";
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1080
        private static final String description = "Software sequencer";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1081
        private static final String version = "Version 1.0";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1082
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1083
        private RealTimeSequencerInfo() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1084
            super(name, vendor, description, version);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1085
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1086
    } // class Info
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1087
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1088
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1089
    private class ControllerListElement {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1090
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1091
        // $$jb: using an array for controllers b/c its
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1092
        //       easier to deal with than turning all the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1093
        //       ints into objects to use a Vector
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1094
        int []  controllers;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1095
        ControllerEventListener listener;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1096
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1097
        private ControllerListElement(ControllerEventListener listener, int[] controllers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1098
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1099
            this.listener = listener;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1100
            if (controllers == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1101
                controllers = new int[128];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1102
                for (int i = 0; i < 128; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1103
                    controllers[i] = i;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1104
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1105
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1106
            this.controllers = controllers;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1107
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1108
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1109
        private void addControllers(int[] c) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1110
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1111
            if (c==null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1112
                controllers = new int[128];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1113
                for (int i = 0; i < 128; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1114
                    controllers[i] = i;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1115
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1116
                return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1117
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1118
            int temp[] = new int[ controllers.length + c.length ];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1119
            int elements;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1120
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1121
            // first add what we have
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1122
            for(int i=0; i<controllers.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1123
                temp[i] = controllers[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1124
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1125
            elements = controllers.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1126
            // now add the new controllers only if we don't already have them
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1127
            for(int i=0; i<c.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1128
                boolean flag = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1129
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1130
                for(int j=0; j<controllers.length; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1131
                    if (c[i] == controllers[j]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1132
                        flag = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1133
                        break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1134
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1135
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1136
                if (!flag) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1137
                    temp[elements++] = c[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1138
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1139
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1140
            // now keep only the elements we need
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1141
            int newc[] = new int[ elements ];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1142
            for(int i=0; i<elements; i++){
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1143
                newc[i] = temp[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1144
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1145
            controllers = newc;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1146
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1147
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1148
        private void removeControllers(int[] c) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1149
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1150
            if (c==null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1151
                controllers = new int[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1152
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1153
                int temp[] = new int[ controllers.length ];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1154
                int elements = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1155
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1156
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1157
                for(int i=0; i<controllers.length; i++){
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1158
                    boolean flag = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1159
                    for(int j=0; j<c.length; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1160
                        if (controllers[i] == c[j]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1161
                            flag = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1162
                            break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1163
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1164
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1165
                    if (!flag){
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1166
                        temp[elements++] = controllers[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1167
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1168
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1169
                // now keep only the elements remaining
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1170
                int newc[] = new int[ elements ];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1171
                for(int i=0; i<elements; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1172
                    newc[i] = temp[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1173
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1174
                controllers = newc;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1175
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1176
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1177
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1178
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1179
        private int[] getControllers() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1180
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1181
            // return a copy of our array of controllers,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1182
            // so others can't mess with it
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1183
            if (controllers == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1184
                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1185
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1186
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1187
            int c[] = new int[controllers.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1188
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1189
            for(int i=0; i<controllers.length; i++){
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1190
                c[i] = controllers[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1191
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1192
            return c;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1193
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1194
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1195
    } // class ControllerListElement
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1196
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1197
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1198
    static class RecordingTrack {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1199
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1200
        private Track track;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1201
        private int channel;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1202
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1203
        RecordingTrack(Track track, int channel) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1204
            this.track = track;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1205
            this.channel = channel;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1206
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1207
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1208
        static RecordingTrack get(List recordingTracks, Track track) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1209
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1210
            synchronized(recordingTracks) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1211
                int size = recordingTracks.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1212
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1213
                for (int i = 0; i < size; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1214
                    RecordingTrack current = (RecordingTrack)recordingTracks.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1215
                    if (current.track == track) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1216
                        return current;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1217
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1218
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1219
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1220
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1221
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1222
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1223
        static Track get(List recordingTracks, int channel) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1224
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1225
            synchronized(recordingTracks) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1226
                int size = recordingTracks.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1227
                for (int i = 0; i < size; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1228
                    RecordingTrack current = (RecordingTrack)recordingTracks.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1229
                    if ((current.channel == channel) || (current.channel == -1)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1230
                        return current.track;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1231
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1232
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1233
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1234
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1235
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1236
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1237
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1238
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1239
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1240
    class PlayThread implements Runnable {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1241
        private Thread thread;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1242
        private Object lock = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1243
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1244
        /** true if playback is interrupted (in close) */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1245
        boolean interrupted = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1246
        boolean isPumping = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1247
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1248
        private DataPump dataPump = new DataPump();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1249
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1250
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1251
        PlayThread() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1252
            // nearly MAX_PRIORITY
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1253
            int priority = Thread.NORM_PRIORITY
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1254
                + ((Thread.MAX_PRIORITY - Thread.NORM_PRIORITY) * 3) / 4;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1255
            thread = JSSecurityManager.createThread(this,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1256
                                                    "Java Sound Sequencer", // name
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1257
                                                    false,                  // daemon
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1258
                                                    priority,               // priority
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1259
                                                    true);                  // doStart
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1260
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1261
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1262
        DataPump getDataPump() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1263
            return dataPump;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1264
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1265
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1266
        synchronized void setSequence(Sequence seq) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1267
            dataPump.setSequence(seq);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1268
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1269
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1270
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1271
        /** start thread and pump. Requires up-to-date tempoCache */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1272
        synchronized void start() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1273
            // mark the sequencer running
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1274
            running = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1275
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1276
            if (!dataPump.hasCachedTempo()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1277
                long tickPos = getTickPosition();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1278
                dataPump.setTempoMPQ(tempoCache.getTempoMPQAt(tickPos));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1279
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1280
            dataPump.checkPointMillis = 0; // means restarted
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1281
            dataPump.clearNoteOnCache();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1282
            dataPump.needReindex = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1283
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1284
            dataPump.resetLoopCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1285
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1286
            // notify the thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1287
            synchronized(lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1288
                lock.notifyAll();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1289
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1290
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1291
            if (Printer.debug) Printer.debug(" ->Started MIDI play thread");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1292
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1293
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1294
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1295
        // waits until stopped
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1296
        synchronized void stop() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1297
            playThreadImplStop();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1298
            long t = System.nanoTime() / 1000000l;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1299
            while (isPumping) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1300
                synchronized(lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1301
                    try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1302
                        lock.wait(2000);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1303
                    } catch (InterruptedException ie) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1304
                        // ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1305
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1306
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1307
                // don't wait for more than 2 seconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1308
                if ((System.nanoTime()/1000000l) - t > 1900) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1309
                    if (Printer.err) Printer.err("Waited more than 2 seconds in RealTimeSequencer.PlayThread.stop()!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1310
                    //break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1311
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1312
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1313
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1314
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1315
        void playThreadImplStop() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1316
            // mark the sequencer running
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1317
            running = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1318
            synchronized(lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1319
                lock.notifyAll();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1320
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1321
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1322
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1323
        void close() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1324
            Thread oldThread = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1325
            synchronized (this) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1326
                // dispose of thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1327
                interrupted = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1328
                oldThread = thread;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1329
                thread = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1330
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1331
            if (oldThread != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1332
                // wake up the thread if it's in wait()
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1333
                synchronized(lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1334
                    lock.notifyAll();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1335
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1336
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1337
            // wait for the thread to terminate itself,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1338
            // but max. 2 seconds. Must not be synchronized!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1339
            if (oldThread != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1340
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1341
                    oldThread.join(2000);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1342
                } catch (InterruptedException ie) {}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1343
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1344
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1345
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1346
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1347
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1348
         * Main process loop driving the media flow.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1349
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1350
         * Make sure to NOT synchronize on RealTimeSequencer
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1351
         * anywhere here (even implicit). That is a sure deadlock!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1352
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1353
        public void run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1354
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1355
            while (!interrupted) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1356
                boolean EOM = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1357
                boolean wasRunning = running;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1358
                isPumping = !interrupted && running;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1359
                while (!EOM && !interrupted && running) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1360
                    EOM = dataPump.pump();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1361
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1362
                    try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1363
                        Thread.sleep(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1364
                    } catch (InterruptedException ie) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1365
                        // ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1366
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1367
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1368
                if (Printer.debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1369
                    Printer.debug("Exited main pump loop because: ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1370
                    if (EOM) Printer.debug(" -> EOM is reached");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1371
                    if (!running) Printer.debug(" -> running was set to false");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1372
                    if (interrupted) Printer.debug(" -> interrupted was set to true");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1373
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1374
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1375
                playThreadImplStop();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1376
                if (wasRunning) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1377
                    dataPump.notesOff(true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1378
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1379
                if (EOM) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1380
                    dataPump.setTickPos(sequence.getTickLength());
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1381
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1382
                    // send EOT event (mis-used for end of media)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1383
                    MetaMessage message = new MetaMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1384
                    try{
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1385
                        message.setMessage(MidiUtils.META_END_OF_TRACK_TYPE, new byte[0], 0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1386
                    } catch(InvalidMidiDataException e1) {}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1387
                    sendMetaEvents(message);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1388
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1389
                synchronized (lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1390
                    isPumping = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1391
                    // wake up a waiting stop() method
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1392
                    lock.notifyAll();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1393
                    while (!running && !interrupted) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1394
                        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1395
                            lock.wait();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1396
                        } catch (Exception ex) {}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1397
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1398
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1399
            } // end of while(!EOM && !interrupted && running)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1400
            if (Printer.debug) Printer.debug("end of play thread");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1401
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1402
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1403
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1404
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1405
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1406
     * class that does the actual dispatching of events,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1407
     * used to be in native in MMAPI
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1408
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1409
    private class DataPump {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1410
        private float currTempo;         // MPQ tempo
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1411
        private float tempoFactor;       // 1.0 is default
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1412
        private float inverseTempoFactor;// = 1.0 / tempoFactor
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1413
        private long ignoreTempoEventAt; // ignore next META tempo during playback at this tick pos only
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1414
        private int resolution;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1415
        private float divisionType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1416
        private long checkPointMillis;   // microseconds at checkoint
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1417
        private long checkPointTick;     // ticks at checkpoint
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1418
        private int[] noteOnCache;       // bit-mask of notes that are currently on
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1419
        private Track[] tracks;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1420
        private boolean[] trackDisabled; // if true, do not play this track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1421
        private int[] trackReadPos;      // read index per track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1422
        private long lastTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1423
        private boolean needReindex = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1424
        private int currLoopCounter = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1425
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1426
        //private sun.misc.Perf perf = sun.misc.Perf.getPerf();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1427
        //private long perfFreq = perf.highResFrequency();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1428
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1429
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1430
        DataPump() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1431
            init();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1432
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1433
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1434
        synchronized void init() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1435
            ignoreTempoEventAt = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1436
            tempoFactor = 1.0f;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1437
            inverseTempoFactor = 1.0f;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1438
            noteOnCache = new int[128];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1439
            tracks = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1440
            trackDisabled = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1441
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1442
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1443
        synchronized void setTickPos(long tickPos) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1444
            long oldLastTick = tickPos;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1445
            lastTick = tickPos;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1446
            if (running) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1447
                notesOff(false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1448
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1449
            if (running || tickPos > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1450
                // will also reindex
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1451
                chaseEvents(oldLastTick, tickPos);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1452
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1453
                needReindex = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1454
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1455
            if (!hasCachedTempo()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1456
                setTempoMPQ(getTempoCache().getTempoMPQAt(lastTick, currTempo));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1457
                // treat this as if it is a real time tempo change
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1458
                ignoreTempoEventAt = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1459
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1460
            // trigger re-configuration
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1461
            checkPointMillis = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1462
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1463
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1464
        long getTickPos() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1465
            return lastTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1466
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1467
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1468
        // hasCachedTempo is only valid if it is the current position
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1469
        boolean hasCachedTempo() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1470
            if (ignoreTempoEventAt != lastTick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1471
                ignoreTempoEventAt = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1472
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1473
            return ignoreTempoEventAt >= 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1474
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1475
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1476
        // this method is also used internally in the pump!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1477
        synchronized void setTempoMPQ(float tempoMPQ) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1478
            if (tempoMPQ > 0 && tempoMPQ != currTempo) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1479
                ignoreTempoEventAt = lastTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1480
                this.currTempo = tempoMPQ;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1481
                // re-calculate check point
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1482
                checkPointMillis = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1483
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1484
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1485
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1486
        float getTempoMPQ() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1487
            return currTempo;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1488
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1489
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1490
        synchronized void setTempoFactor(float factor) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1491
            if (factor > 0 && factor != this.tempoFactor) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1492
                tempoFactor = factor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1493
                inverseTempoFactor = 1.0f / factor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1494
                // re-calculate check point
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1495
                checkPointMillis = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1496
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1497
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1498
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1499
        float getTempoFactor() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1500
            return tempoFactor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1501
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1502
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1503
        synchronized void muteSoloChanged() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1504
            boolean[] newDisabled = makeDisabledArray();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1505
            if (running) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1506
                applyDisabledTracks(trackDisabled, newDisabled);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1507
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1508
            trackDisabled = newDisabled;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1509
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1510
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1511
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1512
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1513
        synchronized void setSequence(Sequence seq) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1514
            if (seq == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1515
                init();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1516
                return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1517
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1518
            tracks = seq.getTracks();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1519
            muteSoloChanged();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1520
            resolution = seq.getResolution();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1521
            divisionType = seq.getDivisionType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1522
            trackReadPos = new int[tracks.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1523
            // trigger re-initialization
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1524
            checkPointMillis = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1525
            needReindex = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1526
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1527
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1528
        synchronized void resetLoopCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1529
            currLoopCounter = loopCount;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1530
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1531
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1532
        void clearNoteOnCache() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1533
            for (int i = 0; i < 128; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1534
                noteOnCache[i] = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1535
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1536
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1537
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1538
        void notesOff(boolean doControllers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1539
            int done = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1540
            for (int ch=0; ch<16; ch++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1541
                int channelMask = (1<<ch);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1542
                for (int i=0; i<128; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1543
                    if ((noteOnCache[i] & channelMask) != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1544
                        noteOnCache[i] ^= channelMask;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1545
                        // send note on with velocity 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1546
                        getTransmitterList().sendMessage((ShortMessage.NOTE_ON | ch) | (i<<8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1547
                        done++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1548
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1549
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1550
                /* all notes off */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1551
                getTransmitterList().sendMessage((ShortMessage.CONTROL_CHANGE | ch) | (123<<8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1552
                /* sustain off */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1553
                getTransmitterList().sendMessage((ShortMessage.CONTROL_CHANGE | ch) | (64<<8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1554
                if (doControllers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1555
                    /* reset all controllers */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1556
                    getTransmitterList().sendMessage((ShortMessage.CONTROL_CHANGE | ch) | (121<<8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1557
                    done++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1558
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1559
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1560
            if (DEBUG_PUMP) Printer.println("  noteOff: sent "+done+" messages.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1561
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1562
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1563
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1564
        private boolean[] makeDisabledArray() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1565
            if (tracks == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1566
                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1567
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1568
            boolean[] newTrackDisabled = new boolean[tracks.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1569
            boolean[] solo;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1570
            boolean[] mute;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1571
            synchronized(RealTimeSequencer.this) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1572
                mute = trackMuted;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1573
                solo = trackSolo;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1574
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1575
            // if one track is solo, then only play solo
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1576
            boolean hasSolo = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1577
            if (solo != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1578
                for (int i = 0; i < solo.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1579
                    if (solo[i]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1580
                        hasSolo = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1581
                        break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1582
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1583
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1584
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1585
            if (hasSolo) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1586
                // only the channels with solo play, regardless of mute
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1587
                for (int i = 0; i < newTrackDisabled.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1588
                    newTrackDisabled[i] = (i >= solo.length) || (!solo[i]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1589
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1590
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1591
                // mute the selected channels
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1592
                for (int i = 0; i < newTrackDisabled.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1593
                    newTrackDisabled[i] = (mute != null) && (i < mute.length) && (mute[i]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1594
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1595
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1596
            return newTrackDisabled;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1597
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1598
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1599
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1600
         * chase all events from beginning of Track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1601
         * and send note off for those events that are active
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1602
         * in noteOnCache array.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1603
         * It is possible, of course, to catch notes from other tracks,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1604
         * but better than more complicated logic to detect
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1605
         * which notes are really from this track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1606
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1607
        private void sendNoteOffIfOn(Track track, long endTick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1608
            int size = track.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1609
            int done = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1610
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1611
                for (int i = 0; i < size; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1612
                    MidiEvent event = track.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1613
                    if (event.getTick() > endTick) break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1614
                    MidiMessage msg = event.getMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1615
                    int status = msg.getStatus();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1616
                    int len = msg.getLength();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1617
                    if (len == 3 && ((status & 0xF0) == ShortMessage.NOTE_ON)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1618
                        int note = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1619
                        if (msg instanceof ShortMessage) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1620
                            ShortMessage smsg = (ShortMessage) msg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1621
                            if (smsg.getData2() > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1622
                                // only consider Note On with velocity > 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1623
                                note = smsg.getData1();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1624
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1625
                        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1626
                            byte[] data = msg.getMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1627
                            if ((data[2] & 0x7F) > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1628
                                // only consider Note On with velocity > 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1629
                                note = data[1] & 0x7F;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1630
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1631
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1632
                        if (note >= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1633
                            int bit = 1<<(status & 0x0F);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1634
                            if ((noteOnCache[note] & bit) != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1635
                                // the bit is set. Send Note Off
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1636
                                getTransmitterList().sendMessage(status | (note<<8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1637
                                // clear the bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1638
                                noteOnCache[note] &= (0xFFFF ^ bit);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1639
                                done++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1640
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1641
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1642
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1643
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1644
            } catch (ArrayIndexOutOfBoundsException aioobe) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1645
                // this happens when messages are removed
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1646
                // from the track while this method executes
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1647
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1648
            if (DEBUG_PUMP) Printer.println("  sendNoteOffIfOn: sent "+done+" messages.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1649
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1650
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1651
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1652
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1653
         * Runtime application of mute/solo:
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1654
         * if a track is muted that was previously playing, send
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1655
         *    note off events for all currently playing notes
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1656
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1657
        private void applyDisabledTracks(boolean[] oldDisabled, boolean[] newDisabled) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1658
            byte[][] tempArray = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1659
            synchronized(RealTimeSequencer.this) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1660
                for (int i = 0; i < newDisabled.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1661
                    if (((oldDisabled == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1662
                         || (i >= oldDisabled.length)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1663
                         || !oldDisabled[i])
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1664
                        && newDisabled[i]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1665
                        // case that a track gets muted: need to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1666
                        // send appropriate note off events to prevent
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1667
                        // hanging notes
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1668
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1669
                        if (tracks.length > i) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1670
                            sendNoteOffIfOn(tracks[i], lastTick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1671
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1672
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1673
                    else if ((oldDisabled != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1674
                             && (i < oldDisabled.length)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1675
                             && oldDisabled[i]
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1676
                             && !newDisabled[i]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1677
                        // case that a track was muted and is now unmuted
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1678
                        // need to chase events and re-index this track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1679
                        if (tempArray == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1680
                            tempArray = new byte[128][16];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1681
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1682
                        chaseTrackEvents(i, 0, lastTick, true, tempArray);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1683
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1684
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1685
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1686
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1687
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1688
        /** go through all events from startTick to endTick
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1689
         * chase the controller state and program change state
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1690
         * and then set the end-states at once.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1691
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1692
         * needs to be called in synchronized state
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1693
         * @param tempArray an byte[128][16] to hold controller messages
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1694
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1695
        private void chaseTrackEvents(int trackNum,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1696
                                      long startTick,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1697
                                      long endTick,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1698
                                      boolean doReindex,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1699
                                      byte[][] tempArray) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1700
            if (startTick > endTick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1701
                // start from the beginning
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1702
                startTick = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1703
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1704
            byte[] progs = new byte[16];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1705
            // init temp array with impossible values
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1706
            for (int ch = 0; ch < 16; ch++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1707
                progs[ch] = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1708
                for (int co = 0; co < 128; co++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1709
                    tempArray[co][ch] = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1710
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1711
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1712
            Track track = tracks[trackNum];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1713
            int size = track.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1714
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1715
                for (int i = 0; i < size; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1716
                    MidiEvent event = track.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1717
                    if (event.getTick() >= endTick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1718
                        if (doReindex && (trackNum < trackReadPos.length)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1719
                            trackReadPos[trackNum] = (i > 0)?(i-1):0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1720
                            if (DEBUG_PUMP) Printer.println("  chaseEvents: setting trackReadPos["+trackNum+"] = "+trackReadPos[trackNum]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1721
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1722
                        break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1723
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1724
                    MidiMessage msg = event.getMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1725
                    int status = msg.getStatus();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1726
                    int len = msg.getLength();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1727
                    if (len == 3 && ((status & 0xF0) == ShortMessage.CONTROL_CHANGE)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1728
                        if (msg instanceof ShortMessage) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1729
                            ShortMessage smsg = (ShortMessage) msg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1730
                            tempArray[smsg.getData1() & 0x7F][status & 0x0F] = (byte) smsg.getData2();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1731
                        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1732
                            byte[] data = msg.getMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1733
                            tempArray[data[1] & 0x7F][status & 0x0F] = data[2];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1734
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1735
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1736
                    if (len == 2 && ((status & 0xF0) == ShortMessage.PROGRAM_CHANGE)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1737
                        if (msg instanceof ShortMessage) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1738
                            ShortMessage smsg = (ShortMessage) msg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1739
                            progs[status & 0x0F] = (byte) smsg.getData1();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1740
                        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1741
                            byte[] data = msg.getMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1742
                            progs[status & 0x0F] = data[1];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1743
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1744
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1745
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1746
            } catch (ArrayIndexOutOfBoundsException aioobe) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1747
                // this happens when messages are removed
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1748
                // from the track while this method executes
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1749
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1750
            int numControllersSent = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1751
            // now send out the aggregated controllers and program changes
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1752
            for (int ch = 0; ch < 16; ch++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1753
                for (int co = 0; co < 128; co++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1754
                    byte controllerValue = tempArray[co][ch];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1755
                    if (controllerValue >= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1756
                        int packedMsg = (ShortMessage.CONTROL_CHANGE | ch) | (co<<8) | (controllerValue<<16);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1757
                        getTransmitterList().sendMessage(packedMsg, -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1758
                        numControllersSent++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1759
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1760
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1761
                // send program change *after* controllers, to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1762
                // correctly initialize banks
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1763
                if (progs[ch] >= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1764
                    getTransmitterList().sendMessage((ShortMessage.PROGRAM_CHANGE | ch) | (progs[ch]<<8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1765
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1766
                if (progs[ch] >= 0 || startTick == 0 || endTick == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1767
                    // reset pitch bend on this channel (E0 00 40)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1768
                    getTransmitterList().sendMessage((ShortMessage.PITCH_BEND | ch) | (0x40 << 16), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1769
                    // reset sustain pedal on this channel
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1770
                    getTransmitterList().sendMessage((ShortMessage.CONTROL_CHANGE | ch) | (64 << 8), -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1771
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1772
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1773
            if (DEBUG_PUMP) Printer.println("  chaseTrackEvents track "+trackNum+": sent "+numControllersSent+" controllers.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1774
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1775
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1776
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1777
        /** chase controllers and program for all tracks */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1778
        synchronized void chaseEvents(long startTick, long endTick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1779
            if (DEBUG_PUMP) Printer.println(">> chaseEvents from tick "+startTick+".."+(endTick-1));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1780
            byte[][] tempArray = new byte[128][16];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1781
            for (int t = 0; t < tracks.length; t++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1782
                if ((trackDisabled == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1783
                    || (trackDisabled.length <= t)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1784
                    || (!trackDisabled[t])) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1785
                    // if track is not disabled, chase the events for it
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1786
                    chaseTrackEvents(t, startTick, endTick, true, tempArray);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1787
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1788
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1789
            if (DEBUG_PUMP) Printer.println("<< chaseEvents");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1790
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1791
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1792
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1793
        // playback related methods (pumping)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1794
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1795
        private long getCurrentTimeMillis() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1796
            return System.nanoTime() / 1000000l;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1797
            //return perf.highResCounter() * 1000 / perfFreq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1798
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1799
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1800
        private long millis2tick(long millis) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1801
            if (divisionType != Sequence.PPQ) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1802
                double dTick = ((((double) millis) * tempoFactor)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1803
                                * ((double) divisionType)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1804
                                * ((double) resolution))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1805
                    / ((double) 1000);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1806
                return (long) dTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1807
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1808
            return MidiUtils.microsec2ticks(millis * 1000,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1809
                                            currTempo * inverseTempoFactor,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1810
                                            resolution);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1811
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1812
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1813
        private long tick2millis(long tick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1814
            if (divisionType != Sequence.PPQ) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1815
                double dMillis = ((((double) tick) * 1000) /
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1816
                                  (tempoFactor * ((double) divisionType) * ((double) resolution)));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1817
                return (long) dMillis;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1818
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1819
            return MidiUtils.ticks2microsec(tick,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1820
                                            currTempo * inverseTempoFactor,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1821
                                            resolution) / 1000;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1822
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1823
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1824
        private void ReindexTrack(int trackNum, long tick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1825
            if (trackNum < trackReadPos.length && trackNum < tracks.length) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1826
                trackReadPos[trackNum] = MidiUtils.tick2index(tracks[trackNum], tick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1827
                if (DEBUG_PUMP) Printer.println("  reindexTrack: setting trackReadPos["+trackNum+"] = "+trackReadPos[trackNum]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1828
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1829
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1830
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1831
        /* returns if changes are pending */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1832
        private boolean dispatchMessage(int trackNum, MidiEvent event) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1833
            boolean changesPending = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1834
            MidiMessage message = event.getMessage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1835
            int msgStatus = message.getStatus();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1836
            int msgLen = message.getLength();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1837
            if (msgStatus == MetaMessage.META && msgLen >= 2) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1838
                // a meta message. Do not send it to the device.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1839
                // 0xFF with length=1 is a MIDI realtime message
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1840
                // which shouldn't be in a Sequence, but we play it
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1841
                // nonetheless.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1842
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1843
                // see if this is a tempo message. Only on track 0.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1844
                if (trackNum == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1845
                    int newTempo = MidiUtils.getTempoMPQ(message);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1846
                    if (newTempo > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1847
                        if (event.getTick() != ignoreTempoEventAt) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1848
                            setTempoMPQ(newTempo); // sets ignoreTempoEventAt!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1849
                            changesPending = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1850
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1851
                        // next loop, do not ignore anymore tempo events.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1852
                        ignoreTempoEventAt = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1853
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1854
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1855
                // send to listeners
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1856
                sendMetaEvents(message);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1857
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1858
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1859
                // not meta, send to device
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1860
                getTransmitterList().sendMessage(message, -1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1861
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1862
                switch (msgStatus & 0xF0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1863
                case ShortMessage.NOTE_OFF: {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1864
                    // note off - clear the bit in the noteOnCache array
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1865
                    int note = ((ShortMessage) message).getData1() & 0x7F;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1866
                    noteOnCache[note] &= (0xFFFF ^ (1<<(msgStatus & 0x0F)));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1867
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1868
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1869
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1870
                case ShortMessage.NOTE_ON: {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1871
                    // note on
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1872
                    ShortMessage smsg = (ShortMessage) message;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1873
                    int note = smsg.getData1() & 0x7F;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1874
                    int vel = smsg.getData2() & 0x7F;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1875
                    if (vel > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1876
                        // if velocity > 0 set the bit in the noteOnCache array
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1877
                        noteOnCache[note] |= 1<<(msgStatus & 0x0F);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1878
                    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1879
                        // if velocity = 0 clear the bit in the noteOnCache array
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1880
                        noteOnCache[note] &= (0xFFFF ^ (1<<(msgStatus & 0x0F)));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1881
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1882
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1883
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1884
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1885
                case ShortMessage.CONTROL_CHANGE:
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1886
                    // if controller message, send controller listeners
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1887
                    sendControllerEvents(message);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1888
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1889
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1890
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1891
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1892
            return changesPending;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1893
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1894
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1895
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1896
        /** the main pump method
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1897
         * @return true if end of sequence is reached
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1898
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1899
        synchronized boolean pump() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1900
            long currMillis;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1901
            long targetTick = lastTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1902
            MidiEvent currEvent;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1903
            boolean changesPending = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1904
            boolean doLoop = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1905
            boolean EOM = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1906
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1907
            currMillis = getCurrentTimeMillis();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1908
            int finishedTracks = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1909
            do {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1910
                changesPending = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1911
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1912
                // need to re-find indexes in tracks?
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1913
                if (needReindex) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1914
                    if (DEBUG_PUMP) Printer.println("Need to re-index at "+currMillis+" millis. TargetTick="+targetTick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1915
                    if (trackReadPos.length < tracks.length) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1916
                        trackReadPos = new int[tracks.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1917
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1918
                    for (int t = 0; t < tracks.length; t++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1919
                        ReindexTrack(t, targetTick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1920
                        if (DEBUG_PUMP_ALL) Printer.println("  Setting trackReadPos["+t+"]="+trackReadPos[t]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1921
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1922
                    needReindex = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1923
                    checkPointMillis = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1924
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1925
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1926
                // get target tick from current time in millis
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1927
                if (checkPointMillis == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1928
                    // new check point
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1929
                    currMillis = getCurrentTimeMillis();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1930
                    checkPointMillis = currMillis;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1931
                    targetTick = lastTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1932
                    checkPointTick = targetTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1933
                    if (DEBUG_PUMP) Printer.println("New checkpoint to "+currMillis+" millis. "
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1934
                                                       +"TargetTick="+targetTick
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1935
                                                       +" new tempo="+MidiUtils.convertTempo(currTempo)+"bpm");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1936
                } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1937
                    // calculate current tick based on current time in milliseconds
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1938
                    targetTick = checkPointTick + millis2tick(currMillis - checkPointMillis);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1939
                    if (DEBUG_PUMP_ALL) Printer.println("targetTick = "+targetTick+" at "+currMillis+" millis");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1940
                    if ((loopEnd != -1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1941
                        && ((loopCount > 0 && currLoopCounter > 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1942
                            || (loopCount == LOOP_CONTINUOUSLY))) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1943
                        if (lastTick <= loopEnd && targetTick >= loopEnd) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1944
                            // need to loop!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1945
                            // only play until loop end
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1946
                            targetTick = loopEnd - 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1947
                            doLoop = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1948
                            if (DEBUG_PUMP) Printer.println("set doLoop to true. lastTick="+lastTick
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1949
                                                               +"  targetTick="+targetTick
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1950
                                                               +"  loopEnd="+loopEnd
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1951
                                                               +"  jumping to loopStart="+loopStart
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1952
                                                               +"  new currLoopCounter="+currLoopCounter);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1953
                            if (DEBUG_PUMP) Printer.println("  currMillis="+currMillis
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1954
                                                               +"  checkPointMillis="+checkPointMillis
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1955
                                                               +"  checkPointTick="+checkPointTick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1956
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1957
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1958
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1959
                    lastTick = targetTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1960
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1961
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1962
                finishedTracks = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1963
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1964
                for (int t = 0; t < tracks.length; t++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1965
                    try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1966
                        boolean disabled = trackDisabled[t];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1967
                        Track thisTrack = tracks[t];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1968
                        int readPos = trackReadPos[t];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1969
                        int size = thisTrack.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1970
                        // play all events that are due until targetTick
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1971
                        while (!changesPending && (readPos < size)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1972
                               && (currEvent = thisTrack.get(readPos)).getTick() <= targetTick) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1973
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1974
                            if ((readPos == size -1) &&  MidiUtils.isMetaEndOfTrack(currEvent.getMessage())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1975
                                // do not send out this message. Finished with this track
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1976
                                readPos = size;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1977
                                break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1978
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1979
                            // TODO: some kind of heuristics if the MIDI messages have changed
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1980
                            // significantly (i.e. deleted or inserted a bunch of messages)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1981
                            // since last time. Would need to set needReindex = true then
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1982
                            readPos++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1983
                            // only play this event if the track is enabled,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1984
                            // or if it is a tempo message on track 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1985
                            // Note: cannot put this check outside
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1986
                            //       this inner loop in order to detect end of file
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1987
                            if (!disabled ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1988
                                ((t == 0) && (MidiUtils.isMetaTempo(currEvent.getMessage())))) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1989
                                changesPending = dispatchMessage(t, currEvent);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1990
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1991
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1992
                        if (readPos >= size) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1993
                            finishedTracks++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1994
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1995
                        if (DEBUG_PUMP_ALL) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1996
                            System.out.print(" pumped track "+t+" ("+size+" events) "
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1997
                                             +" from index: "+trackReadPos[t]
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1998
                                             +" to "+(readPos-1));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1999
                            System.out.print(" -> ticks: ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2000
                            if (trackReadPos[t] < size) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2001
                                System.out.print(""+(thisTrack.get(trackReadPos[t]).getTick()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2002
                            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2003
                                System.out.print("EOT");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2004
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2005
                            System.out.print(" to ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2006
                            if (readPos < size) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2007
                                System.out.print(""+(thisTrack.get(readPos-1).getTick()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2008
                            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2009
                                System.out.print("EOT");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2010
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2011
                            System.out.println();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2012
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2013
                        trackReadPos[t] = readPos;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2014
                    } catch(Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2015
                        if (Printer.debug) Printer.debug("Exception in Sequencer pump!");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2016
                        if (Printer.debug) e.printStackTrace();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2017
                        if (e instanceof ArrayIndexOutOfBoundsException) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2018
                            needReindex = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2019
                            changesPending = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2020
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2021
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2022
                    if (changesPending) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2023
                        break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2024
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2025
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2026
                EOM = (finishedTracks == tracks.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2027
                if (doLoop
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2028
                    || ( ((loopCount > 0 && currLoopCounter > 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2029
                          || (loopCount == LOOP_CONTINUOUSLY))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2030
                         && !changesPending
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2031
                         && (loopEnd == -1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2032
                         && EOM)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2033
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2034
                    long oldCheckPointMillis = checkPointMillis;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2035
                    long loopEndTick = loopEnd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2036
                    if (loopEndTick == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2037
                        loopEndTick = lastTick;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2038
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2039
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2040
                    // need to loop back!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2041
                    if (loopCount != LOOP_CONTINUOUSLY) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2042
                        currLoopCounter--;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2043
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2044
                    if (DEBUG_PUMP) Printer.println("Execute loop: lastTick="+lastTick
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2045
                                                       +"  loopEnd="+loopEnd
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2046
                                                       +"  jumping to loopStart="+loopStart
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2047
                                                       +"  new currLoopCounter="+currLoopCounter);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2048
                    setTickPos(loopStart);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2049
                    // now patch the checkPointMillis so that
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2050
                    // it points to the exact beginning of when the loop was finished
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2051
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2052
                    // $$fb TODO: although this is mathematically correct (i.e. the loop position
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2053
                    //            is correct, and doesn't drift away with several repetition,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2054
                    //            there is a slight lag when looping back, probably caused
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2055
                    //            by the chasing.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2056
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2057
                    checkPointMillis = oldCheckPointMillis + tick2millis(loopEndTick - checkPointTick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2058
                    checkPointTick = loopStart;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2059
                    if (DEBUG_PUMP) Printer.println("  Setting currMillis="+currMillis
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2060
                                                       +"  new checkPointMillis="+checkPointMillis
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2061
                                                       +"  new checkPointTick="+checkPointTick);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2062
                    // no need for reindexing, is done in setTickPos
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2063
                    needReindex = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2064
                    changesPending = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2065
                    // reset doLoop flag
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2066
                    doLoop = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2067
                    EOM = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2068
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2069
            } while (changesPending);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2070
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2071
            return EOM;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2072
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2073
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2074
    } // class DataPump
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2075
90ce3da70b43 Initial load
duke
parents:
diff changeset
  2076
}