Mercurial > hg > sonic-annotator
comparison runner/JAMSFeatureWriter.cpp @ 145:3921e0c1f4dd jams
Start to sketch out JAMS writer
author | Chris Cannam |
---|---|
date | Mon, 13 Oct 2014 16:58:30 +0100 |
parents | |
children | db83ea0e102d |
comparison
equal
deleted
inserted
replaced
144:b3d73c08b6ce | 145:3921e0c1f4dd |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Annotator | |
5 A utility for batch feature extraction from audio files. | |
6 Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. | |
7 Copyright 2007-2014 QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "JAMSFeatureWriter.h" | |
17 | |
18 using namespace std; | |
19 using Vamp::Plugin; | |
20 using Vamp::PluginBase; | |
21 | |
22 #include "base/Exceptions.h" | |
23 #include "rdf/PluginRDFIndexer.h" | |
24 | |
25 JAMSFeatureWriter::JAMSFeatureWriter() : | |
26 FileFeatureWriter(SupportOneFilePerTrackTransform | | |
27 SupportOneFilePerTrack | | |
28 SupportStdOut, | |
29 "json"), | |
30 m_network(false), | |
31 m_networkRetrieved(false) | |
32 { | |
33 } | |
34 | |
35 JAMSFeatureWriter::~JAMSFeatureWriter() | |
36 { | |
37 } | |
38 | |
39 string | |
40 JAMSFeatureWriter::getDescription() const | |
41 { | |
42 return "Write features to JSON files in JAMS (JSON Annotated Music Specification) format."; | |
43 } | |
44 | |
45 JAMSFeatureWriter::ParameterList | |
46 JAMSFeatureWriter::getSupportedParameters() const | |
47 { | |
48 ParameterList pl = FileFeatureWriter::getSupportedParameters(); | |
49 Parameter p; | |
50 | |
51 p.name = "network"; | |
52 p.description = "Attempt to retrieve RDF descriptions of plugins from network, if not available locally"; | |
53 p.hasArg = false; | |
54 pl.push_back(p); | |
55 | |
56 return pl; | |
57 } | |
58 | |
59 void | |
60 JAMSFeatureWriter::setParameters(map<string, string> ¶ms) | |
61 { | |
62 FileFeatureWriter::setParameters(params); | |
63 | |
64 for (map<string, string>::iterator i = params.begin(); | |
65 i != params.end(); ++i) { | |
66 if (i->first == "network") { | |
67 m_network = true; | |
68 } | |
69 } | |
70 } | |
71 | |
72 void | |
73 JAMSFeatureWriter::setTrackMetadata(QString trackId, TrackMetadata metadata) | |
74 { | |
75 QString json | |
76 ("'file_metadata':" | |
77 " { 'artist': \"%1\"," | |
78 " 'title': \"%2\" }"); | |
79 m_metadata[trackId] = json.arg(metadata.maker).arg(metadata.title); | |
80 } | |
81 | |
82 void | |
83 JAMSFeatureWriter::write(QString trackId, | |
84 const Transform &transform, | |
85 const Plugin::OutputDescriptor& , | |
86 const Plugin::FeatureList& features, | |
87 std::string /* summaryType */) | |
88 { | |
89 QString transformId = transform.getIdentifier(); | |
90 | |
91 QTextStream *sptr = getOutputStream(trackId, transformId); | |
92 if (!sptr) { | |
93 throw FailedToOpenOutputStream(trackId, transformId); | |
94 } | |
95 | |
96 QTextStream &stream = *sptr; | |
97 | |
98 if (m_startedTransforms.find(transformId) == m_startedTransforms.end()) { | |
99 | |
100 identifyTask(transform); | |
101 | |
102 if (m_manyFiles || | |
103 (m_startedTracks.find(trackId) == m_startedTracks.end())) { | |
104 | |
105 // track-level preamble | |
106 stream << "{" << m_metadata[trackId] << endl; | |
107 } | |
108 | |
109 stream << "'" << getTaskKey(m_tasks[transformId]) << "':" << endl; | |
110 stream << " [ "; | |
111 } | |
112 | |
113 m_startedTracks.insert(trackId); | |
114 m_startedTransforms.insert(transformId); | |
115 | |
116 for (int i = 0; i < int(features.size()); ++i) { | |
117 | |
118 } | |
119 } | |
120 | |
121 void | |
122 JAMSFeatureWriter::loadRDFDescription(const Transform &transform) | |
123 { | |
124 QString pluginId = transform.getPluginIdentifier(); | |
125 if (m_rdfDescriptions.find(pluginId) != m_rdfDescriptions.end()) return; | |
126 | |
127 if (m_network && !m_networkRetrieved) { | |
128 PluginRDFIndexer::getInstance()->indexConfiguredURLs(); | |
129 m_networkRetrieved = true; | |
130 } | |
131 | |
132 m_rdfDescriptions[pluginId] = PluginRDFDescription(pluginId); | |
133 | |
134 if (m_rdfDescriptions[pluginId].haveDescription()) { | |
135 cerr << "NOTE: Have RDF description for plugin ID \"" | |
136 << pluginId << "\"" << endl; | |
137 } else { | |
138 cerr << "NOTE: No RDF description for plugin ID \"" | |
139 << pluginId << "\"" << endl; | |
140 if (!m_network) { | |
141 cerr << " Consider using the --json-network option to retrieve plugin descriptions" << endl; | |
142 cerr << " from the network where possible." << endl; | |
143 } | |
144 } | |
145 } | |
146 | |
147 void | |
148 JAMSFeatureWriter::identifyTask(const Transform &transform) | |
149 { | |
150 QString transformId = transform.getIdentifier(); | |
151 if (m_tasks.find(transformId) != m_tasks.end()) return; | |
152 | |
153 loadRDFDescription(transform); | |
154 | |
155 Task task = UnknownTask; | |
156 | |
157 QString pluginId = transform.getPluginIdentifier(); | |
158 QString outputId = transform.getOutput(); | |
159 | |
160 const PluginRDFDescription &desc = m_rdfDescriptions[pluginId]; | |
161 | |
162 if (desc.haveDescription()) { | |
163 | |
164 PluginRDFDescription::OutputDisposition disp = | |
165 desc.getOutputDisposition(outputId); | |
166 | |
167 QString af = "http://purl.org/ontology/af/"; | |
168 | |
169 if (disp == PluginRDFDescription::OutputSparse) { | |
170 | |
171 QString eventUri = desc.getOutputEventTypeURI(outputId); | |
172 | |
173 //!!! todo: allow user to prod writer for task type | |
174 | |
175 if (eventUri == af + "Note") { | |
176 task = NoteTask; | |
177 } else if (eventUri == af + "Beat") { | |
178 task = BeatTask; | |
179 } else if (eventUri == af + "ChordSegment") { | |
180 task = ChordTask; | |
181 } else if (eventUri == af + "KeyChange") { | |
182 task = KeyTask; | |
183 } else if (eventUri == af + "KeySegment") { | |
184 task = KeyTask; | |
185 } else if (eventUri == af + "Onset") { | |
186 task = OnsetTask; | |
187 } else if (eventUri == af + "NonTonalOnset") { | |
188 task = OnsetTask; | |
189 } else if (eventUri == af + "Segment") { | |
190 task = SegmentTask; | |
191 } else if (eventUri == af + "SpeechSegment") { | |
192 task = SegmentTask; | |
193 } else if (eventUri == af + "StructuralSegment") { | |
194 task = SegmentTask; | |
195 } else { | |
196 cerr << "WARNING: Unsupported event type URI <" | |
197 << eventUri << ">, proceeding with UnknownTask type" | |
198 << endl; | |
199 } | |
200 | |
201 } else { | |
202 | |
203 cerr << "WARNING: Cannot currently write dense or track-level outputs to JSON format (only sparse ones). Will proceed using UnknownTask type, but this probably isn't going to work" << endl; | |
204 } | |
205 } | |
206 | |
207 m_tasks[transformId] = task; | |
208 } | |
209 | |
210 QString | |
211 JAMSFeatureWriter::getTaskKey(Task task) | |
212 { | |
213 switch (task) { | |
214 case UnknownTask: return "unknown"; | |
215 case BeatTask: return "beat"; | |
216 case OnsetTask: return "onset"; | |
217 case ChordTask: return "chord"; | |
218 case SegmentTask: return "segment"; | |
219 case KeyTask: return "key"; | |
220 case NoteTask: return "note"; | |
221 case MelodyTask: return "melody"; | |
222 case PitchTask: return "pitch"; | |
223 } | |
224 return "unknown"; | |
225 } | |
226 | |
227 void | |
228 JAMSFeatureWriter::finish() | |
229 { | |
230 for (FileStreamMap::const_iterator i = m_streams.begin(); | |
231 i != m_streams.end(); ++i) { | |
232 *(i->second) << "}" << endl; | |
233 } | |
234 | |
235 FileFeatureWriter::finish(); | |
236 } | |
237 |