1 /*
   2  * Copyright (c) 2007, 2013, 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 
  27 import java.io.File;
  28 import java.io.FileInputStream;
  29 import java.io.BufferedInputStream;
  30 import java.io.FileInputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.io.OutputStream;
  34 import java.util.HashMap;
  35 import java.util.Map;
  36 
  37 import javax.sound.sampled.*;
  38 import javax.sound.midi.*;
  39 
  40 import com.sun.media.sound.*;
  41 
  42 public class TestRender1 {
  43 
  44     public static double send(Sequence seq, Receiver recv) {
  45         float divtype = seq.getDivisionType();
  46         assert (seq.getDivisionType() == Sequence.PPQ);
  47         Track[] tracks = seq.getTracks();
  48         int[] trackspos = new int[tracks.length];
  49         int mpq = 60000000 / 100;
  50         int seqres = seq.getResolution();
  51         long lasttick = 0;
  52         long curtime = 0;
  53         while (true) {
  54             MidiEvent selevent = null;
  55             int seltrack = -1;
  56             for (int i = 0; i < tracks.length; i++) {
  57                 int trackpos = trackspos[i];
  58                 Track track = tracks[i];
  59                 if (trackpos < track.size()) {
  60                     MidiEvent event = track.get(trackpos);
  61                     if (selevent == null
  62                             || event.getTick() < selevent.getTick()) {
  63                         selevent = event;
  64                         seltrack = i;
  65                     }
  66                 }
  67             }
  68             if (seltrack == -1)
  69                 break;
  70             trackspos[seltrack]++;
  71             long tick = selevent.getTick();
  72             if (divtype == Sequence.PPQ)
  73                 curtime += ((tick - lasttick) * mpq) / seqres;
  74             else
  75                 curtime = (long) ((tick * 1000000.0 * divtype) / seqres);
  76             lasttick = tick;
  77             MidiMessage msg = selevent.getMessage();
  78             if (msg instanceof MetaMessage) {
  79                 if (divtype == Sequence.PPQ)
  80                     if (((MetaMessage) msg).getType() == 0x51) {
  81                         byte[] data = ((MetaMessage) msg).getData();
  82                         mpq = ((data[0] & 0xff) << 16)
  83                                 | ((data[1] & 0xff) << 8) | (data[2] & 0xff);
  84                     }
  85             } else {
  86                 if (recv != null)
  87                     recv.send(msg, curtime);
  88             }
  89         }
  90 
  91         return curtime / 1000000.0;
  92     }
  93 
  94     public static void test(AudioFormat format, Map<String, Object> info)
  95             throws Exception {
  96         OutputStream nullout = new OutputStream() {
  97             public void write(int b) throws IOException {
  98             }
  99 
 100             public void write(byte[] b, int off, int len) throws IOException {
 101             }
 102 
 103             public void write(byte[] b) throws IOException {
 104             }
 105         };
 106         render(nullout, format, info);
 107     }
 108 
 109     public static void render(OutputStream os, AudioFormat format,
 110             Map<String, Object> info) throws Exception {
 111         AudioSynthesizer synth = (AudioSynthesizer) new SoftSynthesizer();
 112         AudioInputStream stream = synth.openStream(format, info);
 113         Receiver recv = synth.getReceiver();
 114         Soundbank defsbk = synth.getDefaultSoundbank();
 115         if (defsbk != null)
 116             synth.unloadAllInstruments(defsbk);
 117         synth.loadAllInstruments(soundbank);
 118 
 119         double totalTime = 5;
 120         send(sequence, recv);
 121 
 122         long len = (long) (stream.getFormat().getFrameRate() * (totalTime + 4));
 123         stream = new AudioInputStream(stream, stream.getFormat(), len);
 124 
 125         long t = System.currentTimeMillis();
 126         AudioSystem.write(stream, AudioFileFormat.Type.WAVE, os);
 127         t = System.currentTimeMillis() - t;
 128         stream.close();
 129     }
 130 
 131 
 132     static Soundbank soundbank;
 133 
 134     static Sequence sequence;
 135 
 136     public static InputStream getInputStream(String filename) throws IOException
 137     {
 138         File file = new File(System.getProperty("test.src", "."), filename);
 139         FileInputStream fis = new FileInputStream(file);
 140         return new BufferedInputStream(fis);
 141     }
 142 
 143     public static void main(String[] args) throws Exception {
 144 
 145         InputStream sb = getInputStream("ding.sf2");
 146         soundbank = MidiSystem.getSoundbank(sb);
 147         sb.close();
 148 
 149         InputStream si = getInputStream("expresso.mid");
 150         sequence = MidiSystem.getSequence(si);
 151         si.close();
 152 
 153         AudioFormat format;
 154         Map<String, Object> info = new HashMap<String, Object>();
 155         {
 156             format = new AudioFormat(22050, 16, 2, true, false);
 157             test(format, info);
 158             format = new AudioFormat(44100, 16, 2, true, false);
 159             test(format, info);
 160         }
 161         {
 162             format = new AudioFormat(44100, 8, 2, true, false);
 163             test(format, info);
 164             format = new AudioFormat(44100, 16, 2, true, false);
 165             test(format, info);
 166             format = new AudioFormat(44100, 24, 2, true, false);
 167             test(format, info);
 168         }
 169         {
 170             format = new AudioFormat(44100, 16, 1, true, false);
 171             test(format, info);
 172             format = new AudioFormat(44100, 16, 2, true, false);
 173             test(format, info);
 174         }
 175         {
 176             format = new AudioFormat(44100, 16, 2, true, false);
 177 
 178             info.clear();
 179             info.put("control rate", 100f);
 180             test(format, info);
 181             info.clear();
 182             info.put("control rate", 147f);
 183             test(format, info);
 184 
 185         }
 186         {
 187             format = new AudioFormat(44100, 16, 2, true, false);
 188 
 189             info.clear();
 190             info.put("interpolation", "point");
 191             test(format, info);
 192             info.clear();
 193             info.put("interpolation", "linear");
 194             test(format, info);
 195             info.clear();
 196             info.put("interpolation", "cubic");
 197             test(format, info);
 198         }
 199         {
 200             format = new AudioFormat(44100, 16, 2, true, false);
 201             info.clear();
 202             info.put("max polyphony", 4);
 203             test(format, info);
 204             info.clear();
 205             info.put("max polyphony", 16);
 206             test(format, info);
 207             info.clear();
 208 
 209         }
 210 
 211     }
 212 }