1 /***************************************************************************
2 ** **
3 ** Polyphone, a soundfont editor **
4 ** Copyright (C) 2013-2020 Davy Triponney **
5 ** **
6 ** This program is free software: you can redistribute it and/or modify **
7 ** it under the terms of the GNU General Public License as published by **
8 ** the Free Software Foundation, either version 3 of the License, or **
9 ** (at your option) any later version. **
10 ** **
11 ** This program is distributed in the hope that it will be useful, **
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of **
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
14 ** GNU General Public License for more details. **
15 ** **
16 ** You should have received a copy of the GNU General Public License **
17 ** along with this program. If not, see http://www.gnu.org/licenses/. **
18 ** **
19 ****************************************************************************
20 ** Author: Davy Triponney **
21 ** Website/Contact: https://www.polyphone-soundfonts.com **
22 ** Date: 01.01.2013 **
23 ***************************************************************************/
24
25 #include "inputparsersf2.h"
26 #include "soundfontmanager.h"
27 #include <QFile>
28 #include <QDataStream>
29 #include "sf2header.h"
30 #include "sf2sdtapart.h"
31 #include "sf2pdtapart.h"
32
InputParserSf2()33 InputParserSf2::InputParserSf2() : AbstractInputParser() {}
34
processInternal(QString fileName,SoundfontManager * sm,bool & success,QString & error,int & sf2Index,QString & tempFilePath)35 void InputParserSf2::processInternal(QString fileName, SoundfontManager * sm, bool &success, QString &error, int &sf2Index, QString &tempFilePath)
36 {
37 Q_UNUSED(tempFilePath)
38
39 // Keep the variables
40 _sm = sm;
41 _filename = fileName;
42
43 // Open the file
44 QFile fi(fileName);
45 if (!fi.exists())
46 {
47 success = false;
48 error = tr("Cannot find file \"%1\".").arg(fileName);
49 return;
50 }
51
52 if (!fi.open(QIODevice::ReadOnly))
53 {
54 success = false;
55 error = tr("Access denied for reading file \"%1\".").arg(fileName);
56 return;
57 }
58
59 // Parse the file
60 QDataStream stream(&fi);
61 this->parse(stream, success, error, sf2Index);
62 fi.close();
63 }
64
parse(QDataStream & stream,bool & success,QString & error,int & sf2Index)65 void InputParserSf2::parse(QDataStream &stream, bool &success, QString &error, int &sf2Index)
66 {
67 // Parse the different parts of the file
68 Sf2Header header;
69 Sf2SdtaPart sdtaPart;
70 Sf2PdtaPart pdtaPart;
71 stream >> header >> sdtaPart >> pdtaPart;
72
73 if (!header._isValid)
74 {
75 success = false;
76 error = "invalid header";
77 return;
78 }
79
80 if (!sdtaPart._isValid)
81 {
82 success = false;
83 error = "corrupted file (sdta)";
84 return;
85 }
86
87 if (!pdtaPart._isValid)
88 {
89 success = false;
90 error = "corrupted file (pdta)";
91 return;
92 }
93
94 fillSf2(header, sdtaPart, pdtaPart, success, error, sf2Index);
95 }
96
fillSf2(Sf2Header & header,Sf2SdtaPart & sdtaPart,Sf2PdtaPart & pdtaPart,bool & success,QString & error,int & sf2Index)97 void InputParserSf2::fillSf2(Sf2Header &header, Sf2SdtaPart &sdtaPart, Sf2PdtaPart &pdtaPart, bool &success, QString &error, int &sf2Index)
98 {
99 Q_UNUSED(error)
100
101 // Create a new soundfont
102 sf2Index = _sm->add(EltID(elementSf2));
103 EltID id(elementSf2, sf2Index);
104
105 /// General data
106
107 _sm->set(id, champ_ISNG, header.getInfo("isng"));
108 _sm->set(id, champ_name, header.getInfo("INAM"));
109 _sm->set(id, champ_IROM, header.getInfo("irom"));
110 _sm->set(id, champ_ICRD, header.getInfo("ICRD"));
111 _sm->set(id, champ_IENG, header.getInfo("IENG"));
112 _sm->set(id, champ_IPRD, header.getInfo("IPRD"));
113 _sm->set(id, champ_ICOP, header.getInfo("ICOP"));
114 _sm->set(id, champ_ICMT, header.getInfo("ICMT"));
115 _sm->set(id, champ_ISFT, header.getInfo("ISFT"));
116 AttributeValue value;
117 value.sfVerValue = header.getVersion("ifil");
118 _sm->set(id, champ_IFIL, value);
119 value.sfVerValue = header.getVersion("iver");
120 _sm->set(id, champ_IVER, value);
121
122 // Mode 16 ou 24 bits au chargement
123 if (sdtaPart._startSm24Offset > 0)
124 {
125 value.wValue = 24;
126 _sm->set(id, champ_wBpsInit, value);
127 _sm->set(id, champ_wBpsSave, value);
128 }
129 else
130 {
131 value.wValue = 16;
132 _sm->set(id, champ_wBpsInit, value);
133 _sm->set(id, champ_wBpsSave, value);
134 }
135
136 /// Samples
137
138 id = EltID(elementSmpl, sf2Index);
139 for (int i = 0; i < pdtaPart._shdrs.count() - 1; i++) // Terminal sample (EOS) is not read
140 {
141 Sf2PdtaPart_shdr SHDR = pdtaPart._shdrs[i];
142
143 id.indexElt = _sm->add(id);
144 _sm->set(id, champ_name, SHDR._name);
145
146 // Sample properties
147 value.bValue = SHDR._originalPitch;
148 _sm->set(id, champ_byOriginalPitch, value);
149 value.cValue = SHDR._correction;
150 _sm->set(id, champ_chPitchCorrection, value);
151 value.wValue = SHDR._wSampleLink.value;
152 _sm->set(id, champ_wSampleLink, value);
153 value.sfLinkValue = (SFSampleLink)SHDR._sfSampleType.value;
154 _sm->set(id, champ_sfSampleType, value);
155 value.wValue = 1;
156 _sm->set(id, champ_wChannel, value);
157 value.dwValue = SHDR._sampleRate.value;
158 _sm->set(id, champ_dwSampleRate, value);
159 _sm->set(id, champ_filenameForData, _filename);
160
161 // Start / end / length of the sample
162 value.dwValue = SHDR._end.value - SHDR._start.value;
163 _sm->set(id, champ_dwLength, value);
164 value.dwValue = SHDR._start.value * 2 + (20 + header._infoSize.value + sdtaPart._startSmplOffset);
165 _sm->set(id, champ_dwStart16, value);
166 if (sdtaPart._startSm24Offset > 0)
167 {
168 value.dwValue = SHDR._start.value + sdtaPart._startSm24Offset;
169 _sm->set(id, champ_dwStart24, value);
170 value.wValue = 24;
171 _sm->set(id, champ_bpsFile, value);
172 }
173 else
174 {
175 value.dwValue = 0;
176 _sm->set(id, champ_dwStart24, value);
177 value.wValue = 16;
178 _sm->set(id, champ_bpsFile, value);
179 }
180
181 // Loop
182 value.dwValue = SHDR._startLoop.value - SHDR._start.value;
183 _sm->set(id, champ_dwStartLoop, value);
184 value.dwValue = SHDR._endLoop.value - SHDR._start.value;
185 _sm->set(id, champ_dwEndLoop, value);
186 }
187
188 /// Instruments
189
190 EltID id2;
191 id = EltID(elementInst, sf2Index);
192 id2.indexSf2 = sf2Index;
193 quint16 bagmin, bagmax, modmin, modmax, genmin, genmax;
194 int l, global;
195 for (int i = 0; i < pdtaPart._insts.count() - 1; i++) // Terminal instrument (EOI) is not read
196 {
197 Sf2PdtaPart_inst inst = pdtaPart._insts[i];
198
199 l = 0;
200 id.indexElt = _sm->add(id);
201 id2.indexElt = id.indexElt;
202 _sm->set(id, champ_name, inst._name.trimmed());
203
204 // Indexes
205 bagmin = inst._iBagIndex.value;
206 bagmax = pdtaPart._insts[i + 1]._iBagIndex.value;
207
208 // Foreach ibag
209 for (int j = bagmin; j < bagmax; j++)
210 {
211 Sf2PdtaPart_bag bag = pdtaPart._ibags[j];
212
213 // Indexes of IMOD and IGEN
214 modmin = bag._modIndex.value;
215 genmin = bag._genIndex.value;
216 if (j < pdtaPart._ibags.count() - 1)
217 {
218 modmax = pdtaPart._ibags[j + 1]._modIndex.value;
219 genmax = pdtaPart._ibags[j + 1]._genIndex.value;
220 }
221 else
222 {
223 modmax = pdtaPart._imods.count();
224 genmax = pdtaPart._igens.count();
225 }
226
227 // Global zone?
228 global = 1;
229 for (int k = genmin; k < genmax; k++)
230 if (pdtaPart._igens[k]._sfGenOper.value == champ_sampleID)
231 global = 0;
232 id2.indexElt2 = -1;
233
234 // Parameters
235 if (global)
236 id2.typeElement = elementInst;
237 else
238 {
239 // Add a sample to an instrument
240 id2.typeElement = elementInstSmpl;
241 id2.indexElt2 = _sm->add(id2);
242 }
243 for (int k = genmin; k < genmax; k++)
244 {
245 value.wValue = pdtaPart._igens[k]._genAmount.value;
246 _sm->set(id2, (AttributeType)pdtaPart._igens[k]._sfGenOper.value, value);
247 }
248
249 // Modulators
250 for (unsigned int k = modmin; k < modmax; k++)
251 {
252 id2.indexMod = -1;
253 if (global)
254 {
255 // Add a mod to an instrument
256 id2.typeElement = elementInstMod;
257 id2.indexMod = _sm->add(id2);
258 }
259 else
260 {
261 // Add a mod to a sample linked to an instrument
262 id2.typeElement = elementInstSmplMod;
263 id2.indexMod = _sm->add(id2);
264 }
265
266 Sf2PdtaPart_mod mod = pdtaPart._imods[k];
267 value.sfModValue = mod._sfModSrcOper;
268 _sm->set(id2, champ_sfModSrcOper, value);
269 value.wValue = mod._sfModDestOper.value;
270 _sm->set(id2, champ_sfModDestOper, value);
271 value.shValue = mod._modAmount.value;
272 _sm->set(id2, champ_modAmount, value);
273 value.sfModValue = mod._sfModAmtSrcOper;
274 _sm->set(id2, champ_sfModAmtSrcOper, value);
275 value.sfTransValue = (SFTransform)mod._sfModTransOper.value;
276 _sm->set(id2, champ_sfModTransOper, value);
277 value.wValue = l;
278 _sm->set(id2, champ_indexMod, value);
279 l++;
280 }
281 }
282 }
283
284 /// Presets
285
286 id.typeElement = elementPrst;
287 id.indexSf2 = sf2Index;
288 id.indexElt = -1;
289 for (int i = 0; i < pdtaPart._phdrs.count() - 1; i++) // Terminal preset (EOP) is not read
290 {
291 Sf2PdtaPart_phdr prst = pdtaPart._phdrs[i];
292
293 l = 0;
294 id.indexElt = _sm->add(id);
295 id2.indexElt = id.indexElt;
296 _sm->set(id, champ_name, prst._name.trimmed());
297 value.wValue = prst._preset.value;
298 _sm->set(id, champ_wPreset, value);
299 value.wValue = prst._bank.value;
300 _sm->set(id, champ_wBank, value);
301 value.dwValue = prst._library.value;
302 _sm->set(id, champ_dwLibrary, value);
303 value.dwValue = prst._genre.value;
304 _sm->set(id, champ_dwGenre, value);
305 value.dwValue = prst._morphology.value;
306 _sm->set(id, champ_dwMorphology, value);
307
308 // Indexes
309 bagmin = prst._pBagIndex.value;
310 bagmax = pdtaPart._phdrs[i + 1]._pBagIndex.value;
311
312 // Foreach pbag
313 for (int j = bagmin; j < bagmax; j++)
314 {
315 Sf2PdtaPart_bag bag = pdtaPart._pbags[j];
316
317 // Indexes of PMOD and PGEN
318 modmin = bag._modIndex.value;
319 genmin = bag._genIndex.value;
320 if (j < pdtaPart._pbags.count() - 1)
321 {
322 modmax = pdtaPart._pbags[j + 1]._modIndex.value;
323 genmax = pdtaPart._pbags[j + 1]._genIndex.value;
324 }
325 else
326 {
327 modmax = pdtaPart._pmods.count();
328 genmax = pdtaPart._pgens.count();
329 }
330
331 // Global zone?
332 global = 1;
333 for (int k = genmin; k < genmax; k++)
334 if (pdtaPart._pgens[k]._sfGenOper.value == champ_instrument)
335 global = 0;
336
337 // Parameters
338 id2.indexElt2 = -1;
339 if (global)
340 id2.typeElement = elementPrst;
341 else
342 {
343 // Add an instrument to a preset
344 id2.typeElement = elementPrstInst;
345 id2.indexElt2 = _sm->add(id2);
346 }
347 for (int k = genmin; k < genmax; k++)
348 {
349 value.wValue = pdtaPart._pgens[k]._genAmount.value;
350 _sm->set(id2, (AttributeType)pdtaPart._pgens[k]._sfGenOper.value, value);
351 }
352
353 // Modulators
354 for (int k = modmin; k < modmax; k++)
355 {
356 id2.indexMod = -1;
357 if (global)
358 {
359 // Add a mod to a preset
360 id2.typeElement = elementPrstMod;
361 id2.indexMod = _sm->add(id2);
362 }
363 else
364 {
365 // Add a mod to an instrument linked to a preset
366 id2.typeElement = elementPrstInstMod;
367 id2.indexMod = _sm->add(id2);
368 }
369
370 Sf2PdtaPart_mod mod = pdtaPart._pmods[k];
371 value.sfModValue = mod._sfModSrcOper;
372 _sm->set(id2, champ_sfModSrcOper, value);
373 value.wValue = mod._sfModDestOper.value;
374 _sm->set(id2, champ_sfModDestOper, value);
375 value.shValue = mod._modAmount.value;
376 _sm->set(id2, champ_modAmount, value);
377 value.sfModValue = mod._sfModAmtSrcOper;
378 _sm->set(id2, champ_sfModAmtSrcOper, value);
379 value.sfTransValue = (SFTransform)mod._sfModTransOper.value;
380 _sm->set(id2, champ_sfModTransOper, value);
381 value.wValue = l;
382 _sm->set(id2, champ_indexMod, value);
383 l++;
384 }
385 }
386 }
387
388 success = true;
389 }
390