PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/share/classes/com/sun/media/sound/SoftSynthesizer.java

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