1 /*
   2  * Copyright (c) 2007, 2015, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  @summary Test SoftSynthesizer simple note rendering in many settings 
  26  @modules java.desktop/com.sun.media.sound
  27 */
  28 
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.BufferedInputStream;
  32 import java.io.FileInputStream;
  33 import java.io.IOException;
  34 import java.io.InputStream;
  35 import java.io.OutputStream;
  36 import java.util.HashMap;
  37 import java.util.Map;
  38 
  39 import javax.sound.sampled.*;
  40 import javax.sound.midi.*;
  41 
  42 import com.sun.media.sound.*;
  43 
  44 public class TestRender1 {
  45 
  46     public static double send(Sequence seq, Receiver recv) {
  47         float divtype = seq.getDivisionType();
  48         assert (seq.getDivisionType() == Sequence.PPQ);
  49         Track[] tracks = seq.getTracks();
  50         int[] trackspos = new int[tracks.length];
  51         int mpq = 60000000 / 100;
  52         int seqres = seq.getResolution();
  53         long lasttick = 0;
  54         long curtime = 0;
  55         while (true) {
  56             MidiEvent selevent = null;
  57             int seltrack = -1;
  58             for (int i = 0; i < tracks.length; i++) {
  59                 int trackpos = trackspos[i];
  60                 Track track = tracks[i];
  61                 if (trackpos < track.size()) {
  62                     MidiEvent event = track.get(trackpos);
  63                     if (selevent == null
  64                             || event.getTick() < selevent.getTick()) {
  65                         selevent = event;
  66                         seltrack = i;
  67                     }
  68                 }
  69             }
  70             if (seltrack == -1)
  71                 break;
  72             trackspos[seltrack]++;
  73             long tick = selevent.getTick();
  74             if (divtype == Sequence.PPQ)
  75                 curtime += ((tick - lasttick) * mpq) / seqres;
  76             else
  77                 curtime = (long) ((tick * 1000000.0 * divtype) / seqres);
  78             lasttick = tick;
  79             MidiMessage msg = selevent.getMessage();
  80             if (msg instanceof MetaMessage) {
  81                 if (divtype == Sequence.PPQ)
  82                     if (((MetaMessage) msg).getType() == 0x51) {
  83                         byte[] data = ((MetaMessage) msg).getData();
  84                         mpq = ((data[0] & 0xff) << 16)
  85                                 | ((data[1] & 0xff) << 8) | (data[2] & 0xff);
  86                     }
  87             } else {
  88                 if (recv != null)
  89                     recv.send(msg, curtime);
  90             }
  91         }
  92 
  93         return curtime / 1000000.0;
  94     }
  95 
  96     public static void test(AudioFormat format, Map<String, Object> info)
  97             throws Exception {
  98         OutputStream nullout = new OutputStream() {
  99             public void write(int b) throws IOException {
 100             }
 101 
 102             public void write(byte[] b, int off, int len) throws IOException {
 103             }
 104 
 105             public void write(byte[] b) throws IOException {
 106             }
 107         };
 108         render(nullout, format, info);
 109     }
 110 
 111     public static void render(OutputStream os, AudioFormat format,
 112             Map<String, Object> info) throws Exception {
 113         AudioSynthesizer synth = (AudioSynthesizer) new SoftSynthesizer();
 114         AudioInputStream stream = synth.openStream(format, info);
 115         Receiver recv = synth.getReceiver();
 116         Soundbank defsbk = synth.getDefaultSoundbank();
 117         if (defsbk != null)
 118             synth.unloadAllInstruments(defsbk);
 119         synth.loadAllInstruments(soundbank);
 120 
 121         double totalTime = 5;
 122         send(sequence, recv);
 123 
 124         long len = (long) (stream.getFormat().getFrameRate() * (totalTime + 4));
 125         stream = new AudioInputStream(stream, stream.getFormat(), len);
 126 
 127         long t = System.currentTimeMillis();
 128         AudioSystem.write(stream, AudioFileFormat.Type.WAVE, os);
 129         t = System.currentTimeMillis() - t;
 130         stream.close();
 131     }
 132 
 133 
 134     static Soundbank soundbank;
 135 
 136     static Sequence sequence;
 137 
 138     public static InputStream getInputStream(String filename) throws IOException
 139     {
 140         File file = new File(System.getProperty("test.src", "."), filename);
 141         FileInputStream fis = new FileInputStream(file);
 142         return new BufferedInputStream(fis);
 143     }
 144 
 145     public static void main(String[] args) throws Exception {
 146 
 147         InputStream sb = getInputStream("ding.sf2");
 148         soundbank = MidiSystem.getSoundbank(sb);
 149         sb.close();
 150 
 151         InputStream si = getInputStream("expresso.mid");
 152         sequence = MidiSystem.getSequence(si);
 153         si.close();
 154 
 155         AudioFormat format;
 156         Map<String, Object> info = new HashMap<String, Object>();
 157         {
 158             format = new AudioFormat(22050, 16, 2, true, false);
 159             test(format, info);
 160             format = new AudioFormat(44100, 16, 2, true, false);
 161             test(format, info);
 162         }
 163         {
 164             format = new AudioFormat(44100, 8, 2, true, false);
 165             test(format, info);
 166             format = new AudioFormat(44100, 16, 2, true, false);
 167             test(format, info);
 168             format = new AudioFormat(44100, 24, 2, true, false);
 169             test(format, info);
 170         }
 171         {
 172             format = new AudioFormat(44100, 16, 1, true, false);
 173             test(format, info);
 174             format = new AudioFormat(44100, 16, 2, true, false);
 175             test(format, info);
 176         }
 177         {
 178             format = new AudioFormat(44100, 16, 2, true, false);
 179 
 180             info.clear();
 181             info.put("control rate", 100f);
 182             test(format, info);
 183             info.clear();
 184             info.put("control rate", 147f);
 185             test(format, info);
 186 
 187         }
 188         {
 189             format = new AudioFormat(44100, 16, 2, true, false);
 190 
 191             info.clear();
 192             info.put("interpolation", "point");
 193             test(format, info);
 194             info.clear();
 195             info.put("interpolation", "linear");
 196             test(format, info);
 197             info.clear();
 198             info.put("interpolation", "cubic");
 199             test(format, info);
 200         }
 201         {
 202             format = new AudioFormat(44100, 16, 2, true, false);
 203             info.clear();
 204             info.put("max polyphony", 4);
 205             test(format, info);
 206             info.clear();
 207             info.put("max polyphony", 16);
 208             test(format, info);
 209             info.clear();
 210 
 211         }
 212 
 213     }
 214 }