PageRenderTime 66ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/MRI-J/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java

http://github.com/GregBowyer/ManagedRuntimeInitiative
Java | 1196 lines | 926 code | 180 blank | 90 comment | 217 complexity | efac10e0b0f939ef330862e51a2b33a7 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0
  1. /*
  2. * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22. * CA 95054 USA or visit www.sun.com if you need additional information or
  23. * have any questions.
  24. */
  25. package com.sun.media.sound;
  26. import java.io.File;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.lang.ref.WeakReference;
  30. import java.security.AccessControlException;
  31. import java.util.ArrayList;
  32. import java.util.Arrays;
  33. import java.util.HashMap;
  34. import java.util.List;
  35. import java.util.Map;
  36. import javax.sound.midi.Instrument;
  37. import javax.sound.midi.MidiChannel;
  38. import javax.sound.midi.MidiDevice;
  39. import javax.sound.midi.MidiSystem;
  40. import javax.sound.midi.MidiUnavailableException;
  41. import javax.sound.midi.Patch;
  42. import javax.sound.midi.Receiver;
  43. import javax.sound.midi.Soundbank;
  44. import javax.sound.midi.Transmitter;
  45. import javax.sound.midi.VoiceStatus;
  46. import javax.sound.sampled.AudioFormat;
  47. import javax.sound.sampled.AudioInputStream;
  48. import javax.sound.sampled.AudioSystem;
  49. import javax.sound.sampled.LineUnavailableException;
  50. import javax.sound.sampled.SourceDataLine;
  51. /**
  52. * The software synthesizer class.
  53. *
  54. * @author Karl Helgason
  55. */
  56. public class SoftSynthesizer implements AudioSynthesizer,
  57. ReferenceCountingDevice {
  58. protected static class WeakAudioStream extends InputStream
  59. {
  60. private volatile AudioInputStream stream;
  61. public SoftAudioPusher pusher = null;
  62. public AudioInputStream jitter_stream = null;
  63. public SourceDataLine sourceDataLine = null;
  64. private WeakReference<AudioInputStream> weak_stream_link;
  65. private AudioFloatConverter converter;
  66. private float[] silentbuffer = null;
  67. private int samplesize;
  68. public void setInputStream(AudioInputStream stream)
  69. {
  70. this.stream = stream;
  71. }
  72. public int available() throws IOException {
  73. AudioInputStream local_stream = stream;
  74. if(local_stream != null)
  75. return local_stream.available();
  76. return 0;
  77. }
  78. public int read() throws IOException {
  79. byte[] b = new byte[1];
  80. if (read(b) == -1)
  81. return -1;
  82. return b[0] & 0xFF;
  83. }
  84. public int read(byte[] b, int off, int len) throws IOException {
  85. AudioInputStream local_stream = stream;
  86. if(local_stream != null)
  87. return local_stream.read(b, off, len);
  88. else
  89. {
  90. int flen = len / samplesize;
  91. if(silentbuffer == null || silentbuffer.length < flen)
  92. silentbuffer = new float[flen];
  93. converter.toByteArray(silentbuffer, flen, b, off);
  94. if(pusher != null)
  95. if(weak_stream_link.get() == null)
  96. {
  97. Runnable runnable = new Runnable()
  98. {
  99. SoftAudioPusher _pusher = pusher;
  100. AudioInputStream _jitter_stream = jitter_stream;
  101. SourceDataLine _sourceDataLine = sourceDataLine;
  102. public void run()
  103. {
  104. _pusher.stop();
  105. if(_jitter_stream != null)
  106. try {
  107. _jitter_stream.close();
  108. } catch (IOException e) {
  109. e.printStackTrace();
  110. }
  111. if(_sourceDataLine != null)
  112. _sourceDataLine.close();
  113. }
  114. };
  115. pusher = null;
  116. jitter_stream = null;
  117. sourceDataLine = null;
  118. new Thread(runnable).start();
  119. }
  120. return len;
  121. }
  122. }
  123. public WeakAudioStream(AudioInputStream stream) {
  124. this.stream = stream;
  125. weak_stream_link = new WeakReference<AudioInputStream>(stream);
  126. converter = AudioFloatConverter.getConverter(stream.getFormat());
  127. samplesize = stream.getFormat().getFrameSize() / stream.getFormat().getChannels();
  128. }
  129. public AudioInputStream getAudioInputStream()
  130. {
  131. return new AudioInputStream(this, stream.getFormat(), AudioSystem.NOT_SPECIFIED);
  132. }
  133. public void close() throws IOException
  134. {
  135. AudioInputStream astream = weak_stream_link.get();
  136. if(astream != null)
  137. astream.close();
  138. }
  139. }
  140. private static class Info extends MidiDevice.Info {
  141. public Info() {
  142. super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION);
  143. }
  144. }
  145. protected static final String INFO_NAME = "Gervill";
  146. protected static final String INFO_VENDOR = "OpenJDK";
  147. protected static final String INFO_DESCRIPTION = "Software MIDI Synthesizer";
  148. protected static final String INFO_VERSION = "1.0";
  149. protected final static MidiDevice.Info info = new Info();
  150. private static SourceDataLine testline = null;
  151. private static Soundbank defaultSoundBank = null;
  152. protected WeakAudioStream weakstream = null;
  153. protected Object control_mutex = this;
  154. protected int voiceIDCounter = 0;
  155. // 0: default
  156. // 1: DLS Voice Allocation
  157. protected int voice_allocation_mode = 0;
  158. protected boolean reverb_light = true;
  159. protected boolean reverb_on = true;
  160. protected boolean chorus_on = true;
  161. protected boolean agc_on = true;
  162. protected SoftChannel[] channels;
  163. protected SoftChannelProxy[] external_channels = null;
  164. private boolean largemode = false;
  165. // 0: GM Mode off (default)
  166. // 1: GM Level 1
  167. // 2: GM Level 2
  168. private int gmmode = 0;
  169. private int deviceid = 0;
  170. private AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
  171. private SourceDataLine sourceDataLine = null;
  172. private SoftAudioPusher pusher = null;
  173. private AudioInputStream pusher_stream = null;
  174. private float controlrate = 147f;
  175. private boolean open = false;
  176. private boolean implicitOpen = false;
  177. private String resamplerType = "linear";
  178. private SoftResampler resampler = new SoftLinearResampler();
  179. private int number_of_midi_channels = 16;
  180. private int maxpoly = 64;
  181. private long latency = 200000; // 200 msec
  182. private boolean jitter_correction = false;
  183. private SoftMainMixer mainmixer;
  184. private SoftVoice[] voices;
  185. private Map<String, SoftTuning> tunings
  186. = new HashMap<String, SoftTuning>();
  187. private Map<String, SoftInstrument> inslist
  188. = new HashMap<String, SoftInstrument>();
  189. private Map<String, ModelInstrument> availlist
  190. = new HashMap<String, ModelInstrument>();
  191. private Map<String, ModelInstrument> loadedlist
  192. = new HashMap<String, ModelInstrument>();
  193. private ArrayList<Receiver> recvslist = new ArrayList<Receiver>();
  194. private void getBuffers(ModelInstrument instrument,
  195. List<ModelByteBuffer> buffers) {
  196. for (ModelPerformer performer : instrument.getPerformers()) {
  197. if (performer.getOscillators() != null) {
  198. for (ModelOscillator osc : performer.getOscillators()) {
  199. if (osc instanceof ModelByteBufferWavetable) {
  200. ModelByteBufferWavetable w = (ModelByteBufferWavetable)osc;
  201. ModelByteBuffer buff = w.getBuffer();
  202. if (buff != null)
  203. buffers.add(buff);
  204. buff = w.get8BitExtensionBuffer();
  205. if (buff != null)
  206. buffers.add(buff);
  207. }
  208. }
  209. }
  210. }
  211. }
  212. private boolean loadSamples(List<ModelInstrument> instruments) {
  213. if (largemode)
  214. return true;
  215. List<ModelByteBuffer> buffers = new ArrayList<ModelByteBuffer>();
  216. for (ModelInstrument instrument : instruments)
  217. getBuffers(instrument, buffers);
  218. try {
  219. ModelByteBuffer.loadAll(buffers);
  220. } catch (IOException e) {
  221. return false;
  222. }
  223. return true;
  224. }
  225. private boolean loadInstruments(List<ModelInstrument> instruments) {
  226. if (!isOpen())
  227. return false;
  228. if (!loadSamples(instruments))
  229. return false;
  230. synchronized (control_mutex) {
  231. if (channels != null)
  232. for (SoftChannel c : channels)
  233. c.current_instrument = null;
  234. for (Instrument instrument : instruments) {
  235. String pat = patchToString(instrument.getPatch());
  236. availlist.remove(pat);
  237. SoftInstrument softins
  238. = new SoftInstrument((ModelInstrument) instrument);
  239. inslist.put(pat, softins);
  240. loadedlist.put(pat, (ModelInstrument) instrument);
  241. }
  242. }
  243. return true;
  244. }
  245. private void processPropertyInfo(Map<String, Object> info) {
  246. AudioSynthesizerPropertyInfo[] items = getPropertyInfo(info);
  247. String resamplerType = (String)items[0].value;
  248. if (resamplerType.equalsIgnoreCase("point"))
  249. {
  250. this.resampler = new SoftPointResampler();
  251. this.resamplerType = "point";
  252. }
  253. else if (resamplerType.equalsIgnoreCase("linear"))
  254. {
  255. this.resampler = new SoftLinearResampler2();
  256. this.resamplerType = "linear";
  257. }
  258. else if (resamplerType.equalsIgnoreCase("linear1"))
  259. {
  260. this.resampler = new SoftLinearResampler();
  261. this.resamplerType = "linear1";
  262. }
  263. else if (resamplerType.equalsIgnoreCase("linear2"))
  264. {
  265. this.resampler = new SoftLinearResampler2();
  266. this.resamplerType = "linear2";
  267. }
  268. else if (resamplerType.equalsIgnoreCase("cubic"))
  269. {
  270. this.resampler = new SoftCubicResampler();
  271. this.resamplerType = "cubic";
  272. }
  273. else if (resamplerType.equalsIgnoreCase("lanczos"))
  274. {
  275. this.resampler = new SoftLanczosResampler();
  276. this.resamplerType = "lanczos";
  277. }
  278. else if (resamplerType.equalsIgnoreCase("sinc"))
  279. {
  280. this.resampler = new SoftSincResampler();
  281. this.resamplerType = "sinc";
  282. }
  283. setFormat((AudioFormat)items[2].value);
  284. controlrate = (Float)items[1].value;
  285. latency = (Long)items[3].value;
  286. deviceid = (Integer)items[4].value;
  287. maxpoly = (Integer)items[5].value;
  288. reverb_on = (Boolean)items[6].value;
  289. chorus_on = (Boolean)items[7].value;
  290. agc_on = (Boolean)items[8].value;
  291. largemode = (Boolean)items[9].value;
  292. number_of_midi_channels = (Integer)items[10].value;
  293. jitter_correction = (Boolean)items[11].value;
  294. reverb_light = (Boolean)items[12].value;
  295. }
  296. private String patchToString(Patch patch) {
  297. if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion())
  298. return "p." + patch.getProgram() + "." + patch.getBank();
  299. else
  300. return patch.getProgram() + "." + patch.getBank();
  301. }
  302. private void setFormat(AudioFormat format) {
  303. if (format.getChannels() > 2) {
  304. throw new IllegalArgumentException(
  305. "Only mono and stereo audio supported.");
  306. }
  307. if (AudioFloatConverter.getConverter(format) == null)
  308. throw new IllegalArgumentException("Audio format not supported.");
  309. this.format = format;
  310. }
  311. protected void removeReceiver(Receiver recv) {
  312. boolean perform_close = false;
  313. synchronized (control_mutex) {
  314. if (recvslist.remove(recv)) {
  315. if (implicitOpen && recvslist.isEmpty())
  316. perform_close = true;
  317. }
  318. }
  319. if (perform_close)
  320. close();
  321. }
  322. protected SoftMainMixer getMainMixer() {
  323. if (!isOpen())
  324. return null;
  325. return mainmixer;
  326. }
  327. protected SoftInstrument findInstrument(int program, int bank, int channel) {
  328. // Add support for GM2 banks 0x78 and 0x79
  329. // as specified in DLS 2.2 in Section 1.4.6
  330. // which allows using percussion and melodic instruments
  331. // on all channels
  332. if (bank >> 7 == 0x78 || bank >> 7 == 0x79) {
  333. SoftInstrument current_instrument
  334. = inslist.get(program + "." + bank);
  335. if (current_instrument != null)
  336. return current_instrument;
  337. String p_plaf;
  338. if (bank >> 7 == 0x78)
  339. p_plaf = "p.";
  340. else
  341. p_plaf = "";
  342. // Instrument not found fallback to MSB:bank, LSB:0
  343. current_instrument = inslist.get(p_plaf + program + "."
  344. + ((bank & 128) << 7));
  345. if (current_instrument != null)
  346. return current_instrument;
  347. // Instrument not found fallback to MSB:0, LSB:bank
  348. current_instrument = inslist.get(p_plaf + program + "."
  349. + (bank & 128));
  350. if (current_instrument != null)
  351. return current_instrument;
  352. // Instrument not found fallback to MSB:0, LSB:0
  353. current_instrument = inslist.get(p_plaf + program + ".0");
  354. if (current_instrument != null)
  355. return current_instrument;
  356. // Instrument not found fallback to MSB:0, LSB:0, program=0
  357. current_instrument = inslist.get(p_plaf + program + "0.0");
  358. if (current_instrument != null)
  359. return current_instrument;
  360. return null;
  361. }
  362. // Channel 10 uses percussion instruments
  363. String p_plaf;
  364. if (channel == 9)
  365. p_plaf = "p.";
  366. else
  367. p_plaf = "";
  368. SoftInstrument current_instrument
  369. = inslist.get(p_plaf + program + "." + bank);
  370. if (current_instrument != null)
  371. return current_instrument;
  372. // Instrument not found fallback to MSB:0, LSB:0
  373. current_instrument = inslist.get(p_plaf + program + ".0");
  374. if (current_instrument != null)
  375. return current_instrument;
  376. // Instrument not found fallback to MSB:0, LSB:0, program=0
  377. current_instrument = inslist.get(p_plaf + "0.0");
  378. if (current_instrument != null)
  379. return current_instrument;
  380. return null;
  381. }
  382. protected int getVoiceAllocationMode() {
  383. return voice_allocation_mode;
  384. }
  385. protected int getGeneralMidiMode() {
  386. return gmmode;
  387. }
  388. protected void setGeneralMidiMode(int gmmode) {
  389. this.gmmode = gmmode;
  390. }
  391. protected int getDeviceID() {
  392. return deviceid;
  393. }
  394. protected float getControlRate() {
  395. return controlrate;
  396. }
  397. protected SoftVoice[] getVoices() {
  398. return voices;
  399. }
  400. protected SoftTuning getTuning(Patch patch) {
  401. String t_id = patchToString(patch);
  402. SoftTuning tuning = tunings.get(t_id);
  403. if (tuning == null) {
  404. tuning = new SoftTuning(patch);
  405. tunings.put(t_id, tuning);
  406. }
  407. return tuning;
  408. }
  409. public long getLatency() {
  410. synchronized (control_mutex) {
  411. return latency;
  412. }
  413. }
  414. public AudioFormat getFormat() {
  415. synchronized (control_mutex) {
  416. return format;
  417. }
  418. }
  419. public int getMaxPolyphony() {
  420. synchronized (control_mutex) {
  421. return maxpoly;
  422. }
  423. }
  424. public MidiChannel[] getChannels() {
  425. synchronized (control_mutex) {
  426. // if (external_channels == null) => the synthesizer is not open,
  427. // create 16 proxy channels
  428. // otherwise external_channels has the same length as channels array
  429. if (external_channels == null) {
  430. external_channels = new SoftChannelProxy[16];
  431. for (int i = 0; i < external_channels.length; i++)
  432. external_channels[i] = new SoftChannelProxy();
  433. }
  434. MidiChannel[] ret;
  435. if (isOpen())
  436. ret = new MidiChannel[channels.length];
  437. else
  438. ret = new MidiChannel[16];
  439. for (int i = 0; i < ret.length; i++)
  440. ret[i] = external_channels[i];
  441. return ret;
  442. }
  443. }
  444. public VoiceStatus[] getVoiceStatus() {
  445. if (!isOpen()) {
  446. VoiceStatus[] tempVoiceStatusArray
  447. = new VoiceStatus[getMaxPolyphony()];
  448. for (int i = 0; i < tempVoiceStatusArray.length; i++) {
  449. VoiceStatus b = new VoiceStatus();
  450. b.active = false;
  451. b.bank = 0;
  452. b.channel = 0;
  453. b.note = 0;
  454. b.program = 0;
  455. b.volume = 0;
  456. tempVoiceStatusArray[i] = b;
  457. }
  458. return tempVoiceStatusArray;
  459. }
  460. synchronized (control_mutex) {
  461. VoiceStatus[] tempVoiceStatusArray = new VoiceStatus[voices.length];
  462. for (int i = 0; i < voices.length; i++) {
  463. VoiceStatus a = voices[i];
  464. VoiceStatus b = new VoiceStatus();
  465. b.active = a.active;
  466. b.bank = a.bank;
  467. b.channel = a.channel;
  468. b.note = a.note;
  469. b.program = a.program;
  470. b.volume = a.volume;
  471. tempVoiceStatusArray[i] = b;
  472. }
  473. return tempVoiceStatusArray;
  474. }
  475. }
  476. public boolean isSoundbankSupported(Soundbank soundbank) {
  477. for (Instrument ins: soundbank.getInstruments())
  478. if (!(ins instanceof ModelInstrument))
  479. return false;
  480. return true;
  481. }
  482. public boolean loadInstrument(Instrument instrument) {
  483. if (instrument == null || (!(instrument instanceof ModelInstrument))) {
  484. throw new IllegalArgumentException("Unsupported instrument: " +
  485. instrument);
  486. }
  487. List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();
  488. instruments.add((ModelInstrument)instrument);
  489. return loadInstruments(instruments);
  490. }
  491. public void unloadInstrument(Instrument instrument) {
  492. if (instrument == null || (!(instrument instanceof ModelInstrument))) {
  493. throw new IllegalArgumentException("Unsupported instrument: " +
  494. instrument);
  495. }
  496. if (!isOpen())
  497. return;
  498. String pat = patchToString(instrument.getPatch());
  499. synchronized (control_mutex) {
  500. for (SoftChannel c: channels)
  501. c.current_instrument = null;
  502. inslist.remove(pat);
  503. loadedlist.remove(pat);
  504. availlist.remove(pat);
  505. }
  506. }
  507. public boolean remapInstrument(Instrument from, Instrument to) {
  508. if (from == null)
  509. throw new NullPointerException();
  510. if (to == null)
  511. throw new NullPointerException();
  512. if (!(from instanceof ModelInstrument)) {
  513. throw new IllegalArgumentException("Unsupported instrument: " +
  514. from.toString());
  515. }
  516. if (!(to instanceof ModelInstrument)) {
  517. throw new IllegalArgumentException("Unsupported instrument: " +
  518. to.toString());
  519. }
  520. if (!isOpen())
  521. return false;
  522. synchronized (control_mutex) {
  523. if (!loadedlist.containsValue(to) && !availlist.containsValue(to))
  524. throw new IllegalArgumentException("Instrument to is not loaded.");
  525. unloadInstrument(from);
  526. ModelMappedInstrument mfrom = new ModelMappedInstrument(
  527. (ModelInstrument)to, from.getPatch());
  528. return loadInstrument(mfrom);
  529. }
  530. }
  531. public synchronized Soundbank getDefaultSoundbank() {
  532. if (defaultSoundBank == null) {
  533. try {
  534. File javahome = new File(System.getProperties().getProperty(
  535. "java.home"));
  536. File libaudio = new File(new File(javahome, "lib"), "audio");
  537. if (libaudio.exists()) {
  538. File foundfile = null;
  539. File[] files = libaudio.listFiles();
  540. if (files != null) {
  541. for (int i = 0; i < files.length; i++) {
  542. File file = files[i];
  543. if (file.isFile()) {
  544. String lname = file.getName().toLowerCase();
  545. if (lname.endsWith(".sf2") ||
  546. lname.endsWith(".dls")) {
  547. if (foundfile == null || (file.length() >
  548. foundfile.length())) {
  549. foundfile = file;
  550. }
  551. }
  552. }
  553. }
  554. }
  555. if (foundfile != null) {
  556. try {
  557. Soundbank sbk = MidiSystem.getSoundbank(foundfile);
  558. defaultSoundBank = sbk;
  559. return defaultSoundBank;
  560. } catch (Exception e) {
  561. //e.printStackTrace();
  562. }
  563. }
  564. }
  565. if (System.getProperties().getProperty("os.name")
  566. .startsWith("Windows")) {
  567. File gm_dls = new File(System.getenv("SystemRoot")
  568. + "\\system32\\drivers\\gm.dls");
  569. if (gm_dls.exists()) {
  570. try {
  571. Soundbank sbk = MidiSystem.getSoundbank(gm_dls);
  572. defaultSoundBank = sbk;
  573. return defaultSoundBank;
  574. } catch (Exception e) {
  575. //e.printStackTrace();
  576. }
  577. }
  578. }
  579. } catch (AccessControlException e) {
  580. } catch (Exception e) {
  581. //e.printStackTrace();
  582. }
  583. File userhome = null;
  584. File emg_soundbank_file = null;
  585. /*
  586. * Try to load saved generated soundbank
  587. */
  588. try {
  589. userhome = new File(System.getProperty("user.home"),
  590. ".gervill");
  591. emg_soundbank_file = new File(userhome, "soundbank-emg.sf2");
  592. Soundbank sbk = MidiSystem.getSoundbank(emg_soundbank_file);
  593. defaultSoundBank = sbk;
  594. return defaultSoundBank;
  595. } catch (AccessControlException e) {
  596. } catch (Exception e) {
  597. //e.printStackTrace();
  598. }
  599. try {
  600. /*
  601. * Generate emergency soundbank
  602. */
  603. defaultSoundBank = EmergencySoundbank.createSoundbank();
  604. /*
  605. * Save generated soundbank to disk for faster future use.
  606. */
  607. if(defaultSoundBank != null)
  608. {
  609. if(!userhome.exists()) userhome.mkdirs();
  610. if(!emg_soundbank_file.exists())
  611. ((SF2Soundbank)defaultSoundBank).save(emg_soundbank_file);
  612. }
  613. } catch (Exception e) {
  614. //e.printStackTrace();
  615. }
  616. }
  617. return defaultSoundBank;
  618. }
  619. public Instrument[] getAvailableInstruments() {
  620. if (!isOpen()) {
  621. Soundbank defsbk = getDefaultSoundbank();
  622. if (defsbk == null)
  623. return new Instrument[0];
  624. return defsbk.getInstruments();
  625. }
  626. synchronized (control_mutex) {
  627. ModelInstrument[] inslist_array =
  628. new ModelInstrument[availlist.values().size()];
  629. availlist.values().toArray(inslist_array);
  630. Arrays.sort(inslist_array, new ModelInstrumentComparator());
  631. return inslist_array;
  632. }
  633. }
  634. public Instrument[] getLoadedInstruments() {
  635. if (!isOpen())
  636. return new Instrument[0];
  637. synchronized (control_mutex) {
  638. ModelInstrument[] inslist_array =
  639. new ModelInstrument[loadedlist.values().size()];
  640. loadedlist.values().toArray(inslist_array);
  641. Arrays.sort(inslist_array, new ModelInstrumentComparator());
  642. return inslist_array;
  643. }
  644. }
  645. public boolean loadAllInstruments(Soundbank soundbank) {
  646. List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();
  647. for (Instrument ins: soundbank.getInstruments()) {
  648. if (ins == null || !(ins instanceof ModelInstrument)) {
  649. throw new IllegalArgumentException(
  650. "Unsupported instrument: " + ins);
  651. }
  652. instruments.add((ModelInstrument)ins);
  653. }
  654. return loadInstruments(instruments);
  655. }
  656. public void unloadAllInstruments(Soundbank soundbank) {
  657. if (soundbank == null || !isSoundbankSupported(soundbank))
  658. throw new IllegalArgumentException("Unsupported soundbank: " + soundbank);
  659. if (!isOpen())
  660. return;
  661. for (Instrument ins: soundbank.getInstruments()) {
  662. if (ins instanceof ModelInstrument) {
  663. unloadInstrument(ins);
  664. }
  665. }
  666. }
  667. public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) {
  668. List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();
  669. for (Patch patch: patchList) {
  670. Instrument ins = soundbank.getInstrument(patch);
  671. if (ins == null || !(ins instanceof ModelInstrument)) {
  672. throw new IllegalArgumentException(
  673. "Unsupported instrument: " + ins);
  674. }
  675. instruments.add((ModelInstrument)ins);
  676. }
  677. return loadInstruments(instruments);
  678. }
  679. public void unloadInstruments(Soundbank soundbank, Patch[] patchList) {
  680. if (soundbank == null || !isSoundbankSupported(soundbank))
  681. throw new IllegalArgumentException("Unsupported soundbank: " + soundbank);
  682. if (!isOpen())
  683. return;
  684. for (Patch pat: patchList) {
  685. Instrument ins = soundbank.getInstrument(pat);
  686. if (ins instanceof ModelInstrument) {
  687. unloadInstrument(ins);
  688. }
  689. }
  690. }
  691. public MidiDevice.Info getDeviceInfo() {
  692. return info;
  693. }
  694. public AudioSynthesizerPropertyInfo[] getPropertyInfo(Map<String, Object> info) {
  695. List<AudioSynthesizerPropertyInfo> list =
  696. new ArrayList<AudioSynthesizerPropertyInfo>();
  697. AudioSynthesizerPropertyInfo item;
  698. // If info != null or synthesizer is closed
  699. // we return how the synthesizer will be set on next open
  700. // If info == null and synthesizer is open
  701. // we return current synthesizer properties.
  702. boolean o = info == null && open;
  703. item = new AudioSynthesizerPropertyInfo("interpolation", o?resamplerType:"linear");
  704. item.choices = new String[]{"linear", "linear1", "linear2", "cubic",
  705. "lanczos", "sinc", "point"};
  706. item.description = "Interpolation method";
  707. list.add(item);
  708. item = new AudioSynthesizerPropertyInfo("control rate", o?controlrate:147f);
  709. item.description = "Control rate";
  710. list.add(item);
  711. item = new AudioSynthesizerPropertyInfo("format",
  712. o?format:new AudioFormat(44100, 16, 2, true, false));
  713. item.description = "Default audio format";
  714. list.add(item);
  715. item = new AudioSynthesizerPropertyInfo("latency", o?latency:120000L);
  716. item.description = "Default latency";
  717. list.add(item);
  718. item = new AudioSynthesizerPropertyInfo("device id", o?deviceid:0);
  719. item.description = "Device ID for SysEx Messages";
  720. list.add(item);
  721. item = new AudioSynthesizerPropertyInfo("max polyphony", o?maxpoly:64);
  722. item.description = "Maximum polyphony";
  723. list.add(item);
  724. item = new AudioSynthesizerPropertyInfo("reverb", o?reverb_on:true);
  725. item.description = "Turn reverb effect on or off";
  726. list.add(item);
  727. item = new AudioSynthesizerPropertyInfo("chorus", o?chorus_on:true);
  728. item.description = "Turn chorus effect on or off";
  729. list.add(item);
  730. item = new AudioSynthesizerPropertyInfo("auto gain control", o?agc_on:true);
  731. item.description = "Turn auto gain control on or off";
  732. list.add(item);
  733. item = new AudioSynthesizerPropertyInfo("large mode", o?largemode:false);
  734. item.description = "Turn large mode on or off.";
  735. list.add(item);
  736. item = new AudioSynthesizerPropertyInfo("midi channels", o?channels.length:16);
  737. item.description = "Number of midi channels.";
  738. list.add(item);
  739. item = new AudioSynthesizerPropertyInfo("jitter correction", o?jitter_correction:true);
  740. item.description = "Turn jitter correction on or off.";
  741. list.add(item);
  742. item = new AudioSynthesizerPropertyInfo("light reverb", o?reverb_light:true);
  743. item.description = "Turn light reverb mode on or off";
  744. list.add(item);
  745. AudioSynthesizerPropertyInfo[] items;
  746. items = list.toArray(new AudioSynthesizerPropertyInfo[list.size()]);
  747. if (info != null)
  748. for (AudioSynthesizerPropertyInfo item2: items) {
  749. Object v = info.get(item2.name);
  750. Class c = (item2.valueClass);
  751. if (v != null)
  752. if (c.isInstance(v))
  753. item2.value = v;
  754. }
  755. return items;
  756. }
  757. public void open() throws MidiUnavailableException {
  758. if (isOpen()) {
  759. synchronized (control_mutex) {
  760. implicitOpen = false;
  761. }
  762. return;
  763. }
  764. open(null, null);
  765. }
  766. public void open(SourceDataLine line, Map<String, Object> info) throws MidiUnavailableException {
  767. if (isOpen()) {
  768. synchronized (control_mutex) {
  769. implicitOpen = false;
  770. }
  771. return;
  772. }
  773. synchronized (control_mutex) {
  774. Throwable causeException = null;
  775. try {
  776. if (line != null) {
  777. // can throw IllegalArgumentException
  778. setFormat(line.getFormat());
  779. }
  780. AudioInputStream ais = openStream(getFormat(), info);
  781. weakstream = new WeakAudioStream(ais);
  782. ais = weakstream.getAudioInputStream();
  783. if (line == null)
  784. {
  785. if (testline != null) {
  786. line = testline;
  787. } else {
  788. // can throw LineUnavailableException,
  789. // IllegalArgumentException, SecurityException
  790. line = AudioSystem.getSourceDataLine(getFormat());
  791. }
  792. }
  793. double latency = this.latency;
  794. if (!line.isOpen()) {
  795. int bufferSize = getFormat().getFrameSize()
  796. * (int)(getFormat().getFrameRate() * (latency/1000000f));
  797. // can throw LineUnavailableException,
  798. // IllegalArgumentException, SecurityException
  799. line.open(getFormat(), bufferSize);
  800. // Remember that we opened that line
  801. // so we can close again in SoftSynthesizer.close()
  802. sourceDataLine = line;
  803. }
  804. if (!line.isActive())
  805. line.start();
  806. int controlbuffersize = 512;
  807. try {
  808. controlbuffersize = ais.available();
  809. } catch (IOException e) {
  810. }
  811. // Tell mixer not fill read buffers fully.
  812. // This lowers latency, and tells DataPusher
  813. // to read in smaller amounts.
  814. //mainmixer.readfully = false;
  815. //pusher = new DataPusher(line, ais);
  816. int buffersize = line.getBufferSize();
  817. buffersize -= buffersize % controlbuffersize;
  818. if (buffersize < 3 * controlbuffersize)
  819. buffersize = 3 * controlbuffersize;
  820. if (jitter_correction) {
  821. ais = new SoftJitterCorrector(ais, buffersize,
  822. controlbuffersize);
  823. if(weakstream != null)
  824. weakstream.jitter_stream = ais;
  825. }
  826. pusher = new SoftAudioPusher(line, ais, controlbuffersize);
  827. pusher_stream = ais;
  828. pusher.start();
  829. if(weakstream != null)
  830. {
  831. weakstream.pusher = pusher;
  832. weakstream.sourceDataLine = sourceDataLine;
  833. }
  834. } catch (LineUnavailableException e) {
  835. causeException = e;
  836. } catch (IllegalArgumentException e) {
  837. causeException = e;
  838. } catch (SecurityException e) {
  839. causeException = e;
  840. }
  841. if (causeException != null) {
  842. if (isOpen())
  843. close();
  844. // am: need MidiUnavailableException(Throwable) ctor!
  845. MidiUnavailableException ex = new MidiUnavailableException(
  846. "Can not open line");
  847. ex.initCause(causeException);
  848. throw ex;
  849. }
  850. }
  851. }
  852. public AudioInputStream openStream(AudioFormat targetFormat,
  853. Map<String, Object> info) throws MidiUnavailableException {
  854. if (isOpen())
  855. throw new MidiUnavailableException("Synthesizer is already open");
  856. synchronized (control_mutex) {
  857. gmmode = 0;
  858. voice_allocation_mode = 0;
  859. processPropertyInfo(info);
  860. open = true;
  861. implicitOpen = false;
  862. if (targetFormat != null)
  863. setFormat(targetFormat);
  864. Soundbank defbank = getDefaultSoundbank();
  865. if (defbank != null) {
  866. loadAllInstruments(defbank);
  867. availlist.putAll(loadedlist);
  868. loadedlist.clear();
  869. }
  870. voices = new SoftVoice[maxpoly];
  871. for (int i = 0; i < maxpoly; i++)
  872. voices[i] = new SoftVoice(this);
  873. mainmixer = new SoftMainMixer(this);
  874. channels = new SoftChannel[number_of_midi_channels];
  875. for (int i = 0; i < channels.length; i++)
  876. channels[i] = new SoftChannel(this, i);
  877. if (external_channels == null) {
  878. // Always create external_channels array
  879. // with 16 or more channels
  880. // so getChannels works correctly
  881. // when the synhtesizer is closed.
  882. if (channels.length < 16)
  883. external_channels = new SoftChannelProxy[16];
  884. else
  885. external_channels = new SoftChannelProxy[channels.length];
  886. for (int i = 0; i < external_channels.length; i++)
  887. external_channels[i] = new SoftChannelProxy();
  888. } else {
  889. // We must resize external_channels array
  890. // but we must also copy the old SoftChannelProxy
  891. // into the new one
  892. if (channels.length > external_channels.length) {
  893. SoftChannelProxy[] new_external_channels
  894. = new SoftChannelProxy[channels.length];
  895. for (int i = 0; i < external_channels.length; i++)
  896. new_external_channels[i] = external_channels[i];
  897. for (int i = external_channels.length;
  898. i < new_external_channels.length; i++) {
  899. new_external_channels[i] = new SoftChannelProxy();
  900. }
  901. }
  902. }
  903. for (int i = 0; i < channels.length; i++)
  904. external_channels[i].setChannel(channels[i]);
  905. for (SoftVoice voice: getVoices())
  906. voice.resampler = resampler.openStreamer();
  907. for (Receiver recv: getReceivers()) {
  908. SoftReceiver srecv = ((SoftReceiver)recv);
  909. srecv.open = open;
  910. srecv.mainmixer = mainmixer;
  911. srecv.midimessages = mainmixer.midimessages;
  912. }
  913. return mainmixer.getInputStream();
  914. }
  915. }
  916. public void close() {
  917. if (!isOpen())
  918. return;
  919. SoftAudioPusher pusher_to_be_closed = null;
  920. AudioInputStream pusher_stream_to_be_closed = null;
  921. synchronized (control_mutex) {
  922. if (pusher != null) {
  923. pusher_to_be_closed = pusher;
  924. pusher_stream_to_be_closed = pusher_stream;
  925. pusher = null;
  926. pusher_stream = null;
  927. }
  928. }
  929. if (pusher_to_be_closed != null) {
  930. // Pusher must not be closed synchronized against control_mutex,
  931. // this may result in synchronized conflict between pusher
  932. // and current thread.
  933. pusher_to_be_closed.stop();
  934. try {
  935. pusher_stream_to_be_closed.close();
  936. } catch (IOException e) {
  937. //e.printStackTrace();
  938. }
  939. }
  940. synchronized (control_mutex) {
  941. if (mainmixer != null)
  942. mainmixer.close();
  943. open = false;
  944. implicitOpen = false;
  945. mainmixer = null;
  946. voices = null;
  947. channels = null;
  948. if (external_channels != null)
  949. for (int i = 0; i < external_channels.length; i++)
  950. external_channels[i].setChannel(null);
  951. if (sourceDataLine != null) {
  952. sourceDataLine.close();
  953. sourceDataLine = null;
  954. }
  955. inslist.clear();
  956. availlist.clear();
  957. loadedlist.clear();
  958. tunings.clear();
  959. while (recvslist.size() != 0)
  960. recvslist.get(recvslist.size() - 1).close();
  961. }
  962. }
  963. public boolean isOpen() {
  964. synchronized (control_mutex) {
  965. return open;
  966. }
  967. }
  968. public long getMicrosecondPosition() {
  969. if (!isOpen())
  970. return 0;
  971. synchronized (control_mutex) {
  972. return mainmixer.getMicrosecondPosition();
  973. }
  974. }
  975. public int getMaxReceivers() {
  976. return -1;
  977. }
  978. public int getMaxTransmitters() {
  979. return 0;
  980. }
  981. public Receiver getReceiver() throws MidiUnavailableException {
  982. synchronized (control_mutex) {
  983. SoftReceiver receiver = new SoftReceiver(this);
  984. receiver.open = open;
  985. recvslist.add(receiver);
  986. return receiver;
  987. }
  988. }
  989. public List<Receiver> getReceivers() {
  990. synchronized (control_mutex) {
  991. ArrayList<Receiver> recvs = new ArrayList<Receiver>();
  992. recvs.addAll(recvslist);
  993. return recvs;
  994. }
  995. }
  996. public Transmitter getTransmitter() throws MidiUnavailableException {
  997. throw new MidiUnavailableException("No transmitter available");
  998. }
  999. public List<Transmitter> getTransmitters() {
  1000. return new ArrayList<Transmitter>();
  1001. }
  1002. public Receiver getReceiverReferenceCounting()
  1003. throws MidiUnavailableException {
  1004. if (!isOpen()) {
  1005. open();
  1006. synchronized (control_mutex) {
  1007. implicitOpen = true;
  1008. }
  1009. }
  1010. return getReceiver();
  1011. }
  1012. public Transmitter getTransmitterReferenceCounting()
  1013. throws MidiUnavailableException {
  1014. throw new MidiUnavailableException("No transmitter available");
  1015. }
  1016. }