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