1 | /*
|
---|
2 | * AudioDBWrapper.java
|
---|
3 | * Copyright (C) 2011 New Zealand Digital Library, http://www.nzdl.org
|
---|
4 | *
|
---|
5 | * This program is free software; you can redistribute it and/or modify
|
---|
6 | * it under the terms of the GNU General Public License as published by
|
---|
7 | * the Free Software Foundation; either version 2 of the License, or
|
---|
8 | * (at your option) any later version.
|
---|
9 | *
|
---|
10 | * This program is distributed in the hope that it will be useful,
|
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
13 | * GNU General Public License for more details.
|
---|
14 | *
|
---|
15 | * You should have received a copy of the GNU General Public License
|
---|
16 | * along with this program; if not, write to the Free Software
|
---|
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
18 | */
|
---|
19 | package org.greenstone.gsdl3.util;
|
---|
20 |
|
---|
21 | import java.io.*;
|
---|
22 | import java.util.Vector;
|
---|
23 | import java.util.Collections;
|
---|
24 |
|
---|
25 | import org.apache.log4j.*;
|
---|
26 |
|
---|
27 | /** java wrapper class for access to the audioDB executable
|
---|
28 | *
|
---|
29 | * Inspired by MGSearchWrapper.java
|
---|
30 | */
|
---|
31 |
|
---|
32 | public class AudioDBWrapper
|
---|
33 | {
|
---|
34 | /** the query result, filled in by runQuery */
|
---|
35 | protected Vector query_result_;
|
---|
36 |
|
---|
37 | protected int offset_ = 100;
|
---|
38 | protected int length_ = 20;
|
---|
39 |
|
---|
40 | // Approximate matching not yet utilized
|
---|
41 | protected double radius_;
|
---|
42 |
|
---|
43 | protected int max_docs_;
|
---|
44 |
|
---|
45 | static Logger logger = Logger.getLogger (org.greenstone.gsdl3.util.AudioDBWrapper.class.getName ());
|
---|
46 |
|
---|
47 | public AudioDBWrapper() {
|
---|
48 | query_result_ = null;
|
---|
49 | }
|
---|
50 |
|
---|
51 | // query param methods
|
---|
52 |
|
---|
53 | /** start point (offset) into the array of feature vectors for a track
|
---|
54 | - 100 by default which equals 10 seconds (assuming 0.1 frame size) */
|
---|
55 | public void setOffset(int offset) {
|
---|
56 | offset_ = offset;
|
---|
57 | }
|
---|
58 |
|
---|
59 | /** the number of consecutive frames used in match
|
---|
60 | - 20 by default which equals 2 seconds (assuming 0.1 frame size) */
|
---|
61 | public void setLength(int length) {
|
---|
62 | length_ = length;
|
---|
63 | }
|
---|
64 |
|
---|
65 | /** distance used in approximate matching support - default is 50 */
|
---|
66 | public void setRadius(double radius) {
|
---|
67 | radius_ = radius;
|
---|
68 | }
|
---|
69 |
|
---|
70 | public void setMaxDocs(int max_docs) {
|
---|
71 | max_docs_ = max_docs;
|
---|
72 | }
|
---|
73 |
|
---|
74 | /** returns a string with all the current query param settings */
|
---|
75 | // the following was in MG version, do we need this in audioDB version?
|
---|
76 | //public String getQueryParams() {}
|
---|
77 |
|
---|
78 |
|
---|
79 | protected boolean addQueryResult(boolean first_entry, String doc_id,
|
---|
80 | Vector<Double> rankVector, Vector<Integer> offsetVector)
|
---|
81 | {
|
---|
82 |
|
---|
83 | if (first_entry) {
|
---|
84 | AudioDBDocInfo audioDB_doc_info = new AudioDBDocInfo(doc_id,rankVector,offsetVector);
|
---|
85 | query_result_.add(audioDB_doc_info);
|
---|
86 | first_entry = false;
|
---|
87 | }
|
---|
88 | else {
|
---|
89 | double rank = rankVector.get(0);
|
---|
90 | int offset = offsetVector.get(0);
|
---|
91 | AudioDBDocInfo audioDB_doc_info = new AudioDBDocInfo(doc_id,rank,offset);
|
---|
92 |
|
---|
93 | query_result_.add(audioDB_doc_info);
|
---|
94 | }
|
---|
95 |
|
---|
96 | return first_entry;
|
---|
97 | }
|
---|
98 |
|
---|
99 |
|
---|
100 | /** actually carry out the query.
|
---|
101 | Use the set methods to set query results.
|
---|
102 | Writes the result to query_result.
|
---|
103 | * - maintains state between requests as can be slow
|
---|
104 | * base_dir and index_path should join together to provide
|
---|
105 | * the absolute location of the mg index files eg ..../index/dtx/demo
|
---|
106 | * base_dir must end with a file separator (OS dependant)
|
---|
107 | */
|
---|
108 | public void runQuery(String audioDB_index_dir, String adb_file,
|
---|
109 | String assoc_index_dir, String query_string) {
|
---|
110 |
|
---|
111 | // combine index_dir with audiodb fileanem
|
---|
112 |
|
---|
113 | String full_adb_filename = audioDB_index_dir + File.separatorChar + adb_file;
|
---|
114 | String full_chr12_filename = assoc_index_dir + File.separatorChar
|
---|
115 | + query_string + File.separatorChar + "doc.chr12";
|
---|
116 |
|
---|
117 | int num_matches_within_track = 6;
|
---|
118 |
|
---|
119 | String [] cmd_array = new String[] {
|
---|
120 | "audioDB",
|
---|
121 | "-d", full_adb_filename,
|
---|
122 | "-Q", "nsequence",
|
---|
123 | "-p", String.format("%d",offset_),
|
---|
124 | "-n", String.format("%d",num_matches_within_track),
|
---|
125 | "-l", String.format("%d",length_),
|
---|
126 | "-r", String.format("%d",max_docs_),
|
---|
127 | "-f", full_chr12_filename
|
---|
128 | };
|
---|
129 |
|
---|
130 | System.err.println("**** cmd_array = " + String.join(" ", cmd_array));
|
---|
131 |
|
---|
132 | Runtime runtime = Runtime.getRuntime();
|
---|
133 | try {
|
---|
134 | Process audioDB_proc = runtime.exec(cmd_array);
|
---|
135 | //int exitVal = audioDB_proc.waitFor();
|
---|
136 | //System.err.println("*** exit status = " + exitVal);
|
---|
137 |
|
---|
138 | InputStream ais = audioDB_proc.getInputStream();
|
---|
139 | InputStreamReader aisr = new InputStreamReader(ais);
|
---|
140 | BufferedReader abr = new BufferedReader(aisr);
|
---|
141 |
|
---|
142 | query_result_ = new Vector();
|
---|
143 |
|
---|
144 | boolean first_entry = true;
|
---|
145 | int line_count = 0;
|
---|
146 |
|
---|
147 | String root_doc_id = null;
|
---|
148 | Vector<Double> rankVector = new Vector<Double>();
|
---|
149 | Vector<Integer> offsetVector = new Vector<Integer>();
|
---|
150 |
|
---|
151 | // Example output
|
---|
152 | // D8 0.00105175
|
---|
153 | // 1.69786e-16 392 392
|
---|
154 | // 0.00113568 392 673
|
---|
155 | // 0.00127239 392 910
|
---|
156 | // 0.00139736 392 481
|
---|
157 | // 0.00145331 392 303
|
---|
158 | // D2 0.00429758
|
---|
159 | // 0.00403335 392 865
|
---|
160 | // 0.00411288 392 458
|
---|
161 | // 0.00442461 392 866
|
---|
162 | // 0.00444272 392 864
|
---|
163 | // 0.00447434 392 424
|
---|
164 | // ...
|
---|
165 |
|
---|
166 | String line;
|
---|
167 | while ((line = abr.readLine()) != null) {
|
---|
168 | String[] tokens = line.split("\\s+");
|
---|
169 | line_count++;
|
---|
170 |
|
---|
171 | if (tokens.length==2) {
|
---|
172 | // processing a top-level doc line
|
---|
173 |
|
---|
174 | if (line_count>1) {
|
---|
175 | // struck new top-level entry => store vector vals for previous block
|
---|
176 |
|
---|
177 | first_entry = addQueryResult(first_entry,root_doc_id,rankVector,offsetVector);
|
---|
178 | // and now reset vectors to empty to be ready for next chain of values
|
---|
179 | rankVector = new Vector<Double>();
|
---|
180 | offsetVector = new Vector<Integer>();
|
---|
181 | }
|
---|
182 |
|
---|
183 | root_doc_id = tokens[0];
|
---|
184 | }
|
---|
185 | else {
|
---|
186 | // should be 3 items
|
---|
187 | double euclidean_dist = Double.parseDouble(tokens[0]);
|
---|
188 | int src_frame = Integer.parseInt(tokens[1]);
|
---|
189 | int target_frame = Integer.parseInt(tokens[2]);
|
---|
190 |
|
---|
191 | // enforce 1.0 as upper limit due to rounding errors
|
---|
192 | // in audioDB distance calculations
|
---|
193 | double rank = Math.min(1.0 - euclidean_dist,1.0);
|
---|
194 |
|
---|
195 | if ((line_count==2) && (src_frame==target_frame)) {
|
---|
196 | // Found match with self
|
---|
197 | continue;
|
---|
198 | }
|
---|
199 |
|
---|
200 | rankVector.add(rank);
|
---|
201 | offsetVector.add(target_frame);
|
---|
202 | }
|
---|
203 |
|
---|
204 | }
|
---|
205 |
|
---|
206 | addQueryResult(first_entry,root_doc_id,rankVector,offsetVector);
|
---|
207 |
|
---|
208 | abr.close();
|
---|
209 |
|
---|
210 | // sort query_result_ on 'rank' field
|
---|
211 | // note: compareTo() method impelemented to sort into descending order
|
---|
212 |
|
---|
213 | Collections.sort(query_result_);
|
---|
214 |
|
---|
215 |
|
---|
216 | }
|
---|
217 | catch (Exception e) {
|
---|
218 | logger.error("Failed to execute the following command: " + cmd);
|
---|
219 | e.printStackTrace();
|
---|
220 | }
|
---|
221 |
|
---|
222 | }
|
---|
223 |
|
---|
224 |
|
---|
225 | /** get the result out of the wrapper */
|
---|
226 | public Vector getQueryResult()
|
---|
227 | {
|
---|
228 | return query_result_;
|
---|
229 | }
|
---|
230 | }
|
---|
231 |
|
---|