annotate host/host.java @ 55:2b8e1416327d tip

Just change a couple of include guards
author Chris Cannam
date Wed, 16 Nov 2016 09:12:46 +0000
parents aadf45ed0d40
children
rev   line source
Chris@37 1 /*
Chris@37 2 jVamp
Chris@37 3
Chris@37 4 A Java host interface for Vamp audio analysis plugins
Chris@37 5
Chris@37 6 Centre for Digital Music, Queen Mary, University of London.
Chris@37 7 Copyright 2012 Chris Cannam and QMUL.
Chris@37 8
Chris@37 9 Permission is hereby granted, free of charge, to any person
Chris@37 10 obtaining a copy of this software and associated documentation
Chris@37 11 files (the "Software"), to deal in the Software without
Chris@37 12 restriction, including without limitation the rights to use, copy,
Chris@37 13 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@37 14 of the Software, and to permit persons to whom the Software is
Chris@37 15 furnished to do so, subject to the following conditions:
Chris@37 16
Chris@37 17 The above copyright notice and this permission notice shall be
Chris@37 18 included in all copies or substantial portions of the Software.
Chris@37 19
Chris@37 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@37 21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@37 22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@37 23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@37 24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@37 25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@37 26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@37 27
Chris@37 28 Except as contained in this notice, the names of the Centre for
Chris@37 29 Digital Music; Queen Mary, University of London; and Chris Cannam
Chris@37 30 shall not be used in advertising or otherwise to promote the sale,
Chris@37 31 use or other dealings in this Software without prior written
Chris@37 32 authorization.
Chris@37 33 */
Chris@31 34
Chris@43 35 import java.util.List;
Chris@31 36 import java.util.TreeMap;
Chris@31 37 import java.util.Map;
Chris@31 38 import java.util.List;
Chris@31 39 import java.lang.RuntimeException;
Chris@31 40
Chris@31 41 import org.vamp_plugins.PluginLoader;
Chris@31 42 import org.vamp_plugins.Plugin;
Chris@31 43 import org.vamp_plugins.ParameterDescriptor;
Chris@31 44 import org.vamp_plugins.OutputDescriptor;
Chris@31 45 import org.vamp_plugins.Feature;
Chris@31 46 import org.vamp_plugins.RealTime;
Chris@31 47
Chris@31 48 import javax.sound.sampled.AudioSystem;
Chris@31 49 import javax.sound.sampled.AudioInputStream;
Chris@31 50 import javax.sound.sampled.AudioFormat;
Chris@31 51 import javax.sound.sampled.UnsupportedAudioFileException;
Chris@31 52
Chris@31 53 import java.io.File;
Chris@31 54 import java.io.IOException;
Chris@31 55
Chris@31 56 public class host
Chris@31 57 {
Chris@31 58 private static void printFeatures(RealTime frameTime, Integer output,
Chris@43 59 Map<Integer, List<Feature>> features)
Chris@31 60 {
Chris@31 61 if (!features.containsKey(output)) return;
Chris@31 62
Chris@31 63 for (Feature f : features.get(output)) {
Chris@31 64 if (f.hasTimestamp) {
Chris@31 65 System.out.print(f.timestamp);
Chris@31 66 } else {
Chris@31 67 System.out.print(frameTime);
Chris@31 68 }
Chris@31 69 if (f.hasDuration) {
Chris@31 70 System.out.print("," + f.duration);
Chris@31 71 }
Chris@31 72 System.out.print(":");
Chris@31 73 for (float v : f.values) {
Chris@31 74 System.out.print(" " + v);
Chris@31 75 }
Chris@31 76 System.out.print(" " + f.label);
Chris@31 77 System.out.println("");
Chris@31 78 }
Chris@31 79 }
Chris@31 80
Chris@31 81 private static void usage() {
Chris@31 82 System.err.println("Usage: host pluginlibrary:plugin:output file.wav");
Chris@31 83 }
Chris@31 84
Chris@31 85 private static int readBlock(AudioFormat format, AudioInputStream stream,
Chris@31 86 float[][] buffers)
Chris@31 87 throws java.io.IOException
Chris@31 88 {
Chris@31 89 // 16-bit LE signed PCM only
Chris@31 90 int channels = format.getChannels();
Chris@31 91 byte[] raw = new byte[buffers[0].length * channels * 2];
Chris@31 92 int read = stream.read(raw);
Chris@31 93 if (read < 0) return read;
Chris@31 94 int frames = read / (channels * 2);
Chris@31 95 for (int i = 0; i < frames; ++i) {
Chris@31 96 for (int c = 0; c < channels; ++c) {
Chris@31 97 int ix = i * channels + c;
Chris@31 98 int ival = (raw[ix*2] & 0xff) | (raw[ix*2 + 1] << 8);
Chris@31 99 float fval = ival / 32768.0f;
Chris@31 100 buffers[c][i] = fval;
Chris@31 101 }
Chris@31 102 }
Chris@31 103 return frames;
Chris@31 104 }
Chris@31 105
Chris@31 106 public static void main(String[] args)
Chris@31 107 {
Chris@31 108 if (args.length < 2) {
Chris@31 109 usage();
Chris@31 110 return;
Chris@31 111 }
Chris@31 112
Chris@31 113 PluginLoader loader = PluginLoader.getInstance();
Chris@31 114
Chris@31 115 String key = args[0];
Chris@31 116 String filename = args[1];
Chris@31 117
Chris@31 118 String[] keyparts = key.split(":");
Chris@31 119 if (keyparts.length < 3) {
Chris@31 120 usage();
Chris@31 121 return;
Chris@31 122 }
Chris@31 123
Chris@31 124 String pluginKey = keyparts[0] + ":" + keyparts[1];
Chris@31 125 String outputKey = keyparts[2];
Chris@31 126
Chris@31 127 try {
Chris@31 128 File f = new File(filename);
Chris@31 129 AudioInputStream stream = AudioSystem.getAudioInputStream(f);
Chris@31 130 AudioFormat format = stream.getFormat();
Chris@31 131
Chris@31 132 if (format.getSampleSizeInBits() != 16 ||
Chris@31 133 format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED ||
Chris@31 134 format.isBigEndian()) {
Chris@31 135 System.err.println("Sorry, only 16-bit signed little-endian PCM files supported");
Chris@31 136 return;
Chris@31 137 }
Chris@31 138
Chris@31 139 float rate = format.getFrameRate();
Chris@31 140 int channels = format.getChannels();
Chris@31 141 int bytesPerFrame = format.getFrameSize();
Chris@31 142 int blockSize = 1024; // frames
Chris@31 143
Chris@31 144 Plugin p = loader.loadPlugin
Chris@31 145 (pluginKey, rate, PluginLoader.AdapterFlags.ADAPT_ALL);
Chris@31 146
Chris@31 147 OutputDescriptor[] outputs = p.getOutputDescriptors();
Chris@31 148 int outputNumber = -1;
Chris@31 149 for (int i = 0; i < outputs.length; ++i) {
Chris@31 150 if (outputs[i].identifier.equals(outputKey)) outputNumber = i;
Chris@31 151 }
Chris@31 152 if (outputNumber < 0) {
Chris@31 153 System.err.println("Plugin lacks output id: " + outputKey);
Chris@31 154 System.err.print("Outputs are:");
Chris@31 155 for (int i = 0; i < outputs.length; ++i) {
Chris@31 156 System.err.print(" " + outputs[i].identifier);
Chris@31 157 }
Chris@31 158 System.err.println("");
Chris@31 159 return;
Chris@31 160 }
Chris@31 161
Chris@31 162 boolean b = p.initialise(channels, blockSize, blockSize);
Chris@31 163 if (!b) {
Chris@31 164 System.err.println("Plugin initialise failed");
Chris@31 165 return;
Chris@31 166 }
Chris@31 167
Chris@31 168 float[][] buffers = new float[channels][blockSize];
Chris@31 169
Chris@31 170 boolean done = false;
Chris@31 171 boolean incomplete = false;
Chris@31 172 int block = 0;
Chris@31 173
Chris@31 174 while (!done) {
Chris@31 175
Chris@31 176 for (int c = 0; c < channels; ++c) {
Chris@31 177 for (int i = 0; i < blockSize; ++i) {
Chris@31 178 buffers[c][i] = 0.0f;
Chris@31 179 }
Chris@31 180 }
Chris@31 181
Chris@31 182 int read = readBlock(format, stream, buffers);
Chris@31 183
Chris@31 184 if (read < 0) {
Chris@31 185 done = true;
Chris@31 186 } else {
Chris@31 187
Chris@31 188 if (incomplete) {
Chris@31 189 // An incomplete block is only OK if it's the
Chris@31 190 // last one -- so if the previous block was
Chris@31 191 // incomplete, we have trouble
Chris@31 192 System.err.println("Audio file read incomplete! Short buffer detected at " + block * blockSize);
Chris@31 193 return;
Chris@31 194 }
Chris@31 195
Chris@31 196 incomplete = (read < buffers[0].length);
Chris@31 197
Chris@31 198 RealTime timestamp = RealTime.frame2RealTime
Chris@31 199 (block * blockSize, (int)(rate + 0.5));
Chris@31 200
Chris@43 201 Map<Integer, List<Feature>>
Chris@31 202 features = p.process(buffers, timestamp);
Chris@31 203
Chris@31 204 printFeatures(timestamp, outputNumber, features);
Chris@31 205 }
Chris@31 206
Chris@31 207 ++block;
Chris@31 208 }
Chris@31 209
Chris@43 210 Map<Integer, List<Feature>>
Chris@31 211 features = p.getRemainingFeatures();
Chris@31 212
Chris@31 213 RealTime timestamp = RealTime.frame2RealTime
Chris@31 214 (block * blockSize, (int)(rate + 0.5));
Chris@31 215 printFeatures(timestamp, outputNumber, features);
Chris@31 216
Chris@31 217 p.dispose();
Chris@31 218
Chris@31 219 } catch (java.io.IOException e) {
Chris@31 220 System.err.println("Failed to read audio file: " + e.getMessage());
Chris@31 221
Chris@31 222 } catch (javax.sound.sampled.UnsupportedAudioFileException e) {
Chris@31 223 System.err.println("Unsupported audio file format: " + e.getMessage());
Chris@31 224
Chris@31 225 } catch (PluginLoader.LoadFailedException e) {
Chris@31 226 System.err.println("Plugin load failed (unknown plugin?): key is " +
Chris@31 227 key);
Chris@31 228 }
Chris@31 229 }
Chris@31 230 }
Chris@31 231