1 |
/*************************************************************************** |
2 |
* * |
3 |
* libgig - C++ cross-platform Gigasampler format file access library * |
4 |
* * |
5 |
* Copyright (C) 2003-2009 by Christian Schoenebeck * |
6 |
* <cuse@users.sourceforge.net> * |
7 |
* Copyright (C) 2009 by Grigor Iliev <grigor@grigoriliev.com> * |
8 |
* * |
9 |
* This program is part of libsf2. * |
10 |
* * |
11 |
* This program is free software; you can redistribute it and/or modify * |
12 |
* it under the terms of the GNU General Public License as published by * |
13 |
* the Free Software Foundation; either version 2 of the License, or * |
14 |
* (at your option) any later version. * |
15 |
* * |
16 |
* This program is distributed in the hope that it will be useful, * |
17 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
19 |
* GNU General Public License for more details. * |
20 |
* * |
21 |
* You should have received a copy of the GNU General Public License * |
22 |
* along with this program; if not, write to the Free Software * |
23 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * |
24 |
* MA 02111-1307 USA * |
25 |
***************************************************************************/ |
26 |
|
27 |
#ifdef HAVE_CONFIG_H |
28 |
#include <config.h> |
29 |
#endif |
30 |
|
31 |
#include <iostream> |
32 |
#include <cstdlib> |
33 |
#include <string> |
34 |
#include <sstream> |
35 |
|
36 |
#include "SF.h" |
37 |
#include "helper.h" |
38 |
|
39 |
using namespace std; |
40 |
|
41 |
string Revision(); |
42 |
void PrintVersion(); |
43 |
void PrintSamples(sf2::File* sf); |
44 |
void PrintInstruments(sf2::File* sf); |
45 |
void PrintPeresets(sf2::File* sf); |
46 |
void PrintRegion(int idx, sf2::Region* reg); |
47 |
void PrintModulatorItem(sf2::ModulatorItem* mod); |
48 |
void PrintModulator(sf2::Modulator& mod); |
49 |
void PrintUsage(); |
50 |
void PrintSfInfo(sf2::File* sf); |
51 |
|
52 |
string GetControllerType(sf2::Modulator& mod); |
53 |
string GetControllerSource(sf2::Modulator& mod); |
54 |
string GetSampleType(uint16_t type); |
55 |
|
56 |
template<class T> inline string GetValue(T val) { |
57 |
if (val == sf2::NONE) return "NONE"; |
58 |
return ToString(val); |
59 |
} |
60 |
|
61 |
int main(int argc, char *argv[]) |
62 |
{ |
63 |
if (argc <= 1) { |
64 |
PrintUsage(); |
65 |
return EXIT_FAILURE; |
66 |
} |
67 |
if (argv[1][0] == '-') { |
68 |
switch (argv[1][1]) { |
69 |
case 'v': |
70 |
PrintVersion(); |
71 |
return EXIT_SUCCESS; |
72 |
} |
73 |
} |
74 |
FILE* hFile = fopen(argv[1], "r"); |
75 |
if (!hFile) { |
76 |
cout << "Invalid file argument!" << endl << endl; |
77 |
void PrintUsage(); |
78 |
return EXIT_FAILURE; |
79 |
} |
80 |
fclose(hFile); |
81 |
try { |
82 |
RIFF::File* riff = new RIFF::File(argv[1]); |
83 |
sf2::File* sf = new sf2::File(riff); |
84 |
PrintSfInfo(sf); |
85 |
PrintSamples(sf); |
86 |
cout << endl; |
87 |
PrintInstruments(sf); |
88 |
PrintPeresets(sf); |
89 |
delete sf; |
90 |
delete riff; |
91 |
} |
92 |
catch (RIFF::Exception e) { |
93 |
e.PrintMessage(); |
94 |
return EXIT_FAILURE; |
95 |
} |
96 |
catch (...) { |
97 |
cout << "Unknown exception while trying to parse file." << endl; |
98 |
return EXIT_FAILURE; |
99 |
} |
100 |
|
101 |
return EXIT_SUCCESS; |
102 |
} |
103 |
|
104 |
void PrintSfInfo(sf2::File* sf) { |
105 |
cout << "File info:" << endl; |
106 |
cout << "\tVersion: " << sf->pInfo->pVer->Major << "." << sf->pInfo->pVer->Minor << endl; |
107 |
cout << "\tBank Name: " << sf->pInfo->BankName << endl; |
108 |
cout << "\tSound Engine: " << sf->pInfo->SoundEngine << endl; |
109 |
cout << "\tSound ROM Name: " << sf->pInfo->RomName << endl; |
110 |
cout << "\tSound ROM Version: " << sf->pInfo->pRomVer->Major << "." << sf->pInfo->pRomVer->Minor << endl; |
111 |
cout << "\tCreation Date: " << sf->pInfo->CreationDate << endl; |
112 |
cout << "\tEngineers: " << sf->pInfo->Engineers << endl; |
113 |
cout << "\tProduct: " << sf->pInfo->Product << endl; |
114 |
cout << "\tCopyright: " << sf->pInfo->Copyright << endl; |
115 |
cout << "\tComments: " << sf->pInfo->Comments << endl; |
116 |
cout << "\tSoftware: " << sf->pInfo->Software << endl << endl; |
117 |
} |
118 |
|
119 |
void PrintSamples(sf2::File* sf) { |
120 |
cout << "Samples (" << sf->GetSampleCount() << "): " << endl; |
121 |
for (int i = 0; i < sf->GetSampleCount(); i++) { |
122 |
sf2::Sample* s = sf->GetSample(i); |
123 |
cout << "\t" << s->Name << " (Depth: " << ((s->GetFrameSize() / s->GetChannelCount()) * 8); |
124 |
cout << ", SampleRate: " << s->SampleRate; |
125 |
cout << ", Pitch: " << ((int)s->OriginalPitch); |
126 |
cout << ", Pitch Correction: " << ((int)s->PitchCorrection )<< endl; |
127 |
cout << "\t\tStart: " << s->Start << ", End: " << s->End; |
128 |
cout << ", Start Loop: " << s->StartLoop << ", End Loop: " << s->EndLoop << endl; |
129 |
cout << "\t\tSample Type: " << GetSampleType(s->SampleType) << ", Sample Link: " << s->SampleLink << ")" << endl; |
130 |
} |
131 |
} |
132 |
|
133 |
void PrintInstruments(sf2::File* sf) { |
134 |
cout << "Instruments (" << sf->GetInstrumentCount() << "): " << endl; |
135 |
for (int i = 0; i < sf->GetInstrumentCount(); i++) { |
136 |
sf2::Instrument* instr = sf->GetInstrument(i); |
137 |
cout << "\t" << instr->Name << " ("; |
138 |
cout << "Instrument bag: " << instr->InstBagNdx << ")" << endl; |
139 |
cout << "\t Regions (" << instr->GetRegionCount() << ")" << endl; |
140 |
|
141 |
if (instr->pGlobalRegion) PrintRegion(-1, instr->pGlobalRegion); |
142 |
|
143 |
for (int j = 0; j < instr->GetRegionCount(); j++) { |
144 |
PrintRegion(j, instr->GetRegion(j)); |
145 |
} |
146 |
cout << endl; |
147 |
} |
148 |
} |
149 |
|
150 |
void PrintPeresets(sf2::File* sf) { |
151 |
cout << "Presets (" << sf->GetPresetCount() << "): " << endl; |
152 |
for (int i = 0; i < sf->GetPresetCount(); i++) { /* exclude the terminal header - EOP */ |
153 |
sf2::Preset* p = sf->GetPreset(i); |
154 |
cout << "\t" << p->Name << " (Preset: " << p->PresetNum << ", Bank: " << p->Bank; |
155 |
cout << ", Preset bag: " << p->PresetBagNdx << ")" << endl; |
156 |
|
157 |
if (p->pGlobalRegion) PrintRegion(-1, p->pGlobalRegion); |
158 |
|
159 |
for (int j = 0; j < p->GetRegionCount(); j++) { |
160 |
PrintRegion(j, p->GetRegion(j)); |
161 |
} |
162 |
cout << endl; |
163 |
} |
164 |
} |
165 |
|
166 |
void PrintRegion(int idx, sf2::Region* reg) { |
167 |
if (idx == -1) cout << "\t\tGlobal Region " << endl; |
168 |
else cout << "\t\tRegion " << idx << endl; |
169 |
sf2::Sample* s = reg->GetSample(); |
170 |
if (s != NULL) { |
171 |
cout << "\t\t Sample: " << s->Name << ", Fine Tune: " << reg->fineTune; |
172 |
if (reg->coarseTune) cout << ", Coarse Tune: " << reg->coarseTune; |
173 |
if (reg->overridingRootKey != -1) cout << ", Overriding Root Key: " << reg->overridingRootKey; |
174 |
if (reg->HasLoop) { |
175 |
cout << ", Loop Start: " << reg->LoopStart << ", Loop End: " << reg->LoopEnd; |
176 |
} |
177 |
cout << endl; |
178 |
} |
179 |
cout << "\t\t Key range="; |
180 |
if (reg->loKey == ::sf2::NONE && reg->hiKey == ::sf2::NONE) cout << "None"; |
181 |
else cout << reg->loKey << "-" << reg->hiKey; |
182 |
cout << ", Velocity range="; |
183 |
if (reg->minVel == ::sf2::NONE && reg->maxVel == ::sf2::NONE) cout << "None"; |
184 |
else cout << reg->minVel << "-" << reg->maxVel; |
185 |
cout << endl; |
186 |
|
187 |
cout << "\t\t Initial cutoff frequency="; |
188 |
if (reg->initialFilterFc == ::sf2::NONE) cout << "None" << endl; |
189 |
else cout << reg->initialFilterFc << "cents" << endl; |
190 |
|
191 |
cout << "\t\t Initial resonance="; |
192 |
if (reg->initialFilterQ == ::sf2::NONE) cout << "None" << endl; |
193 |
else cout << (reg->initialFilterQ / 10.0) << "dB" << endl; |
194 |
|
195 |
if (reg->exclusiveClass) cout << ", Exclusive group=" << reg->exclusiveClass; |
196 |
cout << endl; |
197 |
|
198 |
if (reg->pInstrument != NULL) { |
199 |
cout << "\t\t Instrument: " << reg->pInstrument->Name << endl << endl; |
200 |
} |
201 |
|
202 |
cout << "\t\t Volume Envelope Generator" << endl; |
203 |
cout << "\t\t\tEG1PreAttackDelay=" << GetValue(reg->GetEG1PreAttackDelay()); |
204 |
cout << "s, EG1Attack=" << GetValue(reg->GetEG1Attack()); |
205 |
cout << "s, EG1Hold=" << GetValue(reg->GetEG1Hold()) << "s, EG1Decay="; |
206 |
cout << GetValue(reg->GetEG1Decay()) << "s, EG1Sustain=" << GetValue(reg->GetEG1Sustain() / 10); |
207 |
cout << "dB, EG1Release=" << GetValue(reg->GetEG1Release()) << "s" << endl << endl; |
208 |
|
209 |
cout << "\t\t Modulation Envelope Generator" << endl; |
210 |
cout << "\t\t\tEG2PreAttackDelay=" << GetValue(reg->GetEG2PreAttackDelay()); |
211 |
cout << "s, EG2Attack=" << GetValue(reg->GetEG2Attack()); |
212 |
cout << "s, EG2Hold=" << GetValue(reg->GetEG2Hold()) << "s, EG2Decay="; |
213 |
cout << GetValue(reg->GetEG2Decay()) << "s, EG2Sustain="; |
214 |
cout << GetValue(reg->GetEG2Sustain()) << "permille, EG2Release="; |
215 |
cout << GetValue(reg->GetEG2Release()) << "s" << endl; |
216 |
cout << "\t\t\tPitch=" << GetValue(reg->modEnvToPitch) << "cents, Cutoff="; |
217 |
cout << GetValue(reg->modEnvToFilterFc) << "cents" << endl << endl; |
218 |
|
219 |
cout << "\t\t Modulation LFO: Delay=" << ::sf2::ToSeconds(reg->delayModLfo) << "s, Frequency="; |
220 |
cout << ::sf2::ToHz(reg->freqModLfo) << "Hz, LFO to Volume=" << (reg->modLfoToVolume / 10) << "dB"; |
221 |
cout << ", LFO to Filter Cutoff=" << reg->modLfoToFilterFc; |
222 |
cout << ", LFO to Pitch=" << reg->modLfoToPitch << endl; |
223 |
|
224 |
cout << "\t\t Vibrato LFO: Delay=" << ::sf2::ToSeconds(reg->delayVibLfo) << "s, Frequency="; |
225 |
cout << ::sf2::ToHz(reg->freqVibLfo) << "Hz, LFO to Pitch=" << reg->vibLfoToPitch << endl; |
226 |
|
227 |
cout << "\t\t\tModulators (" << reg->modulators.size() << ")" << endl; |
228 |
|
229 |
for (int i = 0; i < reg->modulators.size(); i++) { |
230 |
cout << "\t\t\tModulator " << i << endl; |
231 |
PrintModulatorItem(®->modulators[i]); |
232 |
} |
233 |
} |
234 |
|
235 |
void PrintModulatorItem(sf2::ModulatorItem* mod) { |
236 |
cout << "\t\t\t ModSrcOper" << endl; |
237 |
PrintModulator(mod->ModSrcOper); |
238 |
|
239 |
cout << "\t\t\t ModAmtSrcOper" << endl; |
240 |
PrintModulator(mod->ModAmtSrcOper); |
241 |
cout << "\t\t\t Amount: " << mod->ModAmount << endl; |
242 |
|
243 |
if (mod->ModDestOper & (1 << 15)) { |
244 |
cout << "\t\t\t ModDestOper: " << (mod->ModDestOper ^ (1 << 15)) << endl; |
245 |
} else { |
246 |
cout << "\t\t\t ModDestOper: " << mod->ModDestOper << endl; |
247 |
} |
248 |
} |
249 |
|
250 |
void PrintModulator(sf2::Modulator& mod) { |
251 |
cout << "\t\t\t\tController Type: " << GetControllerType(mod) << endl; |
252 |
cout << "\t\t\t\tController Source: " << GetControllerSource(mod) << endl; |
253 |
cout << "\t\t\t\tDirection: "; |
254 |
cout << (mod.Direction ? "max -> min" : "min -> max") << endl; |
255 |
cout << "\t\t\t\tPolarity: "; |
256 |
cout << (mod.Polarity ? "Bipolar" : "Unipolar") << endl; |
257 |
} |
258 |
|
259 |
string GetControllerType(sf2::Modulator& mod) { |
260 |
string s; |
261 |
switch(mod.Type) { |
262 |
case sf2::Modulator::LINEAR: |
263 |
s = "Linear"; break; |
264 |
case sf2::Modulator::CONCAVE: |
265 |
s = "Concave"; break; |
266 |
case sf2::Modulator::CONVEX: |
267 |
s = "Convex"; break; |
268 |
case sf2::Modulator::SWITCH: |
269 |
s = "Switch"; break; |
270 |
} |
271 |
|
272 |
return s; |
273 |
} |
274 |
|
275 |
string GetControllerSource(sf2::Modulator& mod) { |
276 |
if (mod.MidiPalete) { |
277 |
stringstream ss; |
278 |
ss << "MIDI controller " << mod.Index; |
279 |
return ss.str(); |
280 |
} |
281 |
|
282 |
string s; |
283 |
switch(mod.Index) { |
284 |
case sf2::Modulator::NO_CONTROLLER: |
285 |
s = "No controller"; break; |
286 |
case sf2::Modulator::NOTE_ON_VELOCITY: |
287 |
s = "Note-On Velocity"; break; |
288 |
case sf2::Modulator::NOTE_ON_KEY_NUMBER: |
289 |
s = "Note-On Key Number"; break; |
290 |
case sf2::Modulator::POLY_PRESSURE: |
291 |
s = "Poly Pressure"; break; |
292 |
case sf2::Modulator::CHANNEL_PRESSURE: |
293 |
s = "Channel Pressure"; break; |
294 |
case sf2::Modulator::PITCH_WHEEL: |
295 |
s = "Pitch Wheel"; break; |
296 |
case sf2::Modulator::PITCH_WHEEL_SENSITIVITY: |
297 |
s = "Pitch Wheel Sensitivity"; break; |
298 |
case sf2::Modulator::LINK: |
299 |
s = "Link"; break; |
300 |
default: s = "Unknown controller source"; |
301 |
} |
302 |
|
303 |
return s; |
304 |
} |
305 |
|
306 |
string Revision() { |
307 |
string s = "$Revision$"; |
308 |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
309 |
} |
310 |
|
311 |
void PrintVersion() { |
312 |
cout << "sf2dump revision " << Revision() << endl; |
313 |
cout << "using " << sf2::libraryName() << " " << sf2::libraryVersion() << endl; |
314 |
} |
315 |
|
316 |
void PrintUsage() { |
317 |
cout << "sf2dump - parses SF2 files and prints out the content." << endl; |
318 |
cout << endl; |
319 |
cout << "Usage: sf2dump [-v] FILE" << endl; |
320 |
cout << endl; |
321 |
cout << " -v Print version and exit." << endl; |
322 |
cout << endl; |
323 |
} |
324 |
|
325 |
string GetSampleType(uint16_t type) { |
326 |
switch(type) { |
327 |
case sf2::Sample::MONO_SAMPLE : return "Mono Sample"; |
328 |
case sf2::Sample::RIGHT_SAMPLE : return "Right Sample"; |
329 |
case sf2::Sample::LEFT_SAMPLE : return "Left Sample"; |
330 |
case sf2::Sample::LINKED_SAMPLE : return "Linked Sample"; |
331 |
case sf2::Sample::ROM_MONO_SAMPLE : return "ROM Mono Sample"; |
332 |
case sf2::Sample::ROM_RIGHT_SAMPLE : return "ROM Right Sample"; |
333 |
case sf2::Sample::ROM_LEFT_SAMPLE : return "ROM Left Sample"; |
334 |
case sf2::Sample::ROM_LINKED_SAMPLE : return "ROM Linked Sample"; |
335 |
default: return "Unknown"; |
336 |
} |
337 |
} |