PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

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

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