Mercurial > hg > jvamp
comparison host/host.java @ 31:d8ff8c5ad52a
Add host program, working like a minimal version of vamp-simple-host
author | Chris Cannam |
---|---|
date | Thu, 22 Nov 2012 14:31:23 +0000 |
parents | |
children | c9515589be7d |
comparison
equal
deleted
inserted
replaced
30:02db37c2301b | 31:d8ff8c5ad52a |
---|---|
1 | |
2 import java.util.ArrayList; | |
3 import java.util.TreeMap; | |
4 import java.util.Map; | |
5 import java.util.List; | |
6 import java.lang.RuntimeException; | |
7 | |
8 import org.vamp_plugins.PluginLoader; | |
9 import org.vamp_plugins.Plugin; | |
10 import org.vamp_plugins.ParameterDescriptor; | |
11 import org.vamp_plugins.OutputDescriptor; | |
12 import org.vamp_plugins.Feature; | |
13 import org.vamp_plugins.RealTime; | |
14 | |
15 import javax.sound.sampled.AudioSystem; | |
16 import javax.sound.sampled.AudioInputStream; | |
17 import javax.sound.sampled.AudioFormat; | |
18 import javax.sound.sampled.UnsupportedAudioFileException; | |
19 | |
20 import java.io.File; | |
21 import java.io.IOException; | |
22 | |
23 public class host | |
24 { | |
25 private static void printFeatures(RealTime frameTime, Integer output, | |
26 Map<Integer, ArrayList<Feature>> features) | |
27 { | |
28 if (!features.containsKey(output)) return; | |
29 | |
30 for (Feature f : features.get(output)) { | |
31 if (f.hasTimestamp) { | |
32 System.out.print(f.timestamp); | |
33 } else { | |
34 System.out.print(frameTime); | |
35 } | |
36 if (f.hasDuration) { | |
37 System.out.print("," + f.duration); | |
38 } | |
39 System.out.print(":"); | |
40 for (float v : f.values) { | |
41 System.out.print(" " + v); | |
42 } | |
43 System.out.print(" " + f.label); | |
44 System.out.println(""); | |
45 } | |
46 } | |
47 | |
48 private static void usage() { | |
49 System.err.println("Usage: host pluginlibrary:plugin:output file.wav"); | |
50 } | |
51 | |
52 private static int readBlock(AudioFormat format, AudioInputStream stream, | |
53 float[][] buffers) | |
54 throws java.io.IOException | |
55 { | |
56 // 16-bit LE signed PCM only | |
57 int channels = format.getChannels(); | |
58 byte[] raw = new byte[buffers[0].length * channels * 2]; | |
59 int read = stream.read(raw); | |
60 if (read < 0) return read; | |
61 int frames = read / (channels * 2); | |
62 for (int i = 0; i < frames; ++i) { | |
63 for (int c = 0; c < channels; ++c) { | |
64 int ix = i * channels + c; | |
65 int ival = (raw[ix*2] & 0xff) | (raw[ix*2 + 1] << 8); | |
66 float fval = ival / 32768.0f; | |
67 buffers[c][i] = fval; | |
68 } | |
69 } | |
70 return frames; | |
71 } | |
72 | |
73 public static void main(String[] args) | |
74 { | |
75 if (args.length < 2) { | |
76 usage(); | |
77 return; | |
78 } | |
79 | |
80 PluginLoader loader = PluginLoader.getInstance(); | |
81 | |
82 String key = args[0]; | |
83 String filename = args[1]; | |
84 | |
85 String[] keyparts = key.split(":"); | |
86 if (keyparts.length < 3) { | |
87 usage(); | |
88 return; | |
89 } | |
90 | |
91 String pluginKey = keyparts[0] + ":" + keyparts[1]; | |
92 String outputKey = keyparts[2]; | |
93 | |
94 try { | |
95 File f = new File(filename); | |
96 AudioInputStream stream = AudioSystem.getAudioInputStream(f); | |
97 AudioFormat format = stream.getFormat(); | |
98 | |
99 if (format.getSampleSizeInBits() != 16 || | |
100 format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED || | |
101 format.isBigEndian()) { | |
102 System.err.println("Sorry, only 16-bit signed little-endian PCM files supported"); | |
103 return; | |
104 } | |
105 | |
106 float rate = format.getFrameRate(); | |
107 int channels = format.getChannels(); | |
108 int bytesPerFrame = format.getFrameSize(); | |
109 int blockSize = 1024; // frames | |
110 | |
111 Plugin p = loader.loadPlugin | |
112 (pluginKey, rate, PluginLoader.AdapterFlags.ADAPT_ALL); | |
113 | |
114 OutputDescriptor[] outputs = p.getOutputDescriptors(); | |
115 int outputNumber = -1; | |
116 for (int i = 0; i < outputs.length; ++i) { | |
117 if (outputs[i].identifier.equals(outputKey)) outputNumber = i; | |
118 } | |
119 if (outputNumber < 0) { | |
120 System.err.println("Plugin lacks output id: " + outputKey); | |
121 System.err.print("Outputs are:"); | |
122 for (int i = 0; i < outputs.length; ++i) { | |
123 System.err.print(" " + outputs[i].identifier); | |
124 } | |
125 System.err.println(""); | |
126 return; | |
127 } | |
128 | |
129 boolean b = p.initialise(channels, blockSize, blockSize); | |
130 if (!b) { | |
131 System.err.println("Plugin initialise failed"); | |
132 return; | |
133 } | |
134 | |
135 float[][] buffers = new float[channels][blockSize]; | |
136 | |
137 boolean done = false; | |
138 boolean incomplete = false; | |
139 int block = 0; | |
140 | |
141 while (!done) { | |
142 | |
143 for (int c = 0; c < channels; ++c) { | |
144 for (int i = 0; i < blockSize; ++i) { | |
145 buffers[c][i] = 0.0f; | |
146 } | |
147 } | |
148 | |
149 int read = readBlock(format, stream, buffers); | |
150 | |
151 if (read < 0) { | |
152 done = true; | |
153 } else { | |
154 | |
155 if (incomplete) { | |
156 // An incomplete block is only OK if it's the | |
157 // last one -- so if the previous block was | |
158 // incomplete, we have trouble | |
159 System.err.println("Audio file read incomplete! Short buffer detected at " + block * blockSize); | |
160 return; | |
161 } | |
162 | |
163 incomplete = (read < buffers[0].length); | |
164 | |
165 RealTime timestamp = RealTime.frame2RealTime | |
166 (block * blockSize, (int)(rate + 0.5)); | |
167 | |
168 TreeMap<Integer, ArrayList<Feature>> | |
169 features = p.process(buffers, timestamp); | |
170 | |
171 printFeatures(timestamp, outputNumber, features); | |
172 | |
173 timestamp.dispose(); | |
174 } | |
175 | |
176 ++block; | |
177 } | |
178 | |
179 TreeMap<Integer, ArrayList<Feature>> | |
180 features = p.getRemainingFeatures(); | |
181 | |
182 RealTime timestamp = RealTime.frame2RealTime | |
183 (block * blockSize, (int)(rate + 0.5)); | |
184 printFeatures(timestamp, outputNumber, features); | |
185 timestamp.dispose(); | |
186 | |
187 p.dispose(); | |
188 | |
189 } catch (java.io.IOException e) { | |
190 System.err.println("Failed to read audio file: " + e.getMessage()); | |
191 | |
192 } catch (javax.sound.sampled.UnsupportedAudioFileException e) { | |
193 System.err.println("Unsupported audio file format: " + e.getMessage()); | |
194 | |
195 } catch (PluginLoader.LoadFailedException e) { | |
196 System.err.println("Plugin load failed (unknown plugin?): key is " + | |
197 key); | |
198 } | |
199 } | |
200 } | |
201 |