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 "inputparsergrandorgue.h"
26 #include "soundfontmanager.h"
27 #include "grandorguerank.h"
28 #include "grandorguestop.h"
29 #include "grandorguedatathrough.h"
30
InputParserGrandOrgue()31 InputParserGrandOrgue::InputParserGrandOrgue() : AbstractInputParser(),
32 _godt(new GrandOrgueDataThrough())
33 {
34
35 }
36
~InputParserGrandOrgue()37 InputParserGrandOrgue::~InputParserGrandOrgue()
38 {
39 while (!_ranks.empty())
40 delete _ranks.take(_ranks.firstKey());
41 while (!_stops.empty())
42 delete _stops.take(_stops.firstKey());
43 delete _godt;
44 }
45
processInternal(QString fileName,SoundfontManager * sm,bool & success,QString & error,int & sf2Index,QString & tempFilePath)46 void InputParserGrandOrgue::processInternal(QString fileName, SoundfontManager * sm, bool &success, QString &error, int &sf2Index, QString &tempFilePath)
47 {
48 Q_UNUSED(sm)
49 Q_UNUSED(tempFilePath)
50
51 // Initialization
52 _currentSection = SECTION_UNKNOWN;
53 _currentIndex = -1;
54 _ranks.clear();
55 _stops.clear();
56
57 // Parse the file
58 _rootDir = QFileInfo(fileName).dir().path();
59 if (_rootDir.endsWith('/'))
60 _rootDir = _rootDir.left(_rootDir.size() - 1);
61 parseFile(fileName, success, error);
62 if (!success)
63 return;
64
65 // Create a sf2
66 createSf2(sf2Index, fileName);
67 success = true;
68 }
69
parseFile(QString filename,bool & success,QString & error)70 void InputParserGrandOrgue::parseFile(QString filename, bool &success, QString &error)
71 {
72 // Open the file
73 QFile inputFile(filename);
74 if (!inputFile.open(QIODevice::ReadOnly))
75 {
76 success = false;
77 error = tr("Cannot open file \"%1\"").arg(filename);
78 return;
79 }
80
81 QTextStream in(&inputFile);
82 while (!in.atEnd())
83 {
84 // Read one line, skip empty lines or comments
85 QString line = in.readLine();
86
87 // Remove comments
88 int tmp;
89 if ((tmp = line.indexOf(';')) != -1)
90 {
91 line = line.left(tmp);
92 }
93
94 // Trim the line and skip it if empty
95 line = line.trimmed();
96 if (line.isEmpty())
97 continue;
98
99 if (line.startsWith("[") && line.endsWith("]"))
100 {
101 // New section
102 startSection(line.mid(1, line.length() - 2).toLower());
103 }
104 else
105 {
106 // Process data
107 tmp = line.indexOf('=');
108 QString key = line.left(tmp).trimmed().toLower();
109 QString value = line.right(line.length() - tmp - 1).trimmed().replace('\\', '/');
110 if (!key.isEmpty() && !value.isEmpty())
111 processData(key, value);
112 }
113 }
114 inputFile.close();
115
116 success = true;
117 }
118
startSection(QString sectionName)119 void InputParserGrandOrgue::startSection(QString sectionName)
120 {
121 // Track ranks and stops
122 if (sectionName.startsWith("rank"))
123 {
124 bool ok = false;
125 _currentIndex = sectionName.right(sectionName.length() - 4).toInt(&ok);
126 if (!ok)
127 {
128 _currentSection = SECTION_UNKNOWN;
129 _currentIndex = -1;
130 }
131 else
132 _currentSection = SECTION_RANK;
133 }
134 else if (sectionName.startsWith("stop"))
135 {
136 bool ok = false;
137 _currentIndex = sectionName.right(sectionName.length() - 4).toInt(&ok);
138 if (!ok)
139 {
140 _currentSection = SECTION_UNKNOWN;
141 _currentIndex = -1;
142 }
143 else
144 _currentSection = SECTION_STOP;
145 }
146 else if (sectionName == "organ")
147 {
148 _currentSection = SECTION_ORGAN;
149 _currentIndex = -1;
150 }
151 else
152 _currentSection = SECTION_UNKNOWN;
153 }
154
processData(QString key,QString value)155 void InputParserGrandOrgue::processData(QString key, QString value)
156 {
157 switch (_currentSection)
158 {
159 case SECTION_RANK:
160 if (_currentIndex != -1)
161 {
162 if (!_ranks.contains(_currentIndex))
163 _ranks[_currentIndex] = new GrandOrgueRank(_rootDir, _godt, _currentIndex);
164 _ranks[_currentIndex]->readData(key, value);
165 }
166 break;
167 case SECTION_STOP:
168 if (_currentIndex != -1)
169 {
170 if (!_stops.contains(_currentIndex))
171 _stops[_currentIndex] = new GrandOrgueStop(_rootDir, _godt, _currentIndex);
172 _stops[_currentIndex]->readData(key, value);
173 }
174 break;
175 case SECTION_ORGAN:
176 _organProperties[key] = value;
177 break;
178 case SECTION_UNKNOWN:
179 // Nothing
180 break;
181 }
182 }
183
createSf2(int & sf2Index,QString filename)184 void InputParserGrandOrgue::createSf2(int &sf2Index, QString filename)
185 {
186 // Create a new soundfont, store the sf2 index
187 SoundfontManager * sm = SoundfontManager::getInstance();
188 EltID idSf2(elementSf2, -1, -1, -1, -1);
189 idSf2.indexSf2 = sm->add(idSf2);
190 sf2Index = idSf2.indexSf2;
191
192 // Title, comment
193 QFileInfo fileInfo(filename);
194 sm->set(idSf2, champ_name, fileInfo.completeBaseName());
195 sm->set(idSf2, champ_ICMT, this->getComment());
196
197 // Pre-process everything
198 foreach (GrandOrgueRank * rank, _ranks)
199 rank->preProcess();
200 foreach (GrandOrgueStop * stop, _stops)
201 stop->preProcess();
202 _godt->finalizePreprocess();
203
204 // Process stops for creating presets and instruments
205 foreach (GrandOrgueStop * stop, _stops)
206 stop->process(sm, sf2Index, _ranks);
207 }
208
getComment()209 QString InputParserGrandOrgue::getComment()
210 {
211 QString comment = "";
212 if (_organProperties.contains("churchname"))
213 comment = "Church name: " + _organProperties["churchname"];
214 if (_organProperties.contains("churchaddress"))
215 comment += (comment.isEmpty() ? QString("") : "\n") +
216 "Church address: " + _organProperties["churchaddress"];
217 if (_organProperties.contains("organbuilder"))
218 comment += (comment.isEmpty() ? QString("") : "\n") +
219 "Organ builder: " + _organProperties["organbuilder"];
220 if (_organProperties.contains("organbuilddate"))
221 comment += (comment.isEmpty() ? QString("") : "\n") +
222 "Organ build date: " + _organProperties["organbuilddate"];
223 if (_organProperties.contains("organcomments"))
224 comment += (comment.isEmpty() ? QString("") : "\n") +
225 "Organ comments: " + _organProperties["organcomments"];
226 if (_organProperties.contains("recordingdetails"))
227 comment += (comment.isEmpty() ? QString("") : "\n") +
228 "Recording details: " + _organProperties["recordingdetails"];
229 return comment;
230 }
231