1/* 2 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.media.sound; 27 28import java.util.Objects; 29 30import javax.sound.midi.MidiDevice; 31import javax.sound.midi.spi.MidiDeviceProvider; 32 33/** 34 * Super class for MIDI input or output device provider. 35 * 36 * @author Florian Bomers 37 */ 38public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider { 39 40 private static final boolean enabled; 41 42 /** 43 * Create objects representing all MIDI output devices on the system. 44 */ 45 static { 46 if (Printer.trace) Printer.trace("AbstractMidiDeviceProvider: static"); 47 Platform.initialize(); 48 enabled = Platform.isMidiIOEnabled(); 49 if (Printer.trace) Printer.trace("AbstractMidiDeviceProvider: enabled: " + enabled); 50 51 // $$fb number of MIDI devices may change with time 52 // also for memory's sake, do not initialize the arrays here 53 } 54 55 final synchronized void readDeviceInfos() { 56 Info[] infos = getInfoCache(); 57 MidiDevice[] devices = getDeviceCache(); 58 if (!enabled) { 59 if (infos == null || infos.length != 0) { 60 setInfoCache(new Info[0]); 61 } 62 if (devices == null || devices.length != 0) { 63 setDeviceCache(new MidiDevice[0]); 64 } 65 return; 66 } 67 68 int oldNumDevices = (infos==null)?-1:infos.length; 69 int newNumDevices = getNumDevices(); 70 if (oldNumDevices != newNumDevices) { 71 if (Printer.trace) Printer.trace(getClass().toString() 72 +": readDeviceInfos: old numDevices: "+oldNumDevices 73 +" newNumDevices: "+ newNumDevices); 74 75 // initialize the arrays 76 Info[] newInfos = new Info[newNumDevices]; 77 MidiDevice[] newDevices = new MidiDevice[newNumDevices]; 78 79 for (int i = 0; i < newNumDevices; i++) { 80 Info newInfo = createInfo(i); 81 82 // in case that we are re-reading devices, try to find 83 // the previous one and reuse it 84 if (infos != null) { 85 for (int ii = 0; ii < infos.length; ii++) { 86 Info info = infos[ii]; 87 if (info != null && info.equalStrings(newInfo)) { 88 // new info matches the still existing info. Use old one 89 newInfos[i] = info; 90 info.setIndex(i); 91 infos[ii] = null; // prevent re-use 92 newDevices[i] = devices[ii]; 93 devices[ii] = null; 94 break; 95 } 96 } 97 } 98 if (newInfos[i] == null) { 99 newInfos[i] = newInfo; 100 } 101 } 102 // the remaining MidiDevice.Info instances in the infos array 103 // have become obsolete. 104 if (infos != null) { 105 for (int i = 0; i < infos.length; i++) { 106 if (infos[i] != null) { 107 // disable this device info 108 infos[i].setIndex(-1); 109 } 110 // what to do with the MidiDevice instances that are left 111 // in the devices array ?? Close them ? 112 } 113 } 114 // commit new list of infos. 115 setInfoCache(newInfos); 116 setDeviceCache(newDevices); 117 } 118 } 119 120 @Override 121 public final MidiDevice.Info[] getDeviceInfo() { 122 readDeviceInfos(); 123 Info[] infos = getInfoCache(); 124 MidiDevice.Info[] localArray = new MidiDevice.Info[infos.length]; 125 System.arraycopy(infos, 0, localArray, 0, infos.length); 126 return localArray; 127 } 128 129 @Override 130 public final MidiDevice getDevice(final MidiDevice.Info info) { 131 Objects.requireNonNull(info); 132 if (info instanceof Info) { 133 readDeviceInfos(); 134 MidiDevice[] devices = getDeviceCache(); 135 Info[] infos = getInfoCache(); 136 Info thisInfo = (Info) info; 137 int index = thisInfo.getIndex(); 138 if (index >= 0 && index < devices.length && infos[index] == info) { 139 if (devices[index] == null) { 140 devices[index] = createDevice(thisInfo); 141 } 142 if (devices[index] != null) { 143 return devices[index]; 144 } 145 } 146 } 147 throw MidiUtils.unsupportedDevice(info); 148 } 149 150 /** 151 * Info class for MidiDevices. Adds an index value for 152 * making native references to a particular device. 153 */ 154 static class Info extends MidiDevice.Info { 155 private int index; 156 157 Info(String name, String vendor, String description, String version, int index) { 158 super(name, vendor, description, version); 159 this.index = index; 160 } 161 162 final boolean equalStrings(Info info) { 163 return (info != null 164 && getName().equals(info.getName()) 165 && getVendor().equals(info.getVendor()) 166 && getDescription().equals(info.getDescription()) 167 && getVersion().equals(info.getVersion())); 168 } 169 170 final int getIndex() { 171 return index; 172 } 173 174 final void setIndex(int index) { 175 this.index = index; 176 } 177 178 } // class Info 179 180 abstract int getNumDevices(); 181 abstract MidiDevice[] getDeviceCache(); 182 abstract void setDeviceCache(MidiDevice[] devices); 183 abstract Info[] getInfoCache(); 184 abstract void setInfoCache(Info[] infos); 185 186 abstract Info createInfo(int index); 187 abstract MidiDevice createDevice(Info info); 188} 189