1 /* 2 * Copyright (c) 2002, 2014, 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 26 package com.sun.media.sound; 27 28 import javax.sound.midi.MidiDevice; 29 import javax.sound.midi.spi.MidiDeviceProvider; 30 31 32 /** 33 * Super class for MIDI input or output device provider. 34 * 35 * @author Florian Bomers 36 */ 37 public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider { 38 39 private static final boolean enabled; 40 41 /** 42 * Create objects representing all MIDI output devices on the system. 43 */ 44 static { 45 if (Printer.trace) Printer.trace("AbstractMidiDeviceProvider: static"); 46 Platform.initialize(); 47 enabled = Platform.isMidiIOEnabled(); 48 if (Printer.trace) Printer.trace("AbstractMidiDeviceProvider: enabled: " + enabled); 49 50 // $$fb number of MIDI devices may change with time 51 // also for memory's sake, do not initialize the arrays here 52 } 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(MidiDevice.Info info) { 131 if (info instanceof Info) { 132 readDeviceInfos(); 133 MidiDevice[] devices = getDeviceCache(); 134 Info[] infos = getInfoCache(); 135 Info thisInfo = (Info) info; 136 int index = thisInfo.getIndex(); 137 if (index >= 0 && index < devices.length && infos[index] == info) { 138 if (devices[index] == null) { 139 devices[index] = createDevice(thisInfo); 140 } 141 if (devices[index] != null) { 142 return devices[index]; 143 } 144 } 145 } 146 throw MidiUtils.unsupportedDevice(info); 147 } 148 149 150 // INNER CLASSES 151 152 153 /** 154 * Info class for MidiDevices. Adds an index value for 155 * making native references to a particular device. 156 */ 157 static class Info extends MidiDevice.Info { 158 private int index; 159 160 Info(String name, String vendor, String description, String version, int index) { 161 super(name, vendor, description, version); 162 this.index = index; 163 } 164 165 final boolean equalStrings(Info info) { 166 return (info != null 167 && getName().equals(info.getName()) 168 && getVendor().equals(info.getVendor()) 169 && getDescription().equals(info.getDescription()) 170 && getVersion().equals(info.getVersion())); 171 } 172 173 final int getIndex() { 174 return index; 175 } 176 177 final void setIndex(int index) { 178 this.index = index; 179 } 180 181 } // class Info 182 183 184 // ABSTRACT METHODS 185 186 abstract int getNumDevices(); 187 abstract MidiDevice[] getDeviceCache(); 188 abstract void setDeviceCache(MidiDevice[] devices); 189 abstract Info[] getInfoCache(); 190 abstract void setInfoCache(Info[] infos); 191 192 abstract Info createInfo(int index); 193 abstract MidiDevice createDevice(Info info); 194 }