1 /* 2 * Copyright (c) 2002, 2019, 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 java.util.Objects; 29 30 import javax.sound.midi.MidiDevice; 31 import javax.sound.midi.spi.MidiDeviceProvider; 32 33 /** 34 * Super class for MIDI input or output device provider. 35 * 36 * @author Florian Bomers 37 */ 38 public 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 { Platform.initialize()46 Platform.initialize(); 47 enabled = Platform.isMidiIOEnabled(); 48 // $$fb number of MIDI devices may change with time 49 // also for memory's sake, do not initialize the arrays here 50 } 51 readDeviceInfos()52 final synchronized void readDeviceInfos() { 53 Info[] infos = getInfoCache(); 54 MidiDevice[] devices = getDeviceCache(); 55 if (!enabled) { 56 if (infos == null || infos.length != 0) { 57 setInfoCache(new Info[0]); 58 } 59 if (devices == null || devices.length != 0) { 60 setDeviceCache(new MidiDevice[0]); 61 } 62 return; 63 } 64 65 int oldNumDevices = (infos==null)?-1:infos.length; 66 int newNumDevices = getNumDevices(); 67 if (oldNumDevices != newNumDevices) { 68 // initialize the arrays 69 Info[] newInfos = new Info[newNumDevices]; 70 MidiDevice[] newDevices = new MidiDevice[newNumDevices]; 71 72 for (int i = 0; i < newNumDevices; i++) { 73 Info newInfo = createInfo(i); 74 75 // in case that we are re-reading devices, try to find 76 // the previous one and reuse it 77 if (infos != null) { 78 for (int ii = 0; ii < infos.length; ii++) { 79 Info info = infos[ii]; 80 if (info != null && info.equalStrings(newInfo)) { 81 // new info matches the still existing info. Use old one 82 newInfos[i] = info; 83 info.setIndex(i); 84 infos[ii] = null; // prevent re-use 85 newDevices[i] = devices[ii]; 86 devices[ii] = null; 87 break; 88 } 89 } 90 } 91 if (newInfos[i] == null) { 92 newInfos[i] = newInfo; 93 } 94 } 95 // the remaining MidiDevice.Info instances in the infos array 96 // have become obsolete. 97 if (infos != null) { 98 for (int i = 0; i < infos.length; i++) { 99 if (infos[i] != null) { 100 // disable this device info 101 infos[i].setIndex(-1); 102 } 103 // what to do with the MidiDevice instances that are left 104 // in the devices array ?? Close them ? 105 } 106 } 107 // commit new list of infos. 108 setInfoCache(newInfos); 109 setDeviceCache(newDevices); 110 } 111 } 112 113 @Override getDeviceInfo()114 public final MidiDevice.Info[] getDeviceInfo() { 115 readDeviceInfos(); 116 Info[] infos = getInfoCache(); 117 MidiDevice.Info[] localArray = new MidiDevice.Info[infos.length]; 118 System.arraycopy(infos, 0, localArray, 0, infos.length); 119 return localArray; 120 } 121 122 @Override getDevice(final MidiDevice.Info info)123 public final MidiDevice getDevice(final MidiDevice.Info info) { 124 Objects.requireNonNull(info); 125 if (info instanceof Info) { 126 readDeviceInfos(); 127 MidiDevice[] devices = getDeviceCache(); 128 Info[] infos = getInfoCache(); 129 Info thisInfo = (Info) info; 130 int index = thisInfo.getIndex(); 131 if (index >= 0 && index < devices.length && infos[index] == info) { 132 if (devices[index] == null) { 133 devices[index] = createDevice(thisInfo); 134 } 135 if (devices[index] != null) { 136 return devices[index]; 137 } 138 } 139 } 140 throw MidiUtils.unsupportedDevice(info); 141 } 142 143 /** 144 * Info class for MidiDevices. Adds an index value for 145 * making native references to a particular device. 146 */ 147 static class Info extends MidiDevice.Info { 148 private int index; 149 Info(String name, String vendor, String description, String version, int index)150 Info(String name, String vendor, String description, String version, int index) { 151 super(name, vendor, description, version); 152 this.index = index; 153 } 154 equalStrings(Info info)155 final boolean equalStrings(Info info) { 156 return (info != null 157 && getName().equals(info.getName()) 158 && getVendor().equals(info.getVendor()) 159 && getDescription().equals(info.getDescription()) 160 && getVersion().equals(info.getVersion())); 161 } 162 getIndex()163 final int getIndex() { 164 return index; 165 } 166 setIndex(int index)167 final void setIndex(int index) { 168 this.index = index; 169 } 170 171 } // class Info 172 getNumDevices()173 abstract int getNumDevices(); getDeviceCache()174 abstract MidiDevice[] getDeviceCache(); setDeviceCache(MidiDevice[] devices)175 abstract void setDeviceCache(MidiDevice[] devices); getInfoCache()176 abstract Info[] getInfoCache(); setInfoCache(Info[] infos)177 abstract void setInfoCache(Info[] infos); 178 createInfo(int index)179 abstract Info createInfo(int index); createDevice(Info info)180 abstract MidiDevice createDevice(Info info); 181 } 182